From 27f5f5b55e13e482dce5b1c527148308e98a7ee8 Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 02:37:58 +0800 Subject: [PATCH 01/14] upgrade lwip to 2.2.1 Signed-off-by: HuangHaitao --- 0001-add-makefile.patch | 234 - 0002-adapt-lstack.patch | 5569 ----------------- ...asional-coredump-when-the-lwip-exits.patch | 63 - ...or-of-deleting-conn-table-in-connect.patch | 79 - ...n-rcvd-state-reg-conn-into-conntable.patch | 27 - 0006-fix-coredump-in-etharp.patch | 29 - ...lle-fix-epoll_ctl-EPOLLET-mode-error.patch | 102 - ...ix-lwip_accept-memcpy-sockaddr-large.patch | 25 - ...ack-buffer-overflow-when-memcpy-addr.patch | 35 - ...-incomplete-release-of-the-conntable.patch | 115 - 0011-remove-gazelle-tcp-conn-func.patch | 116 - ...plete-resource-release-in-lwip-close.patch | 49 - 0013-remove-gazelle-syscall-thread.patch | 126 - 0014-fix-some-compile-errors.patch | 62 - 0015-fix-tcp-port-alloc-issue.patch | 36 - 0016-lstack-support-mysql-mode.patch | 943 --- 0017-support-REUSEPOR-option.patch | 58 - ...-gazelle_init_sock-before-read-event.patch | 37 - 0019-gazelle-reduce-copy-in-send.patch | 50 - ...ym_handle-function-set-handle-to-RTL.patch | 63 - ...f-ring-is-full-the-node-is-added-to-.patch | 33 - ...hat-sock-state-changes-to-CLOSE_WAIT.patch | 56 - ...r-event-and-checksum-offload-support.patch | 698 --- 0024-refactor-pkt-read-send-performance.patch | 320 - ...place-gettid-with-syscall-SYS_gettid.patch | 57 - ...wait_close-and-move-epoll_events-pos.patch | 30 - 0027-modify-EISCONN-condition.patch | 39 - 0028-per-thread-reassdata-variables.patch | 30 - ...and-remove-same-customized-modificat.patch | 114 - 0030-refactor-tcp-new-port.patch | 195 - ...factor-add-event-limit-send-pkts-num.patch | 71 - 0032-fix-free-pbuf-miss-data.patch | 80 - 0033-alloc-socket-fail-clean-sock.patch | 39 - 0034-add-accept4-and-epoll_create1.patch | 182 - 0035-add-writev-and-readv.patch | 41 - 0036-add-fs-secure-compilation-option.patch | 25 - ...P-QUEUE-to-avoid-sync-packet-dropped.patch | 27 - 0038-add-tso.patch | 380 -- ...optimize-app-thread-write-buff-block.patch | 94 - 0040-add-huge-snd_buf.patch | 86 - ...pcb-list-limit-send-size-and-ack-now.patch | 374 -- 0042-expand-recv-win.patch | 39 - 0043-add-prefetch.patch | 62 - 0044-skip-unnecessary-tcp_route.patch | 103 - 0045-add-variable-in-struct-sock.patch | 26 - ...ck-when-recv-too-many-acks-with-data.patch | 91 - 0047-reduce-struct-pbuf-size.patch | 25 - 0048-listen-pcb-also-use-pcb_if.patch | 37 - 0049-expand-recv-mbox-size.patch | 61 - 0050-lwip-reuse-ip-port.patch | 254 - 0051-lwip-add-need_tso_send.patch | 76 - ...p_fnctl-only-support-F_SETFL-F_GETFL.patch | 30 - ...ncode-improve-lwipopts.h-readability.patch | 2252 ------- 0054-reduce-cpu-usage-when-send.patch | 32 - 0055-add-pbuf-lock-when-aggregate-pbuf.patch | 46 - ...o-small-packet-drop-in-kernel-server.patch | 325 - 0057-same-node-gazellectl-a.patch | 456 -- 0058-lwip-send-recv-thread-bind-numa.patch | 24 - 0059-fix-last_unsent-last_unacked.patch | 114 - 0060-lwip-add-udp-multicast.patch | 337 - 0061-fix-pbuf-leak-in-udp-connection.patch | 29 - ...tbuf-in-recv_udp-to-fix-mem-overflow.patch | 249 - ...oid-too-many-empty-acks-in-tcp_input.patch | 30 - ...-fix-udp-send-recv-in-multiple-queue.patch | 169 - 0065-fix-udp-recvmbox-size-not-set.patch | 24 - 0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch | 144 - ...pointer-when-all-zero-address-listen.patch | 100 - 0068-enable-UDP-CKSUM-in-lwip.patch | 42 - ...k-in-hugepage_init-and-sys_mbox_free.patch | 72 - ...-when-not-support-OFFLOAD_UDP_CHECKS.patch | 180 - ...-incorrect-after-pbuf_split_64k-is-c.patch | 35 - ...ONBLOCK-and-FIONBIO-when-not-defined.patch | 18 - ...ernal-api-start-with-do_lwip_-prefix.patch | 208 - ...elle-offloads-are-registered-to-lwip.patch | 241 - 0075-adapt-read-write-for-rtc-mode.patch | 457 -- 0076-fix-recvmsg-return-EINVAL.patch | 38 - 0077-adpat-event-for-rtc-mode.patch | 123 - 0078-posix_api-support-select.patch | 37 - 0079-enable-vlan-define.patch | 41 - 0080-enable-ipv6.patch | 425 -- 0081-ip6-hdr.patch | 354 -- 0082-add-vlanid-in-netif.patch | 109 - 0083-lwipopts-add-lwip-debug-log-macro.patch | 75 - ...dd-tcpslowtmr-log-and-tcpfasttmr-cnt.patch | 135 - ...ip-log-tcp_rst-tcp_abandon-tcp_abort.patch | 192 - ...ent-log-and-tcp-exception-statistics.patch | 77 - 0087-support-vlan-offload.patch | 56 - 0088-modify-log-info-err.patch | 82 - 0089-add-struct-gz-addr.patch | 97 - 0090-frag-fix-coredump-when-get-netif.patch | 28 - ...log-info-and-fix-wrong-port-log-info.patch | 85 - ...edump-issue-when-UDP-traffic-is-sent.patch | 30 - ...conn-receive-RST-packet-in-listening.patch | 37 - ...p-log-fix-reversed-port-in-tcp_input.patch | 61 - ...ck-del-errevent-log-if-err-is-ERR_OK.patch | 27 - ...d-the-fin-to-the-last-unsent-segment.patch | 27 - ...at-2w-connection-unable-to-establish.patch | 275 - 0098-remove-duplicate-lwip-log.patch | 25 - 0099-fix-rte_ring_create-time-consuming.patch | 142 - BUILD.gn | 10 +- BUILDING | 119 + CHANGELOG | 233 +- CMakeLists.txt | 29 +- COPYING | 27 +- FEATURES | 2 +- FILES | 1 + README | 35 +- README.OpenSource | 8 +- README_en.md | 106 - UPGRADING | 11 + backport-Add-outgoing-VLAN-PCP-support.patch | 143 - ...rt-fix-compiling-ETHARP_SUPPORT_VLAN.patch | 33 - ...t-tcp-fix-sequence-number-comparison.patch | 36 - ...p-tighten-up-checks-for-received-SYN.patch | 58 - codespell_changed_files.sh | 26 + codespell_check.sh | 59 + contrib/Coverity/coverity.c | 106 + contrib/Filelists.cmake | 61 + contrib/Filelists.mk | 57 + contrib/addons/dhcp_extra_opts/README | 5 + .../addons/dhcp_extra_opts/dhcp_extra_opts.c | 91 + .../addons/dhcp_extra_opts/dhcp_extra_opts.h | 61 + contrib/addons/ipv6_static_routing/README | 43 + .../ipv6_static_routing/ip6_route_table.c | 248 + .../ipv6_static_routing/ip6_route_table.h | 94 + .../addons/netconn/external_resolve/dnssd.c | 164 + .../addons/netconn/external_resolve/dnssd.h | 50 + contrib/addons/tcp_isn/tcp_isn.c | 182 + contrib/addons/tcp_isn/tcp_isn.h | 48 + contrib/addons/tcp_md5/README | 27 + contrib/addons/tcp_md5/tcp_md5.c | 534 ++ contrib/addons/tcp_md5/tcp_md5.h | 84 + .../CCodeGeneration/CCodeGeneration.csproj | 67 + .../LwipMibCompiler/CCodeGeneration/CFile.cs | 54 + .../CCodeGeneration/CGenerator.cs | 119 + .../LwipMibCompiler/CCodeGeneration/Code.cs | 56 + .../CCodeGeneration/CodeContainerBase.cs | 139 + .../CCodeGeneration/CodeElement.cs | 41 + .../CCodeGeneration/Comment.cs | 75 + .../CCodeGeneration/EmptyLine.cs | 64 + .../CCodeGeneration/Function.cs | 129 + .../CCodeGeneration/FunctionDeclaration.cs | 114 + .../CCodeGeneration/IfThenElse.cs | 137 + .../LwipMibCompiler/CCodeGeneration/PP_If.cs | 67 + .../CCodeGeneration/PP_Ifdef.cs | 76 + .../CCodeGeneration/PP_Include.cs | 71 + .../CCodeGeneration/PP_Macro.cs | 59 + .../CCodeGeneration/PlainText.cs | 49 + .../Properties/AssemblyInfo.cs | 36 + .../LwipMibCompiler/CCodeGeneration/Switch.cs | 146 + .../CCodeGeneration/VariableDeclaration.cs | 82 + .../CCodeGeneration/VariablePrototype.cs | 73 + .../CCodeGeneration/VariableType.cs | 130 + .../apps/LwipMibCompiler/LwipMibCompiler.sln | 47 + .../LwipMibCompiler/LwipMibCompiler.csproj | 73 + .../LwipMibCompiler/Program.cs | 480 ++ .../Properties/AssemblyInfo.cs | 36 + .../LwipMibCompiler/app.config | 3 + .../LwipSnmpCodeGeneration/IRestriction.cs | 120 + .../LwipSnmpCodeGeneration/LwipSnmp.cs | 199 + .../LwipSnmpCodeGeneration.csproj | 72 + .../LwipSnmpCodeGeneration/MibCFile.cs | 196 + .../LwipSnmpCodeGeneration/MibHeaderFile.cs | 129 + .../Properties/AssemblyInfo.cs | 36 + .../LwipSnmpCodeGeneration/SnmpMib.cs | 97 + .../LwipSnmpCodeGeneration/SnmpNode.cs | 119 + .../SnmpScalarAggregationNode.cs | 293 + .../SnmpScalarArrayNode.cs | 105 + .../LwipSnmpCodeGeneration/SnmpScalarNode.cs | 395 ++ .../SnmpScalarNodeBits.cs | 121 + .../SnmpScalarNodeCounter64.cs | 72 + .../SnmpScalarNodeInt.cs | 86 + .../SnmpScalarNodeObjectIdentifier.cs | 90 + .../SnmpScalarNodeOctetString.cs | 118 + .../SnmpScalarNodeTruthValue.cs | 66 + .../SnmpScalarNodeUint.cs | 91 + .../LwipSnmpCodeGeneration/SnmpTableNode.cs | 332 + .../LwipSnmpCodeGeneration/SnmpTreeNode.cs | 242 + .../MibViewer/FormMain.Designer.cs | 166 + .../LwipMibCompiler/MibViewer/FormMain.cs | 217 + .../LwipMibCompiler/MibViewer/FormMain.resx | 298 + .../MibViewer/MibViewer.csproj | 94 + .../apps/LwipMibCompiler/MibViewer/Program.cs | 51 + .../MibViewer/Properties/AssemblyInfo.cs | 36 + .../Properties/Resources.Designer.cs | 63 + .../MibViewer/Properties/Resources.resx | 117 + .../MibViewer/Properties/Settings.Designer.cs | 26 + .../MibViewer/Properties/Settings.settings | 7 + .../apps/LwipMibCompiler/MibViewer/app.config | 3 + .../Mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB | 131 + .../LwipMibCompiler/Mibs/IANA-CHARSET-MIB | 345 + .../Mibs/IANA/IANA-ITU-ALARM-TC-MIB | 333 + .../Mibs/IANA/IANA-LANGUAGE-MIB | 127 + .../LwipMibCompiler/Mibs/IANA/IANA-MALLOC-MIB | 67 + .../LwipMibCompiler/Mibs/IANA/IANA-MAU-MIB | 770 +++ .../Mibs/IANA/IANA-PRINTER-MIB | 1319 ++++ .../Mibs/IANA/IANA-RTPROTO-MIB | 92 + .../Mibs/IANA/IANATn3270eTC-MIB | 306 + .../LwipMibCompiler/Mibs/IANA/IANAifType-MIB | 572 ++ contrib/apps/LwipMibCompiler/Mibs/IF-MIB | 1899 ++++++ .../LwipMibCompiler/Mibs/INET-ADDRESS-MIB | 421 ++ contrib/apps/LwipMibCompiler/Mibs/IP-MIB | 5254 ++++++++++++++++ contrib/apps/LwipMibCompiler/Mibs/RFC-1212 | 75 + contrib/apps/LwipMibCompiler/Mibs/RFC-1215 | 34 + contrib/apps/LwipMibCompiler/Mibs/RFC1065-SMI | 132 + contrib/apps/LwipMibCompiler/Mibs/RFC1155-SMI | 129 + contrib/apps/LwipMibCompiler/Mibs/RFC1158-MIB | 1493 +++++ contrib/apps/LwipMibCompiler/Mibs/RFC1213-MIB | 2621 ++++++++ contrib/apps/LwipMibCompiler/Mibs/SNMPv2-CONF | 318 + contrib/apps/LwipMibCompiler/Mibs/SNMPv2-MIB | 903 +++ contrib/apps/LwipMibCompiler/Mibs/SNMPv2-SMI | 352 ++ contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TC | 786 +++ contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TM | 194 + contrib/apps/LwipMibCompiler/Mibs/TCP-MIB | 829 +++ contrib/apps/LwipMibCompiler/Mibs/UDP-MIB | 579 ++ .../SharpSnmpLib/Mib/DisplayHint.cs | 84 + .../Elements/Entities/AgentCapabilities.cs | 29 + .../Mib/Elements/Entities/EntityBase.cs | 46 + .../Mib/Elements/Entities/IEntity.cs | 62 + .../Mib/Elements/Entities/ModuleCompliance.cs | 23 + .../Mib/Elements/Entities/ModuleIdentity.cs | 10 + .../Elements/Entities/NotificationGroup.cs | 22 + .../Mib/Elements/Entities/NotificationType.cs | 11 + .../Mib/Elements/Entities/ObjectGroup.cs | 22 + .../Mib/Elements/Entities/ObjectIdentity.cs | 21 + .../Mib/Elements/Entities/ObjectType.cs | 336 + .../Elements/Entities/OidValueAssignment.cs | 30 + .../SharpSnmpLib/Mib/Elements/Exports.cs | 56 + .../SharpSnmpLib/Mib/Elements/IDeclaration.cs | 18 + .../SharpSnmpLib/Mib/Elements/IElement.cs | 35 + .../Mib/Elements/ITypeReferrer.cs | 10 + .../SharpSnmpLib/Mib/Elements/Imports.cs | 81 + .../SharpSnmpLib/Mib/Elements/ImportsFrom.cs | 60 + .../SharpSnmpLib/Mib/Elements/TrapType.cs | 48 + .../Mib/Elements/Types/BaseType.cs | 54 + .../Mib/Elements/Types/BitsType.cs | 26 + .../SharpSnmpLib/Mib/Elements/Types/Choice.cs | 35 + .../Mib/Elements/Types/ITypeAssignment.cs | 6 + .../Mib/Elements/Types/IntegerType.cs | 117 + .../Mib/Elements/Types/IpAddressType.cs | 21 + .../SharpSnmpLib/Mib/Elements/Types/Macro.cs | 34 + .../Elements/Types/ObjectIdentifierType.cs | 11 + .../Mib/Elements/Types/OctetStringType.cs | 31 + .../Mib/Elements/Types/OpaqueType.cs | 11 + .../Mib/Elements/Types/Sequence.cs | 46 + .../Mib/Elements/Types/SequenceOf.cs | 23 + .../Mib/Elements/Types/TextualConvention.cs | 238 + .../Mib/Elements/Types/TypeAssignment.cs | 147 + .../Mib/Elements/Types/UnsignedType.cs | 103 + .../SharpSnmpLib/Mib/IModule.cs | 81 + .../SharpSnmpLib/Mib/ISymbolEnumerator.cs | 9 + .../LwipMibCompiler/SharpSnmpLib/Mib/Lexer.cs | 581 ++ .../SharpSnmpLib/Mib/MaxAccess.cs | 17 + .../SharpSnmpLib/Mib/MibDocument.cs | 57 + .../SharpSnmpLib/Mib/MibException.cs | 113 + .../SharpSnmpLib/Mib/MibModule.cs | 294 + .../SharpSnmpLib/Mib/MibResolver.cs | 97 + .../SharpSnmpLib/Mib/MibTree.cs | 130 + .../SharpSnmpLib/Mib/MibTreeNode.cs | 112 + .../SharpSnmpLib/Mib/MibTypesResolver.cs | 216 + .../SharpSnmpLib/Mib/ObjectIdentifier.cs | 54 + .../SharpSnmpLib/Mib/Status.cs | 17 + .../SharpSnmpLib/Mib/Symbol.cs | 357 ++ .../SharpSnmpLib/Mib/SymbolList.cs | 146 + .../SharpSnmpLib/Mib/ValueMap.cs | 103 + .../SharpSnmpLib/Mib/ValueRange.cs | 76 + .../SharpSnmpLib/Properties/AssemblyInfo.cs | 61 + .../Properties/Resources.Designer.cs | 63 + .../SharpSnmpLib/Properties/Resources.resx | 120 + .../SharpSnmpLib/SharpSnmpLib.Mib.csproj | 140 + .../LwipMibCompiler/SharpSnmpLib/license.txt | 458 ++ .../LwipMibCompiler/SharpSnmpLib/readme.txt | 1 + .../SharpSnmpLib/sharpsnmplib.snk | Bin 0 -> 596 bytes .../example/compile_udp_mib.cmd | 1 + .../example/compile_udp_mib.sh | 1 + contrib/apps/chargen/README | 52 + contrib/apps/chargen/chargen.c | 274 + contrib/apps/chargen/chargen.h | 12 + contrib/apps/httpserver/README | 12 + contrib/apps/httpserver/httpserver-netconn.c | 103 + contrib/apps/httpserver/httpserver-netconn.h | 6 + contrib/apps/netio/netio.c | 55 + contrib/apps/netio/netio.h | 6 + contrib/apps/ping/ping.c | 428 ++ contrib/apps/ping/ping.h | 20 + contrib/apps/rtp/rtp.c | 308 + contrib/apps/rtp/rtp.h | 8 + contrib/apps/rtp/rtpdata.h | 2040 ++++++ contrib/apps/shell/shell.c | 1277 ++++ contrib/apps/shell/shell.h | 37 + .../apps/socket_examples/socket_examples.c | 680 ++ .../apps/socket_examples/socket_examples.h | 6 + contrib/apps/tcpecho/tcpecho.c | 101 + contrib/apps/tcpecho/tcpecho.h | 38 + contrib/apps/tcpecho_raw/tcpecho_raw.c | 301 + contrib/apps/tcpecho_raw/tcpecho_raw.h | 35 + contrib/apps/udpecho/udpecho.c | 88 + contrib/apps/udpecho/udpecho.h | 37 + contrib/apps/udpecho_raw/udpecho_raw.c | 88 + contrib/apps/udpecho_raw/udpecho_raw.h | 39 + contrib/examples/ethernetif/ethernetif.c | 337 + contrib/examples/example_app/default_netif.h | 47 + contrib/examples/example_app/lwipcfg.h.ci | 73 + .../examples/example_app/lwipcfg.h.example | 77 + contrib/examples/example_app/lwipopts.h | 326 + contrib/examples/example_app/lwippools.h | 20 + contrib/examples/example_app/ppp_settings.h | 6 + contrib/examples/example_app/test.c | 773 +++ .../example_app/test_configs/opt_default.h | 295 + .../example_app/test_configs/opt_dualstack.h | 295 + .../example_app/test_configs/opt_ipv4only.h | 295 + .../example_app/test_configs/opt_ipv6only.h | 295 + .../test_configs/opt_no_tcp_dualstack.h | 4 + .../test_configs/opt_no_tcp_ipv4only.h | 4 + .../test_configs/opt_no_tcp_ipv6only.h | 4 + .../test_configs/opt_no_udp_dualstack.h | 4 + .../test_configs/opt_no_udp_ipv4only.h | 4 + .../test_configs/opt_no_udp_ipv6only.h | 4 + .../example_app/test_configs/opt_none.h | 2 + .../example_app/test_configs/opt_nosys_dual.h | 295 + .../example_app/test_configs/opt_nosys_ipv4.h | 295 + .../example_app/test_configs/opt_nosys_ipv6.h | 295 + .../examples/httpd/cgi_example/cgi_example.c | 107 + .../examples/httpd/cgi_example/cgi_example.h | 38 + contrib/examples/httpd/examples_fs/404.html | 21 + .../examples/httpd/examples_fs/img/sics.gif | Bin 0 -> 724 bytes contrib/examples/httpd/examples_fs/index.html | 47 + contrib/examples/httpd/examples_fs/login.html | 28 + .../examples/httpd/examples_fs/loginfail.html | 25 + .../examples/httpd/examples_fs/session.html | 25 + contrib/examples/httpd/examples_fs/ssi.shtml | 315 + contrib/examples/httpd/examples_fsdata.c | 1543 +++++ .../examples/httpd/fs_example/fs_example.c | 324 + .../examples/httpd/fs_example/fs_example.h | 38 + .../httpd/genfiles_example/genfiles_example.c | 186 + .../httpd/genfiles_example/genfiles_example.h | 38 + .../httpd/https_example/https_example.c | 144 + .../httpd/https_example/https_example.h | 38 + .../httpd/post_example/post_example.c | 167 + .../examples/httpd/ssi_example/ssi_example.c | 264 + .../examples/httpd/ssi_example/ssi_example.h | 38 + contrib/examples/lwiperf/lwiperf_example.c | 50 + contrib/examples/lwiperf/lwiperf_example.h | 43 + contrib/examples/mdns/mdns_example.c | 63 + contrib/examples/mdns/mdns_example.h | 43 + contrib/examples/mqtt/mqtt_example.c | 129 + contrib/examples/mqtt/mqtt_example.h | 43 + contrib/examples/ppp/pppos_example.c | 221 + contrib/examples/ppp/pppos_example.h | 43 + contrib/examples/snmp/snmp_example.c | 80 + contrib/examples/snmp/snmp_example.h | 43 + .../snmp/snmp_private_mib/lwip_prvmib.c | 401 ++ .../snmp/snmp_private_mib/private_mib.h | 26 + contrib/examples/snmp/snmp_v3/snmpv3_dummy.c | 395 ++ contrib/examples/snmp/snmp_v3/snmpv3_dummy.h | 53 + contrib/examples/sntp/sntp_example.c | 66 + contrib/examples/sntp/sntp_example.h | 45 + contrib/examples/tftp/tftp_example.c | 156 + contrib/examples/tftp/tftp_example.h | 29 + contrib/ports/CMakeCommon.cmake | 128 + contrib/ports/Common.allports.mk | 91 + .../ports/freertos/include/arch/sys_arch.h | 95 + contrib/ports/freertos/sys_arch.c | 607 ++ contrib/ports/unix/Common.mk | 51 + contrib/ports/unix/Filelists.cmake | 44 + contrib/ports/unix/README | 25 + contrib/ports/unix/check/CMakeLists.txt | 61 + contrib/ports/unix/check/Makefile | 94 + contrib/ports/unix/check/README | 8 + contrib/ports/unix/check/config.h | 2 + contrib/ports/unix/example_app/CMakeLists.txt | 27 + contrib/ports/unix/example_app/Makefile | 60 + .../ports/unix/example_app/default_netif.c | 68 + contrib/ports/unix/example_app/iteropts.sh | 34 + contrib/ports/unix/lib/CMakeLists.txt | 33 + contrib/ports/unix/lib/README | 28 + contrib/ports/unix/lib/lwipopts.h | 435 ++ contrib/ports/unix/port/include/arch/cc.h | 99 + contrib/ports/unix/port/include/arch/perf.h | 71 + .../ports/unix/port/include/arch/sys_arch.h | 98 + contrib/ports/unix/port/include/netif/fifo.h | 62 + contrib/ports/unix/port/include/netif/list.h | 34 + .../ports/unix/port/include/netif/pcapif.h | 47 + contrib/ports/unix/port/include/netif/sio.h | 68 + contrib/ports/unix/port/include/netif/tapif.h | 51 + contrib/ports/unix/port/include/netif/vdeif.h | 51 + contrib/ports/unix/port/netif/fifo.c | 139 + contrib/ports/unix/port/netif/list.c | 152 + contrib/ports/unix/port/netif/pcapif.c | 207 + contrib/ports/unix/port/netif/sio.c | 490 ++ contrib/ports/unix/port/netif/tapif.c | 432 ++ contrib/ports/unix/port/netif/vdeif.c | 344 + contrib/ports/unix/port/perf.c | 65 + contrib/ports/unix/port/sys_arch.c | 840 +++ contrib/ports/unix/posixlib/CMakeLists.txt | 94 + contrib/ports/unix/posixlib/Uninstall.cmake | 22 + .../ports/unix/posixlib/include/posix/inet.h | 76 + .../unix/posixlib/include/posix/sockets.h | 150 + contrib/ports/unix/posixlib/lwipopts.h | 180 + contrib/ports/unix/setup-tapif | 22 + contrib/ports/win32/Common.mk | 51 + contrib/ports/win32/Filelists.cmake | 46 + contrib/ports/win32/check/check_stdint.h | 1 + contrib/ports/win32/check/config.h | 29 + contrib/ports/win32/check/stdbool.h | 9 + contrib/ports/win32/check/sys/time.h | 12 + contrib/ports/win32/check/time.c | 66 + contrib/ports/win32/check/unistd.h | 7 + .../ports/win32/example_app/CMakeLists.txt | 27 + contrib/ports/win32/example_app/Makefile | 55 + .../ports/win32/example_app/default_netif.c | 80 + contrib/ports/win32/include/arch/bpstruct.h | 1 + contrib/ports/win32/include/arch/cc.h | 119 + contrib/ports/win32/include/arch/epstruct.h | 1 + contrib/ports/win32/include/arch/perf.h | 40 + contrib/ports/win32/include/arch/sys_arch.h | 91 + contrib/ports/win32/msvc/build_coverity.cmd | 26 + contrib/ports/win32/msvc/libcheck.vcxproj | 159 + .../ports/win32/msvc/libcheck.vcxproj.filters | 96 + contrib/ports/win32/msvc/lwIP.vcxproj | 1040 +++ contrib/ports/win32/msvc/lwIP.vcxproj.filters | 1075 ++++ contrib/ports/win32/msvc/lwIP_Test.sln | 57 + contrib/ports/win32/msvc/lwIP_Test.vcxproj | 321 + .../win32/msvc/lwIP_Test.vcxproj.filters | 252 + contrib/ports/win32/msvc/lwIP_fuzz.sln | 78 + contrib/ports/win32/msvc/lwIP_pcapif.vcxproj | 190 + .../win32/msvc/lwIP_pcapif.vcxproj.filters | 28 + contrib/ports/win32/msvc/lwIP_unittests.sln | 50 + contrib/ports/win32/msvc/lwip_fuzz.vcxproj | 476 ++ .../ports/win32/msvc/lwip_unittests.vcxproj | 217 + .../win32/msvc/lwip_unittests.vcxproj.filters | 168 + contrib/ports/win32/msvc/makefsdata.vcxproj | 173 + .../win32/msvc/makefsdata.vcxproj.filters | 14 + contrib/ports/win32/pcapif.c | 1129 ++++ contrib/ports/win32/pcapif.h | 32 + contrib/ports/win32/pcapif_helper.c | 172 + contrib/ports/win32/pcapif_helper.h | 31 + contrib/ports/win32/readme.txt | 26 + contrib/ports/win32/sio.c | 304 + contrib/ports/win32/sys_arch.c | 782 +++ doc/FILES | 3 - doc/NO_SYS_SampleCode.c | 1 - doc/ZeroCopyRx.c | 2 +- doc/contrib.txt | 2 +- doc/doxygen/lwip.Doxyfile | 19 +- doc/doxygen/lwip.Doxyfile.cmake.in | 17 +- doc/doxygen/main_page.h | 113 +- doc/mdns.txt | 11 +- doc/mqtt_client.txt | 40 +- doc/ppp.txt | 4 +- doc/savannah.txt | 8 +- lwip-2.1.3.tar.xz | Bin 4192506 -> 0 bytes lwip.spec | 474 -- pax_global_header | 1 - src/Filelists.cmake | 36 +- src/Filelists.mk | 43 +- src/api/api_lib.c | 4 +- src/api/api_msg.c | 91 +- src/api/if_api.c | 2 +- src/api/netbuf.c | 4 +- src/api/netdb.c | 19 +- src/api/netifapi.c | 50 +- src/api/sockets.c | 452 +- src/api/tcpip.c | 151 +- src/apps/altcp_tls/altcp_tls_mbedtls.c | 254 +- src/apps/altcp_tls/altcp_tls_mbedtls_mem.c | 6 +- .../altcp_tls/altcp_tls_mbedtls_structs.h | 2 +- src/apps/http/altcp_proxyconnect.c | 2 +- src/apps/http/fs.c | 25 +- src/apps/http/fsdata.c | 1 - src/apps/http/http_client.c | 70 +- src/apps/http/httpd.c | 78 +- src/apps/http/httpd_structs.h | 6 +- src/apps/http/makefsdata/makefsdata | 4 +- src/apps/http/makefsdata/makefsdata.c | 164 +- src/apps/http/makefsdata/readme.txt | 10 + src/apps/http/makefsdata/tinydir.h | 168 +- src/apps/lwiperf/lwiperf.c | 14 +- src/apps/mdns/mdns.c | 3024 +++++---- src/apps/mdns/mdns_domain.c | 635 ++ src/apps/mdns/mdns_out.c | 1163 ++++ src/apps/mqtt/mqtt.c | 93 +- src/apps/netbiosns/netbiosns.c | 2 +- src/apps/smtp/smtp.c | 17 +- src/apps/snmp/snmp_core.c | 37 +- src/apps/snmp/snmp_core_priv.h | 8 + src/apps/snmp/snmp_mib2_ip.c | 6 +- src/apps/snmp/snmp_mib2_tcp.c | 12 +- src/apps/snmp/snmp_mib2_udp.c | 6 +- src/apps/snmp/snmp_msg.c | 53 +- src/apps/snmp/snmp_netconn.c | 1 - src/apps/snmp/snmp_pbuf_stream.c | 2 +- src/apps/snmp/snmp_snmpv2_usm.c | 2 +- src/apps/snmp/snmp_threadsync.c | 2 +- src/apps/snmp/snmp_traps.c | 598 +- src/apps/sntp/sntp.c | 54 +- src/apps/tftp/{tftp_server.c => tftp.c} | 203 +- src/core/altcp.c | 10 +- src/core/altcp_alloc.c | 2 +- src/core/altcp_tcp.c | 5 +- src/core/def.c | 46 + src/core/distributed_net/distributed_net.c | 157 - .../distributed_net/distributed_net_core.c | 260 - .../distributed_net/distributed_net_utils.c | 105 - src/core/distributed_net/udp_transmit.c | 147 - src/core/dns.c | 174 +- src/core/inet_chksum.c | 4 +- src/core/init.c | 32 +- src/core/ip.c | 14 - src/core/ipv4/acd.c | 557 ++ src/core/ipv4/autoip.c | 403 +- src/core/ipv4/dhcp.c | 392 +- src/core/ipv4/etharp.c | 121 +- src/core/ipv4/icmp.c | 38 +- src/core/ipv4/igmp.c | 63 +- src/core/ipv4/ip4.c | 100 +- src/core/ipv4/ip4_addr.c | 2 +- src/core/ipv4/ip4_frag.c | 24 +- src/core/ipv6/dhcp6.c | 49 +- src/core/ipv6/icmp6.c | 17 +- src/core/ipv6/ip6.c | 103 +- src/core/ipv6/ip6_addr.c | 16 +- src/core/ipv6/ip6_frag.c | 44 +- src/core/ipv6/mld6.c | 51 +- src/core/ipv6/nd6.c | 238 +- src/core/lowpower.c | 489 -- src/core/mem.c | 39 +- src/core/net_group.c | 90 - src/core/netif.c | 219 +- src/core/pbuf.c | 54 +- src/core/raw.c | 45 +- src/core/stats.c | 1 - src/core/sys.c | 12 +- src/core/tcp.c | 251 +- src/core/tcp_in.c | 101 +- src/core/tcp_out.c | 187 +- src/core/timeouts.c | 15 +- src/core/udp.c | 87 +- src/include/compat/posix/net/if.h | 22 +- src/include/lwip/acd.h | 109 + src/include/lwip/altcp.h | 5 +- src/include/lwip/altcp_tcp.h | 2 +- src/include/lwip/altcp_tls.h | 57 +- src/include/lwip/api.h | 27 +- .../lwip/apps/altcp_tls_mbedtls_opts.h | 6 + src/include/lwip/apps/fs.h | 47 +- src/include/lwip/apps/http_client.h | 14 +- src/include/lwip/apps/httpd.h | 1 + src/include/lwip/apps/httpd_opts.h | 26 +- src/include/lwip/apps/lwiperf.h | 11 +- src/include/lwip/apps/mdns.h | 59 +- src/include/lwip/apps/mdns_domain.h | 80 + src/include/lwip/apps/mdns_opts.h | 42 +- src/include/lwip/apps/mdns_out.h | 138 + src/include/lwip/apps/mdns_priv.h | 191 +- src/include/lwip/apps/mqtt.h | 8 +- src/include/lwip/apps/netbiosns_opts.h | 2 +- src/include/lwip/apps/smtp_opts.h | 7 +- src/include/lwip/apps/snmp.h | 14 +- src/include/lwip/apps/snmp_core.h | 2 +- src/include/lwip/apps/snmp_mib2.h | 2 +- src/include/lwip/apps/snmp_threadsync.h | 2 +- src/include/lwip/apps/sntp.h | 1 + src/include/lwip/apps/sntp_opts.h | 4 +- src/include/lwip/apps/tftp_client.h | 50 + src/include/lwip/apps/tftp_common.h | 108 + src/include/lwip/apps/tftp_opts.h | 4 +- src/include/lwip/apps/tftp_server.h | 63 +- src/include/lwip/arch.h | 59 +- src/include/lwip/autoip.h | 27 +- src/include/lwip/debug.h | 10 +- src/include/lwip/def.h | 14 + src/include/lwip/dhcp.h | 90 +- src/include/lwip/dhcp6.h | 4 - .../lwip/distributed_net/distributed_net.h | 83 - .../distributed_net/distributed_net_core.h | 83 - .../distributed_net/distributed_net_utils.h | 48 - .../lwip/distributed_net/udp_transmit.h | 67 - src/include/lwip/dns.h | 4 - src/include/lwip/errno.h | 2 - src/include/lwip/etharp.h | 9 +- src/include/lwip/if_api.h | 3 +- src/include/lwip/igmp.h | 6 +- src/include/lwip/inet.h | 23 +- src/include/lwip/inet_chksum.h | 1 - src/include/lwip/init.h | 4 +- src/include/lwip/ip.h | 51 +- src/include/lwip/ip4.h | 10 - src/include/lwip/ip4_addr.h | 13 +- src/include/lwip/ip4_frag.h | 5 - src/include/lwip/ip6.h | 4 - src/include/lwip/ip6_addr.h | 40 +- src/include/lwip/ip6_frag.h | 4 - src/include/lwip/ip6_zone.h | 14 +- src/include/lwip/ip_addr.h | 76 +- src/include/lwip/lowpower.h | 169 - src/include/lwip/mem.h | 2 +- src/include/lwip/mld6.h | 6 +- src/include/lwip/nd6.h | 4 - src/include/lwip/net_group.h | 61 - src/include/lwip/netif.h | 89 +- src/include/lwip/netifapi.h | 9 - src/include/lwip/opt.h | 199 +- src/include/lwip/pbuf.h | 2 +- src/include/lwip/priv/altcp_priv.h | 2 +- src/include/lwip/priv/api_msg.h | 10 - src/include/lwip/priv/memp_std.h | 5 - src/include/lwip/priv/nd6_priv.h | 1 + src/include/lwip/priv/sockets_priv.h | 2 +- src/include/lwip/priv/tcp_priv.h | 21 +- src/include/lwip/priv/tcpip_priv.h | 15 +- src/include/lwip/prot/acd.h | 91 + src/include/lwip/prot/autoip.h | 19 +- src/include/lwip/prot/ethernet.h | 4 +- src/include/lwip/prot/icmp.h | 30 +- src/include/lwip/prot/ieee.h | 2 +- src/include/lwip/prot/ip4.h | 2 - src/include/lwip/prot/nd6.h | 1 + src/include/lwip/raw.h | 6 +- src/include/lwip/sio.h | 2 +- src/include/lwip/snmp.h | 2 +- src/include/lwip/sockets.h | 46 +- src/include/lwip/stats.h | 5 +- src/include/lwip/sys.h | 41 +- src/include/lwip/tcp.h | 17 +- src/include/lwip/tcpbase.h | 2 +- src/include/lwip/tcpip.h | 5 +- src/include/lwip/timeouts.h | 6 +- src/include/lwip/udp.h | 6 +- src/include/netif/lowpan6.h | 3 - src/include/netif/lowpan6_ble.h | 10 +- src/include/netif/lowpan6_opts.h | 2 +- src/include/netif/ppp/eap.h | 2 +- src/include/netif/ppp/magic.h | 2 +- src/include/netif/ppp/ppp.h | 2 +- src/include/netif/ppp/ppp_impl.h | 82 +- src/include/netif/ppp/ppp_opts.h | 45 +- src/include/netif/ppp/pppoe.h | 2 +- src/include/netif/ppp/pppos.h | 7 +- src/include/netif/ppp/vj.h | 4 +- src/include/netif/slipif.h | 1 - src/netif/bridgeif.c | 4 +- src/netif/bridgeif_fdb.c | 6 +- src/netif/ethernet.c | 28 +- src/netif/lowpan6.c | 34 +- src/netif/lowpan6_ble.c | 38 +- src/netif/lowpan6_common.c | 10 +- src/netif/ppp/auth.c | 91 +- src/netif/ppp/ccp.c | 48 +- src/netif/ppp/chap-new.c | 34 +- src/netif/ppp/chap_ms.c | 16 +- src/netif/ppp/demand.c | 10 +- src/netif/ppp/eap.c | 202 +- src/netif/ppp/fsm.c | 23 +- src/netif/ppp/ipcp.c | 44 +- src/netif/ppp/ipv6cp.c | 22 +- src/netif/ppp/lcp.c | 68 +- src/netif/ppp/magic.c | 64 +- src/netif/ppp/multilink.c | 10 +- src/netif/ppp/ppp.c | 62 +- src/netif/ppp/pppoe.c | 37 +- src/netif/ppp/pppol2tp.c | 28 +- src/netif/ppp/pppos.c | 161 +- src/netif/ppp/upap.c | 18 +- src/netif/ppp/utils.c | 36 +- src/netif/ppp/vj.c | 18 +- src/netif/slipif.c | 12 +- test/fuzz/Makefile | 39 +- test/fuzz/README | 13 +- test/fuzz/fuzz.c | 156 +- test/fuzz/fuzz2.c | 39 + test/fuzz/fuzz3.c | 40 + test/fuzz/fuzz_common.c | 704 +++ test/fuzz/fuzz_common.h | 62 + test/fuzz/lwipopts.h | 32 +- test/unit/Filelists.cmake | 9 +- test/unit/Filelists.mk | 5 +- test/unit/Makefile | 11 + test/unit/api/test_sockets.c | 10 +- test/unit/core/test_dns.c | 52 + test/unit/core/test_dns.h | 8 + test/unit/core/test_mem.c | 3 - test/unit/core/test_netif.c | 10 +- test/unit/core/test_pbuf.c | 126 +- test/unit/dhcp/test_dhcp.c | 89 +- test/unit/etharp/test_etharp.c | 1 + test/unit/ip4/test_ip4.c | 185 +- test/unit/ip6/test_ip6.c | 201 +- test/unit/lwip_unittests.c | 28 +- test/unit/lwipopts.h | 35 +- test/unit/mdns/test_mdns.c | 3 +- test/unit/mqtt/test_mqtt.c | 2 +- test/unit/ppp/test_pppos.c | 67 + test/unit/ppp/test_pppos.h | 13 + test/unit/tcp/tcp_helper.c | 8 +- test/unit/tcp/test_tcp.c | 9 +- test/unit/tcp/test_tcp_oos.c | 4 +- test/unit/tcp/test_tcp_state.c | 665 ++ test/unit/tcp/test_tcp_state.h | 8 + 699 files changed, 74048 insertions(+), 28301 deletions(-) delete mode 100644 0001-add-makefile.patch delete mode 100644 0002-adapt-lstack.patch delete mode 100644 0003-fix-the-occasional-coredump-when-the-lwip-exits.patch delete mode 100644 0004-fix-error-of-deleting-conn-table-in-connect.patch delete mode 100644 0005-syn-rcvd-state-reg-conn-into-conntable.patch delete mode 100644 0006-fix-coredump-in-etharp.patch delete mode 100644 0007-gazelle-fix-epoll_ctl-EPOLLET-mode-error.patch delete mode 100644 0008-gazelle-fix-lwip_accept-memcpy-sockaddr-large.patch delete mode 100644 0009-fix-stack-buffer-overflow-when-memcpy-addr.patch delete mode 100644 0010-fix-the-incomplete-release-of-the-conntable.patch delete mode 100644 0011-remove-gazelle-tcp-conn-func.patch delete mode 100644 0012-fix-incomplete-resource-release-in-lwip-close.patch delete mode 100644 0013-remove-gazelle-syscall-thread.patch delete mode 100644 0014-fix-some-compile-errors.patch delete mode 100644 0015-fix-tcp-port-alloc-issue.patch delete mode 100644 0016-lstack-support-mysql-mode.patch delete mode 100644 0017-support-REUSEPOR-option.patch delete mode 100644 0018-exec-gazelle_init_sock-before-read-event.patch delete mode 100644 0019-gazelle-reduce-copy-in-send.patch delete mode 100644 0020-remove-chose_dlsym_handle-function-set-handle-to-RTL.patch delete mode 100644 0021-refactor-event-if-ring-is-full-the-node-is-added-to-.patch delete mode 100644 0022-notify-app-that-sock-state-changes-to-CLOSE_WAIT.patch delete mode 100644 0023-refactor-event-and-checksum-offload-support.patch delete mode 100644 0024-refactor-pkt-read-send-performance.patch delete mode 100644 0025-Replace-gettid-with-syscall-SYS_gettid.patch delete mode 100644 0026-del-redundant-wait_close-and-move-epoll_events-pos.patch delete mode 100644 0027-modify-EISCONN-condition.patch delete mode 100644 0028-per-thread-reassdata-variables.patch delete mode 100644 0029-fix-EISCONN-err-and-remove-same-customized-modificat.patch delete mode 100644 0030-refactor-tcp-new-port.patch delete mode 100644 0031-refactor-add-event-limit-send-pkts-num.patch delete mode 100644 0032-fix-free-pbuf-miss-data.patch delete mode 100644 0033-alloc-socket-fail-clean-sock.patch delete mode 100644 0034-add-accept4-and-epoll_create1.patch delete mode 100644 0035-add-writev-and-readv.patch delete mode 100644 0036-add-fs-secure-compilation-option.patch delete mode 100644 0037-enable-ARP-QUEUE-to-avoid-sync-packet-dropped.patch delete mode 100644 0038-add-tso.patch delete mode 100644 0039-optimize-app-thread-write-buff-block.patch delete mode 100644 0040-add-huge-snd_buf.patch delete mode 100644 0041-optimite-pcb-list-limit-send-size-and-ack-now.patch delete mode 100644 0042-expand-recv-win.patch delete mode 100644 0043-add-prefetch.patch delete mode 100644 0044-skip-unnecessary-tcp_route.patch delete mode 100644 0045-add-variable-in-struct-sock.patch delete mode 100644 0046-add-dataack-when-recv-too-many-acks-with-data.patch delete mode 100644 0047-reduce-struct-pbuf-size.patch delete mode 100644 0048-listen-pcb-also-use-pcb_if.patch delete mode 100644 0049-expand-recv-mbox-size.patch delete mode 100644 0050-lwip-reuse-ip-port.patch delete mode 100644 0051-lwip-add-need_tso_send.patch delete mode 100644 0052-lwip_fnctl-only-support-F_SETFL-F_GETFL.patch delete mode 100644 0053-cleancode-improve-lwipopts.h-readability.patch delete mode 100644 0054-reduce-cpu-usage-when-send.patch delete mode 100644 0055-add-pbuf-lock-when-aggregate-pbuf.patch delete mode 100644 0056-fix-tso-small-packet-drop-in-kernel-server.patch delete mode 100644 0057-same-node-gazellectl-a.patch delete mode 100644 0058-lwip-send-recv-thread-bind-numa.patch delete mode 100644 0059-fix-last_unsent-last_unacked.patch delete mode 100644 0060-lwip-add-udp-multicast.patch delete mode 100644 0061-fix-pbuf-leak-in-udp-connection.patch delete mode 100644 0062-drop-netbuf-in-recv_udp-to-fix-mem-overflow.patch delete mode 100644 0063-optimize-avoid-too-many-empty-acks-in-tcp_input.patch delete mode 100644 0064-fix-udp-send-recv-in-multiple-queue.patch delete mode 100644 0065-fix-udp-recvmbox-size-not-set.patch delete mode 100644 0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch delete mode 100644 0067-fix-null-pointer-when-all-zero-address-listen.patch delete mode 100644 0068-enable-UDP-CKSUM-in-lwip.patch delete mode 100644 0069-add-error-check-in-hugepage_init-and-sys_mbox_free.patch delete mode 100644 0070-add-CHECKSUM_UDP-when-not-support-OFFLOAD_UDP_CHECKS.patch delete mode 100644 0071-fix-pbuf-tot_len-incorrect-after-pbuf_split_64k-is-c.patch delete mode 100644 0072-add-O_NONBLOCK-and-FIONBIO-when-not-defined.patch delete mode 100644 0073-lstack_lwip-external-api-start-with-do_lwip_-prefix.patch delete mode 100644 0074-gazelle-offloads-are-registered-to-lwip.patch delete mode 100644 0075-adapt-read-write-for-rtc-mode.patch delete mode 100644 0076-fix-recvmsg-return-EINVAL.patch delete mode 100644 0077-adpat-event-for-rtc-mode.patch delete mode 100644 0078-posix_api-support-select.patch delete mode 100644 0079-enable-vlan-define.patch delete mode 100644 0080-enable-ipv6.patch delete mode 100644 0081-ip6-hdr.patch delete mode 100644 0082-add-vlanid-in-netif.patch delete mode 100644 0083-lwipopts-add-lwip-debug-log-macro.patch delete mode 100644 0084-add-tcpslowtmr-log-and-tcpfasttmr-cnt.patch delete mode 100644 0085-add-lwip-log-tcp_rst-tcp_abandon-tcp_abort.patch delete mode 100644 0086-log-add-errevent-log-and-tcp-exception-statistics.patch delete mode 100644 0087-support-vlan-offload.patch delete mode 100644 0088-modify-log-info-err.patch delete mode 100644 0089-add-struct-gz-addr.patch delete mode 100644 0090-frag-fix-coredump-when-get-netif.patch delete mode 100644 0091-add-fd-log-info-and-fix-wrong-port-log-info.patch delete mode 100644 0092-fix-the-coredump-issue-when-UDP-traffic-is-sent.patch delete mode 100644 0093-modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening.patch delete mode 100644 0094-lwip-log-fix-reversed-port-in-tcp_input.patch delete mode 100644 0095-event_callback-del-errevent-log-if-err-is-ERR_OK.patch delete mode 100644 0096-tcp_send_fin-add-the-fin-to-the-last-unsent-segment.patch delete mode 100644 0097-Mod-the-issue-that-2w-connection-unable-to-establish.patch delete mode 100644 0098-remove-duplicate-lwip-log.patch delete mode 100644 0099-fix-rte_ring_create-time-consuming.patch create mode 100644 BUILDING delete mode 100644 README_en.md delete mode 100644 backport-Add-outgoing-VLAN-PCP-support.patch delete mode 100644 backport-fix-compiling-ETHARP_SUPPORT_VLAN.patch delete mode 100644 backport-tcp-fix-sequence-number-comparison.patch delete mode 100644 backport-tcp-tighten-up-checks-for-received-SYN.patch create mode 100644 codespell_changed_files.sh create mode 100755 codespell_check.sh create mode 100644 contrib/Coverity/coverity.c create mode 100644 contrib/Filelists.cmake create mode 100644 contrib/Filelists.mk create mode 100644 contrib/addons/dhcp_extra_opts/README create mode 100644 contrib/addons/dhcp_extra_opts/dhcp_extra_opts.c create mode 100644 contrib/addons/dhcp_extra_opts/dhcp_extra_opts.h create mode 100644 contrib/addons/ipv6_static_routing/README create mode 100644 contrib/addons/ipv6_static_routing/ip6_route_table.c create mode 100644 contrib/addons/ipv6_static_routing/ip6_route_table.h create mode 100644 contrib/addons/netconn/external_resolve/dnssd.c create mode 100644 contrib/addons/netconn/external_resolve/dnssd.h create mode 100644 contrib/addons/tcp_isn/tcp_isn.c create mode 100644 contrib/addons/tcp_isn/tcp_isn.h create mode 100644 contrib/addons/tcp_md5/README create mode 100644 contrib/addons/tcp_md5/tcp_md5.c create mode 100644 contrib/addons/tcp_md5/tcp_md5.h create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/CCodeGeneration.csproj create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/CFile.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/CGenerator.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/Code.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/CodeContainerBase.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/CodeElement.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/Comment.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/EmptyLine.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/Function.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/FunctionDeclaration.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/IfThenElse.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/PP_If.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Ifdef.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Include.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Macro.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/PlainText.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/Properties/AssemblyInfo.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/Switch.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/VariableDeclaration.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/VariablePrototype.cs create mode 100644 contrib/apps/LwipMibCompiler/CCodeGeneration/VariableType.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipMibCompiler.sln create mode 100644 contrib/apps/LwipMibCompiler/LwipMibCompiler/LwipMibCompiler.csproj create mode 100644 contrib/apps/LwipMibCompiler/LwipMibCompiler/Program.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipMibCompiler/Properties/AssemblyInfo.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipMibCompiler/app.config create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/IRestriction.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmp.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmpCodeGeneration.csproj create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibCFile.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibHeaderFile.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/Properties/AssemblyInfo.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpMib.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpNode.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarAggregationNode.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarArrayNode.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNode.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeBits.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeCounter64.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeInt.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeObjectIdentifier.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeOctetString.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeTruthValue.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeUint.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTableNode.cs create mode 100644 contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTreeNode.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/FormMain.Designer.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/FormMain.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/FormMain.resx create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/MibViewer.csproj create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Program.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Properties/AssemblyInfo.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.Designer.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.resx create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.Designer.cs create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.settings create mode 100644 contrib/apps/LwipMibCompiler/MibViewer/app.config create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA-CHARSET-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-ITU-ALARM-TC-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-LANGUAGE-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MALLOC-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MAU-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-PRINTER-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-RTPROTO-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANATn3270eTC-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IANA/IANAifType-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IF-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/INET-ADDRESS-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/IP-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC-1212 create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC-1215 create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC1065-SMI create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC1155-SMI create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC1158-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/RFC1213-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/SNMPv2-CONF create mode 100644 contrib/apps/LwipMibCompiler/Mibs/SNMPv2-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/SNMPv2-SMI create mode 100644 contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TC create mode 100644 contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TM create mode 100644 contrib/apps/LwipMibCompiler/Mibs/TCP-MIB create mode 100644 contrib/apps/LwipMibCompiler/Mibs/UDP-MIB create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/DisplayHint.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/AgentCapabilities.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/EntityBase.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/IEntity.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleCompliance.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleIdentity.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationGroup.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectGroup.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectIdentity.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/OidValueAssignment.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Exports.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IDeclaration.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IElement.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ITypeReferrer.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Imports.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ImportsFrom.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/TrapType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BaseType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BitsType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Choice.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ITypeAssignment.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IntegerType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IpAddressType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Macro.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ObjectIdentifierType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OctetStringType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OpaqueType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Sequence.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/SequenceOf.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TextualConvention.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TypeAssignment.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/UnsignedType.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/IModule.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ISymbolEnumerator.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Lexer.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MaxAccess.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibDocument.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibException.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibModule.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibResolver.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTree.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTreeNode.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTypesResolver.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ObjectIdentifier.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Status.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Symbol.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/SymbolList.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueMap.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueRange.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/AssemblyInfo.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.Designer.cs create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.resx create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/SharpSnmpLib.Mib.csproj create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/license.txt create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/readme.txt create mode 100644 contrib/apps/LwipMibCompiler/SharpSnmpLib/sharpsnmplib.snk create mode 100644 contrib/apps/LwipMibCompiler/example/compile_udp_mib.cmd create mode 100644 contrib/apps/LwipMibCompiler/example/compile_udp_mib.sh create mode 100644 contrib/apps/chargen/README create mode 100644 contrib/apps/chargen/chargen.c create mode 100644 contrib/apps/chargen/chargen.h create mode 100644 contrib/apps/httpserver/README create mode 100644 contrib/apps/httpserver/httpserver-netconn.c create mode 100644 contrib/apps/httpserver/httpserver-netconn.h create mode 100644 contrib/apps/netio/netio.c create mode 100644 contrib/apps/netio/netio.h create mode 100644 contrib/apps/ping/ping.c create mode 100644 contrib/apps/ping/ping.h create mode 100644 contrib/apps/rtp/rtp.c create mode 100644 contrib/apps/rtp/rtp.h create mode 100644 contrib/apps/rtp/rtpdata.h create mode 100644 contrib/apps/shell/shell.c create mode 100644 contrib/apps/shell/shell.h create mode 100644 contrib/apps/socket_examples/socket_examples.c create mode 100644 contrib/apps/socket_examples/socket_examples.h create mode 100644 contrib/apps/tcpecho/tcpecho.c create mode 100644 contrib/apps/tcpecho/tcpecho.h create mode 100644 contrib/apps/tcpecho_raw/tcpecho_raw.c create mode 100644 contrib/apps/tcpecho_raw/tcpecho_raw.h create mode 100644 contrib/apps/udpecho/udpecho.c create mode 100644 contrib/apps/udpecho/udpecho.h create mode 100644 contrib/apps/udpecho_raw/udpecho_raw.c create mode 100644 contrib/apps/udpecho_raw/udpecho_raw.h create mode 100644 contrib/examples/ethernetif/ethernetif.c create mode 100644 contrib/examples/example_app/default_netif.h create mode 100644 contrib/examples/example_app/lwipcfg.h.ci create mode 100644 contrib/examples/example_app/lwipcfg.h.example create mode 100644 contrib/examples/example_app/lwipopts.h create mode 100644 contrib/examples/example_app/lwippools.h create mode 100644 contrib/examples/example_app/ppp_settings.h create mode 100644 contrib/examples/example_app/test.c create mode 100644 contrib/examples/example_app/test_configs/opt_default.h create mode 100644 contrib/examples/example_app/test_configs/opt_dualstack.h create mode 100644 contrib/examples/example_app/test_configs/opt_ipv4only.h create mode 100644 contrib/examples/example_app/test_configs/opt_ipv6only.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_tcp_dualstack.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_tcp_ipv4only.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_tcp_ipv6only.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_udp_dualstack.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_udp_ipv4only.h create mode 100644 contrib/examples/example_app/test_configs/opt_no_udp_ipv6only.h create mode 100644 contrib/examples/example_app/test_configs/opt_none.h create mode 100644 contrib/examples/example_app/test_configs/opt_nosys_dual.h create mode 100644 contrib/examples/example_app/test_configs/opt_nosys_ipv4.h create mode 100644 contrib/examples/example_app/test_configs/opt_nosys_ipv6.h create mode 100644 contrib/examples/httpd/cgi_example/cgi_example.c create mode 100644 contrib/examples/httpd/cgi_example/cgi_example.h create mode 100644 contrib/examples/httpd/examples_fs/404.html create mode 100644 contrib/examples/httpd/examples_fs/img/sics.gif create mode 100644 contrib/examples/httpd/examples_fs/index.html create mode 100644 contrib/examples/httpd/examples_fs/login.html create mode 100644 contrib/examples/httpd/examples_fs/loginfail.html create mode 100644 contrib/examples/httpd/examples_fs/session.html create mode 100644 contrib/examples/httpd/examples_fs/ssi.shtml create mode 100644 contrib/examples/httpd/examples_fsdata.c create mode 100644 contrib/examples/httpd/fs_example/fs_example.c create mode 100644 contrib/examples/httpd/fs_example/fs_example.h create mode 100644 contrib/examples/httpd/genfiles_example/genfiles_example.c create mode 100644 contrib/examples/httpd/genfiles_example/genfiles_example.h create mode 100644 contrib/examples/httpd/https_example/https_example.c create mode 100644 contrib/examples/httpd/https_example/https_example.h create mode 100644 contrib/examples/httpd/post_example/post_example.c create mode 100644 contrib/examples/httpd/ssi_example/ssi_example.c create mode 100644 contrib/examples/httpd/ssi_example/ssi_example.h create mode 100644 contrib/examples/lwiperf/lwiperf_example.c create mode 100644 contrib/examples/lwiperf/lwiperf_example.h create mode 100644 contrib/examples/mdns/mdns_example.c create mode 100644 contrib/examples/mdns/mdns_example.h create mode 100644 contrib/examples/mqtt/mqtt_example.c create mode 100644 contrib/examples/mqtt/mqtt_example.h create mode 100644 contrib/examples/ppp/pppos_example.c create mode 100644 contrib/examples/ppp/pppos_example.h create mode 100644 contrib/examples/snmp/snmp_example.c create mode 100644 contrib/examples/snmp/snmp_example.h create mode 100644 contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c create mode 100644 contrib/examples/snmp/snmp_private_mib/private_mib.h create mode 100644 contrib/examples/snmp/snmp_v3/snmpv3_dummy.c create mode 100644 contrib/examples/snmp/snmp_v3/snmpv3_dummy.h create mode 100644 contrib/examples/sntp/sntp_example.c create mode 100644 contrib/examples/sntp/sntp_example.h create mode 100644 contrib/examples/tftp/tftp_example.c create mode 100644 contrib/examples/tftp/tftp_example.h create mode 100644 contrib/ports/CMakeCommon.cmake create mode 100644 contrib/ports/Common.allports.mk create mode 100644 contrib/ports/freertos/include/arch/sys_arch.h create mode 100644 contrib/ports/freertos/sys_arch.c create mode 100644 contrib/ports/unix/Common.mk create mode 100644 contrib/ports/unix/Filelists.cmake create mode 100644 contrib/ports/unix/README create mode 100644 contrib/ports/unix/check/CMakeLists.txt create mode 100644 contrib/ports/unix/check/Makefile create mode 100644 contrib/ports/unix/check/README create mode 100644 contrib/ports/unix/check/config.h create mode 100644 contrib/ports/unix/example_app/CMakeLists.txt create mode 100644 contrib/ports/unix/example_app/Makefile create mode 100644 contrib/ports/unix/example_app/default_netif.c create mode 100755 contrib/ports/unix/example_app/iteropts.sh create mode 100644 contrib/ports/unix/lib/CMakeLists.txt create mode 100644 contrib/ports/unix/lib/README create mode 100644 contrib/ports/unix/lib/lwipopts.h create mode 100644 contrib/ports/unix/port/include/arch/cc.h create mode 100644 contrib/ports/unix/port/include/arch/perf.h create mode 100644 contrib/ports/unix/port/include/arch/sys_arch.h create mode 100644 contrib/ports/unix/port/include/netif/fifo.h create mode 100644 contrib/ports/unix/port/include/netif/list.h create mode 100644 contrib/ports/unix/port/include/netif/pcapif.h create mode 100644 contrib/ports/unix/port/include/netif/sio.h create mode 100644 contrib/ports/unix/port/include/netif/tapif.h create mode 100644 contrib/ports/unix/port/include/netif/vdeif.h create mode 100644 contrib/ports/unix/port/netif/fifo.c create mode 100644 contrib/ports/unix/port/netif/list.c create mode 100644 contrib/ports/unix/port/netif/pcapif.c create mode 100644 contrib/ports/unix/port/netif/sio.c create mode 100644 contrib/ports/unix/port/netif/tapif.c create mode 100644 contrib/ports/unix/port/netif/vdeif.c create mode 100644 contrib/ports/unix/port/perf.c create mode 100644 contrib/ports/unix/port/sys_arch.c create mode 100644 contrib/ports/unix/posixlib/CMakeLists.txt create mode 100644 contrib/ports/unix/posixlib/Uninstall.cmake create mode 100644 contrib/ports/unix/posixlib/include/posix/inet.h create mode 100644 contrib/ports/unix/posixlib/include/posix/sockets.h create mode 100644 contrib/ports/unix/posixlib/lwipopts.h create mode 100755 contrib/ports/unix/setup-tapif create mode 100644 contrib/ports/win32/Common.mk create mode 100644 contrib/ports/win32/Filelists.cmake create mode 100644 contrib/ports/win32/check/check_stdint.h create mode 100644 contrib/ports/win32/check/config.h create mode 100644 contrib/ports/win32/check/stdbool.h create mode 100644 contrib/ports/win32/check/sys/time.h create mode 100644 contrib/ports/win32/check/time.c create mode 100644 contrib/ports/win32/check/unistd.h create mode 100644 contrib/ports/win32/example_app/CMakeLists.txt create mode 100644 contrib/ports/win32/example_app/Makefile create mode 100644 contrib/ports/win32/example_app/default_netif.c create mode 100644 contrib/ports/win32/include/arch/bpstruct.h create mode 100644 contrib/ports/win32/include/arch/cc.h create mode 100644 contrib/ports/win32/include/arch/epstruct.h create mode 100644 contrib/ports/win32/include/arch/perf.h create mode 100644 contrib/ports/win32/include/arch/sys_arch.h create mode 100644 contrib/ports/win32/msvc/build_coverity.cmd create mode 100644 contrib/ports/win32/msvc/libcheck.vcxproj create mode 100644 contrib/ports/win32/msvc/libcheck.vcxproj.filters create mode 100644 contrib/ports/win32/msvc/lwIP.vcxproj create mode 100644 contrib/ports/win32/msvc/lwIP.vcxproj.filters create mode 100644 contrib/ports/win32/msvc/lwIP_Test.sln create mode 100644 contrib/ports/win32/msvc/lwIP_Test.vcxproj create mode 100644 contrib/ports/win32/msvc/lwIP_Test.vcxproj.filters create mode 100644 contrib/ports/win32/msvc/lwIP_fuzz.sln create mode 100644 contrib/ports/win32/msvc/lwIP_pcapif.vcxproj create mode 100644 contrib/ports/win32/msvc/lwIP_pcapif.vcxproj.filters create mode 100644 contrib/ports/win32/msvc/lwIP_unittests.sln create mode 100644 contrib/ports/win32/msvc/lwip_fuzz.vcxproj create mode 100644 contrib/ports/win32/msvc/lwip_unittests.vcxproj create mode 100644 contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters create mode 100644 contrib/ports/win32/msvc/makefsdata.vcxproj create mode 100644 contrib/ports/win32/msvc/makefsdata.vcxproj.filters create mode 100644 contrib/ports/win32/pcapif.c create mode 100644 contrib/ports/win32/pcapif.h create mode 100644 contrib/ports/win32/pcapif_helper.c create mode 100644 contrib/ports/win32/pcapif_helper.h create mode 100644 contrib/ports/win32/readme.txt create mode 100644 contrib/ports/win32/sio.c create mode 100644 contrib/ports/win32/sys_arch.c delete mode 100644 lwip-2.1.3.tar.xz delete mode 100644 lwip.spec delete mode 100644 pax_global_header create mode 100644 src/apps/mdns/mdns_domain.c create mode 100644 src/apps/mdns/mdns_out.c rename src/apps/tftp/{tftp_server.c => tftp.c} (67%) delete mode 100644 src/core/distributed_net/distributed_net.c delete mode 100644 src/core/distributed_net/distributed_net_core.c delete mode 100644 src/core/distributed_net/distributed_net_utils.c delete mode 100644 src/core/distributed_net/udp_transmit.c create mode 100644 src/core/ipv4/acd.c delete mode 100644 src/core/lowpower.c delete mode 100644 src/core/net_group.c create mode 100644 src/include/lwip/acd.h create mode 100644 src/include/lwip/apps/mdns_domain.h create mode 100644 src/include/lwip/apps/mdns_out.h create mode 100644 src/include/lwip/apps/tftp_client.h create mode 100644 src/include/lwip/apps/tftp_common.h delete mode 100644 src/include/lwip/distributed_net/distributed_net.h delete mode 100644 src/include/lwip/distributed_net/distributed_net_core.h delete mode 100644 src/include/lwip/distributed_net/distributed_net_utils.h delete mode 100644 src/include/lwip/distributed_net/udp_transmit.h delete mode 100644 src/include/lwip/lowpower.h delete mode 100644 src/include/lwip/net_group.h create mode 100644 src/include/lwip/prot/acd.h create mode 100644 test/fuzz/fuzz2.c create mode 100644 test/fuzz/fuzz3.c create mode 100644 test/fuzz/fuzz_common.c create mode 100644 test/fuzz/fuzz_common.h create mode 100644 test/unit/Makefile create mode 100644 test/unit/core/test_dns.c create mode 100644 test/unit/core/test_dns.h create mode 100644 test/unit/ppp/test_pppos.c create mode 100644 test/unit/ppp/test_pppos.h create mode 100644 test/unit/tcp/test_tcp_state.c create mode 100644 test/unit/tcp/test_tcp_state.h diff --git a/0001-add-makefile.patch b/0001-add-makefile.patch deleted file mode 100644 index 9f48bdf..0000000 --- a/0001-add-makefile.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 777db45e3ae9c17abf397daf79a129ad5ed1e0cf Mon Sep 17 00:00:00 2001 -From: peanut_huang -Date: Mon, 30 Nov 2020 06:53:46 +0000 -Subject: [PATCH] add makefile - -Signed-off-by: peanut_huang ---- - src/Makefile | 60 ++++++++++++++++++++++++++++ - src/api/dir.mk | 3 ++ - src/core/dir.mk | 6 +++ - src/include/arch/cc.h | 7 ++++ - src/include/arch/sys_arch.h | 7 ++++ - src/include/lwipopts.h | 80 +++++++++++++++++++++++++++++++++++++ - src/netif/dir.mk | 3 ++ - 7 files changed, 166 insertions(+) - create mode 100644 src/Makefile - create mode 100644 src/api/dir.mk - create mode 100644 src/core/dir.mk - create mode 100644 src/include/arch/cc.h - create mode 100644 src/include/arch/sys_arch.h - create mode 100644 src/include/lwipopts.h - create mode 100644 src/netif/dir.mk - -diff --git a/src/Makefile b/src/Makefile -new file mode 100644 -index 0000000..3ecf8d2 ---- /dev/null -+++ b/src/Makefile -@@ -0,0 +1,60 @@ -+LWIP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -+ROOT_DIR := $(dir $(abspath $(LWIP_DIR))) -+ -+LWIP_INC = $(LWIP_DIR)/include -+#DPDK_INCLUDE_FILE ?= /usr/include/dpdk -+ -+SEC_FLAGS = -fstack-protector-strong -Werror -Wall -Wl,-z,relro,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIC -+ -+CC = gcc -+AR = ar -+OPTIMIZATION = -O3 -+INC = -I$(LWIP_DIR) \ -+ -I$(LWIP_INC) -+ -+CFLAGS = -g $(OPTIMIZATION) $(INC) $(SEC_FLAGS) -+ARFLAGS = crDP -+ -+ifeq ($(shell $(CC) -dumpmachine | cut -d"-" -f1), x86_64) -+ CFLAGS += -mssse3 -+endif -+ -+SRCS = -+DIRS = api core netif -+ -+define register_dir -+SRCS += $(patsubst %, $(1)/%, $(2)) -+endef -+ -+include $(patsubst %, %/dir.mk, $(DIRS)) -+ -+OBJS = $(subst .c,.o,$(SRCS)) -+TMPS := $(subst .c,.s,$(SRCS)) -+TMPS += $(subst .c,.i,$(SRCS)) -+ -+LWIP_LIB = liblwip.a -+ -+INSTALL_LIB = $(DESTDIR)/usr/lib64 -+INSTALL_INC = $(DESTDIR)/usr/include/lwip -+ -+.PHONY: all -+all: $(LWIP_LIB) -+ -+.depend: $(SRCS) -+ rm -f ./.depend -+ $(foreach SRC,$(SRCS),$(CC) $(CFLAGS) -MM -MT $(SRC:.c=.o) $(SRC) >> .depend;) -+ -+-include .depend -+ -+$(LWIP_LIB): $(OBJS) -+ $(AR) $(ARFLAGS) $@ $(OBJS) -+ -+.PHONY: install -+install: -+ install -dp $(INSTALL_LIB) $(INSTALL_INC) -+ install -Dp $(LWIP_DIR)/$(LWIP_LIB) $(INSTALL_LIB) -+ cp -pr $(LWIP_INC)/* $(INSTALL_INC)/ -+ -+.PHONY: clean -+clean: -+ $(RM) $(LWIP_LIB) $(OBJS) $(TMPS) .depend -diff --git a/src/api/dir.mk b/src/api/dir.mk -new file mode 100644 -index 0000000..72142ab ---- /dev/null -+++ b/src/api/dir.mk -@@ -0,0 +1,3 @@ -+SRC = api_lib.c api_msg.c err.c netbuf.c netdb.c netifapi.c sockets.c tcpip.c -+ -+$(eval $(call register_dir, api, $(SRC))) -diff --git a/src/core/dir.mk b/src/core/dir.mk -new file mode 100644 -index 0000000..e5a055b ---- /dev/null -+++ b/src/core/dir.mk -@@ -0,0 +1,6 @@ -+SRC = inet_chksum.c init.c ip.c mem.c memp.c netif.c pbuf.c \ -+ raw.c stats.c tcp.c tcp_in.c tcp_out.c timeouts.c udp.c \ -+ ipv4/etharp.c ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4.c \ -+ ipv4/ip4_frag.c -+ -+$(eval $(call register_dir, core, $(SRC))) -diff --git a/src/include/arch/cc.h b/src/include/arch/cc.h -new file mode 100644 -index 0000000..52b76f9 ---- /dev/null -+++ b/src/include/arch/cc.h -@@ -0,0 +1,7 @@ -+#ifndef LWIP_CC_H -+#define LWIP_CC_H -+ -+ -+ -+#endif /* LWIP_CC_H */ -+ -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -new file mode 100644 -index 0000000..3f555ee ---- /dev/null -+++ b/src/include/arch/sys_arch.h -@@ -0,0 +1,7 @@ -+#ifndef LWIP_SYS_ARCH_H -+#define LWIP_SYS_ARCH_H -+ -+ -+ -+#endif /* LWIP_SYS_ARCH_H */ -+ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -new file mode 100644 -index 0000000..4ab26f2 ---- /dev/null -+++ b/src/include/lwipopts.h -@@ -0,0 +1,80 @@ -+/* -+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Simon Goldschmidt -+ * -+ */ -+#ifndef LWIP_HDR_LWIPOPTS_H__ -+#define LWIP_HDR_LWIPOPTS_H__ -+ -+/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ -+#define NO_SYS 1 -+#define LWIP_NETCONN 0 -+#define LWIP_SOCKET 0 -+#define SYS_LIGHTWEIGHT_PROT 0 -+ -+#define LWIP_IPV6 1 -+#define IPV6_FRAG_COPYHEADER 1 -+#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 0 -+ -+/* Enable some protocols to test them */ -+#define LWIP_DHCP 1 -+#define LWIP_AUTOIP 1 -+ -+#define LWIP_IGMP 1 -+#define LWIP_DNS 1 -+ -+#define LWIP_ALTCP 1 -+ -+/* Turn off checksum verification of fuzzed data */ -+#define CHECKSUM_CHECK_IP 0 -+#define CHECKSUM_CHECK_UDP 0 -+#define CHECKSUM_CHECK_TCP 0 -+#define CHECKSUM_CHECK_ICMP 0 -+#define CHECKSUM_CHECK_ICMP6 0 -+ -+/* Minimal changes to opt.h required for tcp unit tests: */ -+#define MEM_SIZE 16000 -+#define TCP_SND_QUEUELEN 40 -+#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN -+#define TCP_OVERSIZE 1 -+#define TCP_SND_BUF (12 * TCP_MSS) -+#define TCP_WND (10 * TCP_MSS) -+#define LWIP_WND_SCALE 1 -+#define TCP_RCV_SCALE 2 -+#define PBUF_POOL_SIZE 400 /* pbuf tests need ~200KByte */ -+ -+/* Minimal changes to opt.h required for etharp unit tests: */ -+#define ETHARP_SUPPORT_STATIC_ENTRIES 1 -+ -+#define LWIP_NUM_NETIF_CLIENT_DATA 1 -+#define LWIP_SNMP 1 -+#define MIB2_STATS 1 -+#define LWIP_MDNS_RESPONDER 1 -+ -+#endif /* LWIP_HDR_LWIPOPTS_H__ */ -diff --git a/src/netif/dir.mk b/src/netif/dir.mk -new file mode 100644 -index 0000000..233c79a ---- /dev/null -+++ b/src/netif/dir.mk -@@ -0,0 +1,3 @@ -+SRC = ethernet.c -+ -+$(eval $(call register_dir, netif, $(SRC))) --- -2.23.0 - diff --git a/0002-adapt-lstack.patch b/0002-adapt-lstack.patch deleted file mode 100644 index 87f36cd..0000000 --- a/0002-adapt-lstack.patch +++ /dev/null @@ -1,5569 +0,0 @@ -From 388525230f809bfa61fe31921b54ebfb6aae57ec Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 31 Dec 2021 17:32:49 +0800 -Subject: [PATCH] adapt lstack - ---- - src/Makefile | 5 +- - src/api/api_lib.c | 2 + - src/api/api_msg.c | 46 +++ - src/api/dir.mk | 2 +- - src/api/perf.c | 182 ++++++++++++ - src/api/posix_api.c | 156 ++++++++++ - src/api/sockets.c | 558 ++++++++++++++++++++++++++++++++++- - src/api/sys_arch.c | 379 ++++++++++++++++++++++++ - src/api/tcpip.c | 34 ++- - src/core/dir.mk | 8 +- - src/core/init.c | 4 +- - src/core/ip.c | 2 +- - src/core/ipv4/ip4.c | 14 + - src/core/ipv6/ip6.c | 10 + - src/core/mem.c | 6 +- - src/core/memp.c | 4 + - src/core/netif.c | 8 +- - src/core/pbuf.c | 4 + - src/core/stats.c | 13 +- - src/core/tcp.c | 196 +++++++++++- - src/core/tcp_in.c | 101 ++++++- - src/core/tcp_out.c | 25 +- - src/core/timeouts.c | 18 +- - src/core/udp.c | 15 + - src/include/arch/cc.h | 80 ++++- - src/include/arch/perf.h | 155 ++++++++++ - src/include/arch/sys_arch.h | 92 +++++- - src/include/eventpoll.h | 72 +++++ - src/include/hlist.h | 233 +++++++++++++++ - src/include/list.h | 110 +++++++ - src/include/lwip/api.h | 35 +++ - src/include/lwip/debug.h | 1 + - src/include/lwip/def.h | 15 + - src/include/lwip/ip.h | 8 +- - src/include/lwip/memp.h | 17 ++ - src/include/lwip/netif.h | 4 +- - src/include/lwip/opt.h | 62 +++- - src/include/lwip/priv/memp_std.h | 7 + - src/include/lwip/priv/sockets_priv.h | 49 +-- - src/include/lwip/priv/tcp_priv.h | 162 +++++++++- - src/include/lwip/prot/ip4.h | 15 + - src/include/lwip/sockets.h | 67 ++++- - src/include/lwip/stats.h | 4 +- - src/include/lwip/tcp.h | 94 +++++- - src/include/lwip/tcpip.h | 2 +- - src/include/lwip/timeouts.h | 4 + - src/include/lwiplog.h | 81 +++++ - src/include/lwipopts.h | 253 ++++++++++++---- - src/include/lwipsock.h | 155 ++++++++++ - src/include/memp_def.h | 66 +++++ - src/include/posix_api.h | 88 ++++++ - src/include/reg_sock.h | 62 ++++ - src/netif/dir.mk | 2 +- - 53 files changed, 3581 insertions(+), 206 deletions(-) - create mode 100644 src/api/perf.c - create mode 100644 src/api/posix_api.c - create mode 100644 src/api/sys_arch.c - create mode 100644 src/include/arch/perf.h - create mode 100644 src/include/eventpoll.h - create mode 100644 src/include/hlist.h - create mode 100644 src/include/list.h - create mode 100644 src/include/lwiplog.h - create mode 100644 src/include/lwipsock.h - create mode 100644 src/include/memp_def.h - create mode 100644 src/include/posix_api.h - create mode 100644 src/include/reg_sock.h - -diff --git a/src/Makefile b/src/Makefile -index 3ecf8d2..1676a71 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -2,7 +2,7 @@ LWIP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) - ROOT_DIR := $(dir $(abspath $(LWIP_DIR))) - - LWIP_INC = $(LWIP_DIR)/include --#DPDK_INCLUDE_FILE ?= /usr/include/dpdk -+DPDK_INCLUDE_FILE ?= /usr/include/dpdk - - SEC_FLAGS = -fstack-protector-strong -Werror -Wall -Wl,-z,relro,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIC - -@@ -10,7 +10,8 @@ CC = gcc - AR = ar - OPTIMIZATION = -O3 - INC = -I$(LWIP_DIR) \ -- -I$(LWIP_INC) -+ -I$(LWIP_INC) \ -+ -I$(DPDK_INCLUDE_FILE) - - CFLAGS = -g $(OPTIMIZATION) $(INC) $(SEC_FLAGS) - ARFLAGS = crDP -diff --git a/src/api/api_lib.c b/src/api/api_lib.c -index ffa14d6..ba9f3c5 100644 ---- a/src/api/api_lib.c -+++ b/src/api/api_lib.c -@@ -1061,7 +1061,9 @@ netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u1 - /* For locking the core: this _can_ be delayed on low memory/low send buffer, - but if it is, this is done inside api_msg.c:do_write(), so we can use the - non-blocking version here. */ -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_DATA_SEND); - err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); -+ PERF_STOP_INCREASE_COUNT("lwip_netconn_do_write", PERF_LAYER_TCP); - if (err == ERR_OK) { - if (bytes_written != NULL) { - *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset; -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 3f08e03..d5a738f 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -54,6 +54,11 @@ - #include "lwip/mld6.h" - #include "lwip/priv/tcpip_priv.h" - -+#if USE_LIBOS -+#include "lwip/sockets.h" -+#include "lwipsock.h" -+#endif -+ - #include - - /* netconns are polled once per second (e.g. continue write on memory error) */ -@@ -452,6 +457,14 @@ err_tcp(void *arg, err_t err) - old_state = conn->state; - conn->state = NETCONN_NONE; - -+#if USE_LIBOS -+ if (CONN_TYPE_IS_HOST(conn)) { -+ LWIP_DEBUGF(API_MSG_DEBUG, -+ ("linux localhost connection already success, ignore lwip err_tcp fd=%d\n", conn->socket)); -+ return; -+ } -+#endif /* USE_LIBOS */ -+ - SYS_ARCH_UNPROTECT(lev); - - /* Notify the user layer about a connection error. Used to signal select. */ -@@ -595,6 +608,10 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - -+#if USE_LIBOS -+ LWIP_DEBUGF(API_MSG_DEBUG, ("libos incoming connection established\n")); -+ SET_CONN_TYPE_LIBOS(newconn); -+#endif - return ERR_OK; - } - #endif /* LWIP_TCP */ -@@ -1315,6 +1332,31 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - return ERR_VAL; - } - -+#if USE_LIBOS -+ if (CONN_TYPE_IS_HOST(conn)) { -+ LWIP_DEBUGF(API_MSG_DEBUG, -+ ("libos outgoing connection abort fd=%d\n", conn->socket)); -+ return ERR_ABRT; -+ } -+ -+ LWIP_DEBUGF(API_MSG_DEBUG, ("libos outgoing connection established\n")); -+ if (CONN_TYPE_HAS_INPRG(conn) && CONN_TYPE_HAS_HOST(conn)) { -+ int s = conn->socket; -+ struct lwip_sock *sock = get_socket_without_errno(s); -+ -+ if (!!sock && !!sock->epoll_data) { -+ struct epoll_event ee = {0}; -+ ee.data.fd = s; -+ ee.events |= EPOLLIN | EPOLLOUT | EPOLLERR; -+ posix_api->epoll_ctl_fn(sock->epoll_data->fd, EPOLL_CTL_DEL, s, &ee); -+ posix_api->shutdown_fn(s, SHUT_RDWR); -+ LWIP_DEBUGF(API_MSG_DEBUG, -+ ("linux outgoing connection abort fd=%d\n", s)); -+ } -+ } -+ SET_CONN_TYPE_LIBOS(conn); -+#endif -+ - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); - LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", - (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); -@@ -1338,6 +1380,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - if (was_blocking) { - sys_sem_signal(op_completed_sem); - } -+ - return ERR_OK; - } - #endif /* LWIP_TCP */ -@@ -1372,6 +1415,7 @@ lwip_netconn_do_connect(void *m) - #endif /* LWIP_UDP */ - #if LWIP_TCP - case NETCONN_TCP: -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_SEND); - /* Prevent connect while doing any other action. */ - if (msg->conn->state == NETCONN_CONNECT) { - err = ERR_ALREADY; -@@ -1389,6 +1433,7 @@ lwip_netconn_do_connect(void *m) - err = ERR_INPROGRESS; - } else { - msg->conn->current_msg = msg; -+ PERF_STOP_INCREASE_COUNT("lwip_netconn_do_connect", PERF_LAYER_TCP); - /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), - when the connection is established! */ - #if LWIP_TCPIP_CORE_LOCKING -@@ -1402,6 +1447,7 @@ lwip_netconn_do_connect(void *m) - } - } - } -+ PERF_STOP_INCREASE_COUNT("lwip_netconn_do_connect", PERF_LAYER_TCP); - break; - #endif /* LWIP_TCP */ - default: -diff --git a/src/api/dir.mk b/src/api/dir.mk -index 72142ab..afbf863 100644 ---- a/src/api/dir.mk -+++ b/src/api/dir.mk -@@ -1,3 +1,3 @@ --SRC = api_lib.c api_msg.c err.c netbuf.c netdb.c netifapi.c sockets.c tcpip.c -+SRC = api_lib.c api_msg.c err.c netbuf.c netdb.c netifapi.c sockets.c tcpip.c perf.c posix_api.c sys_arch.c - - $(eval $(call register_dir, api, $(SRC))) -diff --git a/src/api/perf.c b/src/api/perf.c -new file mode 100644 -index 0000000..1c2a273 ---- /dev/null -+++ b/src/api/perf.c -@@ -0,0 +1,182 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#include "arch/perf.h" -+ -+#include -+ -+#include -+ -+#if LWIP_RECORD_PERF -+ -+#define SIG_FUNC_NUM 3 -+ -+#define SIG_STATS_DISPLAY 38 -+#define SIG_PERF_BEGIN 39 -+#define SIG_PERF_END 40 -+ -+typedef void (*pSignalFunc) (int); -+static void signal_stats_display(int s); -+static void signal_perf_begin(int s); -+static void signal_perf_end(int s); -+ -+uint32_t g_record_perf; -+__thread uint64_t g_timeTaken[PERF_POINT_END]; -+__thread int g_perfPoint[PERF_LAYER_END]; -+__thread struct timespec tvStart[PERF_LAYER_END]; -+volatile uint64_t g_perfMaxtime[PERF_POINT_END]; -+volatile uint64_t g_astPacketCnt[PERF_POINT_END]; -+volatile uint64_t g_astPacketProcTime[PERF_POINT_END]; -+ -+char *g_ppLayerName[PERF_POINT_END] = { -+ "IP_RECV", -+ "TCP_DATA_RECV", -+ "UDP_PARTIAL", -+ "TCP_SYN_RECV", -+ "TCP_SYN_ACK_SEND", -+ "TCP_ACK_RECV", -+ "TCP_SYN_SEND", -+ "TCP_SYN_ACK_RECV", -+ "TCP_ACK_SEND", -+ "TCP_DATA_SEND", -+ "IP_SEND" -+}; -+ -+static int gsig_arr[SIG_FUNC_NUM] = { -+ SIG_STATS_DISPLAY, -+ SIG_PERF_BEGIN, -+ SIG_PERF_END -+}; -+ -+static pSignalFunc g_Funcs[SIG_FUNC_NUM] = { -+ signal_stats_display, -+ signal_perf_begin, -+ signal_perf_end, -+}; -+ -+static void print_perf_data_and_reset() -+{ -+ int i; -+ printf("\n********* PERF DATA START*************\n"); -+ for (i = 0; i < PERF_POINT_END; i++) { -+ printf("%-20s Total: PacketProcTime: %-15"PRIu64", Maxtime: %-15"PRIu64", packetCnt: %-15"PRIu64"\n", -+ g_ppLayerName[i], __sync_fetch_and_or(&g_astPacketProcTime[i], 0), -+ __sync_fetch_and_or(&g_perfMaxtime[i], 0), -+ __sync_fetch_and_or(&g_astPacketCnt[i], 0)); -+ -+ if (__sync_fetch_and_or(&g_astPacketProcTime[i], 0) && __sync_fetch_and_or(&g_astPacketCnt[i], 0)) { -+ printf("%-20s Average: PacketProcTime: %-15lf, MaxTime: %-15"PRIu64"\n", g_ppLayerName[i], -+ (double)__sync_fetch_and_or(&g_astPacketProcTime[i], 0) / (double)__sync_fetch_and_or(&g_astPacketCnt[i], 0), -+ __sync_or_and_fetch(&g_perfMaxtime[i], 0)); -+ } -+ -+ __sync_fetch_and_and (&g_astPacketProcTime[i], 0); -+ __sync_fetch_and_and (&g_astPacketCnt[i], 0); -+ __sync_fetch_and_and (&g_perfMaxtime[i], 0); -+ } -+ printf("\n********* PERF DATA END*************\n"); -+} -+ -+static void signal_stats_display(int s) -+{ -+ struct sigaction s_test; -+ printf("Received signal %d, stats display.\n", s); -+ stats_display(); -+ s_test.sa_handler = (void *) signal_stats_display; -+ if (sigemptyset(&s_test.sa_mask) != 0) { -+ printf("sigemptyset failed.\n"); -+ } -+ s_test.sa_flags = SA_RESETHAND; -+ if (sigaction(s, &s_test, NULL) != 0) { -+ printf("Could not register %d signal handler.\n", s); -+ } -+} -+ -+static void signal_perf_begin(int s) -+{ -+ struct sigaction s_test; -+ printf("Received signal %d, perf_begin.\n", s); -+ g_record_perf = 1; -+ s_test.sa_handler = (void *) signal_perf_begin; -+ if (sigemptyset(&s_test.sa_mask) != 0) { -+ printf("sigemptyset failed.\n"); -+ } -+ s_test.sa_flags = SA_RESETHAND; -+ if (sigaction(s, &s_test, NULL) != 0) { -+ printf("Could not register %d signal handler.\n", s); -+ } -+} -+ -+static void signal_perf_end(int s) -+{ -+ struct sigaction s_test; -+ printf("Received signal %d, perf_end\n", s); -+ g_record_perf = 0; -+ print_perf_data_and_reset(); -+ s_test.sa_handler = (void *) signal_perf_end; -+ if (sigemptyset(&s_test.sa_mask) != 0) { -+ printf("sigemptyset failed.\n"); -+ } -+ s_test.sa_flags = SA_RESETHAND; -+ if (sigaction(s, &s_test, NULL) != 0) { -+ printf("Could not register %d signal handler.\n", s); -+ } -+} -+ -+int check_layer_point(int layer, int point) -+{ -+ if (point == g_perfPoint[layer]) { -+ return 1; -+ } -+ return 0; -+} -+ -+int perf_init(void) -+{ -+ int i; -+ struct sigaction s_test; -+ for (i = 0; i < SIG_FUNC_NUM; i++) { -+ s_test.sa_handler = (void *) g_Funcs[i]; -+ if (sigemptyset(&s_test.sa_mask) != 0) { -+ printf("sigemptyset failed.\n"); -+ return 1; -+ } -+ -+ s_test.sa_flags = SA_RESETHAND; -+ if (sigaction(gsig_arr[i], &s_test, NULL) != 0) { -+ printf("Could not register %d signal handler.\n", gsig_arr[i]); -+ return 1; -+ } -+ } -+ return 0; -+} -+#endif -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -new file mode 100644 -index 0000000..a917cea ---- /dev/null -+++ b/src/api/posix_api.c -@@ -0,0 +1,156 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "lwip/err.h" -+#include "lwipsock.h" -+ -+posix_api_t *posix_api; -+posix_api_t posix_api_val; -+ -+static int chld_is_epfd(int fd) -+{ -+ return 0; -+} -+ -+static struct lwip_sock *chld_get_socket(int fd) -+{ -+ return NULL; -+} -+ -+void posix_api_fork(void) -+{ -+ /* lstack helper api */ -+ posix_api->is_chld = 1; -+ posix_api->is_epfd = chld_is_epfd; -+ posix_api->get_socket = chld_get_socket; -+} -+ -+static int chose_dlsym_handle(void *__restrict* khandle) -+{ -+ void *dlhandle; -+ int (*gazelle_epoll_create)(int size); -+ dlhandle = dlopen ("liblstack.so", RTLD_LAZY); -+ if (dlhandle == NULL) { -+ return ERR_IF; -+ } -+ -+ gazelle_epoll_create = dlsym(dlhandle, "epoll_create"); -+ if (gazelle_epoll_create == NULL) { -+ return ERR_MEM; -+ } -+ -+ dlclose(dlhandle); -+ -+ *khandle = RTLD_NEXT; -+ if (dlsym(*khandle, "epoll_create") == gazelle_epoll_create) { -+ RTE_LOG(ERR, EAL, "posix api use RTLD_DEFAULT\n"); -+ *khandle = RTLD_DEFAULT; -+ } else { -+ RTE_LOG(ERR, EAL, "posix api use RTLD_NEXT\n"); -+ } -+ -+ return ERR_OK; -+} -+ -+int posix_api_init(void) -+{ -+/* the symbol we use here won't be NULL, so we don't need dlerror() -+ to test error */ -+#define CHECK_DLSYM_RET_RETURN(ret) do { \ -+ if ((ret) == NULL) \ -+ goto err_out; \ -+ } while (0) -+ -+ posix_api = &posix_api_val; -+ -+ void *__restrict handle; -+ int ret = chose_dlsym_handle(&handle); -+ if (ret != ERR_OK) { -+ return ret; -+ } -+ -+ /* glibc standard api */ -+ CHECK_DLSYM_RET_RETURN(posix_api->socket_fn = dlsym(handle, "socket")); -+ CHECK_DLSYM_RET_RETURN(posix_api->accept_fn = dlsym(handle, "accept")); -+ CHECK_DLSYM_RET_RETURN(posix_api->accept4_fn = dlsym(handle, "accept4")); -+ CHECK_DLSYM_RET_RETURN(posix_api->bind_fn = dlsym(handle, "bind")); -+ CHECK_DLSYM_RET_RETURN(posix_api->listen_fn = dlsym(handle, "listen")); -+ CHECK_DLSYM_RET_RETURN(posix_api->connect_fn = dlsym(handle, "connect")); -+ CHECK_DLSYM_RET_RETURN(posix_api->setsockopt_fn = dlsym(handle, "setsockopt")); -+ CHECK_DLSYM_RET_RETURN(posix_api->getsockopt_fn = dlsym(handle, "getsockopt")); -+ CHECK_DLSYM_RET_RETURN(posix_api->getpeername_fn = dlsym(handle, "getpeername")); -+ CHECK_DLSYM_RET_RETURN(posix_api->getsockname_fn = dlsym(handle, "getsockname")); -+ CHECK_DLSYM_RET_RETURN(posix_api->shutdown_fn = dlsym(handle, "shutdown")); -+ CHECK_DLSYM_RET_RETURN(posix_api->close_fn = dlsym(handle, "close")); -+ CHECK_DLSYM_RET_RETURN(posix_api->read_fn = dlsym(handle, "read")); -+ CHECK_DLSYM_RET_RETURN(posix_api->write_fn = dlsym(handle, "write")); -+ CHECK_DLSYM_RET_RETURN(posix_api->recv_fn = dlsym(handle, "recv")); -+ CHECK_DLSYM_RET_RETURN(posix_api->send_fn = dlsym(handle, "send")); -+ CHECK_DLSYM_RET_RETURN(posix_api->recv_msg = dlsym(handle, "recvmsg")); -+ CHECK_DLSYM_RET_RETURN(posix_api->send_msg = dlsym(handle, "sendmsg")); -+ CHECK_DLSYM_RET_RETURN(posix_api->recv_from = dlsym(handle, "recvfrom")); -+ CHECK_DLSYM_RET_RETURN(posix_api->send_to = dlsym(handle, "sendto")); -+ CHECK_DLSYM_RET_RETURN(posix_api->fcntl_fn = dlsym(handle, "fcntl")); -+ CHECK_DLSYM_RET_RETURN(posix_api->fcntl64_fn = dlsym(handle, "fcntl64")); -+ CHECK_DLSYM_RET_RETURN(posix_api->pipe_fn = dlsym(handle, "pipe")); -+ CHECK_DLSYM_RET_RETURN(posix_api->epoll_create_fn = dlsym(handle, "epoll_create")); -+ CHECK_DLSYM_RET_RETURN(posix_api->epoll_ctl_fn = dlsym(handle, "epoll_ctl")); -+ CHECK_DLSYM_RET_RETURN(posix_api->epoll_wait_fn = dlsym(handle, "epoll_wait")); -+ CHECK_DLSYM_RET_RETURN(posix_api->fork_fn = dlsym(handle, "fork")); -+ CHECK_DLSYM_RET_RETURN(posix_api->eventfd_fn = dlsym(handle, "eventfd")); -+ CHECK_DLSYM_RET_RETURN(posix_api->sigaction_fn = dlsym(handle, "sigaction")); -+ CHECK_DLSYM_RET_RETURN(posix_api->poll_fn = dlsym(handle, "poll")); -+ CHECK_DLSYM_RET_RETURN(posix_api->ioctl_fn = dlsym(handle, "ioctl")); -+ -+ /* lstack helper api */ -+ posix_api->get_socket = get_socket; -+ posix_api->is_epfd = lwip_is_epfd; -+ posix_api->epoll_close_fn = lwip_epoll_close; -+ -+ /* support fork */ -+ posix_api->is_chld = 0; -+ return ERR_OK; -+ -+err_out: -+ return ERR_MEM; -+#undef CHECK_DLSYM_RET_RETURN -+} -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 7852635..3262c1b 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -62,6 +62,11 @@ - #include - #endif - -+#if USE_LIBOS -+#include -+#include "lwipsock.h" -+#endif -+ - #include - - #ifdef LWIP_HOOK_FILENAME -@@ -85,13 +90,29 @@ - #define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) - #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) - -+#if USE_LIBOS -+enum KERNEL_LWIP_PATH { -+ PATH_KERNEL = 0, -+ PATH_LWIP, -+ PATH_ERR, -+}; -+#endif -+ - #if LWIP_IPV4 -+#if USE_LIBOS -+#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ -+ (sin)->sin_family = AF_INET; \ -+ (sin)->sin_port = lwip_htons((port)); \ -+ inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ -+ memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) -+#else - #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ - (sin)->sin_len = sizeof(struct sockaddr_in); \ - (sin)->sin_family = AF_INET; \ - (sin)->sin_port = lwip_htons((port)); \ - inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ - memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) -+#endif /* USE_LIBOS */ - #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ - inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ - (port) = lwip_ntohs((sin)->sin_port); }while(0) -@@ -257,7 +278,12 @@ static void lwip_socket_drop_registered_mld6_memberships(int s); - #endif /* LWIP_IPV6_MLD */ - - /** The global array of available sockets */ -+#if USE_LIBOS -+uint32_t sockets_num; -+struct lwip_sock *sockets; -+#else - static struct lwip_sock sockets[NUM_SOCKETS]; -+#endif /* USE_LIBOS */ - - #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL - #if LWIP_TCPIP_CORE_LOCKING -@@ -285,7 +311,7 @@ static struct lwip_select_cb *select_cb_list; - - /* Forward declaration of some functions */ - #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL --static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); -+void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); - #define DEFAULT_SOCKET_EVENTCB event_callback - static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); - #else -@@ -411,7 +437,13 @@ static struct lwip_sock * - tryget_socket_unconn_nouse(int fd) - { - int s = fd - LWIP_SOCKET_OFFSET; -- if ((s < 0) || (s >= NUM_SOCKETS)) { -+ -+#if USE_LIBOS -+ if ((s < 0) || (s >= sockets_num)) -+#else -+ if ((s < 0) || (s >= NUM_SOCKETS)) -+#endif /* USE_LIBOS */ -+ { - LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); - return NULL; - } -@@ -475,8 +507,13 @@ tryget_socket(int fd) - * @param fd externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ -+#if USE_LIBOS -+struct lwip_sock * -+get_socket(int fd) -+#else - static struct lwip_sock * - get_socket(int fd) -+#endif /* USE_LIBOS */ - { - struct lwip_sock *sock = tryget_socket(fd); - if (!sock) { -@@ -489,6 +526,24 @@ get_socket(int fd) - return sock; - } - -+#if USE_LIBOS -+/** -+ * Map a externally used socket index to the internal socket representation. -+ * -+ * @param s externally used socket index -+ * @return struct lwip_sock for the socket or NULL if not found without -+ * checking. -+ */ -+struct lwip_sock * -+get_socket_by_fd(int fd) -+{ -+ if ((fd < LWIP_SOCKET_OFFSET) || (fd >= sockets_num + LWIP_SOCKET_OFFSET)) { -+ return NULL; -+ } -+ return &sockets[fd - LWIP_SOCKET_OFFSET]; -+} -+#endif /* USE_LIBOS */ -+ - /** - * Allocate a new socket for a given netconn. - * -@@ -504,6 +559,62 @@ alloc_socket(struct netconn *newconn, int accepted) - SYS_ARCH_DECL_PROTECT(lev); - LWIP_UNUSED_ARG(accepted); - -+#if USE_LIBOS -+ int type, protocol = 0, domain = AF_INET; -+ switch (NETCONNTYPE_GROUP(newconn->type)) { -+ case NETCONN_RAW: -+ type = SOCK_RAW; -+ break; -+ case NETCONN_UDPLITE: -+ case NETCONN_UDP: -+ type = SOCK_DGRAM; -+ break; -+ case NETCONN_TCP: -+ type = SOCK_STREAM; -+ break; -+ default: -+ type = -1; -+ break; -+ } -+ -+ SYS_ARCH_PROTECT(lev); -+ i = posix_api->socket_fn(domain, type, protocol); -+ if (i == -1) { -+ goto err; -+ } -+ -+ if ((i < LWIP_SOCKET_OFFSET) || (i >= sockets_num + LWIP_SOCKET_OFFSET)) { -+ goto err; -+ } -+ -+ if (!sockets[i].conn && (sockets[i].select_waiting == 0)) { -+ /*initialize state as NETCONN_HOST | NETCONN_LIBOS, -+ *if connection accepted and alloc_socket called, it can be only NETCONN_LIBOS*/ -+ if (accepted) -+ SET_CONN_TYPE_LIBOS(newconn); -+ else -+ SET_CONN_TYPE_LIBOS_OR_HOST(newconn); -+ sockets[i].conn = newconn; -+ /* The socket is not yet known to anyone, so no need to protect -+ after having marked it as used. */ -+ SYS_ARCH_UNPROTECT(lev); -+ sockets[i].lastdata.pbuf = NULL; -+ sockets[i].rcvevent = 0; -+ /* TCP sendbuf is empty, but the socket is not yet writable until connected -+ * (unless it has been created by accept()). */ -+ sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); -+ sockets[i].errevent = 0; -+ sockets[i].epoll_data = NULL; -+ init_list_node_null(&sockets[i].list); -+ return i + LWIP_SOCKET_OFFSET; -+ } -+ -+err: -+ posix_api->close_fn(i); -+ SYS_ARCH_UNPROTECT(lev); -+ return -1; -+#else /* USE_LIBOS */ -+ - /* allocate a new socket identifier */ - for (i = 0; i < NUM_SOCKETS; ++i) { - /* Protect socket array */ -@@ -535,6 +646,8 @@ alloc_socket(struct netconn *newconn, int accepted) - SYS_ARCH_UNPROTECT(lev); - } - return -1; -+ -+#endif /* USE_LIBOS */ - } - - /** Free a socket (under lock) -@@ -629,10 +742,43 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); -+#if USE_LIBOS -+ int sys_errno = 0; -+ -+ sock = posix_api->get_socket(s); -+ /*AF_UNIX case*/ -+ if (!sock) { -+ if (rearm_accept_fd(s) < 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, -+ ("failed to rearm accept fd=%d errno=%d\n", s, errno)); -+ } -+ return posix_api->accept_fn(s, addr, addrlen); -+ } -+ -+ /*for AF_INET, we may try both linux and lwip*/ -+ if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -+ set_errno(EINVAL); -+ return -1; -+ } -+ -+ if (rearm_accept_fd(s) < 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, -+ ("failed to rearm accept fd=%d errno=%d\n", s, errno)); -+ } -+ -+ /* raise accept syscall in palce */ -+ newsock = posix_api->accept_fn(s, addr, addrlen); -+ if (newsock >= 0) { -+ return newsock; -+ } -+ sys_errno = errno; -+#else - sock = get_socket(s); - if (!sock) { - return -1; - } -+#endif - - /* wait for a new connection */ - err = netconn_accept(sock->conn, &newconn); -@@ -646,6 +792,9 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - sock_set_errno(sock, err_to_errno(err)); - } - done_socket(sock); -+#if USE_LIBOS -+ set_errno(sys_errno); -+#endif /* USE_LIBOS */ - return -1; - } - LWIP_ASSERT("newconn != NULL", newconn != NULL); -@@ -657,7 +806,11 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - done_socket(sock); - return -1; - } -+#if USE_LIBOS -+ LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < sockets_num + LWIP_SOCKET_OFFSET)); -+#else - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); -+#endif /* USE_LIBOS */ - nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; - - /* See event_callback: If data comes in right away after an accept, even -@@ -695,9 +848,11 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - } - - IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); -+#if !USE_LIBOS - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; - } -+#endif /* USE_LIBOS */ - MEMCPY(addr, &tempaddr, *addrlen); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); -@@ -720,11 +875,24 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) - ip_addr_t local_addr; - u16_t local_port; - err_t err; -- -+#if USE_LIBOS -+ sock = posix_api->get_socket(s); -+ /*AF_UNIX case*/ -+ if (!sock) { -+ return posix_api->bind_fn(s, name, namelen); -+ } -+ /*for AF_INET, we may try both linux and lwip*/ -+ if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -+ set_errno(EINVAL); -+ return -1; -+ } -+#else - sock = get_socket(s); - if (!sock) { - return -1; - } -+#endif - - if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ -@@ -744,6 +912,18 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) - ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); - -+#if USE_LIBOS -+ /* Supports kernel NIC IP address. */ -+ int ret = posix_api->bind_fn(s, name, namelen); -+ if (ret < 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("bind syscall failed\n")); -+ /* bind must succeed on both linux and libos */ -+ if (!is_host_ipv4(local_addr.addr)) { -+ return ret; -+ } -+ } -+#endif /* USE_LIBOS */ -+ - #if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ - if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { -@@ -776,10 +956,29 @@ lwip_close(int s) - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); - -+#if USE_LIBOS -+ int ret; -+ if (posix_api->is_epfd(s)) { -+ return posix_api->epoll_close_fn(s); -+ } -+ -+ ret = posix_api->close_fn(s); -+ if (ret < 0) -+ return ret; -+ if (posix_api->is_chld == 0) -+ clean_host_fd(s); -+ -+ sock = posix_api->get_socket(s); -+ /*AF_UNIX case*/ -+ if (!sock) { -+ return ret; -+ } -+#else - sock = get_socket(s); - if (!sock) { - return -1; - } -+#endif /* USE_LIBOS */ - - if (sock->conn != NULL) { - is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -@@ -803,6 +1002,13 @@ lwip_close(int s) - return -1; - } - -+#if USE_LIBOS -+ sock->epoll = LIBOS_EPOLLNONE; -+ sock->events = 0; -+ sock->epoll_data = NULL; -+ list_del_node_null(&sock->list); -+#endif -+ - free_socket(sock, is_tcp); - set_errno(0); - return 0; -@@ -814,10 +1020,28 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) - struct lwip_sock *sock; - err_t err; - -+#if USE_LIBOS -+ int ret; -+ -+ sock = posix_api->get_socket(s); -+ if (!sock) { -+ return posix_api->connect_fn(s, name, namelen); -+ } -+ -+ /* raise connect syscall in place */ -+ ADD_CONN_TYPE_INPRG(sock->conn); -+ ret = posix_api->connect_fn(s, name, namelen); -+ if (!ret) { -+ SET_CONN_TYPE_HOST(sock->conn); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("linux connect succeed fd=%d\n", s)); -+ return ret; -+ } -+#else - sock = get_socket(s); - if (!sock) { - return -1; - } -+#endif - - if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ -@@ -862,6 +1086,11 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) - return -1; - } - -+#if USE_LIBOS -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("libos connect succeed fd=%d\n",s)); -+ SET_CONN_TYPE_LIBOS(sock->conn); -+#endif /* USE_LIBOS */ -+ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); - sock_set_errno(sock, 0); - done_socket(sock); -@@ -884,10 +1113,29 @@ lwip_listen(int s, int backlog) - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); - -+#if USE_LIBOS -+ int ret; -+ -+ sock = posix_api->get_socket(s); -+ /*AF_UNIX case*/ -+ if (!sock) { -+ return posix_api->listen_fn(s, backlog); -+ } -+ /*for AF_INET, we may try both linux and lwip*/ -+ if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -+ set_errno(EADDRINUSE); -+ return -1; -+ } -+ -+ if ((ret = posix_api->listen_fn(s, backlog)) == -1) -+ return ret; -+#else - sock = get_socket(s); - if (!sock) { - return -1; - } -+#endif - - /* limit the "backlog" parameter to fit in an u8_t */ - backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); -@@ -919,6 +1167,9 @@ static ssize_t - lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - { - u8_t apiflags = NETCONN_NOAUTORCVD; -+#if USE_LIBOS -+ apiflags = 0; -+#endif - ssize_t recvd = 0; - ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; - -@@ -938,6 +1189,13 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - /* Check if there is data left from the last recv operation. */ - if (sock->lastdata.pbuf) { - p = sock->lastdata.pbuf; -+#if USE_LIBOS -+ if ((flags & MSG_PEEK) == 0) { -+ if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { -+ del_epoll_event(sock->conn, EPOLLIN); -+ } -+ } -+#endif - } else { - /* No data was left from the previous operation, so we try to get - some from the network. */ -@@ -1008,10 +1266,22 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - /* @todo: do we need to support peeking more than one pbuf? */ - } while ((recv_left > 0) && !(flags & MSG_PEEK)); - lwip_recv_tcp_done: -- if ((recvd > 0) && !(flags & MSG_PEEK)) { -- /* ensure window update after copying all data */ -- netconn_tcp_recvd(sock->conn, (size_t)recvd); -+#if USE_LIBOS -+ if (apiflags & NETCONN_NOAUTORCVD) -+#endif -+ { -+ if ((recvd > 0) && !(flags & MSG_PEEK)) { -+ /* ensure window update after copying all data */ -+ netconn_tcp_recvd(sock->conn, (size_t)recvd); -+ } - } -+#if USE_LIBOS -+ if ((flags & MSG_PEEK) == 0) { -+ if (((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) && sock->lastdata.pbuf) { -+ add_epoll_event(sock->conn, EPOLLIN); -+ } -+ } -+#endif - sock_set_errno(sock, 0); - return recvd; - } -@@ -1040,11 +1310,13 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, - #endif /* LWIP_IPV4 && LWIP_IPV6 */ - - IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); -+#if !USE_LIBOS - if (*fromlen < saddr.sa.sa_len) { - truncated = 1; - } else if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; - } -+#endif - MEMCPY(from, &saddr, *fromlen); - return truncated; - } -@@ -1194,6 +1466,43 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - return ERR_OK; - } - -+#if USE_LIBOS -+static inline enum KERNEL_LWIP_PATH select_path(int s) -+{ -+ struct lwip_sock *sock; -+ -+ sock = posix_api->get_socket(s); -+ /*AF_UNIX case*/ -+ if (!sock) { -+ if (rearm_host_fd(s) < 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("failed to rearm fd=%d errno=%d\n", s, errno)); -+ } -+ return PATH_KERNEL; -+ } -+ -+ if (CONN_TYPE_HAS_INPRG(sock->conn)) { -+ set_errno(EWOULDBLOCK); -+ return PATH_ERR; -+ } -+ -+ /*for AF_INET, we can try erther linux or lwip*/ -+ if (CONN_TYPE_IS_HOST(sock->conn)) { -+ if (rearm_host_fd(s) < 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("failed to rearm read fd=%d errno=%d\n", s, errno)); -+ } -+ return PATH_KERNEL; -+ } -+ -+ if (!CONN_TYPE_IS_LIBOS(sock->conn)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type is not libos bit type=%x", netconn_type(sock->conn))); -+ set_errno(EINVAL); -+ return PATH_ERR; -+ } -+ -+ return PATH_LWIP; -+} -+#endif -+ - ssize_t - lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -@@ -1201,6 +1510,15 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct lwip_sock *sock; - ssize_t ret; - -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->recv_from(s, mem, len, flags, from, fromlen); -+ } -+#endif -+ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); - sock = get_socket(s); - if (!sock) { -@@ -1250,6 +1568,14 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, - ssize_t - lwip_read(int s, void *mem, size_t len) - { -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->read_fn(s, mem, len); -+ } -+#endif - return lwip_recvfrom(s, mem, len, 0, NULL, NULL); - } - -@@ -1283,6 +1609,15 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) - int i; - ssize_t buflen; - -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->recv_msg(s, message, flags); -+ } -+#endif -+ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); - LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); - LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, -@@ -1427,6 +1762,15 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags) - #endif - err_t err = ERR_OK; - -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->send_msg(s, msg, flags); -+ } -+#endif -+ - sock = get_socket(s); - if (!sock) { - return -1; -@@ -1436,10 +1780,10 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags) - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); - LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), -- sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); -- LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, -- sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); -+ //LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), -+ // sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); -+ //LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, -+ // sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); - - LWIP_UNUSED_ARG(msg->msg_control); - LWIP_UNUSED_ARG(msg->msg_controllen); -@@ -1590,6 +1934,15 @@ lwip_sendto(int s, const void *data, size_t size, int flags, - u16_t remote_port; - struct netbuf buf; - -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->send_to(s, data, size, flags, to, tolen); -+ } -+#endif -+ - sock = get_socket(s); - if (!sock) { - return -1; -@@ -1688,6 +2041,11 @@ lwip_socket(int domain, int type, int protocol) - - LWIP_UNUSED_ARG(domain); /* @todo: check this */ - -+#if USE_LIBOS -+ if ((domain != AF_INET && domain != AF_UNSPEC) || posix_api->is_chld) -+ return posix_api->socket_fn(domain, type, protocol); -+#endif -+ - /* create a netconn */ - switch (type) { - case SOCK_RAW: -@@ -1744,6 +2102,14 @@ lwip_socket(int domain, int type, int protocol) - ssize_t - lwip_write(int s, const void *data, size_t size) - { -+#if USE_LIBOS -+ enum KERNEL_LWIP_PATH path = select_path(s); -+ if (path == PATH_ERR) { -+ return -1; -+ } else if (path == PATH_KERNEL) { -+ return posix_api->write_fn(s, data, size); -+ } -+#endif - return lwip_send(s, data, size, 0); - } - -@@ -2479,7 +2845,7 @@ lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recveven - * NETCONN_EVT_ERROR - * This requirement will be asserted in select_check_waiters() - */ --static void -+void - event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - { - int s, check_waiters; -@@ -2528,23 +2894,38 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - if (sock->rcvevent > 1) { - check_waiters = 0; - } -+#if USE_LIBOS -+ add_epoll_event(conn, EPOLLIN); -+#endif - break; - case NETCONN_EVT_RCVMINUS: - sock->rcvevent--; - check_waiters = 0; -+#if USE_LIBOS -+ del_epoll_event(conn, EPOLLIN); -+#endif - break; - case NETCONN_EVT_SENDPLUS: - if (sock->sendevent) { - check_waiters = 0; - } - sock->sendevent = 1; -+#if USE_LIBOS -+ add_epoll_event(conn, EPOLLOUT); -+#endif - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; - check_waiters = 0; -+#if USE_LIBOS -+ del_epoll_event(conn, EPOLLOUT); -+#endif - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; -+#if USE_LIBOS -+ add_epoll_event(conn, EPOLLERR); -+#endif - break; - default: - LWIP_ASSERT("unknown event", 0); -@@ -2739,9 +3120,11 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) - ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - -+#if !USE_LIBOS - if (*namelen > saddr.sa.sa_len) { - *namelen = saddr.sa.sa_len; - } -+#endif - MEMCPY(name, &saddr, *namelen); - - sock_set_errno(sock, 0); -@@ -2752,12 +3135,41 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) - int - lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) - { -+#if USE_LIBOS -+ struct lwip_sock *sock; -+ -+ sock = posix_api->get_socket(s); -+ if (!sock) { -+ return posix_api->getpeername_fn(s, name, namelen); -+ } -+ /*for AF_INET, if has only host type bit, just call linux api, -+ *if has libos and host type bits, it's a not connected fd, call -+ *linux api and return -1(errno == ENOTCONN) is also ok*/ -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ return posix_api->getpeername_fn(s, name, namelen); -+ } -+#endif -+ - return lwip_getaddrname(s, name, namelen, 0); - } - - int - lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) - { -+#if USE_LIBOS -+ struct lwip_sock *sock; -+ -+ sock = posix_api->get_socket(s); -+ if (!sock) { -+ return posix_api->getsockname_fn(s, name, namelen); -+ } -+ /*for AF_INET, if has only host type bit, just call linux api, -+ *if has libos and host type bits, also call linux api*/ -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ return posix_api->getsockname_fn(s, name, namelen); -+ } -+#endif -+ - return lwip_getaddrname(s, name, namelen, 1); - } - -@@ -2765,15 +3177,28 @@ int - lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) - { - int err; -- struct lwip_sock *sock = get_socket(s); - #if !LWIP_TCPIP_CORE_LOCKING - err_t cberr; - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); - #endif /* !LWIP_TCPIP_CORE_LOCKING */ - -+#if USE_LIBOS -+ struct lwip_sock *sock = posix_api->get_socket(s); -+ -+ if (!sock) { -+ return posix_api->getsockopt_fn(s, level, optname, optval, optlen); -+ } -+ /*for AF_INET, we return linux result? */ -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ return posix_api->getsockopt_fn(s, level, optname, optval, optlen); -+ } -+#else -+ struct lwip_sock *sock = get_socket(s); -+ - if (!sock) { - return -1; - } -+#endif /* USE_LIBOS */ - - if ((NULL == optval) || (NULL == optlen)) { - sock_set_errno(sock, EFAULT); -@@ -3211,15 +3636,30 @@ int - lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) - { - int err = 0; -- struct lwip_sock *sock = get_socket(s); - #if !LWIP_TCPIP_CORE_LOCKING - err_t cberr; - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); - #endif /* !LWIP_TCPIP_CORE_LOCKING */ - -+#if USE_LIBOS -+ struct lwip_sock *sock = posix_api->get_socket(s); -+ -+ if (!sock) { -+ return posix_api->setsockopt_fn(s, level, optname, optval, optlen); -+ } -+ /*for AF_INET, we may try both linux and lwip*/ -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ if (posix_api->setsockopt_fn(s, level, optname, optval, optlen) < 0) { -+ return -1; -+ } -+ } -+#else -+ struct lwip_sock *sock = get_socket(s); -+ - if (!sock) { - return -1; - } -+#endif /* USE_LIBOS */ - - if (NULL == optval) { - sock_set_errno(sock, EFAULT); -@@ -3333,6 +3773,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ - case SO_KEEPALIVE: - #if SO_REUSE - case SO_REUSEADDR: -+ case SO_REUSEPORT: - #endif /* SO_REUSE */ - if ((optname == SO_BROADCAST) && - (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { -@@ -3745,6 +4186,29 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ - return err; - } - -+#if USE_LIBOS -+int -+lwip_ioctl(int s, long cmd, ...) -+{ -+ struct lwip_sock *sock = posix_api->get_socket(s); -+ u8_t val; -+ -+ int ret = -1; -+ void *argp; -+ va_list ap; -+ -+ va_start(ap, cmd); -+ argp = va_arg(ap, void *); -+ va_end(ap); -+ -+ if (!sock) { -+ return posix_api->ioctl_fn(s, cmd, argp); -+ } -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ if ((ret = posix_api->ioctl_fn(s, cmd, argp)) == -1) -+ return ret; -+ } -+#else - int - lwip_ioctl(int s, long cmd, void *argp) - { -@@ -3757,6 +4221,7 @@ lwip_ioctl(int s, long cmd, void *argp) - if (!sock) { - return -1; - } -+#endif /* USE_LIBOS */ - - switch (cmd) { - #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE -@@ -3839,6 +4304,26 @@ lwip_ioctl(int s, long cmd, void *argp) - * the flag O_NONBLOCK is implemented for F_SETFL. - */ - int -+#if USE_LIBOS -+lwip_fcntl(int s, int cmd, ...) -+{ -+ struct lwip_sock *sock = posix_api->get_socket(s); -+ int val, ret = -1; -+ int op_mode = 0; -+ va_list ap; -+ -+ va_start(ap, cmd); -+ val = va_arg(ap, int); -+ va_end(ap); -+ -+ if (!sock) { -+ return posix_api->fcntl_fn(s, cmd, val); -+ } -+ if (CONN_TYPE_HAS_HOST(sock->conn)) { -+ if ((ret = posix_api->fcntl_fn(s, cmd, val)) == -1) -+ return ret; -+ } -+#else /* USE_LIBOS */ - lwip_fcntl(int s, int cmd, int val) - { - struct lwip_sock *sock = get_socket(s); -@@ -3848,6 +4333,7 @@ lwip_fcntl(int s, int cmd, int val) - if (!sock) { - return -1; - } -+#endif /* USE_LIBOS */ - - switch (cmd) { - case F_GETFL: -@@ -4163,4 +4649,50 @@ lwip_socket_drop_registered_mld6_memberships(int s) - } - #endif /* LWIP_IPV6_MLD */ - -+#if USE_LIBOS -+void lwip_sock_init(void) -+{ -+ if (sockets_num == 0) { -+ sockets_num = NUM_SOCKETS; -+ sockets = calloc(sockets_num, sizeof(struct lwip_sock)); -+ LWIP_ASSERT("sockets != NULL", sockets != NULL); -+ memset(sockets, 0, sockets_num * sizeof(struct lwip_sock)); -+ } -+ return; -+} -+ -+//modify from lwip_close -+void lwip_exit(void) -+{ -+ int i, is_tcp; -+ struct lwip_sock *sock; -+ -+ if (memp_pools[MEMP_SYS_MBOX] == NULL) { -+ return; -+ } -+ -+ for (i = 0; i < sockets_num; i++) { -+ sock = &sockets[i]; -+ if (!sock->conn) -+ continue; -+#if LWIP_IGMP -+ /* drop all possibly joined IGMP memberships */ -+ lwip_socket_drop_registered_memberships(i); -+#endif /* LWIP_IGMP */ -+ /* -+ * process is exiting, call netconn_delete to -+ * close tcp connection, and ignore the return value -+ */ -+ is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -+ netconn_delete(sock->conn); -+ free_socket(sock, is_tcp); -+ } -+ -+ free(sockets); -+ sockets = NULL; -+ sockets_num = 0; -+} -+ -+#endif /* USE_LIBOS */ -+ - #endif /* LWIP_SOCKET */ -diff --git a/src/api/sys_arch.c b/src/api/sys_arch.c -new file mode 100644 -index 0000000..55561b1 ---- /dev/null -+++ b/src/api/sys_arch.c -@@ -0,0 +1,379 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "lwip/err.h" -+#include "lwip/mem.h" -+#include "lwip/memp.h" -+#include "lwip/opt.h" -+#include "lwip/sys.h" -+#include "lwip/timeouts.h" -+#include "arch/sys_arch.h" -+ -+struct sys_mutex { -+ volatile unsigned int m; -+}; -+ -+struct sys_mutex lstack_mutex; -+ -+struct sys_sem lstack_sem; -+ -+#define MAX_THREAD_NAME 64 -+#define MBOX_NAME_PREFIX "_mbox_0x" -+#define MAX_MBOX_NAME_LEN (sizeof(MBOX_NAME_PREFIX) + 32) // log(UINT64_MAX) < 32 -+ -+struct sys_thread { -+ struct sys_thread *next; -+ char name[MAX_THREAD_NAME]; -+ lwip_thread_fn fn; -+ void *arg; -+ int stacksize; -+ int prio; -+ pthread_t tid; -+}; -+ -+ -+struct sys_mem_stats { -+ uint32_t tot_len; -+}; -+ -+static PER_THREAD struct sys_mem_stats hugepage_stats; -+ -+static PER_THREAD uint64_t cycles_per_ms __attribute__((aligned(64))); -+static PER_THREAD uint64_t sys_start_ms __attribute__((aligned(64))); -+ -+/* -+ * Mailbox -+ * */ -+static int mbox_wait_func(void) -+{ -+#if LWIP_TIMERS -+ sys_timer_run(); -+#endif /* LWIP_TIMER */ -+ return eth_dev_poll(); -+} -+ -+err_t sys_mbox_new(struct sys_mbox **mb, int size) -+{ -+ int ret; -+ struct sys_mbox *mbox; -+ -+ mbox = (struct sys_mbox *)memp_malloc(MEMP_SYS_MBOX); -+ if (mbox == NULL) { -+ return ERR_MEM; -+ } -+ -+ mbox->flags = RING_F_SP_ENQ | RING_F_SC_DEQ; -+ -+ ret = snprintf(mbox->name, sizeof(mbox->name), MBOX_NAME_PREFIX"%"PRIXPTR, (uintptr_t)mbox); -+ if (ret < 0) { -+ memp_free(MEMP_SYS_MBOX, mbox); -+ return ERR_VAL; -+ } -+ -+ mbox->size = size; -+ mbox->socket_id = rte_socket_id(); -+ mbox->ring = rte_ring_create(mbox->name, mbox->size, mbox->socket_id, mbox->flags); -+ if (!mbox->ring) { -+ RTE_LOG(ERR, EAL, "cannot create rte_ring for mbox\n"); -+ memp_free(MEMP_SYS_MBOX, mbox); -+ return ERR_MEM; -+ } -+ mbox->wait_fn = mbox_wait_func; -+ *mb = mbox; -+ -+ return ERR_OK; -+} -+ -+void sys_mbox_free(struct sys_mbox **mb) -+{ -+ struct sys_mbox *mbox = *mb; -+ rte_ring_free(mbox->ring); -+ memp_free(MEMP_SYS_MBOX, mbox); -+} -+ -+err_t sys_mbox_trypost(struct sys_mbox **mb, void *msg) -+{ -+ unsigned int n; -+ struct sys_mbox *mbox = *mb; -+ -+ n = rte_ring_sp_enqueue_bulk(mbox->ring, &msg, 1, NULL); -+ if (!n) -+ return ERR_BUF; -+ return ERR_OK; -+} -+ -+void sys_mbox_post(struct sys_mbox **mb, void *msg) -+{ -+ struct sys_mbox *mbox = *mb; -+ -+ /* NOTE: sys_mbox_post is used on mbox defined in src/api/tcpip.c. -+ * If the ring size of mbox is greater than MEMP_NUM_TCPIP_MSG_API, -+ * enqueue failure will never happen. -+ * */ -+ if (!rte_ring_sp_enqueue_bulk(mbox->ring, &msg, 1, NULL)) { -+ LWIP_ASSERT("It is failed to post msg into mbox", 0); -+ } -+} -+ -+err_t sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg) -+{ -+ return sys_mbox_trypost(q, msg); -+} -+ -+uint32_t sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg) -+{ -+ unsigned int n; -+ struct sys_mbox *mbox = *mb; -+ -+ n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ if (!n) { -+ *msg = NULL; -+ return SYS_MBOX_EMPTY; -+ } -+ -+ return 0; -+} -+ -+uint32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, uint32_t timeout) -+{ -+ unsigned int n; -+ uint32_t poll_ts = 0; -+ uint32_t time_needed = 0; -+ struct sys_mbox *mbox = *mb; -+ -+ n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ -+ if (timeout > 0) -+ poll_ts = sys_now(); -+ -+ while (!n) { -+ if (timeout > 0) { -+ time_needed = sys_now() - poll_ts; -+ if (time_needed >= timeout) { -+ return SYS_ARCH_TIMEOUT; -+ } -+ } -+ -+ (void)mbox->wait_fn(); -+ -+ n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ } -+ -+ return time_needed; -+} -+ -+int sys_mbox_empty(struct sys_mbox *mb) -+{ -+ return rte_ring_count(mb->ring) == 0; -+} -+ -+/* -+ * Threads -+ * */ -+sys_thread_t sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) -+{ -+ int err; -+ pthread_t tid; -+ struct sys_thread *thread; -+ -+ thread = (struct sys_thread *)malloc(sizeof(struct sys_thread)); -+ if (thread == NULL) { -+ LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: malloc sys_thread failed\n")); -+ rte_exit(EXIT_FAILURE, "malloc sys_thread failed\n"); -+ } -+ -+ err = pthread_create(&tid, NULL, (void*(*)(void *))function, arg); -+ if (err > 0) { -+ LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create failed\n")); -+ rte_exit(EXIT_FAILURE, "pthread_create failed\n"); -+ } -+ -+ err = pthread_setname_np(tid, name); -+ if (err > 0) { -+ LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_setname_np failed\n")); -+ } -+ thread->tid = tid; -+ thread->stacksize = stacksize; -+ thread->prio = prio; -+ -+ return thread; -+} -+ -+/* -+ * Semaphore -+ * */ -+err_t sys_sem_new(struct sys_sem **sem, uint8_t count) -+{ -+ *sem = (struct sys_sem *)memp_malloc(MEMP_SYS_SEM); -+ if ((*sem) == NULL) { -+ return ERR_MEM; -+ } -+ (*sem)->c = 0; -+ (*sem)->wait_fn = mbox_wait_func; -+ return ERR_OK; -+} -+ -+void sys_sem_signal(struct sys_sem **s) -+{ -+ struct sys_sem *sem = NULL; -+ LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); -+ sem = *s; -+ ++(sem->c); -+} -+ -+static uint32_t cond_wait(struct sys_sem *sem, uint32_t timeout) -+{ -+ uint32_t used_ms = 0; -+ uint32_t poll_ts; -+ -+ if (timeout == 0) { -+ (void)sem->wait_fn(); -+ return 0; -+ } -+ -+ poll_ts = sys_now(); -+ -+ while (used_ms < timeout) { -+ if (sem->c > 0) -+ return timeout - used_ms; -+ -+ (void)sem->wait_fn(); -+ used_ms = sys_now() - poll_ts; -+ } -+ -+ return SYS_ARCH_TIMEOUT; -+} -+ -+uint32_t sys_arch_sem_wait(struct sys_sem **s, uint32_t timeout) -+{ -+ uint32_t time_needed = 0; -+ struct sys_sem *sem = NULL; -+ LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); -+ sem = *s; -+ -+ while (sem->c <= 0) { -+ if (timeout > 0) { -+ time_needed = cond_wait(sem, timeout); -+ -+ if (time_needed == SYS_ARCH_TIMEOUT) { -+ return SYS_ARCH_TIMEOUT; -+ } -+ } else { -+ cond_wait(sem, 0); -+ } -+ } -+ -+ sem->c--; -+ return time_needed; -+} -+ -+void sys_sem_free(struct sys_sem **s) -+{ -+ if ((s != NULL) && (*s != SYS_SEM_NULL)) -+ memp_free(MEMP_SYS_SEM, *s); -+} -+ -+/* -+ * Mutex -+ * */ -+err_t sys_mutex_new(struct sys_mutex **mutex) -+{ -+ return ERR_OK; -+} -+ -+void sys_mutex_lock(struct sys_mutex **mutex) -+{ -+} -+ -+void sys_mutex_unlock(struct sys_mutex **mutex) -+{ -+} -+ -+void sys_mutex_free(struct sys_mutex **mutex) -+{ -+} -+ -+/* Timer from DPDK */ -+void sys_calibrate_tsc(void) -+{ -+#define MS_PER_SEC 1E3 -+ uint64_t freq = rte_get_tsc_hz(); -+ -+ cycles_per_ms = (freq + MS_PER_SEC - 1) / MS_PER_SEC; -+ sys_start_ms = rte_rdtsc() / cycles_per_ms; -+} -+ -+uint32_t sys_now(void) -+{ -+ uint64_t cur_ms = rte_rdtsc() / cycles_per_ms; -+ return (uint32_t)(cur_ms - sys_start_ms); -+} -+ -+/* -+ * Critical section -+ * */ -+sys_prot_t sys_arch_protect(void) -+{ -+ return 0; -+} -+ -+void sys_arch_unprotect(sys_prot_t pval) -+{ -+} -+ -+/* -+ * Hugepage memory manager -+ * */ -+uint8_t *sys_hugepage_malloc(const char *name, uint32_t size) -+{ -+ const struct rte_memzone *mz; -+ -+ mz = rte_memzone_reserve(name, size, rte_socket_id(), 0); -+ if (mz == NULL) { -+ rte_exit(EXIT_FAILURE, "failed to reserver memory for mempool[%s]\n", name); -+ return NULL; -+ } -+ -+ memset(mz->addr, 0, mz->len); -+ hugepage_stats.tot_len += mz->len; -+ -+ return (uint8_t*)mz->addr; -+} -diff --git a/src/api/tcpip.c b/src/api/tcpip.c -index a7e312a..d3d0b55 100644 ---- a/src/api/tcpip.c -+++ b/src/api/tcpip.c -@@ -56,13 +56,13 @@ - #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) - - /* global variables */ --static tcpip_init_done_fn tcpip_init_done; --static void *tcpip_init_done_arg; --static sys_mbox_t tcpip_mbox; -+static PER_THREAD tcpip_init_done_fn tcpip_init_done; -+static PER_THREAD void *tcpip_init_done_arg; -+static PER_THREAD sys_mbox_t tcpip_mbox; - - #if LWIP_TCPIP_CORE_LOCKING - /** The global semaphore to lock the stack. */ --sys_mutex_t lock_tcpip_core; -+PER_THREAD sys_mutex_t lock_tcpip_core; - #endif /* LWIP_TCPIP_CORE_LOCKING */ - - static void tcpip_thread_handle_msg(struct tcpip_msg *msg); -@@ -123,8 +123,13 @@ again: - * - * @param arg unused argument - */ -+#if USE_LIBOS -+__attribute__((unused)) static void -+tcpip_thread(void *arg) -+#else - static void - tcpip_thread(void *arg) -+#endif /* USE_LIBOS */ - { - struct tcpip_msg *msg; - LWIP_UNUSED_ARG(arg); -@@ -242,6 +247,9 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) - #if LWIP_TCPIP_CORE_LOCKING_INPUT - err_t ret; - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); -+#if USE_LIBOS && LWIP_TIMERS -+ sys_timer_run(); -+#endif - LOCK_TCPIP_CORE(); - ret = input_fn(p, inp); - UNLOCK_TCPIP_CORE(); -@@ -321,6 +329,9 @@ tcpip_callback(tcpip_callback_fn function, void *ctx) - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - -+#if USE_LIBOS && LWIP_TIMER -+ sys_timer_run(); -+#endif - sys_mbox_post(&tcpip_mbox, msg); - return ERR_OK; - } -@@ -357,6 +368,9 @@ tcpip_try_callback(tcpip_callback_fn function, void *ctx) - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - -+#if USE_LIBOS && LWIP_TIMER -+ sys_timer_run(); -+#endif - if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { - memp_free(MEMP_TCPIP_MSG_API, msg); - return ERR_MEM; -@@ -438,6 +452,9 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) - { - #if LWIP_TCPIP_CORE_LOCKING - LWIP_UNUSED_ARG(sem); -+#if USE_LIBOS && LWIP_TIMERS -+ sys_timer_run(); -+#endif - LOCK_TCPIP_CORE(); - fn(apimsg); - UNLOCK_TCPIP_CORE(); -@@ -475,6 +492,9 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) - #if LWIP_TCPIP_CORE_LOCKING - err_t err; - LOCK_TCPIP_CORE(); -+#if USE_LIBOS && LWIP_TIMERS -+ sys_timer_run(); -+#endif - err = fn(call); - UNLOCK_TCPIP_CORE(); - return err; -@@ -537,6 +557,10 @@ tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) - msg->type = TCPIP_MSG_CALLBACK_STATIC; - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; -+ -+#if USE_LIBOS && LWIP_TIMER -+ sys_timer_run(); -+#endif - return (struct tcpip_callback_msg *)msg; - } - -@@ -614,7 +638,9 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg) - } - #endif /* LWIP_TCPIP_CORE_LOCKING */ - -+#if !USE_LIBOS - sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); -+#endif - } - - /** -diff --git a/src/core/dir.mk b/src/core/dir.mk -index e5a055b..ebc01a5 100644 ---- a/src/core/dir.mk -+++ b/src/core/dir.mk -@@ -1,6 +1,6 @@ --SRC = inet_chksum.c init.c ip.c mem.c memp.c netif.c pbuf.c \ -- raw.c stats.c tcp.c tcp_in.c tcp_out.c timeouts.c udp.c \ -- ipv4/etharp.c ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4.c \ -- ipv4/ip4_frag.c -+SRC = def.c inet_chksum.c init.c ip.c mem.c memp.c netif.c pbuf.c \ -+ raw.c tcp.c tcp_in.c tcp_out.c timeouts.c udp.c stats.c\ -+ ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4_frag.c ipv4/etharp.c \ -+ ipv4/ip4.c - - $(eval $(call register_dir, core, $(SRC))) -diff --git a/src/core/init.c b/src/core/init.c -index 3620e1d..60e1c68 100644 ---- a/src/core/init.c -+++ b/src/core/init.c -@@ -343,9 +343,7 @@ lwip_init(void) - - /* Modules initialization */ - stats_init(); --#if !NO_SYS -- sys_init(); --#endif /* !NO_SYS */ -+ - mem_init(); - memp_init(); - pbuf_init(); -diff --git a/src/core/ip.c b/src/core/ip.c -index 18514cf..0d39d2d 100644 ---- a/src/core/ip.c -+++ b/src/core/ip.c -@@ -61,7 +61,7 @@ - #include "lwip/ip.h" - - /** Global data for both IPv4 and IPv6 */ --struct ip_globals ip_data; -+PER_THREAD struct ip_globals ip_data; - - #if LWIP_IPV4 && LWIP_IPV6 - -diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c -index 26c26a9..c83afbe 100644 ---- a/src/core/ipv4/ip4.c -+++ b/src/core/ipv4/ip4.c -@@ -282,7 +282,9 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) - { - struct netif *netif; - -+#ifndef LWIP_PERF - PERF_START; -+#endif - LWIP_UNUSED_ARG(inp); - - if (!ip4_canforward(p)) { -@@ -344,7 +346,9 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) - MIB2_STATS_INC(mib2.ipforwdatagrams); - IP_STATS_INC(ip.xmit); - -+#ifndef LWIP_PERF - PERF_STOP("ip4_forward"); -+#endif - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (p->tot_len > netif->mtu)) { - if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { -@@ -438,6 +442,8 @@ ip4_input(struct pbuf *p, struct netif *inp) - - LWIP_ASSERT_CORE_LOCKED(); - -+ PERF_START(PERF_LAYER_IP, PERF_POINT_IP_RECV); -+ - IP_STATS_INC(ip.recv); - MIB2_STATS_INC(mib2.ipinreceives); - -@@ -700,13 +706,19 @@ ip4_input(struct pbuf *p, struct netif *inp) - case IP_PROTO_UDPLITE: - #endif /* LWIP_UDPLITE */ - MIB2_STATS_INC(mib2.ipindelivers); -+ PERF_PAUSE(PERF_LAYER_IP); - udp_input(p, inp); -+ PERF_RESUME(PERF_LAYER_IP, PERF_POINT_IP_RECV); - break; - #endif /* LWIP_UDP */ - #if LWIP_TCP - case IP_PROTO_TCP: - MIB2_STATS_INC(mib2.ipindelivers); -+ PERF_PAUSE(PERF_LAYER_IP); -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_RECV); - tcp_input(p, inp); -+ PERF_STOP_INCREASE_COUNT("tcp_input", PERF_LAYER_TCP); -+ PERF_RESUME(PERF_LAYER_IP, PERF_POINT_IP_RECV); - break; - #endif /* LWIP_TCP */ - #if LWIP_ICMP -@@ -755,6 +767,8 @@ ip4_input(struct pbuf *p, struct netif *inp) - ip4_addr_set_any(ip4_current_src_addr()); - ip4_addr_set_any(ip4_current_dest_addr()); - -+ PERF_STOP_INCREASE_COUNT("ip4_input", PERF_LAYER_IP); -+ - return ERR_OK; - } - -diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c -index 060d5f3..9d904ec 100644 ---- a/src/core/ipv6/ip6.c -+++ b/src/core/ipv6/ip6.c -@@ -522,6 +522,8 @@ ip6_input(struct pbuf *p, struct netif *inp) - - LWIP_ASSERT_CORE_LOCKED(); - -+ PERF_START(PERF_LAYER_IP, PERF_POINT_IP_RECV); -+ - IP6_STATS_INC(ip6.recv); - - /* identify the IP header */ -@@ -1069,12 +1071,18 @@ options_done: - #if LWIP_UDPLITE - case IP6_NEXTH_UDPLITE: - #endif /* LWIP_UDPLITE */ -+ PERF_PAUSE(PERF_LAYER_IP); - udp_input(p, inp); -+ PERF_RESUME(PERF_LAYER_IP, PERF_POINT_IP_RECV); - break; - #endif /* LWIP_UDP */ - #if LWIP_TCP - case IP6_NEXTH_TCP: -+ PERF_PAUSE(PERF_LAYER_IP); -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_RECV); - tcp_input(p, inp); -+ PERF_STOP_INCREASE_COUNT("tcp_input", PERF_LAYER_TCP); -+ PERF_RESUME(PERF_LAYER_IP, PERF_POINT_IP_RECV); - break; - #endif /* LWIP_TCP */ - #if LWIP_ICMP6 -@@ -1115,6 +1123,8 @@ ip6_input_cleanup: - ip6_addr_set_zero(ip6_current_src_addr()); - ip6_addr_set_zero(ip6_current_dest_addr()); - -+ PERF_STOP_INCREASE_COUNT("ip6_input", PERF_LAYER_IP); -+ - return ERR_OK; - } - -diff --git a/src/core/mem.c b/src/core/mem.c -index 315fb3c..84b3fcc 100644 ---- a/src/core/mem.c -+++ b/src/core/mem.c -@@ -381,9 +381,9 @@ LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM - #endif /* LWIP_RAM_HEAP_POINTER */ - - /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ --static u8_t *ram; -+static PER_THREAD u8_t *ram; - /** the last entry, always unused! */ --static struct mem *ram_end; -+static PER_THREAD struct mem *ram_end; - - /** concurrent access protection */ - #if !NO_SYS -@@ -418,7 +418,7 @@ static volatile u8_t mem_free_count; - #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - /** pointer to the lowest free block, this is used for faster search */ --static struct mem * LWIP_MEM_LFREE_VOLATILE lfree; -+static PER_THREAD struct mem * LWIP_MEM_LFREE_VOLATILE lfree; - - #if MEM_SANITY_CHECK - static void mem_sanity(void); -diff --git a/src/core/memp.c b/src/core/memp.c -index 352ce5a..454ba32 100644 ---- a/src/core/memp.c -+++ b/src/core/memp.c -@@ -78,10 +78,14 @@ - #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) - #include "lwip/priv/memp_std.h" - -+#if USE_LIBOS -+PER_THREAD struct memp_desc* memp_pools[MEMP_MAX] = {NULL}; -+#else - const struct memp_desc *const memp_pools[MEMP_MAX] = { - #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, - #include "lwip/priv/memp_std.h" - }; -+#endif /* USE_LIBOS */ - - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME -diff --git a/src/core/netif.c b/src/core/netif.c -index 088b50e..70392cb 100644 ---- a/src/core/netif.c -+++ b/src/core/netif.c -@@ -107,12 +107,12 @@ static netif_ext_callback_t *ext_callback; - #endif - - #if !LWIP_SINGLE_NETIF --struct netif *netif_list; -+PER_THREAD struct netif *netif_list; - #endif /* !LWIP_SINGLE_NETIF */ --struct netif *netif_default; -+PER_THREAD struct netif *netif_default; - - #define netif_index_to_num(index) ((index) - 1) --static u8_t netif_num; -+static PER_THREAD u8_t netif_num; - - #if LWIP_NUM_NETIF_CLIENT_DATA > 0 - static u8_t netif_client_id; -@@ -138,7 +138,7 @@ static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const i - #endif - - --static struct netif loop_netif; -+static PER_THREAD struct netif loop_netif; - - /** - * Initialize a lwip network interface structure for a loopback interface -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 7638dfd..27afc28 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -737,7 +737,9 @@ pbuf_free(struct pbuf *p) - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); - -+#ifndef LWIP_PERF - PERF_START; -+#endif - - count = 0; - /* de-allocate all consecutive pbufs from the head of the chain that -@@ -794,7 +796,9 @@ pbuf_free(struct pbuf *p) - p = NULL; - } - } -+#ifndef LWIP_PERF - PERF_STOP("pbuf_free"); -+#endif - /* return number of de-allocated pbufs */ - return count; - } -diff --git a/src/core/stats.c b/src/core/stats.c -index 34e9b27..f7e0604 100644 ---- a/src/core/stats.c -+++ b/src/core/stats.c -@@ -47,7 +47,7 @@ - - #include - --struct stats_ lwip_stats; -+PER_THREAD struct stats_ lwip_stats; - - void - stats_init(void) -@@ -59,6 +59,17 @@ stats_init(void) - #endif /* LWIP_DEBUG */ - } - -+int get_mib2_stats(char *buf) -+{ -+ int len = 0; -+#if MIB2_STATS -+ len = (long)&((struct stats_mib2 *)0)->udpindatagrams; -+ /* we just need the ip&tcp, others not needed. */ -+ memcpy(buf, &lwip_stats.mib2, len); -+#endif -+ return len; -+} -+ - #if LWIP_STATS_DISPLAY - void - stats_display_proto(struct stats_proto *proto, const char *name) -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 371db2b..9e75810 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -113,6 +113,7 @@ - #include "lwip/nd6.h" - - #include -+#include - - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME -@@ -157,36 +158,50 @@ static const char *const tcp_state_str[] = { - - /* last local TCP port */ - static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; -+static pthread_mutex_t g_tcp_port_mutex = PTHREAD_MUTEX_INITIALIZER; - - /* Incremented every coarse grained timer shot (typically every 500 ms). */ --u32_t tcp_ticks; --static const u8_t tcp_backoff[13] = -+PER_THREAD u32_t tcp_ticks; -+static PER_THREAD const u8_t tcp_backoff[13] = - { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; - /* Times per slowtmr hits */ --static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; -+static PER_THREAD const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; - - /* The TCP PCB lists. */ - - /** List of all TCP PCBs bound but not yet (connected || listening) */ --struct tcp_pcb *tcp_bound_pcbs; -+PER_THREAD struct tcp_pcb *tcp_bound_pcbs; - /** List of all TCP PCBs in LISTEN state */ --union tcp_listen_pcbs_t tcp_listen_pcbs; -+PER_THREAD union tcp_listen_pcbs_t tcp_listen_pcbs; - /** List of all TCP PCBs that are in a state in which - * they accept or send data. */ --struct tcp_pcb *tcp_active_pcbs; -+PER_THREAD struct tcp_pcb *tcp_active_pcbs; - /** List of all TCP PCBs in TIME-WAIT state */ --struct tcp_pcb *tcp_tw_pcbs; -+PER_THREAD struct tcp_pcb *tcp_tw_pcbs; - - /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ --struct tcp_pcb **const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, -- &tcp_active_pcbs, &tcp_tw_pcbs --}; -+PER_THREAD struct tcp_pcb ** tcp_pcb_lists[NUM_TCP_PCB_LISTS] = {NULL, NULL, NULL, NULL}; -+ -+#if TCP_PCB_HASH -+#define INIT_TCP_HTABLE(ht_ptr) \ -+ do { \ -+ int _i; \ -+ (ht_ptr)->size = TCP_HTABLE_SIZE; \ -+ for (_i = 0; _i < TCP_HTABLE_SIZE; ++_i) { \ -+ if (sys_mutex_new(&(ht_ptr)->array[_i].mutex) != ERR_OK) \ -+ LWIP_ASSERT("failed to create ht->array[].mutex", 0);\ -+ INIT_HLIST_HEAD(&(ht_ptr)->array[_i].chain); \ -+ }\ -+ } while (0) -+ -+PER_THREAD struct tcp_hash_table *tcp_active_htable; /* key: lport/fport/lip/fip */ -+#endif - --u8_t tcp_active_pcbs_changed; -+PER_THREAD u8_t tcp_active_pcbs_changed; - - /** Timer counter to handle calling slow-timer from tcp_tmr() */ --static u8_t tcp_timer; --static u8_t tcp_timer_ctr; -+static PER_THREAD u8_t tcp_timer; -+static PER_THREAD u8_t tcp_timer_ctr; - static u16_t tcp_new_port(void); - - static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); -@@ -200,9 +215,20 @@ static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_ - void - tcp_init(void) - { -+ tcp_pcb_lists[0] = &tcp_listen_pcbs.pcbs; -+ tcp_pcb_lists[1] = &tcp_bound_pcbs; -+ tcp_pcb_lists[2] = &tcp_active_pcbs; -+ tcp_pcb_lists[3] = &tcp_tw_pcbs; -+ - #ifdef LWIP_RAND - tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); - #endif /* LWIP_RAND */ -+ -+#if TCP_PCB_HASH -+ tcp_active_htable = (struct tcp_hash_table*)mem_malloc(sizeof(struct tcp_hash_table)); -+ LWIP_ASSERT("malloc tcp_active_htable mem failed.", tcp_active_htable != NULL); -+ INIT_TCP_HTABLE(tcp_active_htable); -+#endif - } - - /** Free a tcp pcb */ -@@ -361,6 +387,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) - pcb->local_port, pcb->remote_port); - - tcp_pcb_purge(pcb); -+#if TCP_PCB_HASH -+ TCP_RMV_ACTIVE_HASH(pcb); -+#endif - TCP_RMV_ACTIVE(pcb); - /* Deallocate the pcb since we already sent a RST for it */ - if (tcp_input_pcb == pcb) { -@@ -395,6 +424,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) - tcp_free_listen(pcb); - break; - case SYN_SENT: -+#if TCP_PCB_HASH -+ TCP_PCB_REMOVE_ACTIVE_HASH(pcb); -+#endif - TCP_PCB_REMOVE_ACTIVE(pcb); - tcp_free(pcb); - MIB2_STATS_INC(mib2.tcpattemptfails); -@@ -494,6 +526,7 @@ tcp_close(struct tcp_pcb *pcb) - /* Set a flag not to receive any more data... */ - tcp_set_flags(pcb, TF_RXCLOSED); - } -+ - /* ... and close */ - return tcp_close_shutdown(pcb, 1); - } -@@ -599,6 +632,9 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) - } else { - send_rst = reset; - local_port = pcb->local_port; -+#if TCP_PCB_HASH -+ TCP_PCB_REMOVE_ACTIVE_HASH(pcb); -+#endif - TCP_PCB_REMOVE_ACTIVE(pcb); - } - if (pcb->unacked != NULL) { -@@ -880,6 +916,11 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - } - } - #endif /* SO_REUSE */ -+ -+#if USE_LIBOS -+ vdev_reg_done(REG_RING_TCP_LISTEN, pcb); -+#endif -+ - lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); - if (lpcb == NULL) { - res = ERR_MEM; -@@ -1015,6 +1056,7 @@ tcp_new_port(void) - u16_t n = 0; - struct tcp_pcb *pcb; - -+ pthread_mutex_lock(&g_tcp_port_mutex); - again: - tcp_port++; - if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { -@@ -1032,6 +1074,8 @@ again: - } - } - } -+ pthread_mutex_unlock(&g_tcp_port_mutex); -+ - return tcp_port; - } - -@@ -1142,6 +1186,10 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - #endif /* SO_REUSE */ - } - -+#if USE_LIBOS -+ vdev_reg_done(REG_RING_TCP_CONNECT, pcb); -+#endif -+ - iss = tcp_next_iss(pcb); - pcb->rcv_nxt = 0; - pcb->snd_nxt = iss; -@@ -1174,6 +1222,9 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - if (old_local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } -+#if TCP_PCB_HASH -+ TCP_REG_ACTIVE_HASH(pcb); -+#endif - TCP_REG_ACTIVE(pcb); - MIB2_STATS_INC(mib2.tcpactiveopens); - -@@ -1389,11 +1440,26 @@ tcp_slowtmr_start: - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); - prev->next = pcb->next; -+#if USE_LIBOS -+ if (pcb->next) -+ pcb->next->prev = prev; -+ //dont set next NULL, it will be used below -+ pcb->prev = NULL; -+#endif - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); - tcp_active_pcbs = pcb->next; -+#if USE_LIBOS -+ if (pcb->next) -+ pcb->next->prev = NULL; -+ //dont set next NULL, it will be used below -+ pcb->prev = NULL; -+#endif - } -+#if TCP_PCB_HASH -+ TCP_RMV_ACTIVE_HASH(pcb); -+#endif - - if (pcb_reset) { - tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, -@@ -1404,6 +1470,9 @@ tcp_slowtmr_start: - last_state = pcb->state; - pcb2 = pcb; - pcb = pcb->next; -+#if USE_LIBOS -+ pcb2->next = NULL; -+#endif - tcp_free(pcb2); - - tcp_active_pcbs_changed = 0; -@@ -1455,13 +1524,28 @@ tcp_slowtmr_start: - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); - prev->next = pcb->next; -+#if USE_LIBOS -+ if (pcb->next) -+ pcb->next->prev = prev; -+ //dont set next NULL, it will be used below -+ pcb->prev = NULL; -+#endif - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); - tcp_tw_pcbs = pcb->next; -+#if USE_LIBOS -+ if (pcb->next) -+ pcb->next->prev = NULL; -+ //dont set next NULL, it will be used below -+ pcb->prev = NULL; -+#endif - } - pcb2 = pcb; - pcb = pcb->next; -+#if USE_LIBOS -+ pcb2->next = NULL; -+#endif - tcp_free(pcb2); - } else { - prev = pcb; -@@ -2210,6 +2294,14 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); - } - -+#if TCP_PCB_HASH -+void -+tcp_pcb_remove_hash(struct tcp_hash_table *htb, struct tcp_pcb *pcb) -+{ -+ TCP_RMV_HASH(htb, pcb); -+} -+#endif /* TCP_PCB_HASH */ -+ - /** - * Calculates a new initial sequence number for new connections. - * -@@ -2384,6 +2476,84 @@ tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t - return ERR_VAL; - } - -+uint32_t tcp_get_conn_num(void) -+{ -+ struct tcp_pcb *pcb = NULL; -+ struct tcp_pcb_listen *pcbl = NULL; -+ uint32_t conn_num = 0; -+ -+ for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { -+ conn_num++; -+ } -+ -+ for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { -+ conn_num++; -+ } -+ -+ for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { -+ conn_num++; -+ } -+ -+ return conn_num; -+} -+ -+void tcp_get_conn(char *buf, int32_t len, uint32_t *conn_num) -+{ -+ int tmp_len = 0; -+ char *tmp_buf = buf; -+ struct tcp_pcb_dp tdp; -+ struct tcp_pcb *pcb = NULL; -+ struct tcp_pcb_listen *pcbl = NULL; -+ -+#define COPY_TDP(b, l) \ -+ do { \ -+ if (l + sizeof(tdp) <= len) { \ -+ memcpy(b, &tdp, sizeof(tdp)); \ -+ b += sizeof(tdp); \ -+ l += sizeof(tdp); \ -+ *conn_num += 1; \ -+ } else \ -+ return; \ -+ } while(0); -+ -+ *conn_num = 0; -+ -+ for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { -+ tdp.state = ACTIVE_LIST; -+ tdp.lip = pcb->local_ip.addr; -+ tdp.rip = pcb->remote_ip.addr; -+ tdp.l_port = pcb->local_port; -+ tdp.r_port = pcb->remote_port; -+ tdp.s_next = pcb->snd_queuelen; -+ /* lwip not cache rcv buf. Set it to 0. */ -+ tdp.r_next = 0; -+ tdp.tcp_sub_state = pcb->state; -+ COPY_TDP(tmp_buf, tmp_len); -+ } -+ -+ for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { -+ tdp.state = LISTEN_LIST; -+ tdp.lip = pcbl->local_ip.addr; -+ tdp.rip = pcbl->remote_ip.addr; -+ tdp.l_port = pcbl->local_port; -+ tdp.tcp_sub_state = pcbl->state; -+ COPY_TDP(tmp_buf, tmp_len); -+ } -+ -+ for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { -+ tdp.state = TIME_WAIT_LIST; -+ tdp.lip = pcb->local_ip.addr; -+ tdp.rip = pcb->remote_ip.addr; -+ tdp.l_port = pcb->local_port; -+ tdp.r_port = pcb->remote_port; -+ tdp.s_next = pcb->snd_queuelen; -+ /* lwip not cache rcv buf. Set it to 0. */ -+ tdp.r_next = 0; -+ tdp.tcp_sub_state = pcb->state; -+ COPY_TDP(tmp_buf, tmp_len); -+ } -+} -+ - #if TCP_QUEUE_OOSEQ - /* Free all ooseq pbufs (and possibly reset SACK state) */ - void -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 2202e38..2b4c160 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -71,21 +71,22 @@ - /* These variables are global to all functions involved in the input - processing of TCP segments. They are set by the tcp_input() - function. */ --static struct tcp_seg inseg; --static struct tcp_hdr *tcphdr; --static u16_t tcphdr_optlen; --static u16_t tcphdr_opt1len; --static u8_t *tcphdr_opt2; --static u16_t tcp_optidx; --static u32_t seqno, ackno; --static tcpwnd_size_t recv_acked; --static u16_t tcplen; --static u8_t flags; -- --static u8_t recv_flags; --static struct pbuf *recv_data; -- --struct tcp_pcb *tcp_input_pcb; -+static PER_THREAD struct tcp_seg inseg; -+static PER_THREAD struct tcp_hdr *tcphdr; -+static PER_THREAD u16_t tcphdr_optlen; -+static PER_THREAD u16_t tcphdr_opt1len; -+static PER_THREAD u8_t *tcphdr_opt2; -+static PER_THREAD u16_t tcp_optidx; -+static PER_THREAD u32_t seqno; -+static PER_THREAD u32_t ackno; -+static PER_THREAD tcpwnd_size_t recv_acked; -+static PER_THREAD u16_t tcplen; -+static PER_THREAD u8_t flags; -+ -+static PER_THREAD u8_t recv_flags; -+static PER_THREAD struct pbuf *recv_data; -+ -+PER_THREAD struct tcp_pcb *tcp_input_pcb; - - /* Forward declarations. */ - static err_t tcp_process(struct tcp_pcb *pcb); -@@ -126,11 +127,20 @@ tcp_input(struct pbuf *p, struct netif *inp) - u8_t hdrlen_bytes; - err_t err; - -+#if TCP_PCB_HASH -+ u32_t idx; -+ struct hlist_head *head; -+ struct hlist_node *node; -+ pcb = NULL; -+#endif -+ - LWIP_UNUSED_ARG(inp); - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("tcp_input: invalid pbuf", p != NULL); - -+#ifndef LWIP_PERF - PERF_START; -+#endif - - TCP_STATS_INC(tcp.recv); - MIB2_STATS_INC(mib2.tcpinsegs); -@@ -247,7 +257,15 @@ tcp_input(struct pbuf *p, struct netif *inp) - for an active connection. */ - prev = NULL; - -+#if TCP_PCB_HASH -+ idx = TUPLE4_HASH_FN( ip_current_dest_addr()->addr, tcphdr->dest, -+ ip_current_src_addr()->addr, tcphdr->src) & -+ (tcp_active_htable->size - 1); -+ head = &tcp_active_htable->array[idx].chain; -+ tcppcb_hlist_for_each(pcb, node, head) { -+#else - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { -+#endif - LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); -@@ -263,6 +281,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { -+#if !TCP_PCB_HASH - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ -@@ -275,9 +294,14 @@ tcp_input(struct pbuf *p, struct netif *inp) - TCP_STATS_INC(tcp.cachehit); - } - LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); -+#endif - break; - } -+#if TCP_PCB_HASH -+ pcb = NULL; -+#else - prev = pcb; -+#endif - } - - if (pcb == NULL) { -@@ -363,8 +387,15 @@ tcp_input(struct pbuf *p, struct netif *inp) - arrivals). */ - if (prev != NULL) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; -+#if USE_LIBOS -+ if (lpcb->next) -+ lpcb->next->prev = (struct tcp_pcb_listen *)prev; -+#endif - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; -+#if USE_LIBOS -+ lpcb->prev = NULL; -+#endif - /* put this listening pcb at the head of the listening list */ - tcp_listen_pcbs.listen_pcbs = lpcb; - } else { -@@ -445,6 +476,9 @@ tcp_input(struct pbuf *p, struct netif *inp) - application that the connection is dead before we - deallocate the PCB. */ - TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); -+#if TCP_PCB_HASH -+ tcp_pcb_remove_hash(tcp_active_htable, pcb); -+#endif - tcp_pcb_remove(&tcp_active_pcbs, pcb); - tcp_free(pcb); - } else { -@@ -550,7 +584,19 @@ tcp_input(struct pbuf *p, struct netif *inp) - goto aborted; - } - /* Try to send something out. */ -+#if LWIP_RECORD_PERF -+ if (check_layer_point(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_ACK_RECV)) { -+ PERF_PAUSE(PERF_LAYER_TCP); -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_ACK_SEND); -+ } -+#endif - tcp_output(pcb); -+#if LWIP_RECORD_PERF -+ if (check_layer_point(PERF_LAYER_TCP, PERF_POINT_TCP_ACK_SEND)) { -+ PERF_STOP_INCREASE_COUNT("tcp_in", PERF_LAYER_TCP); -+ PERF_RESUME(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_ACK_RECV); -+ } -+#endif - #if TCP_INPUT_DEBUG - #if TCP_DEBUG - tcp_debug_print_state(pcb->state); -@@ -583,7 +629,9 @@ aborted: - } - - LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); -+#ifndef LWIP_PERF - PERF_STOP("tcp_input"); -+#endif - return; - dropped: - TCP_STATS_INC(tcp.drop); -@@ -610,6 +658,9 @@ tcp_input_delayed_close(struct tcp_pcb *pcb) - ensure the application doesn't continue using the PCB. */ - TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); - } -+#if TCP_PCB_HASH -+ tcp_pcb_remove_hash(tcp_active_htable, pcb); -+#endif - tcp_pcb_remove(&tcp_active_pcbs, pcb); - tcp_free(pcb); - return 1; -@@ -649,6 +700,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { -+ PERF_UPDATE_POINT(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_RECV); - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); - #if TCP_LISTEN_BACKLOG - if (pcb->accepts_pending >= pcb->backlog) { -@@ -695,6 +747,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - npcb->netif_idx = pcb->netif_idx; - /* Register the new PCB so that we can begin receiving segments - for it. */ -+#if TCP_PCB_HASH -+ TCP_REG_ACTIVE_HASH(npcb); -+#endif - TCP_REG_ACTIVE(npcb); - - /* Parse any options in the SYN. */ -@@ -715,13 +770,18 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - } - #endif - -+ PERF_PAUSE(PERF_LAYER_TCP); -+ PERF_START(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_ACK_SEND); - /* Send a SYN|ACK together with the MSS option. */ - rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); - if (rc != ERR_OK) { - tcp_abandon(npcb, 0); -+ PERF_RESUME(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_RECV); - return; - } - tcp_output(npcb); -+ PERF_STOP_INCREASE_COUNT("tcp_output", PERF_LAYER_TCP); -+ PERF_RESUME(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_RECV); - } - return; - } -@@ -858,6 +918,7 @@ tcp_process(struct tcp_pcb *pcb) - /* received SYN ACK with expected sequence number? */ - if ((flags & TCP_ACK) && (flags & TCP_SYN) - && (ackno == pcb->lastack + 1)) { -+ PERF_UPDATE_POINT(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_ACK_RECV); - pcb->rcv_nxt = seqno + 1; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->lastack = ackno; -@@ -925,6 +986,7 @@ tcp_process(struct tcp_pcb *pcb) - /* expected ACK number? */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { - pcb->state = ESTABLISHED; -+ PERF_UPDATE_POINT(PERF_LAYER_TCP, PERF_POINT_TCP_ACK_RECV); - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG - if (pcb->listener == NULL) { -@@ -995,6 +1057,9 @@ tcp_process(struct tcp_pcb *pcb) - ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); -+#if TCP_PCB_HASH -+ TCP_RMV_ACTIVE_HASH(pcb); -+#endif - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -@@ -1013,6 +1078,9 @@ tcp_process(struct tcp_pcb *pcb) - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); -+#if TCP_PCB_HASH -+ TCP_RMV_ACTIVE_HASH(pcb); -+#endif - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -@@ -1023,6 +1091,9 @@ tcp_process(struct tcp_pcb *pcb) - if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_pcb_purge(pcb); -+#if TCP_PCB_HASH -+ TCP_RMV_ACTIVE_HASH(pcb); -+#endif - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 8149d39..dac498e 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -271,7 +271,7 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, - return p; - } - #else /* TCP_OVERSIZE */ --#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) -+#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_POOL) - #endif /* TCP_OVERSIZE */ - - #if TCP_CHECKSUM_ON_COPY -@@ -640,7 +640,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - ((struct pbuf_rom *)p2)->payload = (const u8_t *)arg + pos; - - /* Second, allocate a pbuf for the headers. */ -- if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { -+ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_POOL)) == NULL) { - /* If allocation fails, we have to deallocate the data pbuf as - * well. */ - pbuf_free(p2); -@@ -1458,6 +1458,11 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - err_t err; - u16_t len; - u32_t *opts; -+ -+#if LWIP_RECORD_PERF -+ int tmpPoint; -+#endif -+ - #if TCP_CHECKSUM_ON_COPY - int seg_chksum_was_swapped = 0; - #endif -@@ -1604,6 +1609,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - #endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - -+ PERF_PAUSE_RETURN_POINT(PERF_LAYER_TCP, tmpPoint); -+ PERF_START(PERF_LAYER_IP, PERF_POINT_IP_SEND); -+ - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); - err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); -@@ -1618,6 +1626,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - } - #endif - -+ PERF_STOP_INCREASE_COUNT("ip_out", PERF_LAYER_IP); -+ PERF_RESUME(PERF_LAYER_TCP, tmpPoint); -+ - return err; - } - -@@ -2024,6 +2035,10 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) - u8_t optlen, optflags = 0; - u8_t num_sacks = 0; - -+#if LWIP_RECORD_PERF -+ int tmpPoint; -+#endif -+ - LWIP_ASSERT("tcp_send_empty_ack: invalid pcb", pcb != NULL); - - #if LWIP_TCP_TIMESTAMPS -@@ -2040,6 +2055,9 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) - } - #endif - -+ PERF_PAUSE_RETURN_POINT(PERF_LAYER_TCP, tmpPoint); -+ PERF_START(PERF_LAYER_IP, PERF_POINT_IP_SEND); -+ - p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt)); - if (p == NULL) { - /* let tcp_fasttmr retry sending this ACK */ -@@ -2064,6 +2082,9 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } - -+ PERF_STOP_INCREASE_COUNT("ip_out", PERF_LAYER_IP); -+ PERF_RESUME(PERF_LAYER_TCP, tmpPoint); -+ - return err; - } - -diff --git a/src/core/timeouts.c b/src/core/timeouts.c -index f37acfe..0542a32 100644 ---- a/src/core/timeouts.c -+++ b/src/core/timeouts.c -@@ -119,9 +119,9 @@ const int lwip_num_cyclic_timers = LWIP_ARRAYSIZE(lwip_cyclic_timers); - #if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM - - /** The one and only timeout list */ --static struct sys_timeo *next_timeout; -+static PER_THREAD struct sys_timeo *next_timeout; - --static u32_t current_timeout_due_time; -+static PER_THREAD u32_t current_timeout_due_time; - - #if LWIP_TESTMODE - struct sys_timeo** -@@ -133,7 +133,7 @@ sys_timeouts_get_next_timeout(void) - - #if LWIP_TCP - /** global variable that shows if the tcp timer is currently scheduled or not */ --static int tcpip_tcp_timer_active; -+static PER_THREAD int tcpip_tcp_timer_active; - - /** - * Timer callback function that calls tcp_tmr() and reschedules itself. -@@ -442,6 +442,18 @@ sys_timeouts_sleeptime(void) - } - } - -+#if USE_LIBOS -+void sys_timer_run(void) -+{ -+ u32_t sleeptime; -+ -+ sleeptime = sys_timeouts_sleeptime(); -+ if (sleeptime == 0) { -+ sys_check_timeouts(); -+ } -+} -+#endif /* USE_LIBOS */ -+ - #else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ - /* Satisfy the TCP code which calls this function */ - void -diff --git a/src/core/udp.c b/src/core/udp.c -index 0b609d3..a5f76b9 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -207,7 +207,11 @@ udp_input(struct pbuf *p, struct netif *inp) - LWIP_ASSERT("udp_input: invalid pbuf", p != NULL); - LWIP_ASSERT("udp_input: invalid netif", inp != NULL); - -+#if LWIP_RECORD_PERF -+ PERF_START(PERF_LAYER_UDP, PERF_POINT_UDP); -+#else - PERF_START; -+#endif - - UDP_STATS_INC(udp.recv); - -@@ -428,7 +432,12 @@ udp_input(struct pbuf *p, struct netif *inp) - pbuf_free(p); - } - end: -+#if LWIP_RECORD_PERF -+ PERF_STOP_INCREASE_COUNT("udp_input", PERF_LAYER_UDP); -+#else - PERF_STOP("udp_input"); -+#endif -+ - return; - #if CHECKSUM_CHECK_UDP - chkerr: -@@ -438,7 +447,13 @@ chkerr: - UDP_STATS_INC(udp.drop); - MIB2_STATS_INC(mib2.udpinerrors); - pbuf_free(p); -+ -+#if LWIP_RECORD_PERF -+ PERF_STOP_INCREASE_COUNT("udp_input", PERF_LAYER_UDP); -+#else - PERF_STOP("udp_input"); -+#endif -+ - #endif /* CHECKSUM_CHECK_UDP */ - } - -diff --git a/src/include/arch/cc.h b/src/include/arch/cc.h -index 52b76f9..33c24b4 100644 ---- a/src/include/arch/cc.h -+++ b/src/include/arch/cc.h -@@ -1,7 +1,81 @@ --#ifndef LWIP_CC_H --#define LWIP_CC_H -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ - -+#ifndef LWIP_ARCH_CC_H -+#define LWIP_ARCH_CC_H - -+#include -+#include -+#include -+#include - --#endif /* LWIP_CC_H */ -+#include "lwiplog.h" - -+#define LWIP_NOASSERT -+ -+#define LWIP_ERRNO_STDINCLUDE 1 -+#define MEMP_MEMORY_BASE_PLACEHOLDER 0 -+#define MEMZONE_NAMESIZE 32 -+ -+#define LWIP_RAND() ((uint32_t)rand()) -+ -+extern uint8_t *sys_hugepage_malloc(const char *name, uint32_t size); -+ -+#define LWIP_DECLARE_MEMP_BASE_ALIGNED(name, __size)\ -+PER_THREAD uint8_t *memp_memory_##name##_base; \ -+void alloc_memp_##name##_base(void) \ -+{ \ -+ memp_ ## name.desc = memp_desc_ ## name; \ -+ memp_ ## name.stats = &memp_stat ## name; \ -+ memp_ ## name.size = memp_size ## name; \ -+ memp_ ## name.num = memp_num ## name; \ -+ memp_ ## name.tab = &memp_tab_ ## name; \ -+ memp_pools[MEMP_##name] = &memp_ ## name; \ -+ \ -+ char mpname[MEMZONE_NAMESIZE] = {0}; \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%ld_%s", gettid(), #name); \ -+ memp_memory_##name##_base = \ -+ sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(__size)); \ -+ memp_pools[MEMP_##name]->base = memp_memory_##name##_base; \ -+} -+ -+#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) \ -+PER_THREAD uint8_t *variable_name; \ -+void alloc_memory_##variable_name(void) \ -+{ \ -+ char mpname[MEMZONE_NAMESIZE] = {0}; \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%ld_%s", gettid(), #variable_name); \ -+ (variable_name) = \ -+ sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(size)); \ -+} -+ -+#endif /* LWIP_ARCH_CC_H */ -diff --git a/src/include/arch/perf.h b/src/include/arch/perf.h -new file mode 100644 -index 0000000..e505da7 ---- /dev/null -+++ b/src/include/arch/perf.h -@@ -0,0 +1,155 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef LWIP_ARCH_PERF_H -+#define LWIP_ARCH_PERF_H -+ -+#include -+ -+#include "lwip/debug.h" -+ -+#if LWIP_RECORD_PERF -+enum PERF_POINT { -+ PERF_POINT_IP_RECV, -+ PERF_POINT_TCP_RECV, -+ PERF_POINT_UDP, -+ PERF_POINT_TCP_SYN_RECV, -+ PERF_POINT_TCP_SYN_ACK_SEND, -+ PERF_POINT_TCP_ACK_RECV, -+ PERF_POINT_TCP_SYN_SEND, -+ PERF_POINT_TCP_SYN_ACK_RECV, -+ PERF_POINT_TCP_ACK_SEND, -+ PERF_POINT_TCP_DATA_SEND, -+ PERF_POINT_IP_SEND, -+ PERF_POINT_END -+}; -+ -+enum PERF_LAYER { -+ PERF_LAYER_IP, -+ PERF_LAYER_TCP, -+ PERF_LAYER_UDP, -+ PERF_LAYER_END -+}; -+ -+extern uint32_t g_record_perf; -+ -+extern __thread uint64_t g_timeTaken[PERF_POINT_END]; -+extern __thread int g_perfPoint[PERF_LAYER_END]; -+extern __thread struct timespec tvStart[PERF_LAYER_END]; -+ -+extern char *g_ppLayerName[PERF_POINT_END]; -+extern volatile uint64_t g_perfMaxtime[PERF_POINT_END]; -+extern volatile uint64_t g_astPacketCnt[PERF_POINT_END]; -+extern volatile uint64_t g_astPacketProcTime[PERF_POINT_END]; -+ -+#define PERF_START(layer, point) do {\ -+ g_perfPoint[(layer)] = (point);\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("set point %d:%s\n", layer, g_ppLayerName[g_perfPoint[(layer)]]));\ -+ clock_gettime(CLOCK_MONOTONIC, &tvStart[(layer)]);\ -+ g_timeTaken[(point)] = 0;\ -+} while (0) -+ -+#define PERF_UPDATE_POINT(layer, point) do {\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("old point %d:%s\n", layer, g_ppLayerName[g_perfPoint[(layer)]]));\ -+ g_timeTaken[(point)] = g_timeTaken[g_perfPoint[(layer)]];\ -+ g_timeTaken[g_perfPoint[(layer)]] = 0;\ -+ g_perfPoint[(layer)] = (point);\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("new point %d:%s\n", layer, g_ppLayerName[g_perfPoint[(layer)]]));\ -+} while (0) -+ -+#define PERF_PAUSE(layer) do {\ -+ struct timespec tvEnd;\ -+ clock_gettime(CLOCK_MONOTONIC, &tvEnd);\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("perf pause layer%d\n", layer));\ -+ g_timeTaken[g_perfPoint[(layer)]] += ((tvEnd.tv_sec - tvStart[(layer)].tv_sec) \ -+ * (1000000000UL) + (tvEnd.tv_nsec - tvStart[(layer)].tv_nsec));\ -+} while (0) -+ -+#define PERF_PAUSE_RETURN_POINT(layer, pause_point) do {\ -+ struct timespec tvEnd;\ -+ clock_gettime(CLOCK_MONOTONIC, &tvEnd);\ -+ g_timeTaken[g_perfPoint[(layer)]] += ((tvEnd.tv_sec - tvStart[(layer)].tv_sec) \ -+ * (1000000000UL) + (tvEnd.tv_nsec - tvStart[(layer)].tv_nsec));\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("perf pause point %d:%s\n", layer, g_ppLayerName[g_perfPoint[(layer)]]));\ -+ (pause_point) = g_perfPoint[(layer)];\ -+} while (0) -+ -+ -+#define PERF_RESUME(layer, point) do {\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("perf resule point %d:%s\n", layer, g_ppLayerName[point]));\ -+ clock_gettime(CLOCK_MONOTONIC, &tvStart[(layer)]);\ -+ g_perfPoint[(layer)] = (point);\ -+} while (0) -+ -+ -+/* x is a prompt */ -+#define PERF_STOP_INCREASE_COUNT(x, layer) do {\ -+ if (g_record_perf)\ -+ {\ -+ struct timespec tvEnd;\ -+ int i = 2;\ -+ uint32_t oldValue = 0;\ -+ clock_gettime(CLOCK_MONOTONIC, &tvEnd);\ -+ g_timeTaken[g_perfPoint[(layer)]] += ((tvEnd.tv_sec - tvStart[(layer)].tv_sec) \ -+ * (1000000000UL) + (tvEnd.tv_nsec - tvStart[(layer)].tv_nsec));\ -+ while (i && !oldValue)\ -+ {\ -+ oldValue = __sync_or_and_fetch(&g_perfMaxtime[g_perfPoint[(layer)]], 0);\ -+ if (oldValue >= g_timeTaken[g_perfPoint[(layer)]])\ -+ {\ -+ break;\ -+ }\ -+ oldValue = __sync_val_compare_and_swap(&g_perfMaxtime[g_perfPoint[(layer)]],\ -+ oldValue, g_timeTaken[g_perfPoint[(layer)]]);\ -+ i--;\ -+ }\ -+ __sync_fetch_and_add(&g_astPacketCnt[g_perfPoint[(layer)]], 1);\ -+ __sync_fetch_and_add(&g_astPacketProcTime[g_perfPoint[(layer)]], g_timeTaken[g_perfPoint[(layer)]]);\ -+ LWIP_DEBUGF(PERF_OUTPUT_DEBUG, ("Time for %s is: %ld\n",\ -+ g_ppLayerName[g_perfPoint[(layer)]], g_timeTaken[g_perfPoint[(layer)]]));\ -+ }\ -+} while (0) -+ -+ -+int check_layer_point(int layer, int point); -+int perf_init(); -+ -+#else -+#define PERF_START(layer, point) do { } while (0) -+#define PERF_UPDATE_POINT(layer, point) do { } while (0) -+#define PERF_PAUSE(layer) do { } while (0) -+#define PERF_PAUSE_RETURN_POINT(layer, pause_point) do { } while (0) -+#define PERF_RESUME(layer, point) do { } while (0) -+#define PERF_STOP_INCREASE_COUNT(x, layer) do { } while (0) -+#endif -+ -+#endif /* LWIP_ARCH_PERF_H */ -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -index 3f555ee..b8a0d28 100644 ---- a/src/include/arch/sys_arch.h -+++ b/src/include/arch/sys_arch.h -@@ -1,7 +1,93 @@ --#ifndef LWIP_SYS_ARCH_H --#define LWIP_SYS_ARCH_H -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ - -+#ifndef LWIP_ARCH_SYS_ARCH_H -+#define LWIP_ARCH_SYS_ARCH_H - -+#include -+#include - --#endif /* LWIP_SYS_ARCH_H */ -+#define SYS_MBOX_NULL NULL -+#define SYS_SEM_NULL NULL -+typedef uint32_t sys_prot_t; - -+struct sys_sem { -+ volatile unsigned int c; -+ int (*wait_fn)(void); -+}; -+ -+#define MBOX_NAME_LEN 64 -+struct sys_mbox { -+ struct rte_ring *ring; -+ char name[MBOX_NAME_LEN]; -+ int size; -+ int socket_id; -+ unsigned flags; -+ int (*wait_fn)(void); -+}; -+ -+typedef struct sys_sem *sys_sem_t; -+#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL)) -+#define sys_sem_valid_val(sem) ((sem) != NULL) -+#define sys_sem_set_invalid(sem) do { if ((sem) != NULL) { *(sem) = NULL; }} while(0) -+#define sys_sem_set_invalid_val(sem) do { (sem) = NULL; } while(0) -+ -+struct sys_mutex; -+typedef struct sys_mutex *sys_mutex_t; -+#define sys_mutex_valid(mutex) sys_sem_valid(mutex) -+#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) -+ -+typedef struct sys_mbox *sys_mbox_t; -+#define sys_mbox_valid(mbox) sys_sem_valid(mbox) -+#define sys_mbox_valid_val(mbox) sys_sem_valid_val(mbox) -+#define sys_mbox_set_invalid(mbox) sys_sem_set_invalid(mbox) -+#define sys_mbox_set_invalid_val(mbox) sys_sem_set_invalid_val(mbox) -+int sys_mbox_empty(struct sys_mbox *); -+ -+struct sys_thread; -+typedef struct sys_thread *sys_thread_t; -+ -+extern int eth_dev_poll(void); -+ -+void sys_calibrate_tsc(void); -+uint32_t sys_now(void); -+__attribute__((always_inline)) inline int update_timeout(int timeout, uint32_t poll_ts) -+{ -+ uint32_t used_ms = sys_now() - poll_ts; -+ if (timeout > 0 && used_ms < timeout) { -+ return timeout; -+ } else { -+ return 0; -+ } -+} -+ -+#endif /* LWIP_ARCH_SYS_ARCH_H */ -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -new file mode 100644 -index 0000000..01f8d64 ---- /dev/null -+++ b/src/include/eventpoll.h -@@ -0,0 +1,72 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __EVENTPOLL_H__ -+#define __EVENTPOLL_H__ -+ -+#include -+ -+#include "lwip/api.h" -+#include "list.h" -+ -+#define MAX_EPOLLFDS 32 -+ -+#define LIBOS_EPOLLNONE (0x0) -+#define LIBOS_BADEP (NULL) -+ -+struct event_queue { -+ struct list_node events; -+ /* total number of sockets have events */ -+ int num_events; -+}; -+ -+struct event_array { -+ sys_mbox_t mbox; -+ volatile int num_events; -+ struct epoll_event events[0]; -+}; -+ -+struct libos_epoll { -+ struct event_queue *libos_queue; -+ struct event_array *host_queue; -+ int num_hostfds; -+ int hints; -+ int fd; /* self fd */ -+ int efd; /* eventfd */ -+}; -+ -+extern int add_epoll_event(struct netconn*, uint32_t); -+extern int del_epoll_event(struct netconn*, uint32_t); -+extern int lwip_epoll_close(int); -+extern int lwip_is_epfd(int); -+ -+#endif /* __EVENTPOLL_H__ */ -diff --git a/src/include/hlist.h b/src/include/hlist.h -new file mode 100644 -index 0000000..7059488 ---- /dev/null -+++ b/src/include/hlist.h -@@ -0,0 +1,233 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __HLIST_H__ -+#define __HLIST_H__ -+ -+#include "list.h" -+ -+//#if TCP_PCB_HASH -+struct hlist_node { -+ /** -+ * @pprev: point the previous node's next pointer -+ */ -+ struct hlist_node *next; -+ struct hlist_node **pprev; -+}; -+ -+struct hlist_head { -+ struct hlist_node *first; -+}; -+ -+struct hlist_tail { -+ struct hlist_node *end; -+}; -+ -+struct hlist_ctl { -+ struct hlist_head head; -+ struct hlist_tail tail; -+}; -+ -+#define INIT_HLIST_CTRL(ptr) {(ptr)->head.first = NULL; (ptr)->tail.end = NULL;} -+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -+#define INIT_HLIST_NODE(ptr) {(ptr)->next = NULL; (ptr)->pprev = NULL;} -+#define hlist_entry(ptr, type, member) \ -+ container_of(ptr, type, member) -+ -+/** -+ * hlist_for_each_entry - iterate over list of given type -+ * @tpos: the type * to use as a loop cursor. -+ * @pos: the &struct hlist_node to use as a loop cursor. -+ * @head: the head for your list. -+ * @member: the name of the hlist_node within the struct. -+ */ -+#define hlist_for_each_entry(tpos, pos, head, member) \ -+ for (pos = (head)->first; \ -+ pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ -+ pos = (pos)->next) -+ -+/** -+ * next must be != NULL -+ * add n node before next node -+ * -+ * @n: new node -+ * @next: node in the hlist -+ */ -+static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) -+{ -+ n->pprev = next->pprev; -+ n->next = next; -+ next->pprev = &n->next; -+ *(n->pprev) = n; -+} -+ -+static inline int hlist_empty(const struct hlist_head *h) -+{ -+ return !h->first; -+} -+ -+static inline int hlist_unhashed(const struct hlist_node *h) -+{ -+ return !h->pprev; -+} -+ -+static inline void hlist_del_init(struct hlist_node *n) -+{ -+ struct hlist_node *next = n->next; -+ struct hlist_node **pprev = n->pprev; -+ -+ if (pprev == NULL) { -+ return; -+ } -+ -+ *pprev = next; -+ if (next != NULL) { -+ next->pprev = pprev; -+ } -+ -+ n->next = NULL; -+ n->pprev = NULL; -+} -+ -+static inline void hlist_ctl_del(struct hlist_ctl *ctl, struct hlist_node *n) -+{ -+ if (ctl->head.first == ctl->tail.end) { -+ ctl->head.first = NULL; -+ ctl->tail.end = NULL; -+ return; -+ } -+ -+ if (ctl->tail.end == n) { -+ ctl->tail.end = (struct hlist_node *)n->pprev; -+ } -+ -+ hlist_del_init(n); -+} -+ -+static inline struct hlist_node *hlist_pop_tail(struct hlist_ctl *ctl) -+{ -+ if (hlist_empty(&ctl->head)) { -+ return NULL; -+ } -+ -+ if (ctl->head.first == ctl->tail.end) { -+ struct hlist_node *ret = ctl->tail.end; -+ ctl->tail.end = NULL; -+ ctl->head.first = NULL; -+ return ret; -+ } -+ -+ struct hlist_node *temp = ctl->tail.end; -+ -+ struct hlist_node **ptailPrev = ctl->tail.end->pprev; -+ *ptailPrev = NULL; -+ -+ ctl->tail.end = (struct hlist_node *)ptailPrev; -+ temp->pprev = NULL; -+ return temp; -+} -+ -+static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) -+{ -+ next->next = n->next; -+ n->next = next; -+ next->pprev = &n->next; -+ if (next->next) { -+ next->next->pprev = &next->next; -+ } -+} -+ -+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -+{ -+ struct hlist_node *first = h->first; -+ -+ n->next = first; -+ if (first != NULL) { -+ first->pprev = &n->next; -+ } -+ -+ h->first = n; -+ n->pprev = &h->first; -+} -+ -+static inline struct hlist_node *hlist_pop_head(struct hlist_ctl *ctl) -+{ -+ if (hlist_empty(&ctl->head)) { -+ return NULL; -+ } -+ -+ struct hlist_node *temp = ctl->head.first; -+ hlist_ctl_del(ctl, temp); -+ return temp; -+} -+ -+static inline void hlist_ctl_add_tail(struct hlist_ctl *ctl, struct hlist_node *node) -+{ -+ if (hlist_empty(&ctl->head)) { -+ hlist_add_head(node, &ctl->head); -+ ctl->tail.end = ctl->head.first; -+ return; -+ } -+ -+ ctl->tail.end->next = node; -+ -+ node->pprev = &(ctl->tail.end->next); -+ node->next = NULL; -+ ctl->tail.end = node; -+} -+ -+static inline void hlist_ctl_add_head(struct hlist_node *node, struct hlist_ctl *ctl) -+{ -+ hlist_add_head(node, &ctl->head); -+ if (ctl->tail.end == NULL) { -+ ctl->tail.end = ctl->head.first; -+ } -+} -+ -+static inline void hlist_ctl_add_before(struct hlist_node *n, struct hlist_node *next, struct hlist_ctl *ctl) -+{ -+ hlist_add_before(n, next); -+ if (next == ctl->head.first) { -+ ctl->head.first = n; -+ } -+} -+ -+static inline void hlist_ctl_add_after(struct hlist_node *n, struct hlist_node *next, struct hlist_ctl *ctl) -+{ -+ hlist_add_after(n, next); -+ if (n == ctl->tail.end) { -+ ctl->tail.end = next; -+ } -+} -+//#endif /* TCP_PCB_HASH */ -+ -+#endif /* __HLIST_H__ */ -diff --git a/src/include/list.h b/src/include/list.h -new file mode 100644 -index 0000000..11f94c2 ---- /dev/null -+++ b/src/include/list.h -@@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __LIST_H__ -+#define __LIST_H__ -+ -+#ifndef NULL -+#ifdef __cplusplus -+#define NULL 0 -+#else -+#define NULL ((void *)0) -+#endif -+#endif -+ -+struct list_node { -+ struct list_node *prev; -+ struct list_node *next; -+}; -+ -+static inline void init_list_node_null(struct list_node *n) -+{ -+ n->prev = NULL; -+ n->next = NULL; -+} -+ -+static inline void init_list_node(struct list_node *n) -+{ -+ n->prev = n; -+ n->next = n; -+} -+ -+static inline void list_add_node(struct list_node *h, struct list_node *n) -+{ -+ n->next = h; -+ n->prev = h->prev; -+ h->prev->next = n; -+ h->prev = n; -+} -+ -+static inline void list_del_node(struct list_node *n) -+{ -+ struct list_node *prev = n->prev; -+ struct list_node *next = n->next; -+ next->prev = prev; -+ prev->next = next; -+} -+ -+static inline void list_del_node_init(struct list_node *n) -+{ -+ list_del_node(n); -+ init_list_node(n); -+} -+ -+static inline void list_del_node_null(struct list_node *n) -+{ -+ if ((n->next) && (n->prev)) { -+ list_del_node(n); -+ } -+ init_list_node_null(n); -+} -+ -+static inline int list_is_null(const struct list_node *n) -+{ -+ return (n->prev == NULL) && (n->next == NULL); -+} -+ -+static inline int list_is_empty(const struct list_node *h) -+{ -+ return h == h->next; -+} -+ -+#define list_for_each_safe(pos, n, head) \ -+ for (pos = (head)->next, n = (pos)->next; pos != (head); pos = n, n = (pos)->next) -+ -+#ifndef container_of -+#define container_of(ptr, type, member) ({ \ -+ typeof( ((type *)0)->member ) *__mptr = (ptr); \ -+ (type *)((char *)__mptr - offsetof(type,member));}) -+#endif /* container_of */ -+ -+#endif /* __LIST_H__ */ -diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h -index c2afaf2..6dec8c0 100644 ---- a/src/include/lwip/api.h -+++ b/src/include/lwip/api.h -@@ -140,8 +140,43 @@ enum netconn_type { - /** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ - , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ - #endif /* LWIP_IPV6 */ -+ -+#if USE_LIBOS -+ /*here must bigger than 0xff, because (type & 0xff) is for lwip inner use*/ -+ , NETCONN_LIBOS = 0x100 -+ , NETCONN_HOST = 0x200 -+ , NETCONN_INPRG = 0x400 -+ , NETCONN_STACK = NETCONN_LIBOS | NETCONN_HOST | NETCONN_INPRG -+#endif /* USE_LIBOS */ - }; - -+#ifdef USE_LIBOS -+#define SET_CONN_TYPE_LIBOS_OR_HOST(conn) do { \ -+ conn->type &= ~(NETCONN_STACK); \ -+ conn->type |= (NETCONN_LIBOS | NETCONN_HOST); } while (0) -+#define SET_CONN_TYPE_LIBOS(conn) do { \ -+ conn->type &= ~(NETCONN_STACK); \ -+ conn->type |= NETCONN_LIBOS; } while (0) -+#define SET_CONN_TYPE_HOST(conn) do { \ -+ conn->type &= ~(NETCONN_STACK); \ -+ conn->type |= NETCONN_HOST; } while (0) -+#define ADD_CONN_TYPE_INPRG(conn) do { \ -+ conn->type |= NETCONN_INPRG; } while(0) -+#define CONN_TYPE_HAS_LIBOS_AND_HOST(conn) ((conn->type & (NETCONN_LIBOS | NETCONN_HOST)) == (NETCONN_LIBOS | NETCONN_HOST)) -+#define CONN_TYPE_HAS_LIBOS(conn) (conn->type & NETCONN_LIBOS) -+#define CONN_TYPE_HAS_HOST(conn) (conn->type & NETCONN_HOST) -+#define CONN_TYPE_HAS_INPRG(conn) (!!(conn->type & NETCONN_INPRG)) -+#define CONN_TYPE_IS_LIBOS(conn) (!!(NETCONN_LIBOS == (conn->type & NETCONN_STACK))) -+#define CONN_TYPE_IS_HOST(conn) (!!(NETCONN_HOST == (conn->type & NETCONN_STACK))) -+#else -+#define SET_CONN_TYPE_LIBOS_OR_HOST(conn) do {} while (0) -+#define SET_CONN_TYPE_LIBOS(conn) do {} while (0) -+#define SET_CONN_TYPE_HOST(conn) do {} while (0) -+#define CONN_TYPE_HAS_LIBOS_AND_HOST(conn) (0) -+#define CONN_TYPE_HAS_LIBOS(conn) (0) -+#define CONN_TYPE_HAS_HOST(conn) (0) -+#endif /* USE_LIBOS */ -+ - /** Current state of the netconn. Non-TCP netconns are always - * in state NETCONN_NONE! */ - enum netconn_state { -diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h -index 579fd24..f47cbfe 100644 ---- a/src/include/lwip/debug.h -+++ b/src/include/lwip/debug.h -@@ -145,6 +145,7 @@ - ((debug) & LWIP_DBG_ON) && \ - ((debug) & LWIP_DBG_TYPES_ON) && \ - ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ -+ LWIP_PLATFORM_LOG(debug, STRIP_BRACES(ESC_ARGS message)); \ - LWIP_PLATFORM_DIAG(message); \ - if ((debug) & LWIP_DBG_HALT) { \ - while(1); \ -diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h -index dfb266d..fea7187 100644 ---- a/src/include/lwip/def.h -+++ b/src/include/lwip/def.h -@@ -116,6 +116,21 @@ u32_t lwip_htonl(u32_t x); - - /* Provide usual function names as macros for users, but this can be turned off */ - #ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS -+ -+/* avoid conflicts with netinet/in.h */ -+#ifdef htons -+#undef htons -+#endif -+#ifdef ntohs -+#undef ntohs -+#endif -+#ifdef htonl -+#undef htonl -+#endif -+#ifdef ntohl -+#undef ntohl -+#endif -+ - #define htons(x) lwip_htons(x) - #define ntohs(x) lwip_ntohs(x) - #define htonl(x) lwip_htonl(x) -diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h -index 653c3b2..d560f6b 100644 ---- a/src/include/lwip/ip.h -+++ b/src/include/lwip/ip.h -@@ -96,9 +96,15 @@ struct ip_pcb { - /* - * Option flags per-socket. These are the same like SO_XXX in sockets.h - */ -+#if USE_LIBOS -+#define SOF_REUSEADDR 0x02U /* allow local address reuse */ -+#define SOF_KEEPALIVE 0x09U /* keep connections alive */ -+#define SOF_BROADCAST 0x06U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -+#else - #define SOF_REUSEADDR 0x04U /* allow local address reuse */ - #define SOF_KEEPALIVE 0x08U /* keep connections alive */ - #define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -+#endif /* USE_LIBOS */ - - /* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ - #define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) -@@ -125,7 +131,7 @@ struct ip_globals - /** Destination IP address of current_header */ - ip_addr_t current_iphdr_dest; - }; --extern struct ip_globals ip_data; -+extern PER_THREAD struct ip_globals ip_data; - - - /** Get the interface that accepted the current packet. -diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h -index 1630b26..64d8f31 100644 ---- a/src/include/lwip/memp.h -+++ b/src/include/lwip/memp.h -@@ -58,7 +58,11 @@ typedef enum { - #include "lwip/priv/memp_priv.h" - #include "lwip/stats.h" - -+#if USE_LIBOS -+extern PER_THREAD struct memp_desc* memp_pools[MEMP_MAX]; -+#else - extern const struct memp_desc* const memp_pools[MEMP_MAX]; -+#endif /* USE_LIBOS */ - - /** - * @ingroup mempool -@@ -92,6 +96,18 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX]; - * To relocate a pool, declare it as extern in cc.h. Example for GCC: - * extern u8_t \_\_attribute\_\_((section(".onchip_mem"))) memp_memory_my_private_pool_base[]; - */ -+#if USE_LIBOS -+#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ -+ PER_THREAD struct memp_desc memp_ ## name = {0}; \ -+ PER_THREAD char memp_desc_ ## name[] = desc; \ -+ PER_THREAD struct stats_mem memp_stat ## name = {0}; \ -+ PER_THREAD u16_t memp_size ## name = size; \ -+ PER_THREAD u16_t memp_num ## name = num; \ -+ PER_THREAD struct memp *memp_tab_ ## name = NULL; \ -+ LWIP_DECLARE_MEMP_BASE_ALIGNED(name, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); -+ -+#else /* USE_LIBOS */ -+ - #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ - LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ - \ -@@ -108,6 +124,7 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX]; - &memp_tab_ ## name \ - }; - -+#endif /* USE_LIBOS */ - #endif /* MEMP_MEM_MALLOC */ - - /** -diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h -index 9a16ded..057c51f 100644 ---- a/src/include/lwip/netif.h -+++ b/src/include/lwip/netif.h -@@ -406,11 +406,11 @@ struct netif { - #define NETIF_FOREACH(netif) if (((netif) = netif_default) != NULL) - #else /* LWIP_SINGLE_NETIF */ - /** The list of network interfaces. */ --extern struct netif *netif_list; -+extern PER_THREAD struct netif *netif_list; - #define NETIF_FOREACH(netif) for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) - #endif /* LWIP_SINGLE_NETIF */ - /** The default network interface. */ --extern struct netif *netif_default; -+extern PER_THREAD struct netif *netif_default; - - void netif_init(void); - -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index d8c82d1..8294cdd 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -533,6 +533,22 @@ - #endif - - /** -+ * MEMP_NUM_SYS_SEM: the number of struct sys_sems. -+ * (only needed if you use the sequential API, like api_lib.c) -+ */ -+#if !defined MEMP_NUM_SYS_SEM || defined __DOXYGEN__ -+#define MEMP_NUM_SYS_SEM 128 -+#endif -+ -+/** -+ * MEMP_NUM_SYS_MBOX: the number of struct sys_sems. -+ * (only needed if you use the sequential API, like api_lib.c) -+ */ -+#if !defined MEMP_NUM_SYS_MBOX || defined __DOXYGEN__ -+#define MEMP_NUM_SYS_MBOX 128 -+#endif -+ -+/** - * MEMP_NUM_SELECT_CB: the number of struct lwip_select_cb. - * (Only needed if you have LWIP_MPU_COMPATIBLE==1 and use the socket API. - * In that case, you need one per thread calling lwip_select.) -@@ -2232,7 +2248,7 @@ - * MIB2_STATS==1: Stats for SNMP MIB2. - */ - #if !defined MIB2_STATS || defined __DOXYGEN__ --#define MIB2_STATS 0 -+#define MIB2_STATS 1 - #endif - - #else -@@ -3422,6 +3438,10 @@ - #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF - #endif - -+#ifndef PERF_OUTPUT_DEBUG -+ #define PERF_OUTPUT_DEBUG LWIP_DBG_OFF -+#endif -+ - /** - * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. - */ -@@ -3502,6 +3522,46 @@ - #define LWIP_TESTMODE 0 - #endif - -+/** -+ * EPOLL_DEBUG: Enable debugging in epoll.c. -+ */ -+#if !defined EPOLL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#define EPOLL_DEBUG LWIP_DBG_OFF -+#endif -+/** -+ * @} -+ */ -+ -+/** -+ * ETHDEV_DEBUG: Enable debugging in ethdev.c. -+ */ -+#if !defined ETHDEV_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#define ETHDEV_DEBUG LWIP_DBG_OFF -+#endif -+/** -+ * @} -+ */ -+ -+/** -+ * ETHDEV_DEBUG: Enable debugging in ethdev.c. -+ */ -+#if !defined SYSCALL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#define SYSCALL_DEBUG LWIP_DBG_OFF -+#endif -+/** -+ * @} -+ */ -+ -+/** -+ * CONTROL_DEBUG: Enable debugging in control_plane.c. -+ */ -+#if !defined CONTROL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#define CONTROL_DEBUG LWIP_DBG_ON -+#endif -+/** -+ * @} -+ */ -+ - /* - -------------------------------------------------- - ---------- Performance tracking options ---------- -diff --git a/src/include/lwip/priv/memp_std.h b/src/include/lwip/priv/memp_std.h -index 669ad4d..395ac0c 100644 ---- a/src/include/lwip/priv/memp_std.h -+++ b/src/include/lwip/priv/memp_std.h -@@ -122,6 +122,13 @@ LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), - #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - - -+#if USE_LIBOS -+#if !LWIP_NETCONN_SEM_PER_THREAD -+LWIP_MEMPOOL(SYS_SEM, MEMP_NUM_SYS_SEM, sizeof(struct sys_sem), "SYS_SEM") -+#endif -+ -+LWIP_MEMPOOL(SYS_MBOX, MEMP_NUM_SYS_MBOX, sizeof(struct sys_mbox), "SYS_MBOX") -+#endif /* USE_LIBOS */ - /* - * A list of pools of pbuf's used by LWIP. - * -diff --git a/src/include/lwip/priv/sockets_priv.h b/src/include/lwip/priv/sockets_priv.h -index d8f9904..7268a17 100644 ---- a/src/include/lwip/priv/sockets_priv.h -+++ b/src/include/lwip/priv/sockets_priv.h -@@ -45,56 +45,17 @@ - #include "lwip/sockets.h" - #include "lwip/sys.h" - -+/* move some definitions to the lwipsock.h for libnet to use, and -+ * at the same time avoid conflict between lwip/sockets.h and sys/socket.h -+ */ -+#include "lwipsock.h" -+ - #ifdef __cplusplus - extern "C" { - #endif - - #define NUM_SOCKETS MEMP_NUM_NETCONN - --/** This is overridable for the rare case where more than 255 threads -- * select on the same socket... -- */ --#ifndef SELWAIT_T --#define SELWAIT_T u8_t --#endif -- --union lwip_sock_lastdata { -- struct netbuf *netbuf; -- struct pbuf *pbuf; --}; -- --/** Contains all internal pointers and states used for a socket */ --struct lwip_sock { -- /** sockets currently are built on netconns, each socket has one netconn */ -- struct netconn *conn; -- /** data that was left from the previous read */ -- union lwip_sock_lastdata lastdata; --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -- /** number of times data was received, set by event_callback(), -- tested by the receive and select functions */ -- s16_t rcvevent; -- /** number of times data was ACKed (free send buffer), set by event_callback(), -- tested by select */ -- u16_t sendevent; -- /** error happened for this socket, set by event_callback(), tested by select */ -- u16_t errevent; -- /** counter of how many threads are waiting for this socket using select */ -- SELWAIT_T select_waiting; --#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ --#if LWIP_NETCONN_FULLDUPLEX -- /* counter of how many threads are using a struct lwip_sock (not the 'int') */ -- u8_t fd_used; -- /* status of pending close/delete actions */ -- u8_t fd_free_pending; --#define LWIP_SOCK_FD_FREE_TCP 1 --#define LWIP_SOCK_FD_FREE_FREE 2 --#endif --}; -- --#ifndef set_errno --#define set_errno(err) do { if (err) { errno = (err); } } while(0) --#endif -- - #if !LWIP_TCPIP_CORE_LOCKING - /** Maximum optlen used by setsockopt/getsockopt */ - #define LWIP_SETGETSOCKOPT_MAXOPTLEN LWIP_MAX(16, sizeof(struct ifreq)) -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index 72f9126..192edc4 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -323,25 +323,42 @@ struct tcp_seg { - #endif /* LWIP_WND_SCALE */ - - /* Global variables: */ --extern struct tcp_pcb *tcp_input_pcb; --extern u32_t tcp_ticks; --extern u8_t tcp_active_pcbs_changed; -+extern PER_THREAD struct tcp_pcb *tcp_input_pcb; -+extern PER_THREAD u32_t tcp_ticks; -+extern PER_THREAD u8_t tcp_active_pcbs_changed; - - /* The TCP PCB lists. */ - union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ - struct tcp_pcb_listen *listen_pcbs; - struct tcp_pcb *pcbs; - }; --extern struct tcp_pcb *tcp_bound_pcbs; --extern union tcp_listen_pcbs_t tcp_listen_pcbs; --extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a -+extern PER_THREAD struct tcp_pcb *tcp_bound_pcbs; -+extern PER_THREAD union tcp_listen_pcbs_t tcp_listen_pcbs; -+extern PER_THREAD struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a - state in which they accept or send - data. */ --extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ -+extern PER_THREAD struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ - - #define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 - #define NUM_TCP_PCB_LISTS 4 --extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; -+extern PER_THREAD struct tcp_pcb ** tcp_pcb_lists[NUM_TCP_PCB_LISTS]; -+ -+#if USE_LIBOS -+#include "reg_sock.h" -+static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pcb *pcb) -+{ -+ LWIP_ASSERT("Invalid parameter", pcb != NULL); -+ -+ struct libnet_quintuple qtuple; -+ qtuple.protocol = 0; -+ qtuple.src_ip = pcb->local_ip.addr; -+ qtuple.src_port = lwip_htons(pcb->local_port); -+ qtuple.dst_ip = pcb->remote_ip.addr; -+ qtuple.dst_port = lwip_htons(pcb->remote_port); -+ -+ return vdev_reg_xmit(reg_type, &qtuple); -+} -+#endif - - /* Axioms about the above lists: - 1) Every TCP PCB that is not CLOSED is in one of the lists. -@@ -355,6 +372,54 @@ extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; - #define TCP_DEBUG_PCB_LISTS 0 - #endif - #if TCP_DEBUG_PCB_LISTS -+#if USE_LIBOS -+#define TCP_REG(pcbs, npcb) do {\ -+ struct tcp_pcb *tcp_tmp_pcb; \ -+ LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ -+ for (tcp_tmp_pcb = *(pcbs); \ -+ tcp_tmp_pcb != NULL; \ -+ tcp_tmp_pcb = tcp_tmp_pcb->next) { \ -+ LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ -+ } \ -+ LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ -+ if (*pcbs) \ -+ (*pcbs)->prev = npcb; \ -+ (npcb)->prev = NULL; \ -+ (npcb)->next = *(pcbs); \ -+ LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ -+ *(pcbs) = (npcb); \ -+ LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ -+ tcp_timer_needed(); \ -+ } while(0) -+#define TCP_RMV(pcbs, npcb) do { \ -+ if (pcb->state == LISTEN) \ -+ vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -+ else \ -+ vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -+ struct tcp_pcb *tcp_tmp_pcb; \ -+ LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ -+ LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ -+ if(*(pcbs) == (npcb)) { \ -+ *(pcbs) = (*pcbs)->next; \ -+ if (*pcbs) \ -+ (*pcbs)->prev = NULL; \ -+ } else { \ -+ struct tcp_pcb *prev, *next; \ -+ prev = npcb->prev; \ -+ next = npcb->next; \ -+ if (prev) \ -+ prev->next = next; \ -+ if (next) \ -+ next->prev = prev; \ -+ } \ -+ } \ -+ (npcb)->prev = NULL; \ -+ (npcb)->next = NULL; \ -+ LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ -+ LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ -+ } while(0) -+ -+#else /* USE_LIBOS */ - #define TCP_REG(pcbs, npcb) do {\ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %"U16_F"\n", (void *)(npcb), (npcb)->local_port)); \ -@@ -387,8 +452,65 @@ extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (void *)(npcb), (void *)(*(pcbs)))); \ - } while(0) - -+#endif /* USE_LIBOS */ - #else /* LWIP_DEBUG */ - -+#if TCP_PCB_HASH -+#define TCP_REG_HASH(pcbs, npcb) \ -+ do { \ -+ u32_t idx; \ -+ struct hlist_head *hd; \ -+ struct tcp_hash_table *htb = pcbs; \ -+ idx = TUPLE4_HASH_FN((npcb)->local_ip.addr, (npcb)->local_port, \ -+ (npcb)->remote_ip.addr, (npcb)->remote_port) & \ -+ (htb->size - 1); \ -+ hd = &htb->array[idx].chain; \ -+ hlist_add_head(&(npcb)->tcp_node, hd); \ -+ tcp_timer_needed(); \ -+ } while (0) -+ -+#define TCP_RMV_HASH(pcbs, npcb) \ -+ do { \ -+ hlist_del_init(&(npcb)->tcp_node); \ -+ } while (0) -+#endif /* TCP_PCB_HASH */ -+ -+#if USE_LIBOS -+#define TCP_REG(pcbs, npcb) \ -+ do { \ -+ if (*pcbs) \ -+ (*pcbs)->prev = npcb; \ -+ (npcb)->prev = NULL; \ -+ (npcb)->next = *pcbs; \ -+ *(pcbs) = (npcb); \ -+ tcp_timer_needed(); \ -+ } while (0) -+ -+#define TCP_RMV(pcbs, npcb) \ -+ do { \ -+ if (pcb->state == LISTEN) \ -+ vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -+ else \ -+ vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -+ if(*(pcbs) == (npcb)) { \ -+ (*(pcbs)) = (*pcbs)->next; \ -+ if (*pcbs) \ -+ (*pcbs)->prev = NULL; \ -+ } \ -+ else { \ -+ struct tcp_pcb *prev, *next; \ -+ prev = npcb->prev; \ -+ next = npcb->next; \ -+ if (prev) \ -+ prev->next = next; \ -+ if (next) \ -+ next->prev = prev; \ -+ } \ -+ (npcb)->prev = NULL; \ -+ (npcb)->next = NULL; \ -+ } while(0) -+ -+#else /* USE_LIBOS */ - #define TCP_REG(pcbs, npcb) \ - do { \ - (npcb)->next = *pcbs; \ -@@ -415,8 +537,32 @@ extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; - (npcb)->next = NULL; \ - } while(0) - -+#endif /* USE_LIBOS */ - #endif /* LWIP_DEBUG */ - -+ -+#if TCP_PCB_HASH -+#define TCP_REG_ACTIVE_HASH(npcb) \ -+ do { \ -+ TCP_REG_HASH(tcp_active_htable, npcb); \ -+ tcp_active_pcbs_changed = 1; \ -+ } while (0) -+ -+#define TCP_RMV_ACTIVE_HASH(npcb) \ -+ do { \ -+ TCP_RMV_HASH(tcp_active_htable, npcb); \ -+ tcp_active_pcbs_changed = 1; \ -+ } while (0) -+ -+#define TCP_PCB_REMOVE_ACTIVE_HASH(pcb) \ -+ do { \ -+ tcp_pcb_remove_hash(tcp_active_htable, pcb); \ -+ tcp_active_pcbs_changed = 1; \ -+ } while (0) -+ -+void tcp_pcb_remove_hash(struct tcp_hash_table *htb, struct tcp_pcb *pcb); -+#endif /* TCP_PCB_HASH */ -+ - #define TCP_REG_ACTIVE(npcb) \ - do { \ - TCP_REG(&tcp_active_pcbs, npcb); \ -diff --git a/src/include/lwip/prot/ip4.h b/src/include/lwip/prot/ip4.h -index 9347461..c9ad89c 100644 ---- a/src/include/lwip/prot/ip4.h -+++ b/src/include/lwip/prot/ip4.h -@@ -81,6 +81,21 @@ struct ip_hdr { - PACK_STRUCT_FIELD(u16_t _id); - /* fragment offset field */ - PACK_STRUCT_FIELD(u16_t _offset); -+ -+/* avoid conflicts with netinet/ip.h */ -+#ifdef IP_RF -+#undef IP_RF -+#endif -+#ifdef IP_DF -+#undef IP_DF -+#endif -+#ifdef IP_MF -+#undef IP_MF -+#endif -+#ifdef IP_OFFMASK -+#undef IP_OFFMASK -+#endif -+ - #define IP_RF 0x8000U /* reserved fragment flag */ - #define IP_DF 0x4000U /* don't fragment flag */ - #define IP_MF 0x2000U /* more fragments flag */ -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index d70d36c..345e26c 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -57,6 +57,11 @@ extern "C" { - - /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED - to prevent this code from redefining it. */ -+#if USE_LIBOS -+#define SA_FAMILY_T_DEFINED -+ typedef u16_t sa_family_t; -+#endif -+ - #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) - typedef u8_t sa_family_t; - #endif -@@ -69,7 +74,9 @@ typedef u16_t in_port_t; - #if LWIP_IPV4 - /* members are in network byte order */ - struct sockaddr_in { -+#if !USE_LIBOS - u8_t sin_len; -+#endif - sa_family_t sin_family; - in_port_t sin_port; - struct in_addr sin_addr; -@@ -90,7 +97,9 @@ struct sockaddr_in6 { - #endif /* LWIP_IPV6 */ - - struct sockaddr { -+#if !USE_LIBOS - u8_t sa_len; -+#endif - sa_family_t sa_family; - char sa_data[14]; - }; -@@ -189,6 +198,9 @@ struct ifreq { - #define SOCK_DGRAM 2 - #define SOCK_RAW 3 - -+#if USE_LIBOS -+#include -+#else - /* - * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) - */ -@@ -221,6 +233,12 @@ struct ifreq { - #define SO_BINDTODEVICE 0x100b /* bind to device */ - - /* -+ * Level number for (get/set)sockopt() to apply to socket itself. -+ */ -+#define SOL_SOCKET 0xfff /* options for socket level */ -+#endif /* USE_LIBOS */ -+ -+/* - * Structure used for manipulating linger option. - */ - struct linger { -@@ -228,11 +246,6 @@ struct linger { - int l_linger; /* linger time in seconds */ - }; - --/* -- * Level number for (get/set)sockopt() to apply to socket itself. -- */ --#define SOL_SOCKET 0xfff /* options for socket level */ -- - - #define AF_UNSPEC 0 - #define AF_INET 2 -@@ -276,11 +289,20 @@ struct linger { - /* - * Options for level IPPROTO_TCP - */ -+#if USE_LIBOS -+/* come from netinet/tcp.h */ -+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -+#define TCP_KEEPALIVE 0x24 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ -+#define TCP_KEEPIDLE 0x04 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ -+#define TCP_KEEPINTVL 0x05 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ -+#define TCP_KEEPCNT 0x06 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ -+#else /* USE_LIBOS */ - #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ - #define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ - #define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ - #define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ - #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ -+#endif /* USE_LIBOS */ - #endif /* LWIP_TCP */ - - #if LWIP_IPV6 -@@ -483,12 +505,30 @@ typedef struct fd_set - unsigned char fd_bits [(FD_SETSIZE+7)/8]; - } fd_set; - --#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) -+#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) && !USE_LIBOS - #error "external FD_SETSIZE too small for number of sockets" - #else - #define LWIP_SELECT_MAXNFDS FD_SETSIZE - #endif /* FD_SET */ - -+#if USE_LIBOS -+#if !defined(POLLIN) && !defined(POLLOUT) -+/* come from bits/poll.h */ -+#define POLLIN 0x001 -+#define POLLOUT 0x004 -+#define POLLERR 0x008 -+#define POLLNVAL 0x020 -+/* Below values are unimplemented */ -+#define POLLRDNORM 0x040 -+#define POLLRDBAND 0x080 -+#define POLLPRI 0x002 -+#define POLLWRNORM 0x100 -+#define POLLWRBAND 0x200 -+#define POLLHUP 0x010 -+#endif -+#endif /* USE_LIBOS */ -+ -+#if LWIP_SOCKET_POLL - /* poll-related defines and types */ - /* @todo: find a better way to guard the definition of these defines and types if already defined */ - #if !defined(POLLIN) && !defined(POLLOUT) -@@ -511,6 +551,7 @@ struct pollfd - short revents; - }; - #endif -+#endif /* LWIP_SOCKET_POLL */ - - /** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided - * by your system, set this to 0 and include in cc.h */ -@@ -603,8 +644,15 @@ int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptse - #if LWIP_SOCKET_POLL - int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); - #endif -+ -+#if USE_LIBOS -+int lwip_ioctl(int s, long cmd, ...); -+int lwip_fcntl(int s, int cmd, ...); -+#else - int lwip_ioctl(int s, long cmd, void *argp); - int lwip_fcntl(int s, int cmd, int val); -+#endif /* USE_LIBOS */ -+ - const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); - int lwip_inet_pton(int af, const char *src, void *dst); - -@@ -670,10 +718,17 @@ int lwip_inet_pton(int af, const char *src, void *dst); - #define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) - /** @ingroup socket */ - #define close(s) lwip_close(s) -+ -+#if USE_LIBOS -+#define fcntl(s,cmd...) lwip_fcntl(s,cmd) -+#define ioctl(s,cmd...) lwip_ioctl(s,cmd) -+#else - /** @ingroup socket */ - #define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) - /** @ingroup socket */ - #define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) -+#endif /* USE_LIBOS */ -+ - #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ - #endif /* LWIP_COMPAT_SOCKETS != 2 */ - -diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h -index b570dba..4470531 100644 ---- a/src/include/lwip/stats.h -+++ b/src/include/lwip/stats.h -@@ -301,7 +301,7 @@ struct stats_ { - }; - - /** Global variable containing lwIP internal statistics. Add this to your debugger's watchlist. */ --extern struct stats_ lwip_stats; -+extern PER_THREAD struct stats_ lwip_stats; - - /** Init statistics */ - void stats_init(void); -@@ -467,6 +467,8 @@ void stats_init(void); - #define MIB2_STATS_INC(x) - #endif - -+int get_mib2_stats(char *buf); -+ - /* Display of statistics */ - #if LWIP_STATS_DISPLAY - void stats_display(void); -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index daf7599..4f86b46 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -51,6 +51,11 @@ - #include "lwip/ip6.h" - #include "lwip/ip6_addr.h" - -+#if TCP_PCB_HASH -+#include "lwip/sys.h" -+#include "hlist.h" -+#endif -+ - #ifdef __cplusplus - extern "C" { - #endif -@@ -209,15 +214,27 @@ typedef u16_t tcpflags_t; - /** - * members common to struct tcp_pcb and struct tcp_listen_pcb - */ -+#if USE_LIBOS - #define TCP_PCB_COMMON(type) \ - type *next; /* for the linked list */ \ -+ type *prev; /* for the linked list */ \ - void *callback_arg; \ - TCP_PCB_EXTARGS \ - enum tcp_state state; /* TCP state */ \ - u8_t prio; \ - /* ports are in host byte order */ \ - u16_t local_port -- -+ -+#else /* USE_LIBOS */ -+#define TCP_PCB_COMMON(type) \ -+ type *next; /* for the linked list */ \ -+ void *callback_arg; \ -+ TCP_PCB_EXTARGS \ -+ enum tcp_state state; /* TCP state */ \ -+ u8_t prio; \ -+ /* ports are in host byte order */ \ -+ u16_t local_port -+#endif /* USE_LIBOS */ - - /** the TCP protocol control block for listening pcbs */ - struct tcp_pcb_listen { -@@ -244,6 +261,9 @@ struct tcp_pcb { - IP_PCB; - /** protocol specific PCB members */ - TCP_PCB_COMMON(struct tcp_pcb); -+#if TCP_PCB_HASH -+ struct hlist_node tcp_node; -+#endif - - /* ports are in host byte order */ - u16_t remote_port; -@@ -388,6 +408,58 @@ struct tcp_pcb { - #endif - }; - -+#if TCP_PCB_HASH -+#define TCP_HTABLE_SIZE MEMP_NUM_NETCONN*12 -+ -+struct tcp_hashbucket -+{ -+ sys_mutex_t mutex; -+ struct hlist_head chain; -+}; -+ -+struct tcp_hash_table -+{ -+ u32_t size; -+ struct tcp_hashbucket array[TCP_HTABLE_SIZE]; -+}; -+ -+extern PER_THREAD struct tcp_hash_table *tcp_active_htable; /* key: lport/fport/lip/fip */ -+ -+#define JHASH_INITVAL 0xdeadbeef -+ -+static inline unsigned int rol32(unsigned int word, unsigned int shift) -+{ -+ return (word << shift) | (word >> (32 - shift)); -+} -+ -+#define __jhash_final(a, b, c) \ -+{ \ -+ c ^= b; c -= rol32(b, 14); \ -+ a ^= c; a -= rol32(c, 11); \ -+ b ^= a; b -= rol32(a, 25); \ -+ c ^= b; c -= rol32(b, 16); \ -+ a ^= c; a -= rol32(c, 4); \ -+ b ^= a; b -= rol32(a, 14); \ -+ c ^= b; c -= rol32(b, 24); \ -+} -+ -+static inline unsigned int jhash_3words(unsigned int a, unsigned int b, unsigned int c) -+{ -+ a += JHASH_INITVAL; -+ b += JHASH_INITVAL;; -+ -+ __jhash_final(a, b, c); -+ -+ return c; -+} -+ -+#define TUPLE4_HASH_FN(laddr, lport, faddr, fport) jhash_3words(laddr, faddr,lport|(fport<<16)) -+ -+#define tcppcb_hlist_for_each(tcppcb, node, list) \ -+ hlist_for_each_entry(tcppcb, node, list, tcp_node) -+ -+#endif /* TCP_PCB_HASH */ -+ - #if LWIP_EVENT_API - - enum lwip_event { -@@ -481,6 +553,26 @@ err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_add - - #define tcp_dbg_get_tcp_state(pcb) ((pcb)->state) - -+enum tcp_list_state { -+ ACTIVE_LIST, -+ LISTEN_LIST, -+ TIME_WAIT_LIST, -+}; -+ -+struct tcp_pcb_dp { -+ uint32_t state; -+ uint32_t lip; -+ uint32_t rip; -+ uint16_t l_port; -+ uint16_t r_port; -+ uint32_t r_next; -+ uint32_t s_next; -+ uint32_t tcp_sub_state; -+}; -+ -+void tcp_get_conn(char *buf, int32_t len, uint32_t *conn_num); -+uint32_t tcp_get_conn_num(void); -+ - /* for compatibility with older implementation */ - #define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) - -diff --git a/src/include/lwip/tcpip.h b/src/include/lwip/tcpip.h -index 0b8880a..d2c2440 100644 ---- a/src/include/lwip/tcpip.h -+++ b/src/include/lwip/tcpip.h -@@ -51,7 +51,7 @@ extern "C" { - - #if LWIP_TCPIP_CORE_LOCKING - /** The global semaphore to lock the stack. */ --extern sys_mutex_t lock_tcpip_core; -+extern PER_THREAD sys_mutex_t lock_tcpip_core; - #if !defined LOCK_TCPIP_CORE || defined __DOXYGEN__ - /** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ - #define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) -diff --git a/src/include/lwip/timeouts.h b/src/include/lwip/timeouts.h -index b601f9e..b451554 100644 ---- a/src/include/lwip/timeouts.h -+++ b/src/include/lwip/timeouts.h -@@ -119,6 +119,10 @@ struct sys_timeo** sys_timeouts_get_next_timeout(void); - void lwip_cyclic_timer(void *arg); - #endif - -+#if USE_LIBOS -+void sys_timer_run(void); -+#endif /* USE_LIBOS */ -+ - #endif /* LWIP_TIMERS */ - - #ifdef __cplusplus -diff --git a/src/include/lwiplog.h b/src/include/lwiplog.h -new file mode 100644 -index 0000000..363e516 ---- /dev/null -+++ b/src/include/lwiplog.h -@@ -0,0 +1,81 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __LWIPLOG_H__ -+#define __LWIPLOG_H__ -+ -+#include -+#include -+ -+#include -+ -+#include "lwipopts.h" -+ -+#define gettid() syscall(__NR_gettid) -+ -+#if USE_DPDK_LOG -+ -+#define LWIP_LOG_WARN LWIP_DBG_LEVEL_WARNING -+#define LWIP_LOG_ERROR LWIP_DBG_LEVEL_SERIOUS -+#define LWIP_LOG_FATAL LWIP_DBG_LEVEL_SEVERE -+ -+#define LWIP_PLATFORM_LOG(level, fmt, ...) \ -+do { \ -+ if ((level) & LWIP_LOG_FATAL) { \ -+ RTE_LOG(ERR, EAL, fmt, ##__VA_ARGS__); \ -+ abort(); \ -+ } else if ((level) & LWIP_LOG_ERROR) { \ -+ RTE_LOG(ERR, EAL, fmt, ##__VA_ARGS__); \ -+ } else if ((level) & LWIP_LOG_WARN) { \ -+ RTE_LOG(WARNING, EAL, fmt, ##__VA_ARGS__); \ -+ } else { \ -+ RTE_LOG(INFO, EAL, fmt, ##__VA_ARGS__); \ -+ } \ -+} while(0) -+ -+ -+#define LWIP_PLATFORM_DIAG(x) -+ -+#define ESC_ARGS(...) __VA_ARGS__ -+#define STRIP_BRACES(args) args -+ -+#define LWIP_PLATFORM_ASSERT(x) \ -+do { LWIP_PLATFORM_LOG(LWIP_LOG_FATAL, "Assertion \"%s\" failed at line %d in %s\n", \ -+ x, __LINE__, __FILE__); abort();} while(0) -+ -+#else -+ -+#define LWIP_PLATFORM_LOG(debug, message) -+ -+#endif /* USE_DPDK_LOG */ -+ -+#endif /* __LWIPLOG_H__ */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 4ab26f2..8893a5f 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -1,8 +1,8 @@ - /* -- * Copyright (c) 2001-2003 Swedish Institute of Computer Science. -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without modification, -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, -@@ -11,70 +11,193 @@ - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products -- * derived from this software without specific prior written permission. -+ * derived from this software without specific prior written permission. - * -- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. -- * -- * Author: Simon Goldschmidt -+ * -+ * Author: Huawei Technologies - * - */ --#ifndef LWIP_HDR_LWIPOPTS_H__ --#define LWIP_HDR_LWIPOPTS_H__ -- --/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ --#define NO_SYS 1 --#define LWIP_NETCONN 0 --#define LWIP_SOCKET 0 --#define SYS_LIGHTWEIGHT_PROT 0 -- --#define LWIP_IPV6 1 --#define IPV6_FRAG_COPYHEADER 1 --#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 0 -- --/* Enable some protocols to test them */ --#define LWIP_DHCP 1 --#define LWIP_AUTOIP 1 -- --#define LWIP_IGMP 1 --#define LWIP_DNS 1 -- --#define LWIP_ALTCP 1 -- --/* Turn off checksum verification of fuzzed data */ --#define CHECKSUM_CHECK_IP 0 --#define CHECKSUM_CHECK_UDP 0 --#define CHECKSUM_CHECK_TCP 0 --#define CHECKSUM_CHECK_ICMP 0 --#define CHECKSUM_CHECK_ICMP6 0 -- --/* Minimal changes to opt.h required for tcp unit tests: */ --#define MEM_SIZE 16000 --#define TCP_SND_QUEUELEN 40 --#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN --#define TCP_OVERSIZE 1 --#define TCP_SND_BUF (12 * TCP_MSS) --#define TCP_WND (10 * TCP_MSS) --#define LWIP_WND_SCALE 1 --#define TCP_RCV_SCALE 2 --#define PBUF_POOL_SIZE 400 /* pbuf tests need ~200KByte */ -- --/* Minimal changes to opt.h required for etharp unit tests: */ --#define ETHARP_SUPPORT_STATIC_ENTRIES 1 -- --#define LWIP_NUM_NETIF_CLIENT_DATA 1 --#define LWIP_SNMP 1 --#define MIB2_STATS 1 --#define LWIP_MDNS_RESPONDER 1 -- --#endif /* LWIP_HDR_LWIPOPTS_H__ */ -+ -+#ifndef __LWIPOPTS_H__ -+#define __LWIPOPTS_H__ -+ -+#define LWIP_TCPIP_CORE_LOCKING 1 -+ -+#define LWIP_NETCONN_SEM_PER_THREAD 0 -+ -+#define LWIP_TCP 1 -+ -+#define LWIP_SO_SENTIMEO 0 -+ -+#define LIP_SO_LINGER 0 -+ -+#define MEMP_USE_CUSTOM_POOLS 0 -+#define MEM_USE_POOLS 0 -+ -+#define PER_TCP_PCB_BUFFER (16 * 128) -+ -+#define MAX_CLIENTS (20000) -+ -+#define RESERVED_CLIENTS (2000) -+ -+#define MEMP_NUM_TCP_PCB (MAX_CLIENTS + RESERVED_CLIENTS) -+ -+/* we use PBUF_POOL instead of PBUF_RAM in tcp_write, so reduce PBUF_RAM size, -+ * and do NOT let PBUF_POOL_BUFSIZE less then TCP_MSS -+*/ -+#define MEM_SIZE (((PER_TCP_PCB_BUFFER + 128) * MEMP_NUM_TCP_SEG) >> 2) -+ -+#define MEMP_NUM_TCP_PCB_LISTEN 3000 -+ -+#define MEMP_NUM_TCP_SEG (128 * 128 * 2) -+ -+#define MEMP_NUM_NETCONN (MAX_CLIENTS + RESERVED_CLIENTS) -+ -+#define MEMP_NUM_SYS_SEM (MAX_CLIENTS + RESERVED_CLIENTS) -+ -+#define MEMP_NUM_SYS_MBOX (MAX_CLIENTS + RESERVED_CLIENTS) -+ -+#define PBUF_POOL_SIZE (MAX_CLIENTS * 2) -+ -+#define MEMP_MEM_MALLOC 0 -+ -+#define LWIP_ARP 1 -+ -+#define ETHARP_SUPPORT_STATIC_ENTRIES 1 -+ -+#define LWIP_IPV4 1 -+ -+#define IP_FORWARD 0 -+ -+#define IP_REASSEMBLY 1 -+ -+#define LWIP_UDP 0 -+ -+#define LWIP_TCP 1 -+ -+#define IP_HLEN 20 -+ -+#define TCP_HLEN 20 -+ -+#define FRAME_MTU 1500 -+ -+#define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) -+ -+#define TCP_WND (40 * TCP_MSS) -+ -+#define TCP_SND_BUF (5 * TCP_MSS) -+ -+#define TCP_SND_QUEUELEN (8191) -+ -+#define TCP_SNDLOWAT (TCP_SND_BUF / 5) -+ -+#define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5) -+ -+#define TCP_LISTEN_BACKLOG 1 -+ -+#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -+ -+#define TCP_OVERSIZE 0 -+ -+#define LWIP_NETIF_API 1 -+ -+#define DEFAULT_TCP_RECVMBOX_SIZE 128 -+ -+#define DEFAULT_ACCEPTMBOX_SIZE 1024 -+ -+#define LWIP_NETCONN 1 -+ -+#define LWIP_TCPIP_TIMEOUT 0 -+ -+#define LWIP_SOCKET 1 -+ -+#define LWIP_TCP_KEEPALIVE 1 -+ -+#define LWIP_STATS 1 -+ -+#define LWIP_STATS_DISPLAY 1 -+ -+#define CHECKSUM_GEN_IP 1 /* master switch */ -+ -+#define CHECKSUM_GEN_TCP 1 /* master switch */ -+ -+#define CHECKSUM_CHECK_IP 1 /* master switch */ -+ -+#define CHECKSUM_CHECK_TCP 1 /* master switch */ -+ -+#define LWIP_TIMEVAL_PRIVATE 0 -+ -+#define USE_LIBOS 1 -+ -+#define LWIP_DEBUG 1 -+ -+#define LWIP_PERF 1 -+ -+#define LWIP_RECORD_PERF 0 -+ -+#define LWIP_SOCKET_POLL 0 -+ -+#define USE_LIBOS_ZC_RING 0 -+ -+#define SO_REUSE 1 -+ -+#define SIOCSHIWAT 1 -+ -+#define O_NONBLOCK 04000 /* same as define in bits/fcntl-linux.h */ -+ -+#define O_NDELAY O_NONBLOCK -+ -+#define FIONBIO 0x5421 /* same as define in asm-generic/ioctls.h */ -+ -+#define LWIP_SUPPORT_CUSTOM_PBUF 1 -+ -+#define MEM_LIBC_MALLOC 0 -+ -+#define LWIP_TIMERS 1 -+ -+#define TCPIP_MBOX_SIZE (MEMP_NUM_TCPIP_MSG_API) -+ -+#define TCP_PCB_HASH 1 -+ -+#define USE_DPDK_LOG 1 -+ -+#define LWIP_EPOOL_WAIT_MAX_EVENTS 30 -+ -+#define ARP_TABLE_SIZE 512 -+ -+/* -+ --------------------------------------- -+ ------- Syscall thread options -------- -+ --------------------------------------- -+*/ -+#define USE_SYSCALL_THREAD 1 -+ -+#define MAX_BLOCKING_ACCEPT_FD (100) -+ -+#define MAX_BLOCKING_CONNECT_FD (100) -+ -+#define MAX_BLOCKING_EPOLL_FD (100) -+ -+#define MAX_SYSCALL_EVENTS (MAX_BLOCKING_ACCEPT_FD + MAX_BLOCKING_CONNECT_FD + MAX_BLOCKING_EPOLL_FD) -+ -+#define MAX_HOST_FD (MAX_CLIENTS + RESERVED_CLIENTS) -+ -+#if USE_LIBOS -+#define PER_THREAD __thread -+#else -+#define PER_THREAD -+#endif -+ -+#endif /* __LWIPOPTS_H__ */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -new file mode 100644 -index 0000000..dbc67b9 ---- /dev/null -+++ b/src/include/lwipsock.h -@@ -0,0 +1,155 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __LWIPSOCK_H__ -+#define __LWIPSOCK_H__ -+ -+#include "lwip/opt.h" -+#include "lwip/api.h" -+ -+#include "posix_api.h" -+#include "eventpoll.h" -+ -+/* move some definitions to the lwipsock.h for libnet to use, and -+ * at the same time avoid conflict between lwip/sockets.h and sys/socket.h -+ */ -+ -+/* -------------------------------------------------- -+ * the following definition is copied from lwip/priv/tcpip_priv.h -+ * -------------------------------------------------- -+ */ -+ -+/** This is overridable for the rare case where more than 255 threads -+ * select on the same socket... -+ */ -+#ifndef SELWAIT_T -+#define SELWAIT_T u8_t -+#endif -+ -+union lwip_sock_lastdata { -+ struct netbuf *netbuf; -+ struct pbuf *pbuf; -+}; -+ -+/** Contains all internal pointers and states used for a socket */ -+struct lwip_sock { -+ /** sockets currently are built on netconns, each socket has one netconn */ -+ struct netconn *conn; -+ /** data that was left from the previous read */ -+ union lwip_sock_lastdata lastdata; -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+ /** number of times data was received, set by event_callback(), -+ tested by the receive and select functions */ -+ s16_t rcvevent; -+ /** number of times data was ACKed (free send buffer), set by event_callback(), -+ tested by select */ -+ u16_t sendevent; -+ /** error happened for this socket, set by event_callback(), tested by select */ -+ u16_t errevent; -+ /** counter of how many threads are waiting for this socket using select */ -+ SELWAIT_T select_waiting; -+#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -+#if LWIP_NETCONN_FULLDUPLEX -+ /* counter of how many threads are using a struct lwip_sock (not the 'int') */ -+ u8_t fd_used; -+ /* status of pending close/delete actions */ -+ u8_t fd_free_pending; -+#define LWIP_SOCK_FD_FREE_TCP 1 -+#define LWIP_SOCK_FD_FREE_FREE 2 -+#endif -+ -+#if USE_LIBOS -+ struct list_node list; -+ /* registered events */ -+ uint32_t epoll; -+ /* available events */ -+ uint32_t events; -+ epoll_data_t ep_data; -+ /* libos_epoll pointer in use */ -+ struct libos_epoll *epoll_data; -+#endif -+}; -+ -+#ifndef set_errno -+#define set_errno(err) do { if (err) { errno = (err); } } while(0) -+#endif -+ -+ -+/* -------------------------------------------------- -+ * --------------- LIBNET references ---------------- -+ * -------------------------------------------------- -+ */ -+#if USE_LIBOS -+extern uint32_t sockets_num; -+extern struct lwip_sock *sockets; -+/** -+ * Map a externally used socket index to the internal socket representation. -+ * -+ * @param s externally used socket index -+ * @return struct lwip_sock for the socket or NULL if not found -+ */ -+static inline struct lwip_sock * -+get_socket_without_errno(int s) -+{ -+ struct lwip_sock *sock = NULL; -+ -+ s -= LWIP_SOCKET_OFFSET; -+ -+ if ((s < 0) || (s >= sockets_num)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET)); -+ return NULL; -+ } -+ -+ sock = &sockets[s]; -+ -+ if (!sock->conn) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET)); -+ return NULL; -+ } -+ -+ return sock; -+} -+#endif /* USE_LIBOS */ -+ -+struct lwip_sock *get_socket(int s); -+struct lwip_sock *get_socket_by_fd(int s); -+void lwip_sock_init(void); -+void lwip_exit(void); -+ -+extern int is_host_ipv4(uint32_t ipv4); -+extern int rearm_host_fd(int fd); -+extern int rearm_accept_fd(int fd); -+extern void unarm_host_fd(int fd); -+extern void clean_host_fd(int fd); -+extern int arm_host_fd(struct libos_epoll *ep, int op, int fd, struct epoll_event *event); -+ -+#endif /* __LWIPSOCK_H__ */ -diff --git a/src/include/memp_def.h b/src/include/memp_def.h -new file mode 100644 -index 0000000..082f685 ---- /dev/null -+++ b/src/include/memp_def.h -@@ -0,0 +1,66 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __MEMP_DEF_H__ -+#define __MEMP_DEF_H__ -+ -+#include "lwip/opt.h" -+#include "arch/cc.h" -+ -+#define LWIP_MEMPOOL_BASE_DECLARE(name) \ -+ extern void alloc_memp_##name##_base(void); -+ -+#define LWIP_MEM_MEMORY_DECLARE(name) \ -+ extern void alloc_memory_##name(void); -+ -+#define LWIP_MEMPOOL_BASE_INIT(name) \ -+ alloc_memp_##name##_base(); -+ -+#define LWIP_MEM_MEMORY_INIT(name) \ -+ alloc_memory_##name(); -+ -+#define LWIP_MEMPOOL(name, num, size, desc) LWIP_MEMPOOL_BASE_DECLARE(name) -+#include -+#undef LWIP_MEMPOOL -+ -+static inline void hugepage_init(void) -+{ -+#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_BASE_INIT(name) -+#include "lwip/priv/memp_std.h" -+ -+#if !MEM_LIBC_MALLOC -+ LWIP_MEM_MEMORY_DECLARE(ram_heap) -+ LWIP_MEM_MEMORY_INIT(ram_heap) -+#endif /* MEM_LIBC_MALLOC */ -+} -+ -+#endif /* __MEMP_DEF_H__ */ -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -new file mode 100644 -index 0000000..8aa8516 ---- /dev/null -+++ b/src/include/posix_api.h -@@ -0,0 +1,88 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __POSIX_API_H__ -+#define __POSIX_API_H__ -+ -+#include -+#include -+#include -+#include -+ -+typedef struct { -+ void *handle; -+ int (*socket_fn)(int domain, int type, int protocol); -+ int (*accept_fn)(int s, struct sockaddr*, socklen_t*); -+ int (*accept4_fn)(int s, struct sockaddr *addr, socklen_t *addrlen, int flags); -+ int (*bind_fn)(int s, const struct sockaddr*, socklen_t); -+ int (*listen_fn)(int s, int backlog); -+ int (*connect_fn)(int s, const struct sockaddr *name, socklen_t namelen); -+ int (*getpeername_fn)(int s, struct sockaddr *name, socklen_t *namelen); -+ int (*getsockname_fn)(int s, struct sockaddr *name, socklen_t *namelen); -+ int (*setsockopt_fn)(int s, int level, int optname, const void *optval, socklen_t optlen); -+ int (*getsockopt_fn)(int s, int level, int optname, void *optval, socklen_t *optlen); -+ int (*shutdown_fn)(int s, int how); -+ int (*close_fn)(int fd); -+ pid_t (*fork_fn)(void); -+ ssize_t (*read_fn)(int fd, void *mem, size_t len); -+ ssize_t (*write_fn)(int fd, const void *data, size_t len); -+ ssize_t (*recv_fn)(int sockfd, void *buf, size_t len, int flags); -+ ssize_t (*send_fn)(int sockfd, const void *buf, size_t len, int flags); -+ ssize_t (*recv_msg)(int sockfd, const struct msghdr *msg, int flags); -+ ssize_t (*send_msg)(int sockfd, const struct msghdr *msg, int flags); -+ ssize_t (*recv_from)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); -+ ssize_t (*send_to)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, -+ socklen_t addrlen); -+ int (*fcntl_fn)(int fd, int cmd, ...); -+ int (*fcntl64_fn)(int fd, int cmd, ...); -+ int (*pipe_fn)(int pipefd[2]); -+ int (*epoll_create_fn)(int size); -+ int (*epoll_ctl_fn)(int epfd, int op, int fd, struct epoll_event *event); -+ int (*epoll_wait_fn)(int epfd, struct epoll_event *events, int maxevents, int timeout); -+ int (*epoll_close_fn)(int epfd); -+ int (*eventfd_fn)(unsigned int initval, int flags); -+ int (*is_epfd)(int fd); -+ struct lwip_sock* (*get_socket)(int fd); -+ int (*sigaction_fn)(int signum, const struct sigaction *act, struct sigaction *oldact); -+ int (*poll_fn)(struct pollfd *fds, nfds_t nfds, int timeout); -+ int (*ioctl_fn)(int fd, int cmd, ...); -+ -+ int is_chld; -+} posix_api_t; -+ -+posix_api_t *posix_api; -+ -+int posix_api_init(void); -+void posix_api_free(void); -+void posix_api_fork(void); -+ -+#endif /* __POSIX_API_H__ */ -diff --git a/src/include/reg_sock.h b/src/include/reg_sock.h -new file mode 100644 -index 0000000..76d4c48 ---- /dev/null -+++ b/src/include/reg_sock.h -@@ -0,0 +1,62 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __REG_SOCK_H__ -+#define __REG_SOCK_H__ -+ -+enum reg_ring_type { -+ REG_RING_TCP_LISTEN = 0, -+ REG_RING_TCP_LISTEN_CLOSE, -+ REG_RING_TCP_CONNECT, -+ REG_RING_TCP_CONNECT_CLOSE, -+ RING_REG_MAX, -+}; -+ -+struct libnet_quintuple { -+ uint32_t protocol; -+ /* net byte order */ -+ uint16_t src_port; -+ uint16_t dst_port; -+ uint32_t src_ip; -+ uint32_t dst_ip; -+}; -+ -+struct reg_ring_msg { -+ enum reg_ring_type type; -+ -+ uint32_t tid; -+ struct libnet_quintuple qtuple; -+}; -+ -+extern int vdev_reg_xmit(enum reg_ring_type type, struct libnet_quintuple *qtuple); -+ -+#endif /* __REG_SOCK_H__ */ -\ No newline at end of file -diff --git a/src/netif/dir.mk b/src/netif/dir.mk -index 233c79a..f585d5e 100644 ---- a/src/netif/dir.mk -+++ b/src/netif/dir.mk -@@ -1,3 +1,3 @@ --SRC = ethernet.c -+SRC = ethernet.c - - $(eval $(call register_dir, netif, $(SRC))) --- -1.8.3.1 - diff --git a/0003-fix-the-occasional-coredump-when-the-lwip-exits.patch b/0003-fix-the-occasional-coredump-when-the-lwip-exits.patch deleted file mode 100644 index a540728..0000000 --- a/0003-fix-the-occasional-coredump-when-the-lwip-exits.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0d5070b4a40912a7921e0101461a9c7d61919acd Mon Sep 17 00:00:00 2001 -From: HuangLiming -Date: Tue, 25 May 2021 03:08:33 -0400 -Subject: [PATCH] fix the occasional coredump when the lwip exits - -Signed-off-by: HuangLiming ---- - src/api/sockets.c | 37 +++++++++---------------------------- - 1 file changed, 9 insertions(+), 28 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index d62e55b..658f762 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -4655,36 +4655,17 @@ void lwip_sock_init(void) - return; - } - --//modify from lwip_close - void lwip_exit(void) - { -- int i, is_tcp; -- struct lwip_sock *sock; -- -- if (memp_pools[MEMP_SYS_MBOX] == NULL) { -- return; -- } -- -- for (i = 0; i < sockets_num; i++) { -- sock = &sockets[i]; -- if (!sock->conn) -- continue; --#if LWIP_IGMP -- /* drop all possibly joined IGMP memberships */ -- lwip_socket_drop_registered_memberships(i); --#endif /* LWIP_IGMP */ -- /* -- * process is exiting, call netconn_delete to -- * close tcp connection, and ignore the return value -- */ -- is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -- netconn_delete(sock->conn); -- free_socket(sock, is_tcp); -- } -- -- free(sockets); -- sockets = NULL; -- sockets_num = 0; -+ /* -+ * LwIP has the following two parts of memory application, but -+ * it is unnecessary to release all memory in sequentially, -+ * which increases complexity. Therefore, we rely on the process -+ * reclamation mechanism of the system to release memory. -+ * 1. a sockets table of the process. -+ * 2. a batch of hugepage memory of each thread. -+ */ -+ return; - } - - #endif /* USE_LIBOS */ --- -2.23.0 - diff --git a/0004-fix-error-of-deleting-conn-table-in-connect.patch b/0004-fix-error-of-deleting-conn-table-in-connect.patch deleted file mode 100644 index 3208182..0000000 --- a/0004-fix-error-of-deleting-conn-table-in-connect.patch +++ /dev/null @@ -1,79 +0,0 @@ -From ed999b65aac44fcb68fc533e8bd5a23cf2d09e7c Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Wed, 26 May 2021 19:09:41 +0800 -Subject: [PATCH] fix-error-of-deleting-conn-table-in-connect - ---- - src/include/lwip/priv/tcp_priv.h | 42 ++++++++++++++++++++++++++------ - 1 file changed, 34 insertions(+), 8 deletions(-) - -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index 192edc4..599289f 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -358,6 +358,28 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - - return vdev_reg_xmit(reg_type, &qtuple); - } -+ -+/* TCP_RMV pcb whether to call vdev_reg_xmit to reg conn-sock table. -+ fix the error of adding conn table in connect func and deleting conn table -+ when moving pcb from tcp_bound_pcbs to tcp_listen_pcbs */ -+static inline int need_vdev_reg(struct tcp_pcb *pcb_list, const struct tcp_pcb *pcb) -+{ -+ /* tw_pcbs_list and tcp_listen_pcbs will not change pcb to other list always reg */ -+ if ((pcb_list == tcp_tw_pcbs) || (pcb_list == tcp_listen_pcbs.pcbs)) { -+ return 1; -+ } -+ -+ /* tcp_active_pcbs in FIN_WAIT_1,FIN_WAIT_2,CLOSING state will change pcb to tw_pcbs_list don't reg. -+ detail info see func tcp_process in tcp_in.c */ -+ if (pcb_list == tcp_active_pcbs) { -+ if ((pcb->state != FIN_WAIT_1) && (pcb->state != FIN_WAIT_2) && (pcb->state != CLOSING)) { -+ return 1; -+ } -+ } -+ -+ /* tcp_bound_pcbs and others don't reg */ -+ return 0; -+} - #endif - - /* Axioms about the above lists: -@@ -392,10 +414,12 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - tcp_timer_needed(); \ - } while(0) - #define TCP_RMV(pcbs, npcb) do { \ -- if (pcb->state == LISTEN) \ -- vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -- else \ -- vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -+ if (need_vdev_reg(*pcbs, npcb)) { \ -+ if (npcb->state == LISTEN) \ -+ vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -+ else \ -+ vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb); \ -+ } \ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ -@@ -488,10 +512,12 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - - #define TCP_RMV(pcbs, npcb) \ - do { \ -- if (pcb->state == LISTEN) \ -- vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -- else \ -- vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -+ if (need_vdev_reg(*pcbs, npcb)) { \ -+ if (npcb->state == LISTEN) \ -+ vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -+ else \ -+ vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -+ } \ - if(*(pcbs) == (npcb)) { \ - (*(pcbs)) = (*pcbs)->next; \ - if (*pcbs) \ --- -2.23.0 - diff --git a/0005-syn-rcvd-state-reg-conn-into-conntable.patch b/0005-syn-rcvd-state-reg-conn-into-conntable.patch deleted file mode 100644 index 2634f11..0000000 --- a/0005-syn-rcvd-state-reg-conn-into-conntable.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 19c51d7baf7eeeae72525f6b716253557be2b31c Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Tue, 29 Jun 2021 14:12:25 +0800 -Subject: [PATCH] add-conn-check - ---- - src/core/tcp_in.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index c3d1f54..57186c7 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -752,6 +752,10 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - #endif - TCP_REG_ACTIVE(npcb); - -+#if USE_LIBOS -+ vdev_reg_done(REG_RING_TCP_CONNECT, npcb); -+#endif -+ - /* Parse any options in the SYN. */ - tcp_parseopt(npcb); - npcb->snd_wnd = tcphdr->wnd; --- -2.23.0 - diff --git a/0006-fix-coredump-in-etharp.patch b/0006-fix-coredump-in-etharp.patch deleted file mode 100644 index d361649..0000000 --- a/0006-fix-coredump-in-etharp.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a066306d783693d3f78b9c5e84feca7d690cf27a Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 2 Jul 2021 16:54:43 +0800 -Subject: [PATCH] fix coredump in etharp - ---- - src/core/ipv4/etharp.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c -index c3a5a10..effb7db 100644 ---- a/src/core/ipv4/etharp.c -+++ b/src/core/ipv4/etharp.c -@@ -102,10 +102,10 @@ struct etharp_entry { - u8_t state; - }; - --static struct etharp_entry arp_table[ARP_TABLE_SIZE]; -+static PER_THREAD struct etharp_entry arp_table[ARP_TABLE_SIZE]; - - #if !LWIP_NETIF_HWADDRHINT --static netif_addr_idx_t etharp_cached_entry; -+static PER_THREAD netif_addr_idx_t etharp_cached_entry; - #endif /* !LWIP_NETIF_HWADDRHINT */ - - /** Try hard to create a new entry - we want the IP address to appear in --- -2.23.0 - diff --git a/0007-gazelle-fix-epoll_ctl-EPOLLET-mode-error.patch b/0007-gazelle-fix-epoll_ctl-EPOLLET-mode-error.patch deleted file mode 100644 index 97b5d78..0000000 --- a/0007-gazelle-fix-epoll_ctl-EPOLLET-mode-error.patch +++ /dev/null @@ -1,102 +0,0 @@ -From b867f6901773def31884a9ae527a1282d274a85d Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Sat, 10 Jul 2021 22:27:19 +0800 -Subject: [PATCH] fix epoll_ctl EPOLLET mode error ---- - src/api/sockets.c | 33 +++++++++++++++++++++++---------- - 1 file changed, 23 insertions(+), 10 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 658f762..eccc7f9 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -714,6 +714,13 @@ free_socket(struct lwip_sock *sock, int is_tcp) - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - -+#if USE_LIBOS -+ sock->epoll = LIBOS_EPOLLNONE; -+ sock->events = 0; -+ sock->epoll_data = NULL; -+ list_del_node_null(&sock->list); -+#endif -+ - freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); - SYS_ARCH_UNPROTECT(lev); - /* don't use 'sock' after this line, as another task might have allocated it */ -@@ -1003,13 +1010,6 @@ lwip_close(int s) - return -1; - } - --#if USE_LIBOS -- sock->epoll = LIBOS_EPOLLNONE; -- sock->events = 0; -- sock->epoll_data = NULL; -- list_del_node_null(&sock->list); --#endif -- - free_socket(sock, is_tcp); - set_errno(0); - return 0; -@@ -1191,7 +1191,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - if (sock->lastdata.pbuf) { - p = sock->lastdata.pbuf; - #if USE_LIBOS -- if ((flags & MSG_PEEK) == 0) { -+ if (((flags & MSG_PEEK) == 0) && ((sock->epoll & EPOLLET) == 0)) { - if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { - del_epoll_event(sock->conn, EPOLLIN); - } -@@ -2889,6 +2889,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - check_waiters = 0; - } - #if USE_LIBOS -+ if (sock->epoll & EPOLLET) { -+ list_del_node_null(&sock->list); -+ } - add_epoll_event(conn, EPOLLIN); - #endif - break; -@@ -2896,7 +2899,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - sock->rcvevent--; - check_waiters = 0; - #if USE_LIBOS -- del_epoll_event(conn, EPOLLIN); -+ if ((sock->epoll & EPOLLET) == 0) { -+ del_epoll_event(conn, EPOLLIN); -+ } - #endif - break; - case NETCONN_EVT_SENDPLUS: -@@ -2905,6 +2910,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - } - sock->sendevent = 1; - #if USE_LIBOS -+ if (sock->epoll & EPOLLET) { -+ list_del_node_null(&sock->list); -+ } - add_epoll_event(conn, EPOLLOUT); - #endif - break; -@@ -2912,12 +2920,17 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - sock->sendevent = 0; - check_waiters = 0; - #if USE_LIBOS -- del_epoll_event(conn, EPOLLOUT); -+ if ((sock->epoll & EPOLLET) == 0) { -+ del_epoll_event(conn, EPOLLOUT); -+ } - #endif - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; - #if USE_LIBOS -+ if (sock->epoll & EPOLLET) { -+ list_del_node_null(&sock->list); -+ } - add_epoll_event(conn, EPOLLERR); - #endif - break; --- -2.23.0 - diff --git a/0008-gazelle-fix-lwip_accept-memcpy-sockaddr-large.patch b/0008-gazelle-fix-lwip_accept-memcpy-sockaddr-large.patch deleted file mode 100644 index 94eec7f..0000000 --- a/0008-gazelle-fix-lwip_accept-memcpy-sockaddr-large.patch +++ /dev/null @@ -1,25 +0,0 @@ -From bf1c7febb9f6c3a2336f18f658694393dea451ae Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 16 Jul 2021 14:44:03 +0800 -Subject: [PATCH] [Huawei]gazelle: fix lwip_accept memcpy sockaddr larger than - actual ---- - src/api/sockets.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index eccc7f9..e640945 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -860,6 +860,8 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; - } -+#else -+ *addrlen = LWIP_MIN(*addrlen, sizeof(tempaddr)); - #endif /* USE_LIBOS */ - MEMCPY(addr, &tempaddr, *addrlen); - --- -2.23.0 - diff --git a/0009-fix-stack-buffer-overflow-when-memcpy-addr.patch b/0009-fix-stack-buffer-overflow-when-memcpy-addr.patch deleted file mode 100644 index 38f97ee..0000000 --- a/0009-fix-stack-buffer-overflow-when-memcpy-addr.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d1f9ccd5da1712477f30bf2662e8888395ed95cd Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Wed, 21 Jul 2021 20:01:47 +0800 -Subject: [PATCH] fix stack-buffer-overflow in lwip_sock_make_addr and - lwip_getaddrname - ---- - src/api/sockets.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index e640945..7ce9378 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1319,6 +1319,8 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, - } else if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; - } -+#else -+ *fromlen = LWIP_MIN(*fromlen, sizeof(saddr)); - #endif - MEMCPY(from, &saddr, *fromlen); - return truncated; -@@ -3133,6 +3135,8 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) - if (*namelen > saddr.sa.sa_len) { - *namelen = saddr.sa.sa_len; - } -+#else -+ *namelen = LWIP_MIN(*namelen, sizeof(saddr)); - #endif - MEMCPY(name, &saddr, *namelen); - --- -2.23.0 - diff --git a/0010-fix-the-incomplete-release-of-the-conntable.patch b/0010-fix-the-incomplete-release-of-the-conntable.patch deleted file mode 100644 index 8c7c4f0..0000000 --- a/0010-fix-the-incomplete-release-of-the-conntable.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 70a1cdd2618f117c9f7da17b111a6c51db242f4b Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Tue, 3 Aug 2021 11:23:10 +0800 -Subject: [PATCH] fix-the-incomplete-release-of-the-conntable - ---- - src/core/tcp.c | 12 +++++++++++ - src/include/lwip/priv/tcp_priv.h | 37 ++++++-------------------------- - 2 files changed, 19 insertions(+), 30 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 0aafa9b..2cfbce2 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -235,6 +235,9 @@ tcp_init(void) - void - tcp_free(struct tcp_pcb *pcb) - { -+#if USE_LIBOS -+ vdev_unreg_done(pcb); -+#endif - LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN); - #if LWIP_TCP_PCB_NUM_EXT_ARGS - tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); -@@ -943,6 +946,11 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - #if LWIP_TCP_PCB_NUM_EXT_ARGS - /* copy over ext_args to listening pcb */ - memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args)); -+#endif -+#if USE_LIBOS -+ /* pcb transfer to lpcb and reg into tcp_listen_pcbs. freeing pcb shouldn't release sock table in here. -+ * local_port=0 avoid to release sock table in tcp_free */ -+ pcb->local_port = 0; - #endif - tcp_free(pcb); - #if LWIP_CALLBACK_API -@@ -2263,6 +2271,10 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - LWIP_ASSERT("tcp_pcb_remove: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_pcb_remove: invalid pcblist", pcblist != NULL); - -+#if USE_LIBOS -+ vdev_unreg_done(pcb); -+#endif -+ - TCP_RMV(pcblist, pcb); - - tcp_pcb_purge(pcb); -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index 599289f..f771725 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -358,27 +358,16 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - - return vdev_reg_xmit(reg_type, &qtuple); - } -- --/* TCP_RMV pcb whether to call vdev_reg_xmit to reg conn-sock table. -- fix the error of adding conn table in connect func and deleting conn table -- when moving pcb from tcp_bound_pcbs to tcp_listen_pcbs */ --static inline int need_vdev_reg(struct tcp_pcb *pcb_list, const struct tcp_pcb *pcb) -+static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - { -- /* tw_pcbs_list and tcp_listen_pcbs will not change pcb to other list always reg */ -- if ((pcb_list == tcp_tw_pcbs) || (pcb_list == tcp_listen_pcbs.pcbs)) { -- return 1; -+ if (pcb->local_port == 0) { -+ return; - } -- -- /* tcp_active_pcbs in FIN_WAIT_1,FIN_WAIT_2,CLOSING state will change pcb to tw_pcbs_list don't reg. -- detail info see func tcp_process in tcp_in.c */ -- if (pcb_list == tcp_active_pcbs) { -- if ((pcb->state != FIN_WAIT_1) && (pcb->state != FIN_WAIT_2) && (pcb->state != CLOSING)) { -- return 1; -- } -+ if (pcb->state == LISTEN) { -+ vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, pcb); -+ } else { -+ vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, pcb); - } -- -- /* tcp_bound_pcbs and others don't reg */ -- return 0; - } - #endif - -@@ -414,12 +403,6 @@ static inline int need_vdev_reg(struct tcp_pcb *pcb_list, const struct tcp_pcb * - tcp_timer_needed(); \ - } while(0) - #define TCP_RMV(pcbs, npcb) do { \ -- if (need_vdev_reg(*pcbs, npcb)) { \ -- if (npcb->state == LISTEN) \ -- vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -- else \ -- vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb); \ -- } \ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ -@@ -512,12 +495,6 @@ static inline int need_vdev_reg(struct tcp_pcb *pcb_list, const struct tcp_pcb * - - #define TCP_RMV(pcbs, npcb) \ - do { \ -- if (need_vdev_reg(*pcbs, npcb)) { \ -- if (npcb->state == LISTEN) \ -- vdev_reg_done(REG_RING_TCP_LISTEN_CLOSE, npcb); \ -- else \ -- vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, npcb);\ -- } \ - if(*(pcbs) == (npcb)) { \ - (*(pcbs)) = (*pcbs)->next; \ - if (*pcbs) \ --- -2.23.0 - diff --git a/0011-remove-gazelle-tcp-conn-func.patch b/0011-remove-gazelle-tcp-conn-func.patch deleted file mode 100644 index 08a3dd3..0000000 --- a/0011-remove-gazelle-tcp-conn-func.patch +++ /dev/null @@ -1,116 +0,0 @@ -From fdccb3a2c430c6270ff5272220cf471bf760fda7 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Sat, 21 Aug 2021 15:22:52 +0800 -Subject: [PATCH] del tcp_conn - ---- - src/core/tcp.c | 78 ------------------------------------------ - src/include/lwip/tcp.h | 3 -- - 2 files changed, 81 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 2cfbce2..0f3e830 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -2484,84 +2484,6 @@ tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t - return ERR_VAL; - } - --uint32_t tcp_get_conn_num(void) --{ -- struct tcp_pcb *pcb = NULL; -- struct tcp_pcb_listen *pcbl = NULL; -- uint32_t conn_num = 0; -- -- for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { -- conn_num++; -- } -- -- for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { -- conn_num++; -- } -- -- for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { -- conn_num++; -- } -- -- return conn_num; --} -- --void tcp_get_conn(char *buf, int32_t len, uint32_t *conn_num) --{ -- int tmp_len = 0; -- char *tmp_buf = buf; -- struct tcp_pcb_dp tdp; -- struct tcp_pcb *pcb = NULL; -- struct tcp_pcb_listen *pcbl = NULL; -- --#define COPY_TDP(b, l) \ -- do { \ -- if (l + sizeof(tdp) <= len) { \ -- memcpy(b, &tdp, sizeof(tdp)); \ -- b += sizeof(tdp); \ -- l += sizeof(tdp); \ -- *conn_num += 1; \ -- } else \ -- return; \ -- } while(0); -- -- *conn_num = 0; -- -- for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { -- tdp.state = ACTIVE_LIST; -- tdp.lip = pcb->local_ip.addr; -- tdp.rip = pcb->remote_ip.addr; -- tdp.l_port = pcb->local_port; -- tdp.r_port = pcb->remote_port; -- tdp.s_next = pcb->snd_queuelen; -- /* lwip not cache rcv buf. Set it to 0. */ -- tdp.r_next = 0; -- tdp.tcp_sub_state = pcb->state; -- COPY_TDP(tmp_buf, tmp_len); -- } -- -- for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { -- tdp.state = LISTEN_LIST; -- tdp.lip = pcbl->local_ip.addr; -- tdp.rip = pcbl->remote_ip.addr; -- tdp.l_port = pcbl->local_port; -- tdp.tcp_sub_state = pcbl->state; -- COPY_TDP(tmp_buf, tmp_len); -- } -- -- for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { -- tdp.state = TIME_WAIT_LIST; -- tdp.lip = pcb->local_ip.addr; -- tdp.rip = pcb->remote_ip.addr; -- tdp.l_port = pcb->local_port; -- tdp.r_port = pcb->remote_port; -- tdp.s_next = pcb->snd_queuelen; -- /* lwip not cache rcv buf. Set it to 0. */ -- tdp.r_next = 0; -- tdp.tcp_sub_state = pcb->state; -- COPY_TDP(tmp_buf, tmp_len); -- } --} -- - #if TCP_QUEUE_OOSEQ - /* Free all ooseq pbufs (and possibly reset SACK state) */ - void -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 4f86b46..b36bf33 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -570,9 +570,6 @@ struct tcp_pcb_dp { - uint32_t tcp_sub_state; - }; - --void tcp_get_conn(char *buf, int32_t len, uint32_t *conn_num); --uint32_t tcp_get_conn_num(void); -- - /* for compatibility with older implementation */ - #define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) - --- -2.23.0 - diff --git a/0012-fix-incomplete-resource-release-in-lwip-close.patch b/0012-fix-incomplete-resource-release-in-lwip-close.patch deleted file mode 100644 index 5ea8368..0000000 --- a/0012-fix-incomplete-resource-release-in-lwip-close.patch +++ /dev/null @@ -1,49 +0,0 @@ -From c5db70bef7f1ac6627b278fdf06be57bce0ef00b Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 19 Aug 2021 14:53:14 +0800 -Subject: [PATCH] fix event.data.ptr double free due to socket don't free in -lwip_close - ---- -src/api/sockets.c | 10 ++++++---- -1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 7ce9378..ac4cccb 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -963,18 +963,20 @@ lwip_close(int s) - struct lwip_sock *sock; - int is_tcp = 0; - err_t err; -+ int ret = 0; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); - - #if USE_LIBOS -- int ret; - if (posix_api->is_epfd(s)) { - return posix_api->epoll_close_fn(s); - } - -+ /* No matter what the result of close, lwip_sock resources should release -+ * to prevent the potential double freee problem caused by reporting events after the close */ - ret = posix_api->close_fn(s); -- if (ret < 0) -- return ret; -+ if ((ret < 0) && (errno == EINTR)) -+ ret = posix_api->close_fn(s); - if (posix_api->is_chld == 0) - clean_host_fd(s); - -@@ -1014,7 +1016,7 @@ lwip_close(int s) - - free_socket(sock, is_tcp); - set_errno(0); -- return 0; -+ return ret; - } - - int --- -2.23.0 diff --git a/0013-remove-gazelle-syscall-thread.patch b/0013-remove-gazelle-syscall-thread.patch deleted file mode 100644 index 64e0c0d..0000000 --- a/0013-remove-gazelle-syscall-thread.patch +++ /dev/null @@ -1,126 +0,0 @@ -From afd0d39d31196a74d6808120d1ca5664825d477c Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Mon, 6 Sep 2021 22:52:41 +0800 -Subject: [PATCH] aaa - ---- - src/api/sockets.c | 17 ----------------- - src/include/eventpoll.h | 1 - - src/include/lwipopts.h | 17 ----------------- - src/include/lwipsock.h | 5 ----- - 4 files changed, 40 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index ac4cccb..8719568 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -755,10 +755,6 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - sock = posix_api->get_socket(s); - /*AF_UNIX case*/ - if (!sock) { -- if (rearm_accept_fd(s) < 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, -- ("failed to rearm accept fd=%d errno=%d\n", s, errno)); -- } - return posix_api->accept_fn(s, addr, addrlen); - } - -@@ -769,11 +765,6 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - return -1; - } - -- if (rearm_accept_fd(s) < 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, -- ("failed to rearm accept fd=%d errno=%d\n", s, errno)); -- } -- - /* raise accept syscall in palce */ - newsock = posix_api->accept_fn(s, addr, addrlen); - if (newsock >= 0) { -@@ -977,8 +968,6 @@ lwip_close(int s) - ret = posix_api->close_fn(s); - if ((ret < 0) && (errno == EINTR)) - ret = posix_api->close_fn(s); -- if (posix_api->is_chld == 0) -- clean_host_fd(s); - - sock = posix_api->get_socket(s); - /*AF_UNIX case*/ -@@ -1481,9 +1470,6 @@ static inline enum KERNEL_LWIP_PATH select_path(int s) - sock = posix_api->get_socket(s); - /*AF_UNIX case*/ - if (!sock) { -- if (rearm_host_fd(s) < 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("failed to rearm fd=%d errno=%d\n", s, errno)); -- } - return PATH_KERNEL; - } - -@@ -1494,9 +1480,6 @@ static inline enum KERNEL_LWIP_PATH select_path(int s) - - /*for AF_INET, we can try erther linux or lwip*/ - if (CONN_TYPE_IS_HOST(sock->conn)) { -- if (rearm_host_fd(s) < 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("failed to rearm read fd=%d errno=%d\n", s, errno)); -- } - return PATH_KERNEL; - } - -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -index 01f8d64..f525bc2 100644 ---- a/src/include/eventpoll.h -+++ b/src/include/eventpoll.h -@@ -57,7 +57,6 @@ struct event_array { - - struct libos_epoll { - struct event_queue *libos_queue; -- struct event_array *host_queue; - int num_hostfds; - int hints; - int fd; /* self fd */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 8893a5f..e0364a2 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -177,23 +177,6 @@ - - #define ARP_TABLE_SIZE 512 - --/* -- --------------------------------------- -- ------- Syscall thread options -------- -- --------------------------------------- --*/ --#define USE_SYSCALL_THREAD 1 -- --#define MAX_BLOCKING_ACCEPT_FD (100) -- --#define MAX_BLOCKING_CONNECT_FD (100) -- --#define MAX_BLOCKING_EPOLL_FD (100) -- --#define MAX_SYSCALL_EVENTS (MAX_BLOCKING_ACCEPT_FD + MAX_BLOCKING_CONNECT_FD + MAX_BLOCKING_EPOLL_FD) -- --#define MAX_HOST_FD (MAX_CLIENTS + RESERVED_CLIENTS) -- - #if USE_LIBOS - #define PER_THREAD __thread - #else -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index dbc67b9..e9ffbb1 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -146,10 +146,5 @@ void lwip_sock_init(void); - void lwip_exit(void); - - extern int is_host_ipv4(uint32_t ipv4); --extern int rearm_host_fd(int fd); --extern int rearm_accept_fd(int fd); --extern void unarm_host_fd(int fd); --extern void clean_host_fd(int fd); --extern int arm_host_fd(struct libos_epoll *ep, int op, int fd, struct epoll_event *event); - - #endif /* __LWIPSOCK_H__ */ --- -2.23.0 - diff --git a/0014-fix-some-compile-errors.patch b/0014-fix-some-compile-errors.patch deleted file mode 100644 index 5be2bdf..0000000 --- a/0014-fix-some-compile-errors.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4970d00fecf52a472a28d55243f87142d3d08268 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 4 Jan 2022 17:23:03 +0800 -Subject: [PATCH] fix some compile errors - ---- - src/include/arch/cc.h | 4 ++-- - src/include/lwiplog.h | 2 +- - src/include/posix_api.h | 2 +- - 3 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/include/arch/cc.h b/src/include/arch/cc.h -index 33c24b4..222b0c9 100644 ---- a/src/include/arch/cc.h -+++ b/src/include/arch/cc.h -@@ -62,7 +62,7 @@ void alloc_memp_##name##_base(void) \ - memp_pools[MEMP_##name] = &memp_ ## name; \ - \ - char mpname[MEMZONE_NAMESIZE] = {0}; \ -- snprintf(mpname, MEMZONE_NAMESIZE, "%ld_%s", gettid(), #name); \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", gettid(), #name); \ - memp_memory_##name##_base = \ - sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(__size)); \ - memp_pools[MEMP_##name]->base = memp_memory_##name##_base; \ -@@ -73,7 +73,7 @@ PER_THREAD uint8_t *variable_name; \ - void alloc_memory_##variable_name(void) \ - { \ - char mpname[MEMZONE_NAMESIZE] = {0}; \ -- snprintf(mpname, MEMZONE_NAMESIZE, "%ld_%s", gettid(), #variable_name); \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", gettid(), #variable_name); \ - (variable_name) = \ - sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(size)); \ - } -diff --git a/src/include/lwiplog.h b/src/include/lwiplog.h -index 363e516..6fccac8 100644 ---- a/src/include/lwiplog.h -+++ b/src/include/lwiplog.h -@@ -40,7 +40,7 @@ - - #include "lwipopts.h" - --#define gettid() syscall(__NR_gettid) -+extern int gettid(void); - - #if USE_DPDK_LOG - -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index 8aa8516..0dca8eb 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -79,7 +79,7 @@ typedef struct { - int is_chld; - } posix_api_t; - --posix_api_t *posix_api; -+extern posix_api_t *posix_api; - - int posix_api_init(void); - void posix_api_free(void); --- -1.8.3.1 - diff --git a/0015-fix-tcp-port-alloc-issue.patch b/0015-fix-tcp-port-alloc-issue.patch deleted file mode 100644 index 4576af8..0000000 --- a/0015-fix-tcp-port-alloc-issue.patch +++ /dev/null @@ -1,36 +0,0 @@ -From bd0fdaf755544da1a276820a7cc3f664a2765194 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 18 Jan 2022 10:34:42 +0800 -Subject: [PATCH] fix tcp port alloc issue - ---- - src/core/tcp.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index a9a91fd..b65ab33 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -1062,6 +1062,7 @@ tcp_new_port(void) - { - u8_t i; - u16_t n = 0; -+ u16_t tmp_port; - struct tcp_pcb *pcb; - - pthread_mutex_lock(&g_tcp_port_mutex); -@@ -1082,9 +1083,10 @@ again: - } - } - } -+ tmp_port = tcp_port; - pthread_mutex_unlock(&g_tcp_port_mutex); - -- return tcp_port; -+ return tmp_port; - } - - /** --- -1.8.3.1 - diff --git a/0016-lstack-support-mysql-mode.patch b/0016-lstack-support-mysql-mode.patch deleted file mode 100644 index 0ac7fe1..0000000 --- a/0016-lstack-support-mysql-mode.patch +++ /dev/null @@ -1,943 +0,0 @@ -From 1f0f3742019e2fa62ba1669c5a880fb63a3fee12 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Thu, 24 Feb 2022 20:08:46 +0800 -Subject: [PATCH] lstack support mysql mode - ---- - src/api/api_msg.c | 26 +-- - src/api/posix_api.c | 5 +- - src/api/sockets.c | 350 ++----------------------------- - src/api/sys_arch.c | 12 +- - src/core/tcp_out.c | 13 ++ - src/include/eventpoll.h | 6 +- - src/include/lwip/priv/tcp_priv.h | 2 +- - src/include/lwip/sockets.h | 2 +- - src/include/lwipsock.h | 29 ++- - src/include/posix_api.h | 2 +- - src/include/reg_sock.h | 8 +- - 11 files changed, 85 insertions(+), 370 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index d5a738f..3072dd9 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -342,6 +342,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) - #endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); -+#if USE_LIBOS -+ if (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE || -+ conn->state == NETCONN_CONNECT) { -+ add_recv_list(conn->socket); -+ } -+#endif - } - - return ERR_OK; -@@ -457,14 +463,6 @@ err_tcp(void *arg, err_t err) - old_state = conn->state; - conn->state = NETCONN_NONE; - --#if USE_LIBOS -- if (CONN_TYPE_IS_HOST(conn)) { -- LWIP_DEBUGF(API_MSG_DEBUG, -- ("linux localhost connection already success, ignore lwip err_tcp fd=%d\n", conn->socket)); -- return; -- } --#endif /* USE_LIBOS */ -- - SYS_ARCH_UNPROTECT(lev); - - /* Notify the user layer about a connection error. Used to signal select. */ -@@ -479,6 +477,12 @@ err_tcp(void *arg, err_t err) - if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, mbox_msg); -+#if USE_LIBOS -+ if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || -+ (old_state == NETCONN_CONNECT)) { -+ add_recv_list(conn->socket); -+ } -+#endif - } - /* pass error message to acceptmbox to wake up pending accept */ - if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { -@@ -1344,11 +1348,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - int s = conn->socket; - struct lwip_sock *sock = get_socket_without_errno(s); - -- if (!!sock && !!sock->epoll_data) { -- struct epoll_event ee = {0}; -- ee.data.fd = s; -- ee.events |= EPOLLIN | EPOLLOUT | EPOLLERR; -- posix_api->epoll_ctl_fn(sock->epoll_data->fd, EPOLL_CTL_DEL, s, &ee); -+ if (!!sock) { - posix_api->shutdown_fn(s, SHUT_RDWR); - LWIP_DEBUGF(API_MSG_DEBUG, - ("linux outgoing connection abort fd=%d\n", s)); -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index a917cea..eff9f46 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -143,11 +143,10 @@ int posix_api_init(void) - - /* lstack helper api */ - posix_api->get_socket = get_socket; -- posix_api->is_epfd = lwip_is_epfd; -- posix_api->epoll_close_fn = lwip_epoll_close; -+ posix_api->epoll_close_fn = lstack_epoll_close; - - /* support fork */ -- posix_api->is_chld = 0; -+ posix_api->is_chld = 1; - return ERR_OK; - - err_out: -diff --git a/src/api/sockets.c b/src/api/sockets.c -index f44c34f..b032ce9 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -90,14 +90,6 @@ - #define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) - #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) - --#if USE_LIBOS --enum KERNEL_LWIP_PATH { -- PATH_KERNEL = 0, -- PATH_LWIP, -- PATH_ERR, --}; --#endif -- - #if LWIP_IPV4 - #if USE_LIBOS - #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ -@@ -604,8 +596,6 @@ alloc_socket(struct netconn *newconn, int accepted) - * (unless it has been created by accept()). */ - sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); - sockets[i].errevent = 0; -- sockets[i].epoll_data = NULL; -- init_list_node_null(&sockets[i].list); - return i + LWIP_SOCKET_OFFSET; - } - -@@ -714,13 +704,6 @@ free_socket(struct lwip_sock *sock, int is_tcp) - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - --#if USE_LIBOS -- sock->epoll = LIBOS_EPOLLNONE; -- sock->events = 0; -- sock->epoll_data = NULL; -- list_del_node_null(&sock->list); --#endif -- - freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); - SYS_ARCH_UNPROTECT(lev); - /* don't use 'sock' after this line, as another task might have allocated it */ -@@ -749,34 +732,11 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); --#if USE_LIBOS -- int sys_errno = 0; -- -- sock = posix_api->get_socket(s); -- /*AF_UNIX case*/ -- if (!sock) { -- return posix_api->accept_fn(s, addr, addrlen); -- } -- -- /*for AF_INET, we may try both linux and lwip*/ -- if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -- set_errno(EINVAL); -- return -1; -- } -- -- /* raise accept syscall in palce */ -- newsock = posix_api->accept_fn(s, addr, addrlen); -- if (newsock >= 0) { -- return newsock; -- } -- sys_errno = errno; --#else -+ - sock = get_socket(s); - if (!sock) { - return -1; - } --#endif - - /* wait for a new connection */ - err = netconn_accept(sock->conn, &newconn); -@@ -790,9 +750,6 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - sock_set_errno(sock, err_to_errno(err)); - } - done_socket(sock); --#if USE_LIBOS -- set_errno(sys_errno); --#endif /* USE_LIBOS */ - return -1; - } - LWIP_ASSERT("newconn != NULL", newconn != NULL); -@@ -875,24 +832,11 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) - ip_addr_t local_addr; - u16_t local_port; - err_t err; --#if USE_LIBOS -- sock = posix_api->get_socket(s); -- /*AF_UNIX case*/ -- if (!sock) { -- return posix_api->bind_fn(s, name, namelen); -- } -- /*for AF_INET, we may try both linux and lwip*/ -- if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -- set_errno(EINVAL); -- return -1; -- } --#else -+ - sock = get_socket(s); - if (!sock) { - return -1; - } --#endif - - if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ -@@ -912,18 +856,6 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) - ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); - --#if USE_LIBOS -- /* Supports kernel NIC IP address. */ -- int ret = posix_api->bind_fn(s, name, namelen); -- if (ret < 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("bind syscall failed\n")); -- /* bind must succeed on both linux and libos */ -- if (!is_host_ipv4(local_addr.addr)) { -- return ret; -- } -- } --#endif /* USE_LIBOS */ -- - #if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ - if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { -@@ -953,32 +885,13 @@ lwip_close(int s) - struct lwip_sock *sock; - int is_tcp = 0; - err_t err; -- int ret = 0; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); - --#if USE_LIBOS -- if (posix_api->is_epfd(s)) { -- return posix_api->epoll_close_fn(s); -- } -- -- /* No matter what the result of close, lwip_sock resources should release -- * to prevent the potential double freee problem caused by reporting events after the close */ -- ret = posix_api->close_fn(s); -- if ((ret < 0) && (errno == EINTR)) -- ret = posix_api->close_fn(s); -- -- sock = posix_api->get_socket(s); -- /*AF_UNIX case*/ -- if (!sock) { -- return ret; -- } --#else - sock = get_socket(s); - if (!sock) { - return -1; - } --#endif /* USE_LIBOS */ - - if (sock->conn != NULL) { - is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -@@ -1004,7 +917,7 @@ lwip_close(int s) - - free_socket(sock, is_tcp); - set_errno(0); -- return ret; -+ return 0; - } - - int -@@ -1013,28 +926,10 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) - struct lwip_sock *sock; - err_t err; - --#if USE_LIBOS -- int ret; -- -- sock = posix_api->get_socket(s); -- if (!sock) { -- return posix_api->connect_fn(s, name, namelen); -- } -- -- /* raise connect syscall in place */ -- ADD_CONN_TYPE_INPRG(sock->conn); -- ret = posix_api->connect_fn(s, name, namelen); -- if (!ret) { -- SET_CONN_TYPE_HOST(sock->conn); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("linux connect succeed fd=%d\n", s)); -- return ret; -- } --#else - sock = get_socket(s); - if (!sock) { - return -1; - } --#endif - - if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ -@@ -1106,29 +1001,10 @@ lwip_listen(int s, int backlog) - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); - --#if USE_LIBOS -- int ret; -- -- sock = posix_api->get_socket(s); -- /*AF_UNIX case*/ -- if (!sock) { -- return posix_api->listen_fn(s, backlog); -- } -- /*for AF_INET, we may try both linux and lwip*/ -- if (!CONN_TYPE_HAS_LIBOS_AND_HOST(sock->conn)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type has libos and host bits")); -- set_errno(EADDRINUSE); -- return -1; -- } -- -- if ((ret = posix_api->listen_fn(s, backlog)) == -1) -- return ret; --#else - sock = get_socket(s); - if (!sock) { - return -1; - } --#endif - - /* limit the "backlog" parameter to fit in an u8_t */ - backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); -@@ -1160,11 +1036,12 @@ static ssize_t - lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - { - u8_t apiflags = NETCONN_NOAUTORCVD; -+ ssize_t recvd = 0; - #if USE_LIBOS - apiflags = 0; --#endif -- ssize_t recvd = 0; -+#else - ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; -+#endif - - LWIP_ASSERT("no socket given", sock != NULL); - LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); -@@ -1173,6 +1050,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - apiflags |= NETCONN_DONTBLOCK; - } - -+#if !USE_LIBOS - do { - struct pbuf *p; - err_t err; -@@ -1182,13 +1060,6 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - /* Check if there is data left from the last recv operation. */ - if (sock->lastdata.pbuf) { - p = sock->lastdata.pbuf; --#if USE_LIBOS -- if (((flags & MSG_PEEK) == 0) && ((sock->epoll & EPOLLET) == 0)) { -- if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { -- del_epoll_event(sock->conn, EPOLLIN); -- } -- } --#endif - } else { - /* No data was left from the previous operation, so we try to get - some from the network. */ -@@ -1258,23 +1129,21 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; - /* @todo: do we need to support peeking more than one pbuf? */ - } while ((recv_left > 0) && !(flags & MSG_PEEK)); -+ - lwip_recv_tcp_done: --#if USE_LIBOS -- if (apiflags & NETCONN_NOAUTORCVD) --#endif -- { -+#else /* USE_LIBOS */ -+ recvd = read_lwip_data(sock, flags, apiflags); -+ if (recvd <= 0) { -+ return recvd; -+ } -+#endif /* USE_LIBOS */ -+ if (apiflags & NETCONN_NOAUTORCVD) { - if ((recvd > 0) && !(flags & MSG_PEEK)) { - /* ensure window update after copying all data */ - netconn_tcp_recvd(sock->conn, (size_t)recvd); - } - } --#if USE_LIBOS -- if ((flags & MSG_PEEK) == 0) { -- if (((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) && sock->lastdata.pbuf) { -- add_epoll_event(sock->conn, EPOLLIN); -- } -- } --#endif -+ - sock_set_errno(sock, 0); - return recvd; - } -@@ -1461,37 +1330,6 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - return ERR_OK; - } - --#if USE_LIBOS --static inline enum KERNEL_LWIP_PATH select_path(int s) --{ -- struct lwip_sock *sock; -- -- sock = posix_api->get_socket(s); -- /*AF_UNIX case*/ -- if (!sock) { -- return PATH_KERNEL; -- } -- -- if (CONN_TYPE_HAS_INPRG(sock->conn)) { -- set_errno(EWOULDBLOCK); -- return PATH_ERR; -- } -- -- /*for AF_INET, we can try erther linux or lwip*/ -- if (CONN_TYPE_IS_HOST(sock->conn)) { -- return PATH_KERNEL; -- } -- -- if (!CONN_TYPE_IS_LIBOS(sock->conn)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("conn->type is not libos bit type=%x", netconn_type(sock->conn))); -- set_errno(EINVAL); -- return PATH_ERR; -- } -- -- return PATH_LWIP; --} --#endif -- - ssize_t - lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -@@ -1499,15 +1337,6 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct lwip_sock *sock; - ssize_t ret; - --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->recv_from(s, mem, len, flags, from, fromlen); -- } --#endif -- - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); - sock = get_socket(s); - if (!sock) { -@@ -1557,14 +1386,6 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, - ssize_t - lwip_read(int s, void *mem, size_t len) - { --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->read_fn(s, mem, len); -- } --#endif - return lwip_recvfrom(s, mem, len, 0, NULL, NULL); - } - -@@ -1598,15 +1419,6 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) - int i; - ssize_t buflen; - --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->recv_msg(s, message, flags); -- } --#endif -- - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); - LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); - LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, -@@ -1751,15 +1563,6 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags) - #endif - err_t err = ERR_OK; - --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->send_msg(s, msg, flags); -- } --#endif -- - sock = get_socket(s); - if (!sock) { - return -1; -@@ -1923,15 +1726,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags, - u16_t remote_port; - struct netbuf buf; - --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->send_to(s, data, size, flags, to, tolen); -- } --#endif -- - sock = get_socket(s); - if (!sock) { - return -1; -@@ -2030,11 +1824,6 @@ lwip_socket(int domain, int type, int protocol) - - LWIP_UNUSED_ARG(domain); /* @todo: check this */ - --#if USE_LIBOS -- if ((domain != AF_INET && domain != AF_UNSPEC) || posix_api->is_chld) -- return posix_api->socket_fn(domain, type, protocol); --#endif -- - /* create a netconn */ - switch (type) { - case SOCK_RAW: -@@ -2091,14 +1880,6 @@ lwip_socket(int domain, int type, int protocol) - ssize_t - lwip_write(int s, const void *data, size_t size) - { --#if USE_LIBOS -- enum KERNEL_LWIP_PATH path = select_path(s); -- if (path == PATH_ERR) { -- return -1; -- } else if (path == PATH_KERNEL) { -- return posix_api->write_fn(s, data, size); -- } --#endif - return lwip_send(s, data, size, 0); - } - -@@ -2884,20 +2665,16 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - check_waiters = 0; - } - #if USE_LIBOS -- if (sock->epoll & EPOLLET) { -- list_del_node_null(&sock->list); -+ if (conn->state == NETCONN_LISTEN) { -+ add_epoll_event(conn, EPOLLIN); -+ } else { -+ add_recv_list(conn->socket); - } -- add_epoll_event(conn, EPOLLIN); - #endif - break; - case NETCONN_EVT_RCVMINUS: - sock->rcvevent--; - check_waiters = 0; --#if USE_LIBOS -- if ((sock->epoll & EPOLLET) == 0) { -- del_epoll_event(conn, EPOLLIN); -- } --#endif - break; - case NETCONN_EVT_SENDPLUS: - if (sock->sendevent) { -@@ -2905,27 +2682,16 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - } - sock->sendevent = 1; - #if USE_LIBOS -- if (sock->epoll & EPOLLET) { -- list_del_node_null(&sock->list); -- } - add_epoll_event(conn, EPOLLOUT); - #endif - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; - check_waiters = 0; --#if USE_LIBOS -- if ((sock->epoll & EPOLLET) == 0) { -- del_epoll_event(conn, EPOLLOUT); -- } --#endif - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; - #if USE_LIBOS -- if (sock->epoll & EPOLLET) { -- list_del_node_null(&sock->list); -- } - add_epoll_event(conn, EPOLLERR); - #endif - break; -@@ -3139,41 +2905,12 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) - int - lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) - { --#if USE_LIBOS -- struct lwip_sock *sock; -- -- sock = posix_api->get_socket(s); -- if (!sock) { -- return posix_api->getpeername_fn(s, name, namelen); -- } -- /*for AF_INET, if has only host type bit, just call linux api, -- *if has libos and host type bits, it's a not connected fd, call -- *linux api and return -1(errno == ENOTCONN) is also ok*/ -- if (CONN_TYPE_HAS_HOST(sock->conn)) { -- return posix_api->getpeername_fn(s, name, namelen); -- } --#endif -- - return lwip_getaddrname(s, name, namelen, 0); - } - - int - lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) - { --#if USE_LIBOS -- struct lwip_sock *sock; -- -- sock = posix_api->get_socket(s); -- if (!sock) { -- return posix_api->getsockname_fn(s, name, namelen); -- } -- /*for AF_INET, if has only host type bit, just call linux api, -- *if has libos and host type bits, also call linux api*/ -- if (CONN_TYPE_HAS_HOST(sock->conn)) { -- return posix_api->getsockname_fn(s, name, namelen); -- } --#endif -- - return lwip_getaddrname(s, name, namelen, 1); - } - -@@ -3186,23 +2923,11 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); - #endif /* !LWIP_TCPIP_CORE_LOCKING */ - --#if USE_LIBOS -- struct lwip_sock *sock = posix_api->get_socket(s); -- -- if (!sock) { -- return posix_api->getsockopt_fn(s, level, optname, optval, optlen); -- } -- /*for AF_INET, we return linux result? */ -- if (CONN_TYPE_HAS_HOST(sock->conn)) { -- return posix_api->getsockopt_fn(s, level, optname, optval, optlen); -- } --#else - struct lwip_sock *sock = get_socket(s); - - if (!sock) { - return -1; - } --#endif /* USE_LIBOS */ - - if ((NULL == optval) || (NULL == optlen)) { - sock_set_errno(sock, EFAULT); -@@ -3645,25 +3370,11 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); - #endif /* !LWIP_TCPIP_CORE_LOCKING */ - --#if USE_LIBOS -- struct lwip_sock *sock = posix_api->get_socket(s); -- -- if (!sock) { -- return posix_api->setsockopt_fn(s, level, optname, optval, optlen); -- } -- /*for AF_INET, we may try both linux and lwip*/ -- if (CONN_TYPE_HAS_HOST(sock->conn)) { -- if (posix_api->setsockopt_fn(s, level, optname, optval, optlen) < 0) { -- return -1; -- } -- } --#else - struct lwip_sock *sock = get_socket(s); - - if (!sock) { - return -1; - } --#endif /* USE_LIBOS */ - - if (NULL == optval) { - sock_set_errno(sock, EFAULT); -@@ -4308,26 +4019,6 @@ lwip_ioctl(int s, long cmd, void *argp) - * the flag O_NONBLOCK is implemented for F_SETFL. - */ - int --#if USE_LIBOS --lwip_fcntl(int s, int cmd, ...) --{ -- struct lwip_sock *sock = posix_api->get_socket(s); -- int val, ret = -1; -- int op_mode = 0; -- va_list ap; -- -- va_start(ap, cmd); -- val = va_arg(ap, int); -- va_end(ap); -- -- if (!sock) { -- return posix_api->fcntl_fn(s, cmd, val); -- } -- if (CONN_TYPE_HAS_HOST(sock->conn)) { -- if ((ret = posix_api->fcntl_fn(s, cmd, val)) == -1) -- return ret; -- } --#else /* USE_LIBOS */ - lwip_fcntl(int s, int cmd, int val) - { - struct lwip_sock *sock = get_socket(s); -@@ -4337,7 +4028,6 @@ lwip_fcntl(int s, int cmd, int val) - if (!sock) { - return -1; - } --#endif /* USE_LIBOS */ - - switch (cmd) { - case F_GETFL: -diff --git a/src/api/sys_arch.c b/src/api/sys_arch.c -index 55561b1..9a92143 100644 ---- a/src/api/sys_arch.c -+++ b/src/api/sys_arch.c -@@ -76,8 +76,8 @@ struct sys_mem_stats { - - static PER_THREAD struct sys_mem_stats hugepage_stats; - --static PER_THREAD uint64_t cycles_per_ms __attribute__((aligned(64))); --static PER_THREAD uint64_t sys_start_ms __attribute__((aligned(64))); -+static uint64_t cycles_per_ms __attribute__((aligned(64))); -+static uint64_t sys_start_ms __attribute__((aligned(64))); - - /* - * Mailbox -@@ -337,8 +337,12 @@ void sys_calibrate_tsc(void) - #define MS_PER_SEC 1E3 - uint64_t freq = rte_get_tsc_hz(); - -- cycles_per_ms = (freq + MS_PER_SEC - 1) / MS_PER_SEC; -- sys_start_ms = rte_rdtsc() / cycles_per_ms; -+ if (cycles_per_ms == 0) { -+ cycles_per_ms = (freq + MS_PER_SEC - 1) / MS_PER_SEC; -+ } -+ if (sys_start_ms == 0) { -+ sys_start_ms = rte_rdtsc() / cycles_per_ms; -+ } - } - - uint32_t sys_now(void) -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index dac498e..b99974d 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -472,6 +472,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - * pos records progress as data is segmented. - */ - -+#if !USE_LIBOS - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; -@@ -587,6 +588,13 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - pcb->unsent_oversize == 0); - #endif /* TCP_OVERSIZE */ - } -+#else /* USE_LIBOS */ -+ if (pcb->unsent != NULL) { -+ /* @todo: this could be sped up by keeping last_unsent in the pcb */ -+ for (last_unsent = pcb->unsent; last_unsent->next != NULL; -+ last_unsent = last_unsent->next); -+ } -+#endif /* USE_LIBOS */ - - /* - * Phase 3: Create new segments. -@@ -604,6 +612,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - u8_t chksum_swapped = 0; - #endif /* TCP_CHECKSUM_ON_COPY */ - -+#if !USE_LIBOS - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ -@@ -650,6 +659,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(p/*header*/, p2/*data*/); - } -+#else /* USE_LIBOS */ -+ p = (struct pbuf *)arg; -+ seglen = p->len; -+#endif /* USE_LIBOS */ - - queuelen += pbuf_clen(p); - -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -index f525bc2..aacc1d2 100644 ---- a/src/include/eventpoll.h -+++ b/src/include/eventpoll.h -@@ -63,9 +63,7 @@ struct libos_epoll { - int efd; /* eventfd */ - }; - --extern int add_epoll_event(struct netconn*, uint32_t); --extern int del_epoll_event(struct netconn*, uint32_t); --extern int lwip_epoll_close(int); --extern int lwip_is_epfd(int); -+extern void add_epoll_event(struct netconn*, uint32_t); -+extern int32_t lstack_epoll_close(int32_t); - - #endif /* __EVENTPOLL_H__ */ -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index f771725..83208bf 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -349,7 +349,7 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - { - LWIP_ASSERT("Invalid parameter", pcb != NULL); - -- struct libnet_quintuple qtuple; -+ struct gazelle_quintuple qtuple; - qtuple.protocol = 0; - qtuple.src_ip = pcb->local_ip.addr; - qtuple.src_port = lwip_htons(pcb->local_port); -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index 345e26c..4e7e671 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -647,7 +647,7 @@ int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); - - #if USE_LIBOS - int lwip_ioctl(int s, long cmd, ...); --int lwip_fcntl(int s, int cmd, ...); -+int lwip_fcntl(int s, int cmd, int val); - #else - int lwip_ioctl(int s, long cmd, void *argp); - int lwip_fcntl(int s, int cmd, int val); -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index e9ffbb1..069cdcb 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -60,6 +60,10 @@ union lwip_sock_lastdata { - struct pbuf *pbuf; - }; - -+#if USE_LIBOS -+struct protocol_stack; -+struct weakup_poll; -+#endif - /** Contains all internal pointers and states used for a socket */ - struct lwip_sock { - /** sockets currently are built on netconns, each socket has one netconn */ -@@ -88,14 +92,19 @@ struct lwip_sock { - #endif - - #if USE_LIBOS -- struct list_node list; -- /* registered events */ -- uint32_t epoll; -- /* available events */ -- uint32_t events; -+ uint32_t epoll_events; /* registered events */ -+ uint32_t events; /* available events */ -+ int32_t in_event; /* avoid recurring events */ - epoll_data_t ep_data; -- /* libos_epoll pointer in use */ -- struct libos_epoll *epoll_data; -+ struct weakup_poll *weakup; -+ struct protocol_stack *stack; -+ void *recv_ring; -+ struct pbuf *recv_lastdata; /* unread data in one pbuf */ -+ struct pbuf *send_lastdata; /* unread data in one pbuf */ -+ void *send_ring; -+ int32_t recv_flags; -+ int32_t nextfd; /* listenfd list */ -+ struct list_node recv_list; - #endif - }; - -@@ -138,6 +147,10 @@ get_socket_without_errno(int s) - - return sock; - } -+ -+extern void add_recv_list(int32_t fd); -+extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); -+extern void gazelle_clean_sock(int32_t fd); - #endif /* USE_LIBOS */ - - struct lwip_sock *get_socket(int s); -@@ -145,6 +158,4 @@ struct lwip_sock *get_socket_by_fd(int s); - void lwip_sock_init(void); - void lwip_exit(void); - --extern int is_host_ipv4(uint32_t ipv4); -- - #endif /* __LWIPSOCK_H__ */ -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index 0dca8eb..2afd266 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -34,7 +34,7 @@ - #define __POSIX_API_H__ - - #include --#include -+#include - #include - #include - -diff --git a/src/include/reg_sock.h b/src/include/reg_sock.h -index 76d4c48..76673da 100644 ---- a/src/include/reg_sock.h -+++ b/src/include/reg_sock.h -@@ -41,7 +41,7 @@ enum reg_ring_type { - RING_REG_MAX, - }; - --struct libnet_quintuple { -+struct gazelle_quintuple { - uint32_t protocol; - /* net byte order */ - uint16_t src_port; -@@ -54,9 +54,9 @@ struct reg_ring_msg { - enum reg_ring_type type; - - uint32_t tid; -- struct libnet_quintuple qtuple; -+ struct gazelle_quintuple qtuple; - }; - --extern int vdev_reg_xmit(enum reg_ring_type type, struct libnet_quintuple *qtuple); -+extern int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); - --#endif /* __REG_SOCK_H__ */ -\ No newline at end of file -+#endif /* __REG_SOCK_H__ */ --- -2.30.0 - diff --git a/0017-support-REUSEPOR-option.patch b/0017-support-REUSEPOR-option.patch deleted file mode 100644 index c6c8b0f..0000000 --- a/0017-support-REUSEPOR-option.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 670f888704c7bbb1121e63bc380ca34b83c43464 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Thu, 3 Mar 2022 17:06:03 +0800 -Subject: [PATCH] support REUSEPOR option fix rpc msg too much - fix recurring events - ---- - src/api/sockets.c | 4 ++++ - src/include/lwipsock.h | 10 ++++++++-- - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index b032ce9..4b682f3 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -3029,6 +3029,10 @@ lwip_sockopt_to_ipopt(int optname) - return SOF_KEEPALIVE; - case SO_REUSEADDR: - return SOF_REUSEADDR; -+#if USE_LIBOS -+ case SO_REUSEPORT: -+ return SO_REUSEPORT; -+#endif - default: - LWIP_ASSERT("Unknown socket option", 0); - return 0; -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 069cdcb..e2519ff 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -94,7 +94,8 @@ struct lwip_sock { - #if USE_LIBOS - uint32_t epoll_events; /* registered events */ - uint32_t events; /* available events */ -- int32_t in_event; /* avoid recurring events */ -+ volatile bool have_event; /* avoid recurring events */ -+ volatile bool have_rpc_send; /* avoid recurring rpc_send */ - epoll_data_t ep_data; - struct weakup_poll *weakup; - struct protocol_stack *stack; -@@ -103,8 +104,13 @@ struct lwip_sock { - struct pbuf *send_lastdata; /* unread data in one pbuf */ - void *send_ring; - int32_t recv_flags; -- int32_t nextfd; /* listenfd list */ -+ bool wait_close; -+ int32_t attach_fd; -+ struct lwip_sock *shadowed_sock; -+ struct list_node attach_list; -+ struct list_node listen_list; - struct list_node recv_list; -+ int32_t nextfd; /* listenfd list */ - #endif - }; - --- -1.8.3.1 - diff --git a/0018-exec-gazelle_init_sock-before-read-event.patch b/0018-exec-gazelle_init_sock-before-read-event.patch deleted file mode 100644 index 11d4db0..0000000 --- a/0018-exec-gazelle_init_sock-before-read-event.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 544bf45ec99c853ad5e9ec2607669df01b4e0572 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Mon, 7 Mar 2022 21:06:39 +0800 -Subject: [PATCH] exec gazelle_init_sock() before read event - ---- - src/api/sockets.c | 1 + - src/include/lwipsock.h | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 4b682f3..21de5d9 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -763,6 +763,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - } - #if USE_LIBOS - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < sockets_num + LWIP_SOCKET_OFFSET)); -+ gazelle_init_sock(newsock); - #else - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); - #endif /* USE_LIBOS */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index e2519ff..355bf47 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -157,6 +157,7 @@ get_socket_without_errno(int s) - extern void add_recv_list(int32_t fd); - extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); - extern void gazelle_clean_sock(int32_t fd); -+extern void gazelle_init_sock(int32_t fd); - #endif /* USE_LIBOS */ - - struct lwip_sock *get_socket(int s); --- -1.8.3.1 - diff --git a/0019-gazelle-reduce-copy-in-send.patch b/0019-gazelle-reduce-copy-in-send.patch deleted file mode 100644 index fffa8b7..0000000 --- a/0019-gazelle-reduce-copy-in-send.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 05bfdb54fc744d835c8b3b50b54d220fe7e87277 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Mon, 7 Mar 2022 21:10:06 +0800 -Subject: [PATCH] reduce copy in send - ---- - src/core/pbuf.c | 5 +++++ - src/include/lwip/pbuf.h | 3 +++ - 2 files changed, 8 insertions(+) - -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 27afc28..cd6b558 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -281,6 +281,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - } - - /* If pbuf is to be allocated in RAM, allocate memory for it. */ -+#if USE_LIBOS -+ /* alloc mbuf to reduce copy in sending */ -+ p = lwip_alloc_pbuf(layer, length, type); -+#else - p = (struct pbuf *)mem_malloc(alloc_len); - if (p == NULL) { - return NULL; -@@ -289,6 +293,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - length, length, type, 0); - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); -+#endif - break; - } - default: -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index e5daf96..3894574 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -272,6 +272,9 @@ void pbuf_free_ooseq(void); - /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ - #define pbuf_init() - -+#if USE_LIBOS -+struct pbuf *lwip_alloc_pbuf(pbuf_layer l, u16_t length, pbuf_type type); -+#endif - struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); - struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); - #if LWIP_SUPPORT_CUSTOM_PBUF --- -2.30.0 - diff --git a/0020-remove-chose_dlsym_handle-function-set-handle-to-RTL.patch b/0020-remove-chose_dlsym_handle-function-set-handle-to-RTL.patch deleted file mode 100644 index 54243bc..0000000 --- a/0020-remove-chose_dlsym_handle-function-set-handle-to-RTL.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 970d9d6fd15c433af20bbbd7418c5e9773d58471 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Mon, 7 Mar 2022 21:08:13 +0800 -Subject: [PATCH] remove chose_dlsym_handle function, set handle to RTLD_NEXT - ---- - src/api/posix_api.c | 33 +-------------------------------- - 1 file changed, 1 insertion(+), 32 deletions(-) - -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index eff9f46..bce07f5 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -64,33 +64,6 @@ void posix_api_fork(void) - posix_api->get_socket = chld_get_socket; - } - --static int chose_dlsym_handle(void *__restrict* khandle) --{ -- void *dlhandle; -- int (*gazelle_epoll_create)(int size); -- dlhandle = dlopen ("liblstack.so", RTLD_LAZY); -- if (dlhandle == NULL) { -- return ERR_IF; -- } -- -- gazelle_epoll_create = dlsym(dlhandle, "epoll_create"); -- if (gazelle_epoll_create == NULL) { -- return ERR_MEM; -- } -- -- dlclose(dlhandle); -- -- *khandle = RTLD_NEXT; -- if (dlsym(*khandle, "epoll_create") == gazelle_epoll_create) { -- RTE_LOG(ERR, EAL, "posix api use RTLD_DEFAULT\n"); -- *khandle = RTLD_DEFAULT; -- } else { -- RTE_LOG(ERR, EAL, "posix api use RTLD_NEXT\n"); -- } -- -- return ERR_OK; --} -- - int posix_api_init(void) - { - /* the symbol we use here won't be NULL, so we don't need dlerror() -@@ -102,11 +75,7 @@ int posix_api_init(void) - - posix_api = &posix_api_val; - -- void *__restrict handle; -- int ret = chose_dlsym_handle(&handle); -- if (ret != ERR_OK) { -- return ret; -- } -+ void *__restrict handle = RTLD_NEXT; - - /* glibc standard api */ - CHECK_DLSYM_RET_RETURN(posix_api->socket_fn = dlsym(handle, "socket")); --- -1.8.3.1 - diff --git a/0021-refactor-event-if-ring-is-full-the-node-is-added-to-.patch b/0021-refactor-event-if-ring-is-full-the-node-is-added-to-.patch deleted file mode 100644 index b5b5e29..0000000 --- a/0021-refactor-event-if-ring-is-full-the-node-is-added-to-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From b7faf0800631668d4d23cb497f1ceeb5948e4a41 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 15 Mar 2022 19:22:22 +0800 -Subject: [PATCH] refactor event, if ring is full, the node is added to list - ---- - src/include/lwipsock.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 355bf47..36bcaed 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -104,12 +104,16 @@ struct lwip_sock { - struct pbuf *send_lastdata; /* unread data in one pbuf */ - void *send_ring; - int32_t recv_flags; -+ int32_t send_flags; - bool wait_close; - int32_t attach_fd; - struct lwip_sock *shadowed_sock; - struct list_node attach_list; - struct list_node listen_list; - struct list_node recv_list; -+ struct list_node event_list; -+ struct list_node wakeup_list; -+ struct list_node send_list; - int32_t nextfd; /* listenfd list */ - #endif - }; --- -1.8.3.1 - diff --git a/0022-notify-app-that-sock-state-changes-to-CLOSE_WAIT.patch b/0022-notify-app-that-sock-state-changes-to-CLOSE_WAIT.patch deleted file mode 100644 index be4b0e7..0000000 --- a/0022-notify-app-that-sock-state-changes-to-CLOSE_WAIT.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 05159c41efdc2f07ddbe3520330faf2675baa3d6 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 15 Mar 2022 20:10:07 +0800 -Subject: [PATCH] notify app that sock changes to CLOSE_WAAIT - ---- - src/core/tcp_in.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 1652b86..0d3a2f1 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -58,6 +58,9 @@ - #if LWIP_ND6_TCP_REACHABILITY_HINTS - #include "lwip/nd6.h" - #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ -+#if USE_LIBOS -+#include "lwip/api.h" -+#endif - - #include - -@@ -1032,6 +1035,9 @@ tcp_process(struct tcp_pcb *pcb) - if (recv_flags & TF_GOT_FIN) { - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; -+#if USE_LIBOS -+ API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); -+#endif - } - } else { - /* incorrect ACK number, send RST */ -@@ -1050,6 +1056,9 @@ tcp_process(struct tcp_pcb *pcb) - if (recv_flags & TF_GOT_FIN) { /* passive close */ - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; -+#if USE_LIBOS -+ API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); -+#endif - } - break; - case FIN_WAIT_1: -@@ -1676,6 +1685,9 @@ tcp_receive(struct tcp_pcb *pcb) - recv_flags |= TF_GOT_FIN; - if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ - pcb->state = CLOSE_WAIT; -+#if USE_LIBOS -+ API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); -+#endif - } - } - --- -1.8.3.1 - diff --git a/0023-refactor-event-and-checksum-offload-support.patch b/0023-refactor-event-and-checksum-offload-support.patch deleted file mode 100644 index b092d04..0000000 --- a/0023-refactor-event-and-checksum-offload-support.patch +++ /dev/null @@ -1,698 +0,0 @@ -From 8dd0a15e60cfee7e7f1be1ea051d0e09031f8fdd Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 29 Mar 2022 21:33:17 +0800 -Subject: [PATCH] refactor event and add HW checksum offload - ---- - src/api/api_msg.c | 9 ++++ - src/api/posix_api.c | 2 + - src/api/sockets.c | 4 +- - src/core/ipv4/icmp.c | 13 +++++ - src/core/ipv4/ip4.c | 24 ++++++++- - src/core/ipv4/ip4_frag.c | 23 +++++++++ - src/core/pbuf.c | 9 +++- - src/core/tcp_in.c | 17 +++++++ - src/core/tcp_out.c | 72 +++++++++++++++++++++++++- - src/include/dpdk_cksum.h | 107 +++++++++++++++++++++++++++++++++++++++ - src/include/lwip/pbuf.h | 12 ++++- - src/include/lwipopts.h | 30 ++++++++--- - src/include/lwipsock.h | 18 +++---- - src/netif/ethernet.c | 8 +++ - 14 files changed, 322 insertions(+), 26 deletions(-) - create mode 100644 src/include/dpdk_cksum.h - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 3072dd9..672f022 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -57,6 +57,7 @@ - #if USE_LIBOS - #include "lwip/sockets.h" - #include "lwipsock.h" -+#include "posix_api.h" - #endif - - #include -@@ -1758,7 +1759,15 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) - } else { - write_more = 0; - } -+#if USE_LIBOS -+ /* vector->ptr is private arg sock */ -+ LWIP_UNUSED_ARG(dataptr); -+ write_more = 0; -+ err = tcp_write(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags); -+ conn->current_msg->msg.w.len = len; -+#else - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); -+#endif - if (err == ERR_OK) { - conn->current_msg->msg.w.offset += len; - conn->current_msg->msg.w.vector_off += len; -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index bce07f5..3f85bad 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -42,6 +42,7 @@ - - #include "lwip/err.h" - #include "lwipsock.h" -+#include "posix_api.h" - - posix_api_t *posix_api; - posix_api_t posix_api_val; -@@ -64,6 +65,7 @@ void posix_api_fork(void) - posix_api->get_socket = chld_get_socket; - } - -+ - int posix_api_init(void) - { - /* the symbol we use here won't be NULL, so we don't need dlerror() -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 21de5d9..3d94454 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -65,6 +65,7 @@ - #if USE_LIBOS - #include - #include "lwipsock.h" -+#include "posix_api.h" - #endif - - #include -@@ -2682,9 +2683,6 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - check_waiters = 0; - } - sock->sendevent = 1; --#if USE_LIBOS -- add_epoll_event(conn, EPOLLOUT); --#endif - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; -diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c -index 59b493a..c58ae25 100644 ---- a/src/core/ipv4/icmp.c -+++ b/src/core/ipv4/icmp.c -@@ -51,6 +51,10 @@ - - #include - -+#if USE_LIBOS && CHECKSUM_GEN_IP_HW -+#include "dpdk_cksum.h" -+#endif -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -236,7 +240,16 @@ icmp_input(struct pbuf *p, struct netif *inp) - IPH_CHKSUM_SET(iphdr, 0); - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { -+#if CHECKSUM_GEN_IP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ iph_cksum_set(p, hlen, 1); -+ } else { -+ iph_cksum_set(p, hlen, 0); -+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); -+ } -+#else - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); -+#endif - } - #endif /* CHECKSUM_GEN_IP */ - -diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c -index c83afbe..1334cdc 100644 ---- a/src/core/ipv4/ip4.c -+++ b/src/core/ipv4/ip4.c -@@ -59,6 +59,10 @@ - - #include - -+#if USE_LIBOS && (CHECKSUM_CHECK_IP_HW || CHECKSUM_GEN_IP_HW) -+#include "dpdk_cksum.h" -+#endif -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -503,8 +507,17 @@ ip4_input(struct pbuf *p, struct netif *inp) - /* verify checksum */ - #if CHECKSUM_CHECK_IP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) { -+#if CHECKSUM_CHECK_IP_HW -+ u64_t ret; -+ if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_IPV4_CKSUM) { -+ ret = is_cksum_ipbad(p); -+ } else { -+ ret = (u64_t)inet_chksum(iphdr, iphdr_hlen); -+ } -+ if (ret != 0) { -+#else - if (inet_chksum(iphdr, iphdr_hlen) != 0) { -- -+#endif - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); - ip4_debug_print(p); -@@ -972,7 +985,16 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d - IPH_CHKSUM_SET(iphdr, 0); - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { -+#if CHECKSUM_GEN_IP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ iph_cksum_set(p, ip_hlen, 1); -+ } else { -+ iph_cksum_set(p, ip_hlen, 0); -+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); -+ } -+#else - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); -+#endif - } - #endif /* CHECKSUM_GEN_IP */ - #endif /* CHECKSUM_GEN_IP_INLINE */ -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index a445530..17a4ccd 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -51,6 +51,10 @@ - - #include - -+#if USE_LIBOS && CHECKSUM_GEN_IP_HW -+#include "dpdk_cksum.h" -+#endif -+ - #if IP_REASSEMBLY - /** - * The IP reassembly code currently has the following limitations: -@@ -632,8 +636,17 @@ ip4_reass(struct pbuf *p) - /* @todo: do we need to set/calculate the correct checksum? */ - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { -+#if CHECKSUM_GEN_IP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ iph_cksum_set(p, IP_HLEN, 1); -+ } else { -+ iph_cksum_set(p, IP_HLEN, 0); - IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); - } -+#else -+ IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); -+#endif -+ } - #endif /* CHECKSUM_GEN_IP */ - - p = ipr->p; -@@ -862,8 +875,18 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) - IPH_CHKSUM_SET(iphdr, 0); - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { -+#if CHECKSUM_GEN_IP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ iph_cksum_set(p, IP_HLEN, 1); -+ } else { -+ iph_cksum_set(p, IP_HLEN, 0); - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); - } -+ -+#else -+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); -+#endif -+ } - #endif /* CHECKSUM_GEN_IP */ - - /* No need for separate header pbuf - we allowed room for it in rambuf -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index cd6b558..247681d 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -282,7 +282,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - - /* If pbuf is to be allocated in RAM, allocate memory for it. */ - #if USE_LIBOS -- /* alloc mbuf to reduce copy in sending */ -+ /* alloc mbuf avoid send copy */ - p = lwip_alloc_pbuf(layer, length, type); - #else - p = (struct pbuf *)mem_malloc(alloc_len); -@@ -1019,6 +1019,13 @@ pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_ - /* current p_from does not fit into current p_to */ - len_calc = p_to->len - offset_to; - } -+ -+#if USE_LIBOS && (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW) -+ p_to->l2_len = p_from->l2_len; -+ p_to->l3_len = p_from->l3_len; -+ p_to->ol_flags = p_from->ol_flags; -+#endif -+ - len = (u16_t)LWIP_MIN(copy_len, len_calc); - MEMCPY((u8_t *)p_to->payload + offset_to, (u8_t *)p_from->payload + offset_from, len); - offset_to += len; -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 0d3a2f1..b1bbe00 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -64,6 +64,10 @@ - - #include - -+#if USE_LIBOS && CHECKSUM_CHECK_TCP_HW -+#include -+#endif /* CHECKSUM_CHECK_TCP_HW */ -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -172,11 +176,24 @@ tcp_input(struct pbuf *p, struct netif *inp) - #if CHECKSUM_CHECK_TCP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { - /* Verify TCP checksum. */ -+#if CHECKSUM_CHECK_TCP_HW -+ u64_t ret; -+ if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_TCP_CKSUM) { -+ ret = is_cksum_tcpbad(p); -+ } else { -+ ret = (u64_t)ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, -+ ip_current_src_addr(), ip_current_dest_addr()); -+ -+ } -+ if (ret != 0) { -+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum\n")); -+#else - u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - ip_current_src_addr(), ip_current_dest_addr()); - if (chksum != 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - chksum)); -+#endif - tcp_debug_print(tcphdr); - TCP_STATS_INC(tcp.chkerr); - goto dropped; -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index b99974d..1b0af8d 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -80,6 +80,13 @@ - - #include - -+#if USE_LIBOS -+#include "lwipsock.h" -+#if CHECKSUM_GEN_TCP_HW -+#include "dpdk_cksum.h" -+#endif -+#endif -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -660,8 +667,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - pbuf_cat(p/*header*/, p2/*data*/); - } - #else /* USE_LIBOS */ -- p = (struct pbuf *)arg; -- seglen = p->len; -+ p = write_lwip_data((struct lwip_sock *)arg, len - pos, &apiflags); -+ if (p == NULL) { -+ break; -+ } -+ seglen = p->tot_len; - #endif /* USE_LIBOS */ - - queuelen += pbuf_clen(p); -@@ -789,8 +799,13 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - /* - * Finally update the pcb state. - */ -+#if USE_LIBOS -+ pcb->snd_lbb += pos; -+ pcb->snd_buf -= pos; -+#else - pcb->snd_lbb += len; - pcb->snd_buf -= len; -+#endif - pcb->snd_queuelen = queuelen; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", -@@ -1584,6 +1599,11 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - - #if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { -+#if CHECKSUM_GEN_TCP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -+ tcph_cksum_set(seg->p, TCP_HLEN); -+ seg->tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP,seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -+ } else { - #if TCP_CHECKSUM_ON_COPY - u32_t acc; - #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK -@@ -1618,6 +1638,44 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, - seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); - #endif /* TCP_CHECKSUM_ON_COPY */ -+ -+ } -+#else -+#if TCP_CHECKSUM_ON_COPY -+ u32_t acc; -+#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK -+ u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, -+ seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -+#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ -+ if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { -+ LWIP_ASSERT("data included but not checksummed", -+ seg->p->tot_len == TCPH_HDRLEN_BYTES(seg->tcphdr)); -+ } -+ -+ /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ -+ acc = ip_chksum_pseudo_partial(seg->p, IP_PROTO_TCP, -+ seg->p->tot_len, TCPH_HDRLEN_BYTES(seg->tcphdr), &pcb->local_ip, &pcb->remote_ip); -+ /* add payload checksum */ -+ if (seg->chksum_swapped) { -+ seg_chksum_was_swapped = 1; -+ seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); -+ seg->chksum_swapped = 0; -+ } -+ acc = (u16_t)~acc + seg->chksum; -+ seg->tcphdr->chksum = (u16_t)~FOLD_U32T(acc); -+#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK -+ if (chksum_slow != seg->tcphdr->chksum) { -+ TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL( -+ ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", -+ seg->tcphdr->chksum, chksum_slow)); -+ seg->tcphdr->chksum = chksum_slow; -+ } -+#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ -+#else /* TCP_CHECKSUM_ON_COPY */ -+ seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, -+ seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -+#endif /* TCP_CHECKSUM_ON_COPY */ -+#endif /* CHECKSUM_GEN_TCP_HW */ - } - #endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); -@@ -1959,8 +2017,18 @@ tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, - #if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; -+#if CHECKSUM_GEN_TCP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -+ tcph_cksum_set(p, TCP_HLEN); -+ tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP, p->tot_len, src, dst); -+ } else { -+ tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, -+ src, dst); -+ } -+#else - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - src, dst); -+#endif - } - #endif - if (pcb != NULL) { -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -new file mode 100644 -index 0000000..e57be4d ---- /dev/null -+++ b/src/include/dpdk_cksum.h -@@ -0,0 +1,107 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __DPDK_CKSUM_H__ -+#define __DPDK_CKSUM_H__ -+ -+#include "lwipopts.h" -+#if USE_LIBOS -+#include -+ -+#if CHECKSUM_OFFLOAD_ALL -+#include -+#include "lwip/pbuf.h" -+#endif -+ -+extern uint64_t get_eth_params_rx_ol(void); -+extern uint64_t get_eth_params_tx_ol(void); -+#if CHECKSUM_CHECK_IP_HW -+// for ip4_input -+static inline u64_t is_cksum_ipbad(struct pbuf *p) { -+ return p->ol_flags & (RTE_MBUF_F_RX_IP_CKSUM_BAD); -+} -+#endif /* CHECKSUM_CHECK_IP_HW */ -+ -+#if CHECKSUM_CHECK_TCP_HW -+// for tcp_input -+static inline u64_t is_cksum_tcpbad(struct pbuf *p) { -+ return p->ol_flags & (RTE_MBUF_F_RX_L4_CKSUM_BAD); -+} -+#endif /* CHECKSUM_CHECK_TCP_HW */ -+ -+#if CHECKSUM_GEN_IP_HW -+static inline void ethh_cksum_set(struct pbuf *p, u16_t len) { -+ p->l2_len = len; -+} -+ -+// replaces IPH_CHKSUM_SET -+static inline void iph_cksum_set(struct pbuf *p, u16_t len, bool do_ipcksum) { -+ p->ol_flags |= RTE_MBUF_F_TX_IPV4; -+ if (do_ipcksum) { -+ p->ol_flags |= RTE_MBUF_F_TX_IP_CKSUM; -+ } -+ p->l3_len = len; -+} -+#endif /* CHECKSUM_GEN_IP_HW */ -+ -+// replace ip_chksum_pseudo -+#if CHECKSUM_GEN_TCP_HW -+#include -+ -+static inline void tcph_cksum_set(struct pbuf *p, u16_t len) { -+ (void)len; -+ p->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; -+} -+ -+static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, -+ const ip_addr_t *src, const ip_addr_t *dst) -+{ -+ struct ipv4_psd_header { -+ uint32_t src_addr; /* IP address of source host. */ -+ uint32_t dst_addr; /* IP address of destination host. */ -+ uint8_t zero; /* zero. */ -+ uint8_t proto; /* L4 protocol type. */ -+ uint16_t len; /* L4 length. */ -+ } psd_hdr; -+ -+ psd_hdr.src_addr = ip4_addr_get_u32(src); -+ psd_hdr.dst_addr = ip4_addr_get_u32(dst); -+ psd_hdr.proto = proto; -+ psd_hdr.len = lwip_htons(proto_len); -+ psd_hdr.zero = 0; -+ -+ return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); -+} -+#endif /* CHECKSUM_GEN_TCP_HW */ -+ -+#endif /* USE_LIBOS */ -+#endif /* __DPDK_CKSUM_H__ */ -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 3894574..87cd960 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -220,6 +220,15 @@ struct pbuf { - /** For incoming packets, this contains the input netif's index */ - u8_t if_idx; - -+#if USE_LIBOS && CHECKSUM_OFFLOAD_ALL -+ /** checksum offload ol_flags */ -+ u64_t ol_flags; -+ /** checksum offload l2_len */ -+ u64_t l2_len:7; -+ /** checksum offload l3_len */ -+ u64_t l3_len:9; -+#endif /* USE_LIBOS CHECKSUM_OFFLOAD_SWITCH */ -+ - /** In case the user needs to store data custom data on a pbuf */ - LWIP_PBUF_CUSTOM_DATA - }; -@@ -271,9 +280,8 @@ void pbuf_free_ooseq(void); - - /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ - #define pbuf_init() -- - #if USE_LIBOS --struct pbuf *lwip_alloc_pbuf(pbuf_layer l, u16_t length, pbuf_type type); -+struct pbuf *lwip_alloc_pbuf(pbuf_layer layer, uint16_t length, pbuf_type type); - #endif - struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); - struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index e0364a2..df587c0 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -129,14 +129,6 @@ - - #define LWIP_STATS_DISPLAY 1 - --#define CHECKSUM_GEN_IP 1 /* master switch */ -- --#define CHECKSUM_GEN_TCP 1 /* master switch */ -- --#define CHECKSUM_CHECK_IP 1 /* master switch */ -- --#define CHECKSUM_CHECK_TCP 1 /* master switch */ -- - #define LWIP_TIMEVAL_PRIVATE 0 - - #define USE_LIBOS 1 -@@ -177,6 +169,28 @@ - - #define ARP_TABLE_SIZE 512 - -+/* --------------------------------------- -+ * ------- NIC offloads -------- -+ * --------------------------------------- -+ */ -+#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 /* checksum ability check before checksum*/ -+ -+// rx cksum -+#define CHECKSUM_CHECK_IP 1 /* master switch */ -+#define CHECKSUM_CHECK_TCP 1 /* master switch */ -+// tx cksum -+#define CHECKSUM_GEN_IP 1 /* master switch */ -+#define CHECKSUM_GEN_TCP 1 /* master switch */ -+ -+// rx offload cksum -+#define CHECKSUM_CHECK_IP_HW (1 && CHECKSUM_CHECK_IP) /* hardware switch */ -+#define CHECKSUM_CHECK_TCP_HW (1 && CHECKSUM_CHECK_TCP) /* hardware switch */ -+// tx offload cksum -+#define CHECKSUM_GEN_IP_HW (1 && CHECKSUM_GEN_IP) /* hardware switch */ -+#define CHECKSUM_GEN_TCP_HW (1 && CHECKSUM_GEN_TCP) /* hardware switch */ -+ -+#define CHECKSUM_OFFLOAD_ALL (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW || CHECKSUM_CHECK_IP_HW || CHECKSUM_CHECK_TCP_HW) -+ - #if USE_LIBOS - #define PER_THREAD __thread - #else -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 36bcaed..eec4e8e 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -36,7 +36,6 @@ - #include "lwip/opt.h" - #include "lwip/api.h" - --#include "posix_api.h" - #include "eventpoll.h" - - /* move some definitions to the lwipsock.h for libnet to use, and -@@ -62,7 +61,8 @@ union lwip_sock_lastdata { - - #if USE_LIBOS - struct protocol_stack; --struct weakup_poll; -+struct wakeup_poll; -+struct rte_ring; - #endif - /** Contains all internal pointers and states used for a socket */ - struct lwip_sock { -@@ -93,16 +93,16 @@ struct lwip_sock { - - #if USE_LIBOS - uint32_t epoll_events; /* registered events */ -- uint32_t events; /* available events */ -- volatile bool have_event; /* avoid recurring events */ -- volatile bool have_rpc_send; /* avoid recurring rpc_send */ -+ volatile uint32_t events; /* available events */ - epoll_data_t ep_data; -- struct weakup_poll *weakup; -+ struct wakeup_poll *wakeup; - struct protocol_stack *stack; -- void *recv_ring; -+ struct rte_ring *recv_ring; -+ struct rte_ring *recv_wait_free; - struct pbuf *recv_lastdata; /* unread data in one pbuf */ - struct pbuf *send_lastdata; /* unread data in one pbuf */ -- void *send_ring; -+ struct rte_ring *send_ring; -+ struct rte_ring *send_idle_ring; - int32_t recv_flags; - int32_t send_flags; - bool wait_close; -@@ -112,7 +112,6 @@ struct lwip_sock { - struct list_node listen_list; - struct list_node recv_list; - struct list_node event_list; -- struct list_node wakeup_list; - struct list_node send_list; - int32_t nextfd; /* listenfd list */ - #endif -@@ -160,6 +159,7 @@ get_socket_without_errno(int s) - - extern void add_recv_list(int32_t fd); - extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); -+extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); - extern void gazelle_clean_sock(int32_t fd); - extern void gazelle_init_sock(int32_t fd); - #endif /* USE_LIBOS */ -diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c -index dd171e2..ab976a8 100644 ---- a/src/netif/ethernet.c -+++ b/src/netif/ethernet.c -@@ -56,6 +56,10 @@ - #include "netif/ppp/pppoe.h" - #endif /* PPPOE_SUPPORT */ - -+#if USE_LIBOS && (CHECKSUM_GEN_TCP_HW || CHECKSUM_GEN_IP_HW) -+#include "dpdk_cksum.h" -+#endif -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -308,6 +312,10 @@ ethernet_output(struct netif * netif, struct pbuf * p, - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, - ("ethernet_output: sending packet %p\n", (void *)p)); - -+#if CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW -+ ethh_cksum_set(p, sizeof(*ethhdr)); -+#endif -+ - /* send the packet */ - return netif->linkoutput(netif, p); - --- -2.23.0 diff --git a/0024-refactor-pkt-read-send-performance.patch b/0024-refactor-pkt-read-send-performance.patch deleted file mode 100644 index 529738a..0000000 --- a/0024-refactor-pkt-read-send-performance.patch +++ /dev/null @@ -1,320 +0,0 @@ -From 10e21843fc3fde51cb99510792835a65c9b5baad Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 7 Jul 2022 20:00:14 +0800 -Subject: [PATCH] refactor pkt read/send - ---- - src/api/api_msg.c | 15 ++++++--------- - src/api/posix_api.c | 4 ++-- - src/api/sockets.c | 11 +++-------- - src/api/sys_arch.c | 11 +++++------ - src/include/arch/sys_arch.h | 46 +++++++++++++++++++++++++++++++++++++++++++++ - src/include/lwipopts.h | 2 +- - src/include/lwipsock.h | 29 +++++++++++----------------- - src/include/posix_api.h | 2 +- - 8 files changed, 75 insertions(+), 45 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 672f022..7839526 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -341,13 +341,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) - #if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ -- /* Register event with callback */ -- API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - #if USE_LIBOS -- if (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE || -- conn->state == NETCONN_CONNECT) { - add_recv_list(conn->socket); -- } -+ LWIP_UNUSED_ARG(len); -+#else -+ /* Register event with callback */ -+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - #endif - } - -@@ -479,10 +478,7 @@ err_tcp(void *arg, err_t err) - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, mbox_msg); - #if USE_LIBOS -- if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || -- (old_state == NETCONN_CONNECT)) { -- add_recv_list(conn->socket); -- } -+ add_recv_list(conn->socket); - #endif - } - /* pass error message to acceptmbox to wake up pending accept */ -@@ -1356,6 +1352,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - } - } - SET_CONN_TYPE_LIBOS(conn); -+ add_epoll_event(conn, EPOLLOUT); - #endif - - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index 3f85bad..6afb9c6 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -60,7 +60,7 @@ static struct lwip_sock *chld_get_socket(int fd) - void posix_api_fork(void) - { - /* lstack helper api */ -- posix_api->is_chld = 1; -+ posix_api->ues_posix = 1; - posix_api->is_epfd = chld_is_epfd; - posix_api->get_socket = chld_get_socket; - } -@@ -117,7 +117,7 @@ int posix_api_init(void) - posix_api->epoll_close_fn = lstack_epoll_close; - - /* support fork */ -- posix_api->is_chld = 1; -+ posix_api->ues_posix = 1; - return ERR_OK; - - err_out: -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 3d94454..4d4cea1 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1039,11 +1039,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - { - u8_t apiflags = NETCONN_NOAUTORCVD; - ssize_t recvd = 0; --#if USE_LIBOS -- apiflags = 0; --#else - ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; --#endif - - LWIP_ASSERT("no socket given", sock != NULL); - LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); -@@ -1134,6 +1130,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - - lwip_recv_tcp_done: - #else /* USE_LIBOS */ -+ LWIP_UNUSED_ARG(recv_left); - recvd = read_lwip_data(sock, flags, apiflags); - if (recvd <= 0) { - return recvd; -@@ -2667,10 +2664,8 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - check_waiters = 0; - } - #if USE_LIBOS -- if (conn->state == NETCONN_LISTEN) { -- add_epoll_event(conn, EPOLLIN); -- } else { -- add_recv_list(conn->socket); -+ if (conn->acceptmbox != NULL && !sys_mbox_empty(conn->acceptmbox)) { -+ add_epoll_event(conn, POLLIN); - } - #endif - break; -diff --git a/src/api/sys_arch.c b/src/api/sys_arch.c -index 9a92143..f93a00e 100644 ---- a/src/api/sys_arch.c -+++ b/src/api/sys_arch.c -@@ -37,7 +37,6 @@ - #include - - #include --#include - - #include "lwip/err.h" - #include "lwip/mem.h" -@@ -134,7 +133,7 @@ err_t sys_mbox_trypost(struct sys_mbox **mb, void *msg) - unsigned int n; - struct sys_mbox *mbox = *mb; - -- n = rte_ring_sp_enqueue_bulk(mbox->ring, &msg, 1, NULL); -+ n = gazelle_st_ring_enqueue_busrt(mbox->ring, &msg, 1); - if (!n) - return ERR_BUF; - return ERR_OK; -@@ -148,7 +147,7 @@ void sys_mbox_post(struct sys_mbox **mb, void *msg) - * If the ring size of mbox is greater than MEMP_NUM_TCPIP_MSG_API, - * enqueue failure will never happen. - * */ -- if (!rte_ring_sp_enqueue_bulk(mbox->ring, &msg, 1, NULL)) { -+ if (!gazelle_st_ring_enqueue_busrt(mbox->ring, &msg, 1)) { - LWIP_ASSERT("It is failed to post msg into mbox", 0); - } - } -@@ -163,7 +162,7 @@ uint32_t sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg) - unsigned int n; - struct sys_mbox *mbox = *mb; - -- n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ n = gazelle_st_ring_dequeue_burst(mbox->ring, msg, 1); - if (!n) { - *msg = NULL; - return SYS_MBOX_EMPTY; -@@ -179,7 +178,7 @@ uint32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, uint32_t timeout) - uint32_t time_needed = 0; - struct sys_mbox *mbox = *mb; - -- n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ n = gazelle_st_ring_dequeue_burst(mbox->ring, msg, 1); - - if (timeout > 0) - poll_ts = sys_now(); -@@ -194,7 +193,7 @@ uint32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, uint32_t timeout) - - (void)mbox->wait_fn(); - -- n = rte_ring_sc_dequeue_bulk(mbox->ring, msg, 1, NULL); -+ n = gazelle_st_ring_dequeue_burst(mbox->ring, msg, 1); - } - - return time_needed; -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -index b8a0d28..fc4a9fd 100644 ---- a/src/include/arch/sys_arch.h -+++ b/src/include/arch/sys_arch.h -@@ -76,7 +76,53 @@ int sys_mbox_empty(struct sys_mbox *); - struct sys_thread; - typedef struct sys_thread *sys_thread_t; - -+#if USE_LIBOS - extern int eth_dev_poll(void); -+#include -+ -+/* -+ gazelle custom rte ring interface -+ lightweight ring no atomic. -+ only surpport in single thread. -+ */ -+static __rte_always_inline uint32_t gazelle_st_ring_enqueue_busrt(struct rte_ring *r, void **obj_table, uint32_t n) -+{ -+ uint32_t prod = r->prod.tail; -+ uint32_t cons = r->cons.tail; -+ uint32_t free_entries = r->capacity + cons - prod; -+ -+ if (n > free_entries) { -+ return 0; -+ } -+ -+ __rte_ring_enqueue_elems(r, prod, obj_table, sizeof(void *), n); -+ -+ r->prod.tail = prod + n; -+ -+ return n; -+} -+ -+static __rte_always_inline uint32_t gazelle_st_ring_dequeue_burst(struct rte_ring *r, void **obj_table, uint32_t n) -+{ -+ uint32_t cons = r->cons.tail; -+ uint32_t prod = r->prod.tail; -+ uint32_t entries = prod - cons; -+ -+ if (n > entries) { -+ n = entries; -+ } -+ -+ if (n == 0) { -+ return 0; -+ } -+ -+ __rte_ring_dequeue_elems(r, cons, obj_table, sizeof(void *), n); -+ -+ r->cons.tail = cons + n; -+ -+ return n; -+} -+#endif - - void sys_calibrate_tsc(void); - uint32_t sys_now(void); -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index df587c0..75d3c74 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -97,7 +97,7 @@ - - #define TCP_WND (40 * TCP_MSS) - --#define TCP_SND_BUF (5 * TCP_MSS) -+#define TCP_SND_BUF (40 * TCP_MSS) - - #define TCP_SND_QUEUELEN (8191) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index eec4e8e..500292d 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -63,6 +63,7 @@ union lwip_sock_lastdata { - struct protocol_stack; - struct wakeup_poll; - struct rte_ring; -+#include - #endif - /** Contains all internal pointers and states used for a socket */ - struct lwip_sock { -@@ -92,28 +93,21 @@ struct lwip_sock { - #endif - - #if USE_LIBOS -+ volatile uint32_t events __rte_cache_aligned; /* available events */ -+ struct pbuf *recv_lastdata __rte_cache_aligned; /* unread data in one pbuf */ -+ struct list_node recv_list __rte_cache_aligned; -+ struct list_node event_list __rte_cache_aligned; -+ struct list_node send_list __rte_cache_aligned; -+ char pad __rte_cache_aligned; -+ - uint32_t epoll_events; /* registered events */ -- volatile uint32_t events; /* available events */ -- epoll_data_t ep_data; - struct wakeup_poll *wakeup; -+ epoll_data_t ep_data; -+ bool wait_close; -+ struct lwip_sock *listen_next; /* listenfd list */ - struct protocol_stack *stack; - struct rte_ring *recv_ring; -- struct rte_ring *recv_wait_free; -- struct pbuf *recv_lastdata; /* unread data in one pbuf */ -- struct pbuf *send_lastdata; /* unread data in one pbuf */ - struct rte_ring *send_ring; -- struct rte_ring *send_idle_ring; -- int32_t recv_flags; -- int32_t send_flags; -- bool wait_close; -- int32_t attach_fd; -- struct lwip_sock *shadowed_sock; -- struct list_node attach_list; -- struct list_node listen_list; -- struct list_node recv_list; -- struct list_node event_list; -- struct list_node send_list; -- int32_t nextfd; /* listenfd list */ - #endif - }; - -@@ -160,7 +154,6 @@ get_socket_without_errno(int s) - extern void add_recv_list(int32_t fd); - extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); - extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); --extern void gazelle_clean_sock(int32_t fd); - extern void gazelle_init_sock(int32_t fd); - #endif /* USE_LIBOS */ - -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index 2afd266..c8f2cf9 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -76,7 +76,7 @@ typedef struct { - int (*poll_fn)(struct pollfd *fds, nfds_t nfds, int timeout); - int (*ioctl_fn)(int fd, int cmd, ...); - -- int is_chld; -+ int ues_posix; - } posix_api_t; - - extern posix_api_t *posix_api; --- -2.8.4.windows.1 - diff --git a/0025-Replace-gettid-with-syscall-SYS_gettid.patch b/0025-Replace-gettid-with-syscall-SYS_gettid.patch deleted file mode 100644 index 92abd14..0000000 --- a/0025-Replace-gettid-with-syscall-SYS_gettid.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 35300925c26ce9eba9f4f1c9a4181708da771392 Mon Sep 17 00:00:00 2001 -From: Honggang LI -Date: Tue, 12 Jul 2022 10:15:36 +0800 -Subject: [PATCH] Replace gettid() with syscall(SYS_gettid) - -Remove gettid() to address a backport issue for gazelle library. - -Signed-off-by: Honggang LI ---- - src/include/arch/cc.h | 4 ++-- - src/include/lwiplog.h | 3 +-- - 2 files changed, 3 insertions(+), 4 deletions(-) - -diff --git a/src/include/arch/cc.h b/src/include/arch/cc.h -index 222b0c9..aa18573 100644 ---- a/src/include/arch/cc.h -+++ b/src/include/arch/cc.h -@@ -62,7 +62,7 @@ void alloc_memp_##name##_base(void) \ - memp_pools[MEMP_##name] = &memp_ ## name; \ - \ - char mpname[MEMZONE_NAMESIZE] = {0}; \ -- snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", gettid(), #name); \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", (int)syscall(SYS_gettid), #name); \ - memp_memory_##name##_base = \ - sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(__size)); \ - memp_pools[MEMP_##name]->base = memp_memory_##name##_base; \ -@@ -73,7 +73,7 @@ PER_THREAD uint8_t *variable_name; \ - void alloc_memory_##variable_name(void) \ - { \ - char mpname[MEMZONE_NAMESIZE] = {0}; \ -- snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", gettid(), #variable_name); \ -+ snprintf(mpname, MEMZONE_NAMESIZE, "%d_%s", (int)syscall(SYS_gettid), #variable_name); \ - (variable_name) = \ - sys_hugepage_malloc(mpname, LWIP_MEM_ALIGN_BUFFER(size)); \ - } -diff --git a/src/include/lwiplog.h b/src/include/lwiplog.h -index 6fccac8..011ed21 100644 ---- a/src/include/lwiplog.h -+++ b/src/include/lwiplog.h -@@ -35,13 +35,12 @@ - - #include - #include -+#include - - #include - - #include "lwipopts.h" - --extern int gettid(void); -- - #if USE_DPDK_LOG - - #define LWIP_LOG_WARN LWIP_DBG_LEVEL_WARNING --- -2.31.1 - diff --git a/0026-del-redundant-wait_close-and-move-epoll_events-pos.patch b/0026-del-redundant-wait_close-and-move-epoll_events-pos.patch deleted file mode 100644 index cee127b..0000000 --- a/0026-del-redundant-wait_close-and-move-epoll_events-pos.patch +++ /dev/null @@ -1,30 +0,0 @@ -From ab62f970793c257c712c357a6976b9aca2e63b98 Mon Sep 17 00:00:00 2001 -From: wu-changsheng -Date: Tue, 26 Jul 2022 17:36:29 +0800 -Subject: [PATCH] del redundant wait_close and move epoll_events pos - ---- - src/include/lwipsock.h | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 500292d..16e0dd3 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -98,12 +98,11 @@ struct lwip_sock { - struct list_node recv_list __rte_cache_aligned; - struct list_node event_list __rte_cache_aligned; - struct list_node send_list __rte_cache_aligned; -+ uint32_t epoll_events; /* registered events, EPOLLONESHOT write frequently */ - char pad __rte_cache_aligned; - -- uint32_t epoll_events; /* registered events */ - struct wakeup_poll *wakeup; - epoll_data_t ep_data; -- bool wait_close; - struct lwip_sock *listen_next; /* listenfd list */ - struct protocol_stack *stack; - struct rte_ring *recv_ring; --- -2.23.0 - diff --git a/0027-modify-EISCONN-condition.patch b/0027-modify-EISCONN-condition.patch deleted file mode 100644 index 2693e91..0000000 --- a/0027-modify-EISCONN-condition.patch +++ /dev/null @@ -1,39 +0,0 @@ -From b8c388a7adef4dc53d3bb135102da64bf8a08b76 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 15:57:33 +0800 -Subject: [PATCH] modify-EISCONN-condition - ---- - src/api/api_msg.c | 2 +- - src/include/lwipsock.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 7839526..2dded75 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -1417,7 +1417,7 @@ lwip_netconn_do_connect(void *m) - /* Prevent connect while doing any other action. */ - if (msg->conn->state == NETCONN_CONNECT) { - err = ERR_ALREADY; -- } else if (msg->conn->state != NETCONN_NONE) { -+ } else if (msg->conn->pcb.tcp->state != ESTABLISHED) { - err = ERR_ISCONN; - } else { - setup_tcp(msg->conn); -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 16e0dd3..3c5c44b 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -98,6 +98,8 @@ struct lwip_sock { - struct list_node recv_list __rte_cache_aligned; - struct list_node event_list __rte_cache_aligned; - struct list_node send_list __rte_cache_aligned; -+ uint32_t in_send __rte_cache_aligned; /* avoid sock too much send rpc msg*/ -+ uint32_t send_flag __rte_cache_aligned; /* avoid sock too much send rpc msg*/ - uint32_t epoll_events; /* registered events, EPOLLONESHOT write frequently */ - char pad __rte_cache_aligned; - --- -2.27.0 - diff --git a/0028-per-thread-reassdata-variables.patch b/0028-per-thread-reassdata-variables.patch deleted file mode 100644 index 28eff78..0000000 --- a/0028-per-thread-reassdata-variables.patch +++ /dev/null @@ -1,30 +0,0 @@ -From a554661e9dd189f2d4b5dee8970fd009db89d9aa Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 17:33:16 +0800 -Subject: [PATCH] per thread reassdata variables - ---- - src/core/ipv4/ip4_frag.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index 17a4ccd..c60523d 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -115,8 +115,13 @@ PACK_STRUCT_END - IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 - - /* global variables */ -+#if USE_LIBOS -+static PER_THREAD struct ip_reassdata *reassdatagrams; -+static PER_THREAD u16_t ip_reass_pbufcount; -+#else - static struct ip_reassdata *reassdatagrams; - static u16_t ip_reass_pbufcount; -+#endif - - /* function prototypes */ - static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); --- -2.27.0 - diff --git a/0029-fix-EISCONN-err-and-remove-same-customized-modificat.patch b/0029-fix-EISCONN-err-and-remove-same-customized-modificat.patch deleted file mode 100644 index 91ac15e..0000000 --- a/0029-fix-EISCONN-err-and-remove-same-customized-modificat.patch +++ /dev/null @@ -1,114 +0,0 @@ -From ec2f5414c6c98b63376e4bce9534abc5c01ce13c Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 18:47:06 +0800 -Subject: [PATCH] fix EISCONN err and remove same customized modification - ---- - src/api/api_msg.c | 22 ++-------------------- - src/include/lwipsock.h | 33 ++++----------------------------- - 2 files changed, 6 insertions(+), 49 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 2dded75..1fedaad 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -1334,25 +1334,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - } - - #if USE_LIBOS -- if (CONN_TYPE_IS_HOST(conn)) { -- LWIP_DEBUGF(API_MSG_DEBUG, -- ("libos outgoing connection abort fd=%d\n", conn->socket)); -- return ERR_ABRT; -- } -- -- LWIP_DEBUGF(API_MSG_DEBUG, ("libos outgoing connection established\n")); -- if (CONN_TYPE_HAS_INPRG(conn) && CONN_TYPE_HAS_HOST(conn)) { -- int s = conn->socket; -- struct lwip_sock *sock = get_socket_without_errno(s); -- -- if (!!sock) { -- posix_api->shutdown_fn(s, SHUT_RDWR); -- LWIP_DEBUGF(API_MSG_DEBUG, -- ("linux outgoing connection abort fd=%d\n", s)); -- } -- } -- SET_CONN_TYPE_LIBOS(conn); -- add_epoll_event(conn, EPOLLOUT); -+ gazelle_connected_callback(conn); - #endif - - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); -@@ -1417,7 +1399,7 @@ lwip_netconn_do_connect(void *m) - /* Prevent connect while doing any other action. */ - if (msg->conn->state == NETCONN_CONNECT) { - err = ERR_ALREADY; -- } else if (msg->conn->pcb.tcp->state != ESTABLISHED) { -+ } else if (msg->conn->pcb.tcp->state == ESTABLISHED) { - err = ERR_ISCONN; - } else { - setup_tcp(msg->conn); -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 3c5c44b..912d471 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -93,13 +93,14 @@ struct lwip_sock { - #endif - - #if USE_LIBOS -+ struct pbuf *send_lastdata; -+ uint16_t send_datalen; - volatile uint32_t events __rte_cache_aligned; /* available events */ - struct pbuf *recv_lastdata __rte_cache_aligned; /* unread data in one pbuf */ - struct list_node recv_list __rte_cache_aligned; - struct list_node event_list __rte_cache_aligned; - struct list_node send_list __rte_cache_aligned; - uint32_t in_send __rte_cache_aligned; /* avoid sock too much send rpc msg*/ -- uint32_t send_flag __rte_cache_aligned; /* avoid sock too much send rpc msg*/ - uint32_t epoll_events; /* registered events, EPOLLONESHOT write frequently */ - char pad __rte_cache_aligned; - -@@ -124,38 +125,12 @@ struct lwip_sock { - #if USE_LIBOS - extern uint32_t sockets_num; - extern struct lwip_sock *sockets; --/** -- * Map a externally used socket index to the internal socket representation. -- * -- * @param s externally used socket index -- * @return struct lwip_sock for the socket or NULL if not found -- */ --static inline struct lwip_sock * --get_socket_without_errno(int s) --{ -- struct lwip_sock *sock = NULL; -- -- s -= LWIP_SOCKET_OFFSET; -- -- if ((s < 0) || (s >= sockets_num)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET)); -- return NULL; -- } -- -- sock = &sockets[s]; -- -- if (!sock->conn) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET)); -- return NULL; -- } -- -- return sock; --} -- -+extern void gazelle_connected_callback(struct netconn *conn); - extern void add_recv_list(int32_t fd); - extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); - extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); - extern void gazelle_init_sock(int32_t fd); -+extern void write_lwip_over(struct lwip_sock *sock, uint32_t n); - #endif /* USE_LIBOS */ - - struct lwip_sock *get_socket(int s); --- -2.27.0 - diff --git a/0030-refactor-tcp-new-port.patch b/0030-refactor-tcp-new-port.patch deleted file mode 100644 index 8d59fbc..0000000 --- a/0030-refactor-tcp-new-port.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 68c1fe8794077eab032b542094608338947f3d4f Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 19:27:41 +0800 -Subject: [PATCH] fix tcp new port - ---- - src/core/tcp.c | 87 +++++++++++++++++++++++++++++------------- - src/include/reg_sock.h | 1 + - 2 files changed, 61 insertions(+), 27 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index b65ab33..436ef85 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -202,13 +202,26 @@ PER_THREAD u8_t tcp_active_pcbs_changed; - /** Timer counter to handle calling slow-timer from tcp_tmr() */ - static PER_THREAD u8_t tcp_timer; - static PER_THREAD u8_t tcp_timer_ctr; -+#if USE_LIBOS -+static u16_t tcp_new_port(struct tcp_pcb *pcb); -+#else - static u16_t tcp_new_port(void); -+#endif - - static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); - #if LWIP_TCP_PCB_NUM_EXT_ARGS - static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); - #endif - -+#if USE_LIBOS -+static u8_t port_state[TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START + 1] = {0}; -+void release_port(u16_t port) -+{ -+ if (port >= TCP_LOCAL_PORT_RANGE_START && port <= TCP_LOCAL_PORT_RANGE_END) { -+ port_state[port - TCP_LOCAL_PORT_RANGE_START] = 0; -+ } -+} -+#endif - /** - * Initialize this module. - */ -@@ -237,6 +250,7 @@ tcp_free(struct tcp_pcb *pcb) - { - #if USE_LIBOS - vdev_unreg_done(pcb); -+ release_port(pcb->local_port); - #endif - LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN); - #if LWIP_TCP_PCB_NUM_EXT_ARGS -@@ -746,7 +760,11 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - if (port == 0) { -+#if USE_LIBOS -+ port = tcp_new_port(pcb); -+#else - port = tcp_new_port(); -+#endif - if (port == 0) { - return ERR_BUF; - } -@@ -1057,33 +1075,43 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) - * - * @return a new (free) local TCP port number - */ -+#if USE_LIBOS -+static u16_t -+tcp_new_port(struct tcp_pcb *pcb) -+#else - static u16_t - tcp_new_port(void) -+#endif - { -- u8_t i; - u16_t n = 0; -- u16_t tmp_port; -- struct tcp_pcb *pcb; -+ u16_t tmp_port = 0; - - pthread_mutex_lock(&g_tcp_port_mutex); --again: -- tcp_port++; -- if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { -- tcp_port = TCP_LOCAL_PORT_RANGE_START; -- } -- /* Check all PCB lists. */ -- for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { -- for (pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { -- if (pcb->local_port == tcp_port) { -- n++; -- if (n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { -- return 0; -+ do { -+ tcp_port++; -+ if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { -+ tcp_port = TCP_LOCAL_PORT_RANGE_START; -+ } -+ -+ if (__atomic_load_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { -+#if USE_LIBOS -+ if (port_in_stack_queue(pcb->remote_ip.addr, pcb->local_ip.addr, pcb->remote_port, tcp_port)) { -+ tmp_port = tcp_port; -+ __atomic_store_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); -+ break; - } -- goto again; -+#else -+ __atomic_store_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); -+ break; -+#endif - } -- } -- } -- tmp_port = tcp_port; -+ -+ n++; -+ if (n > TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START) { -+ break; -+ } -+ } while (tmp_port == 0); -+ - pthread_mutex_unlock(&g_tcp_port_mutex); - - return tmp_port; -@@ -1169,7 +1197,11 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - - old_local_port = pcb->local_port; - if (pcb->local_port == 0) { -+#if USE_LIBOS -+ pcb->local_port = tcp_new_port(pcb); -+#else - pcb->local_port = tcp_new_port(); -+#endif - if (pcb->local_port == 0) { - return ERR_BUF; - } -@@ -1196,10 +1228,6 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - #endif /* SO_REUSE */ - } - --#if USE_LIBOS -- vdev_reg_done(REG_RING_TCP_CONNECT, pcb); --#endif -- - iss = tcp_next_iss(pcb); - pcb->rcv_nxt = 0; - pcb->snd_nxt = iss; -@@ -1227,6 +1255,10 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - /* Send a SYN together with the MSS option. */ - ret = tcp_enqueue_flags(pcb, TCP_SYN); - if (ret == ERR_OK) { -+#if USE_LIBOS -+ vdev_reg_done(REG_RING_TCP_CONNECT, pcb); -+#endif -+ - /* SYN segment was enqueued, changed the pcbs state now */ - pcb->state = SYN_SENT; - if (old_local_port != 0) { -@@ -2277,10 +2309,6 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - LWIP_ASSERT("tcp_pcb_remove: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_pcb_remove: invalid pcblist", pcblist != NULL); - --#if USE_LIBOS -- vdev_unreg_done(pcb); --#endif -- - TCP_RMV(pcblist, pcb); - - tcp_pcb_purge(pcb); -@@ -2301,6 +2329,11 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - #endif /* TCP_QUEUE_OOSEQ */ - } - -+#if USE_LIBOS -+ vdev_unreg_done(pcb); -+ release_port(pcb->local_port); -+#endif -+ - pcb->state = CLOSED; - /* reset the local port to prevent the pcb from being 'bound' */ - pcb->local_port = 0; -diff --git a/src/include/reg_sock.h b/src/include/reg_sock.h -index 76673da..e349e85 100644 ---- a/src/include/reg_sock.h -+++ b/src/include/reg_sock.h -@@ -58,5 +58,6 @@ struct reg_ring_msg { - }; - - extern int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); -+extern bool port_in_stack_queue(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); - - #endif /* __REG_SOCK_H__ */ --- -2.27.0 - diff --git a/0031-refactor-add-event-limit-send-pkts-num.patch b/0031-refactor-add-event-limit-send-pkts-num.patch deleted file mode 100644 index 63ba303..0000000 --- a/0031-refactor-add-event-limit-send-pkts-num.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 87166f699e0febd36b81d914713b770119ead471 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 20:16:06 +0800 -Subject: [PATCH] refactor add event, limit send pkts num - ---- - src/api/sockets.c | 4 ++-- - src/core/tcp_out.c | 8 ++++++++ - src/include/eventpoll.h | 3 ++- - 3 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 4d4cea1..d5b69eb 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2665,7 +2665,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - } - #if USE_LIBOS - if (conn->acceptmbox != NULL && !sys_mbox_empty(conn->acceptmbox)) { -- add_epoll_event(conn, POLLIN); -+ add_sock_event(sock, POLLIN); - } - #endif - break; -@@ -2686,7 +2686,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - case NETCONN_EVT_ERROR: - sock->errevent = 1; - #if USE_LIBOS -- add_epoll_event(conn, EPOLLERR); -+ add_sock_event(sock, EPOLLERR); - #endif - break; - default: -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 1b0af8d..dd780d3 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1358,8 +1358,16 @@ tcp_output(struct tcp_pcb *pcb) - for (; useg->next != NULL; useg = useg->next); - } - /* data available and window allows it to be sent? */ -+#if USE_LIBOS -+ /* avoid send cose too much time, limit send pkts num max 10 */ -+ uint16_t send_pkt = 0; -+ while (seg != NULL && send_pkt < 10 && -+ lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { -+ send_pkt++; -+#else - while (seg != NULL && - lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { -+#endif - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); - /* Stop sending if the nagle algorithm would prevent it -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -index aacc1d2..a10c84b 100644 ---- a/src/include/eventpoll.h -+++ b/src/include/eventpoll.h -@@ -63,7 +63,8 @@ struct libos_epoll { - int efd; /* eventfd */ - }; - --extern void add_epoll_event(struct netconn*, uint32_t); -+struct lwip_sock; -+extern void add_sock_event(struct lwip_sock *sock, uint32_t event); - extern int32_t lstack_epoll_close(int32_t); - - #endif /* __EVENTPOLL_H__ */ --- -2.27.0 - diff --git a/0032-fix-free-pbuf-miss-data.patch b/0032-fix-free-pbuf-miss-data.patch deleted file mode 100644 index 0816127..0000000 --- a/0032-fix-free-pbuf-miss-data.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0c7d7ad7f9a79a557a867a6009aa2aac067d454e Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Thu, 6 Oct 2022 21:07:12 +0800 -Subject: [PATCH] fix free pbuf miss data - ---- - src/core/tcp_out.c | 18 ++++++++++++++++++ - src/include/lwipopts.h | 2 +- - 2 files changed, 19 insertions(+), 1 deletion(-) - -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index dd780d3..2834ba3 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -682,11 +682,24 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", - queuelen, (int)TCP_SND_QUEUELEN)); -+#if USE_LIBOS -+ if (pos > 0) { -+ queuelen -= pbuf_clen(p); -+ break; -+ } -+#else - pbuf_free(p); -+#endif - goto memerr; - } - - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { -+#if USE_LIBOS -+ if (pos > 0) { -+ queuelen -= pbuf_clen(p); -+ break; -+ } -+#endif - goto memerr; - } - #if TCP_OVERSIZE_DBGCHECK -@@ -714,6 +727,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; -+#if USE_LIBOS -+ write_lwip_over((struct lwip_sock*)arg, 1); -+#endif - } - - /* -@@ -825,12 +841,14 @@ memerr: - tcp_set_flags(pcb, TF_NAGLEMEMERR); - TCP_STATS_INC(tcp.memerr); - -+#if !USE_LIBOS - if (concat_p != NULL) { - pbuf_free(concat_p); - } - if (queue != NULL) { - tcp_segs_free(queue); - } -+#endif - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 75d3c74..7459991 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -133,7 +133,7 @@ - - #define USE_LIBOS 1 - --#define LWIP_DEBUG 1 -+//#define LWIP_DEBUG 1 - - #define LWIP_PERF 1 - --- -2.27.0 - diff --git a/0033-alloc-socket-fail-clean-sock.patch b/0033-alloc-socket-fail-clean-sock.patch deleted file mode 100644 index 0a932dd..0000000 --- a/0033-alloc-socket-fail-clean-sock.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fc2a5b52f7d9f02eb43931414767635e5cf4c8c1 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 11 Oct 2022 21:47:24 +0800 -Subject: [PATCH] alloc socket fail clean sock - ---- - src/api/sockets.c | 3 +++ - src/include/lwipsock.h | 1 + - 2 files changed, 4 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 14f2b35..3552599 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -598,6 +598,9 @@ alloc_socket(struct netconn *newconn, int accepted) - sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); - sockets[i].errevent = 0; - return i + LWIP_SOCKET_OFFSET; -+ } else { -+ lwip_close(i); -+ gazelle_clean_sock(i); - } - - err: -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 912d471..2ffb077 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -130,6 +130,7 @@ extern void add_recv_list(int32_t fd); - extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); - extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); - extern void gazelle_init_sock(int32_t fd); -+extern void gazelle_clean_sock(int32_t fd); - extern void write_lwip_over(struct lwip_sock *sock, uint32_t n); - #endif /* USE_LIBOS */ - --- -2.23.0 - diff --git a/0034-add-accept4-and-epoll_create1.patch b/0034-add-accept4-and-epoll_create1.patch deleted file mode 100644 index 37594eb..0000000 --- a/0034-add-accept4-and-epoll_create1.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 547f316821a3b24e028d539f7f48b5e3e5ba5c36 Mon Sep 17 00:00:00 2001 -From: compile_success <980965867@qq.com> -Date: Wed, 19 Oct 2022 12:14:08 +0000 -Subject: [PATCH] add epoll_create1 and accept4 - ---- - src/api/posix_api.c | 1 + - src/api/sockets.c | 34 ++++++++++++++++++++++++++++++---- - src/include/lwip/sockets.h | 21 +++++++++++++++++++++ - src/include/posix_api.h | 1 + - 4 files changed, 53 insertions(+), 4 deletions(-) - -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index 6afb9c6..e721381 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -104,6 +104,7 @@ int posix_api_init(void) - CHECK_DLSYM_RET_RETURN(posix_api->fcntl64_fn = dlsym(handle, "fcntl64")); - CHECK_DLSYM_RET_RETURN(posix_api->pipe_fn = dlsym(handle, "pipe")); - CHECK_DLSYM_RET_RETURN(posix_api->epoll_create_fn = dlsym(handle, "epoll_create")); -+ CHECK_DLSYM_RET_RETURN(posix_api->epoll_create1_fn = dlsym(handle, "epoll_create1")); - CHECK_DLSYM_RET_RETURN(posix_api->epoll_ctl_fn = dlsym(handle, "epoll_ctl")); - CHECK_DLSYM_RET_RETURN(posix_api->epoll_wait_fn = dlsym(handle, "epoll_wait")); - CHECK_DLSYM_RET_RETURN(posix_api->fork_fn = dlsym(handle, "fork")); -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 4d4cea1..c939899 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -543,10 +543,11 @@ get_socket_by_fd(int fd) - * @param newconn the netconn for which to allocate a socket - * @param accepted 1 if socket has been created by accept(), - * 0 if socket has been created by socket() -+ * @param flags only support SOCK_CLOEXEC and SOCK_NONBLOCK - * @return the index of the new socket; -1 on error - */ - static int --alloc_socket(struct netconn *newconn, int accepted) -+alloc_socket(struct netconn *newconn, int accepted, int flags) - { - int i; - SYS_ARCH_DECL_PROTECT(lev); -@@ -570,12 +571,19 @@ alloc_socket(struct netconn *newconn, int accepted) - break; - } - -+ /*add CLOEXEC OR NONBLOCK OR NONE*/ -+ type |= flags; -+ - SYS_ARCH_PROTECT(lev); - i = posix_api->socket_fn(domain, type, protocol); - if (i == -1) { - goto err; - } - -+ if ((flags & O_NONBLOCK) != 0){ -+ netconn_set_nonblocking(newconn, flags & O_NONBLOCK); -+ } -+ - if ((i < LWIP_SOCKET_OFFSET) || (i >= sockets_num + LWIP_SOCKET_OFFSET)) { - goto err; - } -@@ -721,7 +729,7 @@ free_socket(struct lwip_sock *sock, int is_tcp) - */ - - int --lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -+lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - { - struct lwip_sock *sock, *nsock; - struct netconn *newconn; -@@ -755,7 +763,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - } - LWIP_ASSERT("newconn != NULL", newconn != NULL); - -- newsock = alloc_socket(newconn, 1); -+ newsock = alloc_socket(newconn, 1, flags); - if (newsock == -1) { - netconn_delete(newconn); - sock_set_errno(sock, ENFILE); -@@ -827,6 +835,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) - return newsock; - } - -+int -+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -+{ -+ return lwip_accept4(s, addr, addrlen, 0); -+} -+ - int - lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) - { -@@ -1823,6 +1837,10 @@ lwip_socket(int domain, int type, int protocol) - - LWIP_UNUSED_ARG(domain); /* @todo: check this */ - -+ int flags = type & ~SOCK_TYPE_MASK; -+ type &= SOCK_TYPE_MASK; -+ -+ - /* create a netconn */ - switch (type) { - case SOCK_RAW: -@@ -1862,7 +1880,15 @@ lwip_socket(int domain, int type, int protocol) - return -1; - } - -- i = alloc_socket(conn, 0); -+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)){ -+ set_errno(EINVAL); -+ return -1; -+ } -+ -+ if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) -+ flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; -+ -+ i = alloc_socket(conn, 0, flags); - - if (i == -1) { - netconn_delete(conn); -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index 4e7e671..3c5b87b 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -573,6 +573,7 @@ void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destro - #if LWIP_COMPAT_SOCKETS == 2 - /* This helps code parsers/code completion by not having the COMPAT functions as defines */ - #define lwip_accept accept -+#define lwip_accept4 accept4 - #define lwip_bind bind - #define lwip_shutdown shutdown - #define lwip_getpeername getpeername -@@ -614,7 +615,25 @@ int fcntl(int s, int cmd, ...); - #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ - #endif /* LWIP_COMPAT_SOCKETS == 2 */ - -+#ifndef O_CLOEXEC -+#define O_CLOEXEC 02000000 -+#endif -+ -+#ifndef SOCK_TYPE_MASK -+#define SOCK_TYPE_MASK 0xf -+#endif -+ -+#ifndef SOCK_CLOEXEC -+#define SOCK_CLOEXEC O_CLOEXEC -+#endif -+ -+#ifndef SOCK_NONBLOCK -+#define SOCK_NONBLOCK O_NONBLOCK -+#endif -+ -+ - int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); -+int lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags); - int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); - int lwip_shutdown(int s, int how); - int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); -@@ -661,6 +680,8 @@ int lwip_inet_pton(int af, const char *src, void *dst); - /** @ingroup socket */ - #define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) - /** @ingroup socket */ -+#define accept4(s,addr,addrlen,flags) lwip_accept4(s,addr,addrlen,flags) -+/** @ingroup socket */ - #define bind(s,name,namelen) lwip_bind(s,name,namelen) - /** @ingroup socket */ - #define shutdown(s,how) lwip_shutdown(s,how) -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index c8f2cf9..e958ded 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -66,6 +66,7 @@ typedef struct { - int (*fcntl64_fn)(int fd, int cmd, ...); - int (*pipe_fn)(int pipefd[2]); - int (*epoll_create_fn)(int size); -+ int (*epoll_create1_fn)(int size); - int (*epoll_ctl_fn)(int epfd, int op, int fd, struct epoll_event *event); - int (*epoll_wait_fn)(int epfd, struct epoll_event *events, int maxevents, int timeout); - int (*epoll_close_fn)(int epfd); --- -2.33.0 - diff --git a/0035-add-writev-and-readv.patch b/0035-add-writev-and-readv.patch deleted file mode 100644 index fc43028..0000000 --- a/0035-add-writev-and-readv.patch +++ /dev/null @@ -1,41 +0,0 @@ -From d5aca360e7518791d21ca63b44ae2dfaa6c35072 Mon Sep 17 00:00:00 2001 -From: compile_success <980965867@qq.com> -Date: Mon, 17 Oct 2022 14:18:53 +0000 -Subject: [PATCH] add writev and readv - ---- - src/api/posix_api.c | 2 ++ - src/include/posix_api.h | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index e721381..b7334da 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -93,7 +93,9 @@ int posix_api_init(void) - CHECK_DLSYM_RET_RETURN(posix_api->shutdown_fn = dlsym(handle, "shutdown")); - CHECK_DLSYM_RET_RETURN(posix_api->close_fn = dlsym(handle, "close")); - CHECK_DLSYM_RET_RETURN(posix_api->read_fn = dlsym(handle, "read")); -+ CHECK_DLSYM_RET_RETURN(posix_api->readv_fn = dlsym(handle, "readv")); - CHECK_DLSYM_RET_RETURN(posix_api->write_fn = dlsym(handle, "write")); -+ CHECK_DLSYM_RET_RETURN(posix_api->writev_fn = dlsym(handle, "writev")); - CHECK_DLSYM_RET_RETURN(posix_api->recv_fn = dlsym(handle, "recv")); - CHECK_DLSYM_RET_RETURN(posix_api->send_fn = dlsym(handle, "send")); - CHECK_DLSYM_RET_RETURN(posix_api->recv_msg = dlsym(handle, "recvmsg")); -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index e958ded..a73e2ec 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -54,7 +54,9 @@ typedef struct { - int (*close_fn)(int fd); - pid_t (*fork_fn)(void); - ssize_t (*read_fn)(int fd, void *mem, size_t len); -+ ssize_t (*readv_fn)(int s, const struct iovec *iov, int iovcnt); - ssize_t (*write_fn)(int fd, const void *data, size_t len); -+ ssize_t (*writev_fn)(int s, const struct iovec *iov, int iovcnt); - ssize_t (*recv_fn)(int sockfd, void *buf, size_t len, int flags); - ssize_t (*send_fn)(int sockfd, const void *buf, size_t len, int flags); - ssize_t (*recv_msg)(int sockfd, const struct msghdr *msg, int flags); --- -2.33.0 - diff --git a/0036-add-fs-secure-compilation-option.patch b/0036-add-fs-secure-compilation-option.patch deleted file mode 100644 index 3021f6e..0000000 --- a/0036-add-fs-secure-compilation-option.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c2c7c2f5bbf84f62acc6468113b1f11cdc6b8410 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Sat, 22 Oct 2022 16:05:37 +0800 -Subject: [PATCH] add fs secure compilation option - ---- - src/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/Makefile b/src/Makefile -index 1676a71..f445601 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -4,7 +4,7 @@ ROOT_DIR := $(dir $(abspath $(LWIP_DIR))) - LWIP_INC = $(LWIP_DIR)/include - DPDK_INCLUDE_FILE ?= /usr/include/dpdk - --SEC_FLAGS = -fstack-protector-strong -Werror -Wall -Wl,-z,relro,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIC -+SEC_FLAGS = -fstack-protector-strong -Werror -Wall -Wl,-z,relro,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIC -D_FORTIRY_SOURCE=2 -O2 - - CC = gcc - AR = ar --- -2.23.0 - diff --git a/0037-enable-ARP-QUEUE-to-avoid-sync-packet-dropped.patch b/0037-enable-ARP-QUEUE-to-avoid-sync-packet-dropped.patch deleted file mode 100644 index ea99146..0000000 --- a/0037-enable-ARP-QUEUE-to-avoid-sync-packet-dropped.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 2acba8aecef2140045a8ae50b05f9f36f5dc865f Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Wed, 23 Nov 2022 09:37:34 +0800 -Subject: [PATCH] enable ARP QUEUE to avoid sync packet dropped - ---- - src/include/lwipopts.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 7459991..a5add21 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -169,6 +169,10 @@ - - #define ARP_TABLE_SIZE 512 - -+#define ARP_QUEUEING 1 -+ -+#define ARP_QUEUE_LEN 32 -+ - /* --------------------------------------- - * ------- NIC offloads -------- - * --------------------------------------- --- -2.23.0 - diff --git a/0038-add-tso.patch b/0038-add-tso.patch deleted file mode 100644 index d6a9841..0000000 --- a/0038-add-tso.patch +++ /dev/null @@ -1,380 +0,0 @@ -From af8ac36acb103aa27b498dafa0ae8ba4332faac8 Mon Sep 17 00:00:00 2001 -From: wu-changsheng -Date: Sat, 3 Dec 2022 21:38:09 +0800 -Subject: [PATCH] add-tso - ---- - src/core/ipv4/etharp.c | 17 +++- - src/core/ipv4/ip4.c | 10 ++- - src/core/tcp.c | 6 ++ - src/core/tcp_out.c | 178 +++++++++++++++++++++++++++++++++++++-- - src/include/dpdk_cksum.h | 2 +- - src/include/lwip/pbuf.h | 8 +- - src/include/lwipopts.h | 4 + - 7 files changed, 211 insertions(+), 14 deletions(-) - -diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c -index effb7db..f1903e4 100644 ---- a/src/core/ipv4/etharp.c -+++ b/src/core/ipv4/etharp.c -@@ -482,6 +482,13 @@ etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct et - struct pbuf *p = arp_table[i].q; - arp_table[i].q = NULL; - #endif /* ARP_QUEUEING */ -+#if USE_LIBOS -+ struct pbuf *tmp = p->next; -+ while (tmp != NULL) { -+ tmp->ref--; -+ tmp = tmp->next; -+ } -+#endif - /* send the queued IP packet */ - ethernet_output(netif, p, (struct eth_addr *)(netif->hwaddr), ethaddr, ETHTYPE_IP); - /* free the queued IP packet */ -@@ -1027,7 +1034,15 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) - } else { - /* referencing the old pbuf is enough */ - p = q; -- pbuf_ref(p); -+#if USE_LIBOS -+ struct pbuf *tmp = p; -+ while (tmp != NULL) { -+ pbuf_ref(tmp); -+ tmp = tmp->next; -+ } -+#else -+ pbuf_ref(p); -+#endif - } - /* packet could be taken over? */ - if (p != NULL) { -diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c -index 1334cdc..d823491 100644 ---- a/src/core/ipv4/ip4.c -+++ b/src/core/ipv4/ip4.c -@@ -1034,9 +1034,15 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d - #endif /* ENABLE_LOOPBACK */ - #if IP_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ -- if (netif->mtu && (p->tot_len > netif->mtu)) { -- return ip4_frag(p, netif, dest); -+#if USE_LIBOS -+ if (!(get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO)) { -+#endif -+ if (netif->mtu && (p->tot_len > netif->mtu)) { -+ return ip4_frag(p, netif, dest); -+ } -+#if USE_LIBOS - } -+#endif - #endif /* IP_FRAG */ - - LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n")); -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 7c18408..51ada38 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -1756,7 +1756,9 @@ tcp_seg_free(struct tcp_seg *seg) - seg->p = NULL; - #endif /* TCP_DEBUG */ - } -+#if !USE_LIBOS - memp_free(MEMP_TCP_SEG, seg); -+#endif - } - } - -@@ -1792,10 +1794,14 @@ tcp_seg_copy(struct tcp_seg *seg) - - LWIP_ASSERT("tcp_seg_copy: invalid seg", seg != NULL); - -+#if USE_LIBOS -+ cseg = (struct tcp_seg *)((uint8_t *)seg->p + sizeof(struct pbuf_custom)); -+#else - cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); - if (cseg == NULL) { - return NULL; - } -+#endif - SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); - pbuf_ref(cseg->p); - return cseg; -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 2834ba3..ee6f40b 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -161,6 +161,40 @@ tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) - * The TCP header is filled in except ackno and wnd. - * p is freed on failure. - */ -+#if USE_LIBOS -+void tcp_init_segment(struct tcp_seg *seg, const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, -+ u32_t seqno, u8_t optflags) -+{ -+ u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); -+ -+ seg->flags = optflags; -+ seg->next = NULL; -+ seg->p = p; -+ seg->len = p->tot_len - optlen; -+ -+ /* build TCP header */ -+ pbuf_add_header(p, TCP_HLEN); -+ seg->tcphdr = (struct tcp_hdr *)seg->p->payload; -+ seg->tcphdr->src = lwip_htons(pcb->local_port); -+ seg->tcphdr->dest = lwip_htons(pcb->remote_port); -+ seg->tcphdr->seqno = lwip_htonl(seqno); -+ -+ TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (TCP_HLEN + optlen) / 4, hdrflags); -+ seg->tcphdr->urgp = 0; -+} -+ -+static struct tcp_seg * -+tcp_create_segment(const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, u32_t seqno, u8_t optflags) -+{ -+ struct tcp_seg *seg; -+ -+ seg = (struct tcp_seg *)((uint8_t *)p + sizeof(struct pbuf_custom)); -+ -+ tcp_init_segment(seg, pcb, p, hdrflags, seqno, optflags); -+ -+ return seg; -+} -+#else - static struct tcp_seg * - tcp_create_segment(const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, u32_t seqno, u8_t optflags) - { -@@ -210,6 +244,7 @@ tcp_create_segment(const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, u32 - seg->tcphdr->urgp = 0; - return seg; - } -+#endif - - /** - * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. -@@ -1272,6 +1307,60 @@ tcp_build_wnd_scale_option(u32_t *opts) - } - #endif - -+#if USE_LIBOS -+static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg, struct tcp_seg *useg) -+{ -+ if (TCP_TCPLEN(seg) > 0) { -+ seg->next = NULL; -+ if (useg == NULL) { -+ pcb->unacked = seg; -+ useg = seg; -+ } else { -+ if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { -+ /* add segment to before tail of unacked list, keeping the list sorted */ -+ struct tcp_seg **cur_seg = &(pcb->unacked); -+ while (*cur_seg && -+ TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { -+ cur_seg = &((*cur_seg)->next ); -+ } -+ seg->next = (*cur_seg); -+ (*cur_seg) = seg; -+ } else { -+ /* add segment to tail of unacked list */ -+ useg->next = seg; -+ useg = seg; -+ } -+ } -+ } else { -+ tcp_seg_free(seg); -+ } -+ -+ return useg; -+} -+static err_t tcp_output_seg(struct tcp_pcb *pcb, struct tcp_seg *seg, struct netif *netif, u32_t snd_nxt) -+{ -+ if (pcb->state != SYN_SENT) { -+ TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); -+ } -+ -+ err_t err = tcp_output_segment(seg, pcb, netif); -+ if (err != ERR_OK) { -+ /* segment could not be sent, for whatever reason */ -+ tcp_set_flags(pcb, TF_NAGLEMEMERR); -+ return err; -+ } -+ -+ if (pcb->state != SYN_SENT) { -+ tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); -+ } -+ -+ if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { -+ pcb->snd_nxt = snd_nxt; -+ } -+ -+ return ERR_OK; -+} -+#endif - /** - * @ingroup tcp_raw - * Find out what we can send and send it -@@ -1376,16 +1465,88 @@ tcp_output(struct tcp_pcb *pcb) - for (; useg->next != NULL; useg = useg->next); - } - /* data available and window allows it to be sent? */ -+ - #if USE_LIBOS -- /* avoid send cose too much time, limit send pkts num max 10 */ -- uint16_t send_pkt = 0; -- while (seg != NULL && send_pkt < 10 && -- lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { -- send_pkt++; --#else -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) { -+ while(seg) { -+ /** -+ * 1)é历unsent队列,找到所有的待å‘é€seg. å°†segçš„bufä¸²èµ·æ¥ -+ * 2) ç”Ÿæˆæ–°çš„seg, 调用tcp_output_segment, æ–°çš„seg释放掉 -+ * 3) è‹¥æˆåŠŸï¼Œåˆ™æ›´æ–°snd_nxt, unacked队列,和unsent队列。 -+ */ -+ struct tcp_seg *start_seg = seg; -+ struct pbuf *first_pbuf = NULL; -+ struct pbuf *pre_pbuf = NULL; -+ u8_t pbuf_chain_len = 0; -+ u32_t next_seqno = lwip_ntohl(seg->tcphdr->seqno); -+ while (seg != NULL && pbuf_chain_len < MAX_PBUF_CHAIN_LEN) { -+ u32_t seg_seqno = lwip_ntohl(seg->tcphdr->seqno); -+ if (seg_seqno - pcb->lastack + seg->len > wnd) { -+ if (first_pbuf) -+ break; -+ else -+ goto output_done; -+ } -+ -+ if ((tcp_do_output_nagle(pcb) == 0) && ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { -+ if (first_pbuf) -+ break; -+ else -+ goto output_done; -+ } -+ -+ if (seg->len < TCP_MSS || next_seqno != seg_seqno || pbuf_chain_len >= MAX_PBUF_CHAIN_LEN) { -+ break; -+ } -+ if (first_pbuf == NULL && (seg->next == NULL || seg->next->len < TCP_MSS)) { -+ break; -+ } -+ -+ pbuf_remove_header(seg->p, seg->p->tot_len - seg->len); -+ if (first_pbuf == NULL) { -+ first_pbuf = seg->p; -+ } else { -+ first_pbuf->tot_len += seg->p->len; -+ pre_pbuf->next = seg->p; -+ } -+ -+ pre_pbuf = seg->p; -+ next_seqno = seg_seqno + TCP_TCPLEN(seg); -+ seg = seg->next; -+ pcb->unsent = seg; -+ pbuf_chain_len++; -+ } -+ -+ if (first_pbuf == NULL) { -+ err = tcp_output_seg(pcb, seg, netif, next_seqno + seg->len); -+ if (err != ERR_OK) -+ return err; -+ pcb->unsent = seg->next; -+ useg = tcp_output_over(pcb, seg, useg); -+ seg = pcb->unsent; -+ continue; -+ } -+ -+ struct tcp_seg new_seg; -+ tcp_init_segment(&new_seg, pcb, first_pbuf, 0, lwip_ntohl(start_seg->tcphdr->seqno), 0); -+ -+ err = tcp_output_seg(pcb, &new_seg, netif, next_seqno); -+ -+ for (u32_t i = 0; i < pbuf_chain_len; i++) { -+ struct tcp_seg *next_seg = start_seg->next; -+ start_seg->p->next = NULL; -+ useg = tcp_output_over(pcb, start_seg, useg); -+ start_seg = next_seg; -+ } -+ -+ pbuf_remove_header(new_seg.p, new_seg.p->tot_len - new_seg.len - TCPH_HDRLEN_BYTES(new_seg.tcphdr)); -+ new_seg.p->tot_len = new_seg.p->len; -+ } -+ } else -+#endif -+{ - while (seg != NULL && - lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { --#endif - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); - /* Stop sending if the nagle algorithm would prevent it -@@ -1462,6 +1623,7 @@ tcp_output(struct tcp_pcb *pcb) - } - seg = pcb->unsent; - } -+} - #if TCP_OVERSIZE - if (pcb->unsent == NULL) { - /* last unsent has been removed, reset unsent_oversize */ -@@ -1627,7 +1789,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - #if CHECKSUM_GEN_TCP_HW - if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -- tcph_cksum_set(seg->p, TCP_HLEN); -+ tcph_cksum_set(seg->p, TCPH_HDRLEN_BYTES(seg->tcphdr)); - seg->tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP,seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); - } else { - #if TCP_CHECKSUM_ON_COPY -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index e57be4d..83c9c38 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -78,7 +78,7 @@ static inline void iph_cksum_set(struct pbuf *p, u16_t len, bool do_ipcksum) { - #include - - static inline void tcph_cksum_set(struct pbuf *p, u16_t len) { -- (void)len; -+ p->l4_len = len; - p->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; - } - -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 87cd960..ef879da 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -223,10 +223,14 @@ struct pbuf { - #if USE_LIBOS && CHECKSUM_OFFLOAD_ALL - /** checksum offload ol_flags */ - u64_t ol_flags; -- /** checksum offload l2_len */ -+ /* < L2 (MAC) Header Length for non-tunneling pkt. */ - u64_t l2_len:7; -- /** checksum offload l3_len */ -+ /* < L3 (IP) Header Length. */ - u64_t l3_len:9; -+ /* < L4 (TCP/UDP) Header Length. */ -+ u64_t l4_len:8; -+ u16_t header_off; -+ u8_t rexmit; - #endif /* USE_LIBOS CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index a5add21..7c819d0 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -173,6 +173,10 @@ - - #define ARP_QUEUE_LEN 32 - -+#define MAX_PBUF_CHAIN_LEN 40 -+ -+#define MIN_TSO_SEG_LEN 256 -+ - /* --------------------------------------- - * ------- NIC offloads -------- - * --------------------------------------- --- -2.23.0 - diff --git a/0039-optimize-app-thread-write-buff-block.patch b/0039-optimize-app-thread-write-buff-block.patch deleted file mode 100644 index 42280e3..0000000 --- a/0039-optimize-app-thread-write-buff-block.patch +++ /dev/null @@ -1,94 +0,0 @@ -From be541628552ccc3a8dcd3c6ad6e5a1aed07c4928 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Sat, 3 Dec 2022 20:35:34 +0800 -Subject: [PATCH 2/2] fix app thread write fail - ---- - src/core/tcp_out.c | 2 +- - src/include/lwip/pbuf.h | 3 +++ - src/include/lwipsock.h | 33 +++++++++++++++++++++++---------- - 3 files changed, 27 insertions(+), 11 deletions(-) - -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index ee6f40b..f53750b 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -763,7 +763,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - - pos += seglen; - #if USE_LIBOS -- write_lwip_over((struct lwip_sock*)arg, 1); -+ write_lwip_over((struct lwip_sock*)arg); - #endif - } - -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index ef879da..10e2af9 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -231,6 +231,9 @@ struct pbuf { - u64_t l4_len:8; - u16_t header_off; - u8_t rexmit; -+ u8_t in_write; -+ u8_t head; -+ struct pbuf *last; - #endif /* USE_LIBOS CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 2ffb077..f919330 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -93,17 +93,30 @@ struct lwip_sock { - #endif - - #if USE_LIBOS -- struct pbuf *send_lastdata; -- uint16_t send_datalen; -- volatile uint32_t events __rte_cache_aligned; /* available events */ -- struct pbuf *recv_lastdata __rte_cache_aligned; /* unread data in one pbuf */ -- struct list_node recv_list __rte_cache_aligned; -- struct list_node event_list __rte_cache_aligned; -- struct list_node send_list __rte_cache_aligned; -- uint32_t in_send __rte_cache_aligned; /* avoid sock too much send rpc msg*/ -+ char pad0 __rte_cache_aligned; -+ /* app thread use */ -+ struct pbuf *recv_lastdata; /* unread data in one pbuf */ -+ uint16_t remain_len; - uint32_t epoll_events; /* registered events, EPOLLONESHOT write frequently */ -- char pad __rte_cache_aligned; -+ volatile uint32_t events; /* available events */ -+ struct list_node event_list; -+ -+ char pad1 __rte_cache_aligned; -+ /* app and stack thread all use */ -+ uint32_t in_send; /* avoid sock too much send rpc msg*/ -+ pthread_spinlock_t sock_lock; -+ -+ char pad2 __rte_cache_aligned; -+ /* stack thread all use */ -+ struct list_node recv_list; -+ struct list_node send_list; -+ struct pbuf *send_lastdata; -+ struct pbuf *send_pre_del; -+ uint64_t recv_all; -+ uint64_t send_all; - -+ char pad3 __rte_cache_aligned; -+ /* nerver change */ - struct wakeup_poll *wakeup; - epoll_data_t ep_data; - struct lwip_sock *listen_next; /* listenfd list */ -@@ -131,7 +144,7 @@ extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apifla - extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); - extern void gazelle_init_sock(int32_t fd); - extern void gazelle_clean_sock(int32_t fd); --extern void write_lwip_over(struct lwip_sock *sock, uint32_t n); -+extern void write_lwip_over(struct lwip_sock *sock); - #endif /* USE_LIBOS */ - - struct lwip_sock *get_socket(int s); --- -2.8.4.windows.1 - diff --git a/0040-add-huge-snd_buf.patch b/0040-add-huge-snd_buf.patch deleted file mode 100644 index 73fa142..0000000 --- a/0040-add-huge-snd_buf.patch +++ /dev/null @@ -1,86 +0,0 @@ -diff -Nur lwip-2.1.3-org/src/core/init.c lwip-2.1.3/src/core/init.c ---- lwip-2.1.3-org/src/core/init.c 2022-12-06 14:40:45.280000000 +0000 -+++ lwip-2.1.3/src/core/init.c 2022-12-06 14:41:01.452000000 +0000 -@@ -306,7 +306,7 @@ - #if TCP_SNDLOWAT >= TCP_SND_BUF - #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." - #endif --#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) -+#if TCP_SNDLOWAT >= (0xFFFFFFFF - (4 * TCP_MSS)) - #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" - #endif - #if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN -diff -Nur lwip-2.1.3-org/src/core/pbuf.c lwip-2.1.3/src/core/pbuf.c ---- lwip-2.1.3-org/src/core/pbuf.c 2022-12-06 14:40:45.280000000 +0000 -+++ lwip-2.1.3/src/core/pbuf.c 2022-12-06 14:46:04.860000000 +0000 -@@ -869,13 +869,13 @@ - /* proceed to last pbuf of chain */ - for (p = h; p->next != NULL; p = p->next) { - /* add total length of second chain to all totals of first chain */ -- p->tot_len = (u16_t)(p->tot_len + t->tot_len); -+ p->tot_len = p->tot_len + t->tot_len; - } - /* { p is last pbuf of first h chain, p->next == NULL } */ - LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); - LWIP_ASSERT("p->next == NULL", p->next == NULL); - /* add total length of second chain to last pbuf total of first chain */ -- p->tot_len = (u16_t)(p->tot_len + t->tot_len); -+ p->tot_len = p->tot_len + t->tot_len; - /* chain last pbuf of head (p) with first of tail (t) */ - p->next = t; - /* p->next now references t, but the caller will drop its reference to t, -@@ -1181,7 +1181,7 @@ - if (r != NULL) { - /* Update the tot_len field in the first part */ - for (i = p; i != NULL; i = i->next) { -- i->tot_len = (u16_t)(i->tot_len - r->tot_len); -+ i->tot_len = tot_len_front; - LWIP_ASSERT("tot_len/len mismatch in last pbuf", - (i->next != NULL) || (i->tot_len == i->len)); - } -@@ -1192,6 +1192,9 @@ - /* tot_len field in rest does not need modifications */ - /* reference counters do not need modifications */ - *rest = r; -+ r->tot_len = r->len; -+ }else{ -+ p->tot_len = tot_len_front; - } - } - } -diff -Nur lwip-2.1.3-org/src/include/lwip/opt.h lwip-2.1.3/src/include/lwip/opt.h ---- lwip-2.1.3-org/src/include/lwip/opt.h 2022-12-06 14:40:45.292000000 +0000 -+++ lwip-2.1.3/src/include/lwip/opt.h 2022-12-06 14:41:01.456000000 +0000 -@@ -1482,7 +1482,7 @@ - * send window while having a small receive window only. - */ - #if !defined LWIP_WND_SCALE || defined __DOXYGEN__ --#define LWIP_WND_SCALE 0 -+#define LWIP_WND_SCALE 1 - #define TCP_RCV_SCALE 0 - #endif - -diff -Nur lwip-2.1.3-org/src/include/lwip/pbuf.h lwip-2.1.3/src/include/lwip/pbuf.h ---- lwip-2.1.3-org/src/include/lwip/pbuf.h 2022-12-06 14:40:45.284000000 +0000 -+++ lwip-2.1.3/src/include/lwip/pbuf.h 2022-12-06 14:46:36.720000000 +0000 -@@ -197,7 +197,7 @@ - * For non-queue packet chains this is the invariant: - * p->tot_len == p->len + (p->next? p->next->tot_len: 0) - */ -- u16_t tot_len; -+ u32_t tot_len; - - /** length of this buffer */ - u16_t len; -diff -Nur lwip-2.1.3-org/src/include/lwipopts.h lwip-2.1.3/src/include/lwipopts.h ---- lwip-2.1.3-org/src/include/lwipopts.h 2022-12-06 14:40:45.292000000 +0000 -+++ lwip-2.1.3/src/include/lwipopts.h 2022-12-06 14:41:01.456000000 +0000 -@@ -97,7 +97,7 @@ - - #define TCP_WND (40 * TCP_MSS) - --#define TCP_SND_BUF (40 * TCP_MSS) -+#define TCP_SND_BUF (2500 * TCP_MSS) - - #define TCP_SND_QUEUELEN (8191) - diff --git a/0041-optimite-pcb-list-limit-send-size-and-ack-now.patch b/0041-optimite-pcb-list-limit-send-size-and-ack-now.patch deleted file mode 100644 index 2c47b15..0000000 --- a/0041-optimite-pcb-list-limit-send-size-and-ack-now.patch +++ /dev/null @@ -1,374 +0,0 @@ -From 08716b71ccb93c6d998d1654c1fac137f29d2851 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Tue, 13 Dec 2022 22:27:33 +0800 -Subject: [PATCH] optimite pcb-list limit , send size and ack now - ---- - src/core/tcp.c | 1 + - src/core/tcp_in.c | 16 +++++++- - src/core/tcp_out.c | 103 ++++++++++++++++++++++++++++++------------------- - src/include/lwip/opt.h | 2 +- - src/include/lwip/tcp.h | 2 + - src/include/lwipsock.h | 2 - - 6 files changed, 83 insertions(+), 43 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 51ada38..cb08f95 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -2297,6 +2297,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb) - tcp_segs_free(pcb->unsent); - tcp_segs_free(pcb->unacked); - pcb->unacked = pcb->unsent = NULL; -+ pcb->last_unacked = pcb->last_unsent = NULL; - #if TCP_OVERSIZE - pcb->unsent_oversize = 0; - #endif /* TCP_OVERSIZE */ -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 2d6cb6a..78954bd 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -976,8 +976,14 @@ tcp_process(struct tcp_pcb *pcb) - rseg = pcb->unsent; - LWIP_ASSERT("no segment to free", rseg != NULL); - pcb->unsent = rseg->next; -+ if (pcb->last_unsent == rseg) { -+ pcb->last_unsent = rseg->next; -+ } - } else { - pcb->unacked = rseg->next; -+ if (pcb->last_unacked == rseg) { -+ pcb->last_unacked = rseg->next; -+ } - } - tcp_seg_free(rseg); - -@@ -1393,6 +1399,8 @@ tcp_receive(struct tcp_pcb *pcb) - /* Remove segment from the unacknowledged list if the incoming - ACK acknowledges them. */ - pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); -+ if (pcb->unacked == NULL) -+ pcb->last_unacked = NULL; - /* We go through the ->unsent list to see if any of the segments - on the list are acknowledged by the ACK. This may seem - strange since an "unsent" segment shouldn't be acked. The -@@ -1400,6 +1408,8 @@ tcp_receive(struct tcp_pcb *pcb) - ->unsent list after a retransmission, so these segments may - in fact have been sent once. */ - pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); -+ if (pcb->unsent == NULL) -+ pcb->last_unsent = NULL; - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ -@@ -1736,7 +1746,11 @@ tcp_receive(struct tcp_pcb *pcb) - - - /* Acknowledge the segment(s). */ -- tcp_ack(pcb); -+ if (flags & TCP_PSH) { -+ tcp_ack_now(pcb); -+ } else { -+ tcp_ack(pcb); -+ } - - #if LWIP_TCP_SACK_OUT - if (LWIP_TCP_SACK_VALID(pcb, 0)) { -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index f53750b..55053d8 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -631,11 +631,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - #endif /* TCP_OVERSIZE */ - } - #else /* USE_LIBOS */ -- if (pcb->unsent != NULL) { -- /* @todo: this could be sped up by keeping last_unsent in the pcb */ -- for (last_unsent = pcb->unsent; last_unsent->next != NULL; -- last_unsent = last_unsent->next); -- } -+ last_unsent = pcb->last_unsent; - #endif /* USE_LIBOS */ - - /* -@@ -851,6 +847,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - * Finally update the pcb state. - */ - #if USE_LIBOS -+ if (queue) { -+ pcb->last_unsent = prev_seg; -+ } - pcb->snd_lbb += pos; - pcb->snd_buf -= pos; - #else -@@ -1050,6 +1049,8 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split) - /* Finally insert remainder into queue after split (which stays head) */ - seg->next = useg->next; - useg->next = seg; -+ if (pcb->last_unsent == useg) -+ pcb->last_unsent = seg; - - #if TCP_OVERSIZE - /* If remainder is last segment on the unsent, ensure we clear the oversize amount -@@ -1086,9 +1087,7 @@ tcp_send_fin(struct tcp_pcb *pcb) - - /* first, try to add the fin to the last unsent segment */ - if (pcb->unsent != NULL) { -- struct tcp_seg *last_unsent; -- for (last_unsent = pcb->unsent; last_unsent->next != NULL; -- last_unsent = last_unsent->next); -+ struct tcp_seg *last_unsent = pcb->unsent; - - if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { - /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ -@@ -1182,10 +1181,10 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) - if (pcb->unsent == NULL) { - pcb->unsent = seg; - } else { -- struct tcp_seg *useg; -- for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); -+ struct tcp_seg *useg = pcb->last_unsent; - useg->next = seg; - } -+ pcb->last_unsent = seg; - #if TCP_OVERSIZE - /* The new unsent tail has no space */ - pcb->unsent_oversize = 0; -@@ -1314,6 +1313,7 @@ static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg, - seg->next = NULL; - if (useg == NULL) { - pcb->unacked = seg; -+ pcb->last_unacked = seg; - useg = seg; - } else { - if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { -@@ -1329,6 +1329,7 @@ static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg, - /* add segment to tail of unacked list */ - useg->next = seg; - useg = seg; -+ pcb->last_unacked = seg; - } - } - } else { -@@ -1460,15 +1461,14 @@ tcp_output(struct tcp_pcb *pcb) - pcb->persist_backoff = 0; - - /* useg should point to last segment on unacked queue */ -- useg = pcb->unacked; -- if (useg != NULL) { -- for (; useg->next != NULL; useg = useg->next); -- } -+ useg = pcb->last_unacked; -+ - /* data available and window allows it to be sent? */ - -+ u32_t send_len = 0; - #if USE_LIBOS - if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) { -- while(seg) { -+ while(seg && send_len < 0xffff) { - /** - * 1)é历unsent队列,找到所有的待å‘é€seg. å°†segçš„bufä¸²èµ·æ¥ - * 2) ç”Ÿæˆæ–°çš„seg, 调用tcp_output_segment, æ–°çš„seg释放掉 -@@ -1510,6 +1510,7 @@ tcp_output(struct tcp_pcb *pcb) - pre_pbuf->next = seg->p; - } - -+ send_len += seg->len; - pre_pbuf = seg->p; - next_seqno = seg_seqno + TCP_TCPLEN(seg); - seg = seg->next; -@@ -1519,8 +1520,11 @@ tcp_output(struct tcp_pcb *pcb) - - if (first_pbuf == NULL) { - err = tcp_output_seg(pcb, seg, netif, next_seqno + seg->len); -- if (err != ERR_OK) -+ if (err != ERR_OK) { -+ if (pcb->unsent == NULL) -+ pcb->last_unsent = NULL; - return err; -+ } - pcb->unsent = seg->next; - useg = tcp_output_over(pcb, seg, useg); - seg = pcb->unsent; -@@ -1545,7 +1549,7 @@ tcp_output(struct tcp_pcb *pcb) - } else - #endif - { -- while (seg != NULL && -+ while (seg != NULL && send_len < 0xffff && - lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); -@@ -1560,6 +1564,7 @@ tcp_output(struct tcp_pcb *pcb) - ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { - break; - } -+ send_len += seg->len; - #if TCP_CWND_DEBUG - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, -@@ -1577,6 +1582,8 @@ tcp_output(struct tcp_pcb *pcb) - if (err != ERR_OK) { - /* segment could not be sent, for whatever reason */ - tcp_set_flags(pcb, TF_NAGLEMEMERR); -+ if (pcb->unsent == NULL) -+ pcb->last_unsent = NULL; - return err; - } - #if TCP_OVERSIZE_DBGCHECK -@@ -1596,6 +1603,7 @@ tcp_output(struct tcp_pcb *pcb) - /* unacked list is empty? */ - if (pcb->unacked == NULL) { - pcb->unacked = seg; -+ pcb->last_unacked = seg; - useg = seg; - /* unacked list is not empty? */ - } else { -@@ -1615,6 +1623,7 @@ tcp_output(struct tcp_pcb *pcb) - /* add segment to tail of unacked list */ - useg->next = seg; - useg = useg->next; -+ pcb->last_unacked = seg; - } - } - /* do not queue empty segments on the unacked list */ -@@ -1632,6 +1641,8 @@ tcp_output(struct tcp_pcb *pcb) - #endif /* TCP_OVERSIZE */ - - output_done: -+ if (pcb->unsent == NULL) -+ pcb->last_unsent = NULL; - tcp_clear_flags(pcb, TF_NAGLEMEMERR); - return ERR_OK; - } -@@ -1932,9 +1943,13 @@ tcp_rexmit_rto_prepare(struct tcp_pcb *pcb) - } - #endif /* TCP_OVERSIZE_DBGCHECK */ - /* unsent queue is the concatenated queue (of unacked, unsent) */ -+ if (pcb->unsent == NULL) { -+ pcb->last_unsent = pcb->last_unacked; -+ } - pcb->unsent = pcb->unacked; - /* unacked queue is now empty */ - pcb->unacked = NULL; -+ pcb->last_unacked = NULL; - - /* Mark RTO in-progress */ - tcp_set_flags(pcb, TF_RTO); -@@ -2004,32 +2019,42 @@ tcp_rexmit(struct tcp_pcb *pcb) - } - - seg = pcb->unacked; -+ while (seg) { -+ /* Give up if the segment is still referenced by the netif driver -+ due to deferred transmission. */ -+ if (tcp_output_segment_busy(seg)) { -+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n")); -+ if (seg == pcb->unacked) -+ return ERR_VAL; -+ else -+ break; -+ } - -- /* Give up if the segment is still referenced by the netif driver -- due to deferred transmission. */ -- if (tcp_output_segment_busy(seg)) { -- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n")); -- return ERR_VAL; -- } -- -- /* Move the first unacked segment to the unsent queue */ -- /* Keep the unsent queue sorted. */ -- pcb->unacked = seg->next; -+ /* Move the first unacked segment to the unsent queue */ -+ /* Keep the unsent queue sorted. */ -+ if (pcb->last_unacked == pcb->unacked) -+ pcb->last_unacked = pcb->unacked->next; -+ pcb->unacked = pcb->unacked->next; - -- cur_seg = &(pcb->unsent); -- while (*cur_seg && -- TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { -- cur_seg = &((*cur_seg)->next ); -- } -- seg->next = *cur_seg; -- *cur_seg = seg; -+ cur_seg = &(pcb->unsent); -+ while (*cur_seg && -+ TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { -+ cur_seg = &((*cur_seg)->next); -+ } -+ if (*cur_seg == NULL) -+ pcb->last_unsent = seg; -+ seg->next = *cur_seg; -+ *cur_seg = seg; - #if TCP_OVERSIZE -- if (seg->next == NULL) { -- /* the retransmitted segment is last in unsent, so reset unsent_oversize */ -- pcb->unsent_oversize = 0; -- } -+ if (seg->next == NULL) { -+ /* the retransmitted segment is last in unsent, so reset unsent_oversize */ -+ pcb->unsent_oversize = 0; -+ } - #endif /* TCP_OVERSIZE */ - -+ seg = pcb->unacked; -+ } -+ - if (pcb->nrtx < 0xFF) { - ++pcb->nrtx; - } -@@ -2207,7 +2232,7 @@ tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, - struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; - #if CHECKSUM_GEN_TCP_HW - if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -- tcph_cksum_set(p, TCP_HLEN); -+ tcph_cksum_set(p, TCPH_HDRLEN_BYTES(tcphdr)); - tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP, p->tot_len, src, dst); - } else { - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 8294cdd..83e7e93 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -1281,7 +1281,7 @@ - * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). - */ - #if !defined LWIP_TCP_SACK_OUT || defined __DOXYGEN__ --#define LWIP_TCP_SACK_OUT 0 -+#define LWIP_TCP_SACK_OUT 1 - #endif - - /** -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index b36bf33..b0ae02c 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -356,7 +356,9 @@ struct tcp_pcb { - - /* These are ordered by sequence number: */ - struct tcp_seg *unsent; /* Unsent (queued) segments. */ -+ struct tcp_seg *last_unsent; - struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ -+ struct tcp_seg *last_unacked; - #if TCP_QUEUE_OOSEQ - struct tcp_seg *ooseq; /* Received out of sequence segments. */ - #endif /* TCP_QUEUE_OOSEQ */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index f919330..bf0d753 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -112,8 +112,6 @@ struct lwip_sock { - struct list_node send_list; - struct pbuf *send_lastdata; - struct pbuf *send_pre_del; -- uint64_t recv_all; -- uint64_t send_all; - - char pad3 __rte_cache_aligned; - /* nerver change */ --- -2.8.4.windows.1 - diff --git a/0042-expand-recv-win.patch b/0042-expand-recv-win.patch deleted file mode 100644 index 38438ac..0000000 --- a/0042-expand-recv-win.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 288d56ebd68f366d3fa2ee1521120016fb21bf31 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Sat, 17 Dec 2022 19:14:36 +0800 -Subject: [PATCH 1/2] expand recv win - ---- - src/include/lwip/opt.h | 2 +- - src/include/lwipopts.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 9d41a09..718816b 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -1483,7 +1483,7 @@ - */ - #if !defined LWIP_WND_SCALE || defined __DOXYGEN__ - #define LWIP_WND_SCALE 1 --#define TCP_RCV_SCALE 0 -+#define TCP_RCV_SCALE 6 - #endif - - /** -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index d7b9635..907c630 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -95,7 +95,7 @@ - - #define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) - --#define TCP_WND (40 * TCP_MSS) -+#define TCP_WND (2500 * TCP_MSS) - - #define TCP_SND_BUF (2500 * TCP_MSS) - --- -2.8.4.windows.1 - diff --git a/0043-add-prefetch.patch b/0043-add-prefetch.patch deleted file mode 100644 index 082503f..0000000 --- a/0043-add-prefetch.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 3d63cb611a0b7a3cde0bb9e74b0ec83501966c51 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Sun, 18 Dec 2022 18:50:33 +0800 -Subject: [PATCH 2/2] add prefetch - ---- - src/core/pbuf.c | 7 +++++++ - src/core/tcp_out.c | 6 ++++++ - 2 files changed, 13 insertions(+) - -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 404c8a7..ad75aa6 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -83,6 +83,9 @@ - #if LWIP_CHECKSUM_ON_COPY - #include "lwip/inet_chksum.h" - #endif -+#if USE_LIBOS -+#include -+#endif - - #include - -@@ -750,6 +753,10 @@ pbuf_free(struct pbuf *p) - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { -+#if USE_LIBOS -+ if (p->next) -+ rte_prefetch0(p->next); -+#endif - LWIP_PBUF_REF_T ref; - SYS_ARCH_DECL_PROTECT(old_level); - /* Since decrementing ref cannot be guaranteed to be a single machine operation -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 55053d8..3c4dc4b 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -82,6 +82,7 @@ - - #if USE_LIBOS - #include "lwipsock.h" -+#include - #if CHECKSUM_GEN_TCP_HW - #include "dpdk_cksum.h" - #endif -@@ -1762,6 +1763,11 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - } - #endif - -+#if USE_LIBOS -+ /* pbuf into mbuf. ref dpdk_common.h */ -+ rte_prefetch0((uint8_t *)(seg->p) - sizeof(struct rte_mbuf) - sizeof(uint64_t) * 2); -+#endif -+ - /* Set retransmission timer running if it is not currently enabled - This must be set before checking the route. */ - if (pcb->rtime < 0) { --- -2.8.4.windows.1 - diff --git a/0044-skip-unnecessary-tcp_route.patch b/0044-skip-unnecessary-tcp_route.patch deleted file mode 100644 index b93b7d5..0000000 --- a/0044-skip-unnecessary-tcp_route.patch +++ /dev/null @@ -1,103 +0,0 @@ -From b23520dcddbdf088ededeac7a0a1611db73db191 Mon Sep 17 00:00:00 2001 -From: kircher -Date: Mon, 19 Dec 2022 19:23:42 +0800 -Subject: [PATCH] skip unnecessary tcp_route - ---- - src/core/tcp.c | 1 + - src/core/tcp_out.c | 20 ++++++++++++++++---- - src/include/lwip/tcp.h | 1 + - src/include/lwipsock.h | 1 + - 4 files changed, 19 insertions(+), 4 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 252f27f..abfcc00 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -2294,6 +2294,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb) - tcp_segs_free(pcb->unacked); - pcb->unacked = pcb->unsent = NULL; - pcb->last_unacked = pcb->last_unsent = NULL; -+ pcb->pcb_if = NULL; - #if TCP_OVERSIZE - pcb->unsent_oversize = 0; - #endif /* TCP_OVERSIZE */ -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 25aeb23..1c5734b 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1425,7 +1425,12 @@ tcp_output(struct tcp_pcb *pcb) - lwip_ntohl(seg->tcphdr->seqno), pcb->lastack)); - } - -- netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); -+ if (pcb->pcb_if == NULL) { -+ netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); -+ pcb->pcb_if = netif; -+ } else { -+ netif = pcb->pcb_if; -+ } - if (netif == NULL) { - return ERR_RTE; - } -@@ -2220,7 +2225,7 @@ tcp_output_fill_options(const struct tcp_pcb *pcb, struct pbuf *p, u8_t optflags - * header checksum and calling ip_output_if while handling netif hints and stats. - */ - static err_t --tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, -+tcp_output_control_segment(struct tcp_pcb *pcb, struct pbuf *p, - const ip_addr_t *src, const ip_addr_t *dst) - { - err_t err; -@@ -2228,7 +2233,14 @@ tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, - - LWIP_ASSERT("tcp_output_control_segment: invalid pbuf", p != NULL); - -- netif = tcp_route(pcb, src, dst); -+ if (pcb == NULL || pcb->pcb_if == NULL) { -+ netif = tcp_route(pcb, src, dst); -+ if (pcb) { -+ pcb->pcb_if = netif; -+ } -+ } else { -+ netif = pcb->pcb_if; -+ } - if (netif == NULL) { - err = ERR_RTE; - } else { -@@ -2318,7 +2330,7 @@ tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, - - MIB2_STATS_INC(mib2.tcpoutrsts); - -- tcp_output_control_segment(pcb, p, local_ip, remote_ip); -+ tcp_output_control_segment((struct tcp_pcb*)pcb, p, local_ip, remote_ip); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); - } - -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index b0ae02c..2a61776 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -408,6 +408,7 @@ struct tcp_pcb { - u8_t snd_scale; - u8_t rcv_scale; - #endif -+ struct netif* pcb_if; - }; - - #if TCP_PCB_HASH -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 62e5bf1..ec4d78c 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -111,6 +111,7 @@ struct lwip_sock { - /* stack thread all use */ - struct list_node recv_list; - struct list_node send_list; -+ struct pbuf *lwip_lastdata; - struct pbuf *send_lastdata; - struct pbuf *send_pre_del; - --- -2.33.0 - diff --git a/0045-add-variable-in-struct-sock.patch b/0045-add-variable-in-struct-sock.patch deleted file mode 100644 index 8fcb6da..0000000 --- a/0045-add-variable-in-struct-sock.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1ede4a00c1eca575314af02374846cb086798c08 Mon Sep 17 00:00:00 2001 -From: wu-changsheng -Date: Tue, 20 Dec 2022 14:37:21 +0800 -Subject: [PATCH] add variable in struct sock - ---- - src/include/lwipsock.h | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index ec4d78c..8924728 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -105,8 +105,7 @@ struct lwip_sock { - char pad1 __rte_cache_aligned; - /* app and stack thread all use */ - uint32_t in_send; /* avoid sock too much send rpc msg*/ -- pthread_spinlock_t sock_lock; -- -+ bool read_wait; - char pad2 __rte_cache_aligned; - /* stack thread all use */ - struct list_node recv_list; --- -2.23.0 - diff --git a/0046-add-dataack-when-recv-too-many-acks-with-data.patch b/0046-add-dataack-when-recv-too-many-acks-with-data.patch deleted file mode 100644 index 70131e5..0000000 --- a/0046-add-dataack-when-recv-too-many-acks-with-data.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 1aa27395a4c4b73b6db472c4ae75ed91637a11bf Mon Sep 17 00:00:00 2001 -From: kircher -Date: Wed, 21 Dec 2022 17:50:50 +0800 -Subject: [PATCH] add dataack when recv too many acks with data - ---- - src/core/tcp_in.c | 22 ++++++++++++++++++++++ - src/include/lwip/tcp.h | 1 + - src/include/lwipopts.h | 2 ++ - 3 files changed, 25 insertions(+) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 78954bd..35ec6d9 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -1260,6 +1260,7 @@ tcp_receive(struct tcp_pcb *pcb) - s16_t m; - u32_t right_wnd_edge; - int found_dupack = 0; -+ int found_dataack = 0; - - LWIP_ASSERT("tcp_receive: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); -@@ -1337,11 +1338,31 @@ tcp_receive(struct tcp_pcb *pcb) - } - } - } -+ /* fast rexmit when receive too many acks with data */ -+ if (TCP_SEQ_LT(ackno + 1, pcb->snd_nxt)) { -+ if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { -+ if (pcb->rtime >= 0) { -+ if (pcb->lastack == ackno) { -+ found_dataack = 1; -+ ++pcb->dataacks; -+ if (pcb->dataacks > MAX_DATA_ACK_NUM) { -+ if (tcp_rexmit(pcb) == ERR_OK) { -+ pcb->rtime = 0; -+ pcb->dataacks = 0; -+ } -+ } -+ } -+ } -+ } -+ } - /* If Clause (1) or more is true, but not a duplicate ack, reset - * count of consecutive duplicate acks */ - if (!found_dupack) { - pcb->dupacks = 0; - } -+ if (!found_dataack) { -+ pcb->dataacks = 0; -+ } - } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { - /* We come here when the ACK acknowledges new data. */ - tcpwnd_size_t acked; -@@ -1367,6 +1388,7 @@ tcp_receive(struct tcp_pcb *pcb) - /* Reset the fast retransmit variables. */ - pcb->dupacks = 0; - pcb->lastack = ackno; -+ pcb->dataacks = 0; - - /* Update the congestion control variables (cwnd and - ssthresh). */ -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 2a61776..97cb882 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -326,6 +326,7 @@ struct tcp_pcb { - - /* fast retransmit/recovery */ - u8_t dupacks; -+ u32_t dataacks; - u32_t lastack; /* Highest acknowledged seqno. */ - - /* congestion avoidance/control variables */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 907c630..405cf11 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -177,6 +177,8 @@ - - #define MIN_TSO_SEG_LEN 256 - -+#define MAX_DATA_ACK_NUM 256 -+ - /* --------------------------------------- - * ------- NIC offloads -------- - * --------------------------------------- --- -2.33.0 - diff --git a/0047-reduce-struct-pbuf-size.patch b/0047-reduce-struct-pbuf-size.patch deleted file mode 100644 index fed1ba5..0000000 --- a/0047-reduce-struct-pbuf-size.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 5527e02b7ae7f27db8964ad55747326b98e33634 Mon Sep 17 00:00:00 2001 -From: wu-changsheng -Date: Wed, 21 Dec 2022 22:47:04 +0800 -Subject: [PATCH] reduce struct pbuf size - ---- - src/include/lwip/pbuf.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 380ac8e..1124408 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -229,7 +229,7 @@ struct pbuf { - u64_t l3_len:9; - /* < L4 (TCP/UDP) Header Length. */ - u64_t l4_len:8; -- u16_t header_off; -+ u8_t header_off; - u8_t rexmit; - u8_t in_write; - u8_t head; --- -2.23.0 - diff --git a/0048-listen-pcb-also-use-pcb_if.patch b/0048-listen-pcb-also-use-pcb_if.patch deleted file mode 100644 index 81ff5ba..0000000 --- a/0048-listen-pcb-also-use-pcb_if.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 11d8e9f6d54a606163a452f1c8beaa5bc90e949c Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Wed, 28 Dec 2022 21:25:36 +0800 -Subject: [PATCH] listen pcb also use pcb_if - ---- - src/include/lwip/ip.h | 1 + - src/include/lwip/tcp.h | 1 - - 2 files changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h -index d560f6b..4cf5f5e 100644 ---- a/src/include/lwip/ip.h -+++ b/src/include/lwip/ip.h -@@ -79,6 +79,7 @@ extern "C" { - ip_addr_t remote_ip; \ - /* Bound netif index */ \ - u8_t netif_idx; \ -+ struct netif *pcb_if; \ - /* Socket options */ \ - u8_t so_options; \ - /* Type Of Service */ \ -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 97cb882..0b65b01 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -409,7 +409,6 @@ struct tcp_pcb { - u8_t snd_scale; - u8_t rcv_scale; - #endif -- struct netif* pcb_if; - }; - - #if TCP_PCB_HASH --- -2.23.0 - diff --git a/0049-expand-recv-mbox-size.patch b/0049-expand-recv-mbox-size.patch deleted file mode 100644 index b8a9e76..0000000 --- a/0049-expand-recv-mbox-size.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c18ca96d1c2ef02153ce9fb22386b4e8a44b60e9 Mon Sep 17 00:00:00 2001 -From: wuchangsheng -Date: Fri, 30 Dec 2022 11:34:31 +0800 -Subject: [PATCH] expand recv mbox size - ---- - src/core/tcp_out.c | 6 +++--- - src/include/lwipopts.h | 2 +- - src/include/lwipsock.h | 2 -- - 3 files changed, 4 insertions(+), 6 deletions(-) - -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 4feeb69..f84ff57 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1476,9 +1476,9 @@ tcp_output(struct tcp_pcb *pcb) - if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) { - while(seg && send_len < 0xffff) { - /** -- * 1)é历unsent队列,找到所有的待å‘é€seg. å°†segçš„bufä¸²èµ·æ¥ -- * 2) ç”Ÿæˆæ–°çš„seg, 调用tcp_output_segment, æ–°çš„seg释放掉 -- * 3) è‹¥æˆåŠŸï¼Œåˆ™æ›´æ–°snd_nxt, unacked队列,和unsent队列。 -+ * 1) walk unsent queue, find all seg witch wait to send. chain buf in these segs. -+ * 2) create new segment, send and free new segment. -+ * 3) update snd_nxt, unacked queue, and unsent queue - */ - struct tcp_seg *start_seg = seg; - struct pbuf *first_pbuf = NULL; -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 405cf11..fedded9 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -113,7 +113,7 @@ - - #define LWIP_NETIF_API 1 - --#define DEFAULT_TCP_RECVMBOX_SIZE 128 -+#define DEFAULT_TCP_RECVMBOX_SIZE 4096 - - #define DEFAULT_ACCEPTMBOX_SIZE 1024 - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index fef5b6d..a807e3e 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -104,12 +104,10 @@ struct lwip_sock { - char pad1 __rte_cache_aligned; - /* app and stack thread all use */ - uint32_t in_send; /* avoid sock too much send rpc msg*/ -- bool read_wait; - char pad2 __rte_cache_aligned; - /* stack thread all use */ - struct list_node recv_list; - struct list_node send_list; -- struct pbuf *lwip_lastdata; - struct pbuf *send_lastdata; - struct pbuf *send_pre_del; - --- -2.8.4.windows.1 - diff --git a/0050-lwip-reuse-ip-port.patch b/0050-lwip-reuse-ip-port.patch deleted file mode 100644 index 08cdcdd..0000000 --- a/0050-lwip-reuse-ip-port.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 28f8ba80cd733e14e0540c414a18134b3c3fcc94 Mon Sep 17 00:00:00 2001 -From: FanBin -Date: Wed, 15 Feb 2023 10:09:39 +0800 -Subject: [PATCH] lwip reuse ip port - ---- - src/core/tcp.c | 40 +++++++++++++++++++++++++++++--- - src/core/tcp_in.c | 32 +++++++++++++++++++++++++ - src/include/lwip/api.h | 4 ++++ - src/include/lwip/priv/tcp_priv.h | 19 +++++++++++++++ - src/include/lwip/tcp.h | 8 +++++++ - src/include/lwipopts.h | 4 ++++ - 6 files changed, 104 insertions(+), 3 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index f75d214..3171c5e 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -111,6 +111,7 @@ - #include "lwip/ip6.h" - #include "lwip/ip6_addr.h" - #include "lwip/nd6.h" -+#include "lwip/api.h" - - #include - #include -@@ -772,6 +773,9 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - /* Check if the address already is in use (on all lists) */ - for (i = 0; i < max_pcb_list; i++) { - for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { -+#if REUSE_IPPORT -+ continue; -+#else - if (cpcb->local_port == port) { - #if SO_REUSE - /* Omit checking for the same port if both pcbs have REUSEADDR set. -@@ -790,6 +794,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - } - } - } -+#endif /* REUSE_IPORT */ - } - } - } -@@ -921,7 +926,18 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - res = ERR_ALREADY; - goto done; - } --#if SO_REUSE -+ -+#if REUSE_IPPORT -+ struct tcp_pcb_listen *first_same_port_pcb = NULL; -+ for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { -+ if ((lpcb->local_port == pcb->local_port) && -+ ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { -+ /* this address/port is already used */ -+ first_same_port_pcb = lpcb; -+ break; -+ } -+ } -+#else - if (ip_get_option(pcb, SOF_REUSEADDR)) { - /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage - is declared (listen-/connection-pcb), we have to make sure now that -@@ -936,7 +952,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - } - } - } --#endif /* SO_REUSE */ -+#endif /* REUSE_IPPORT */ - - #if USE_LIBOS - vdev_reg_done(REG_RING_TCP_LISTEN, pcb); -@@ -955,6 +971,16 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - lpcb->netif_idx = pcb->netif_idx; - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; -+ -+#if REUSE_IPPORT -+ lpcb->connect_num = 0; -+ lpcb->next_same_port_pcb = NULL; -+ -+ struct netconn* conn = pcb->callback_arg; -+ lpcb->socket_fd = conn->socket; -+ lpcb->master_lpcb = conn->is_master_fd; -+#endif -+ - #if LWIP_IPV4 && LWIP_IPV6 - IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); - #endif /* LWIP_IPV4 && LWIP_IPV6 */ -@@ -979,7 +1005,15 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - lpcb->accepts_pending = 0; - tcp_backlog_set(lpcb, backlog); - #endif /* TCP_LISTEN_BACKLOG */ -- TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); -+ -+#if REUSE_IPPORT -+ if (first_same_port_pcb != NULL) { -+ TCP_REG_SAMEPORT((struct tcp_pcb_listen *)first_same_port_pcb, (struct tcp_pcb_listen *)lpcb); -+ } else -+#endif -+ { -+ TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); -+ } - res = ERR_OK; - done: - if (err != NULL) { -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 35ec6d9..9f5c34a 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -356,6 +356,9 @@ tcp_input(struct pbuf *p, struct netif *inp) - } - } - -+#if REUSE_IPPORT -+ struct tcp_pcb_listen *min_cnts_lpcb = NULL; -+#endif - /* Finally, if we still did not get a match, we check all PCBs that - are LISTENing for incoming connections. */ - prev = NULL; -@@ -379,6 +382,30 @@ tcp_input(struct pbuf *p, struct netif *inp) - } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { - if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { - /* found an exact match */ -+#if REUSE_IPPORT -+ // check master fd -+ struct tcp_pcb_listen *tmp_lpcb = lpcb; -+ u8_t have_master_fd = 0; -+ while (tmp_lpcb != NULL) { -+ if (tmp_lpcb->master_lpcb) { -+ have_master_fd = 1; -+ } -+ tmp_lpcb = tmp_lpcb->next_same_port_pcb; -+ } -+ -+ tmp_lpcb = lpcb; -+ min_cnts_lpcb = lpcb; -+ u16_t min_conn_num = MAX_CONN_NUM_PER_THREAD; -+ while (tmp_lpcb != NULL) { -+ if (!have_master_fd || tmp_lpcb->master_lpcb) { -+ if (tmp_lpcb->connect_num < min_conn_num) { -+ min_cnts_lpcb = tmp_lpcb; -+ min_conn_num = tmp_lpcb->connect_num; -+ } -+ } -+ tmp_lpcb = tmp_lpcb->next_same_port_pcb; -+ } -+#endif - break; - } else if (ip_addr_isany(&lpcb->local_ip)) { - /* found an ANY-match */ -@@ -428,7 +455,12 @@ tcp_input(struct pbuf *p, struct netif *inp) - tcphdr_opt1len, tcphdr_opt2, p) == ERR_OK) - #endif - { -+#if REUSE_IPPORT -+ tcp_listen_input(min_cnts_lpcb); -+ min_cnts_lpcb->connect_num++; -+#else - tcp_listen_input(lpcb); -+#endif - } - pbuf_free(p); - return; -diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h -index 6dec8c0..430a7a0 100644 ---- a/src/include/lwip/api.h -+++ b/src/include/lwip/api.h -@@ -318,6 +318,10 @@ struct netconn { - #endif /* LWIP_TCP */ - /** A callback function that is informed about events for this netconn */ - netconn_callback callback; -+ -+#if REUSE_IPPORT -+ u8_t is_master_fd; -+#endif - }; - - /** This vector type is passed to @ref netconn_write_vectors_partly to send -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index b242428..97f799e 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -353,6 +353,15 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - qtuple.dst_ip = pcb->remote_ip.addr; - qtuple.dst_port = lwip_htons(pcb->remote_port); - -+#if REUSE_IPPORT -+ if (reg_type == REG_RING_TCP_CONNECT_CLOSE) { -+ struct tcp_pcb_listen* lpcb = pcb->listener; -+ if (lpcb != NULL) { -+ lpcb->connect_num--; -+ } -+ } -+#endif -+ - return vdev_reg_xmit(reg_type, &qtuple); - } - static inline void vdev_unreg_done(const struct tcp_pcb *pcb) -@@ -473,6 +482,16 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - tcp_timer_needed(); \ - } while (0) - -+#define TCP_REG_SAMEPORT(first_pcb, lpcb) \ -+ do { \ -+ struct tcp_pcb_listen *tmp_pcb = first_pcb; \ -+ while (tmp_pcb->next_same_port_pcb != NULL) { \ -+ tmp_pcb = tmp_pcb->next_same_port_pcb; \ -+ }; \ -+ tmp_pcb->next_same_port_pcb = lpcb; \ -+ tcp_timer_needed(); \ -+ } while (0) -+ - #define TCP_RMV_HASH(pcbs, npcb) \ - do { \ - hlist_del_init(&(npcb)->tcp_node); \ -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 0b65b01..312320b 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -252,6 +252,14 @@ struct tcp_pcb_listen { - u8_t backlog; - u8_t accepts_pending; - #endif /* TCP_LISTEN_BACKLOG */ -+ -+#if REUSE_IPPORT -+ struct tcp_pcb_listen* next_same_port_pcb; -+ u16_t connect_num; -+ int socket_fd; -+ u8_t master_lpcb; -+#endif -+ - }; - - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index fedded9..be58ec3 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -143,6 +143,10 @@ - - #define USE_LIBOS_ZC_RING 0 - -+#define REUSE_IPPORT 1 -+ -+#define MAX_CONN_NUM_PER_THREAD 65535 -+ - #define SO_REUSE 1 - - #define SIOCSHIWAT 1 --- -2.33.0 - diff --git a/0051-lwip-add-need_tso_send.patch b/0051-lwip-add-need_tso_send.patch deleted file mode 100644 index 5e45768..0000000 --- a/0051-lwip-add-need_tso_send.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 590873482f9b6a5e2635a95720acb37b5f516ab0 Mon Sep 17 00:00:00 2001 -From: kircher -Date: Tue, 21 Feb 2023 15:05:41 +0800 -Subject: [PATCH] lwip add need_tso_send - ---- - src/api/api_msg.c | 1 + - src/core/tcp_out.c | 5 ++++- - src/include/lwip/tcp.h | 2 ++ - 3 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 1fedaad..3a4a473 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -1744,6 +1744,7 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) - write_more = 0; - err = tcp_write(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags); - conn->current_msg->msg.w.len = len; -+ conn->pcb.tcp->need_tso_send = 1; - #else - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); - #endif -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index c538f2a..bf23381 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1473,7 +1473,7 @@ tcp_output(struct tcp_pcb *pcb) - - u32_t send_len = 0; - #if USE_LIBOS -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) { -+ if ((get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) && pcb->need_tso_send) { - while(seg && send_len < 0xffff) { - /** - * 1) walk unsent queue, find all seg witch wait to send. chain buf in these segs. -@@ -1529,6 +1529,7 @@ tcp_output(struct tcp_pcb *pcb) - if (err != ERR_OK) { - if (pcb->unsent == NULL) - pcb->last_unsent = NULL; -+ pcb->need_tso_send = 0; - return err; - } - pcb->unsent = seg->next; -@@ -1552,6 +1553,7 @@ tcp_output(struct tcp_pcb *pcb) - pbuf_remove_header(new_seg.p, new_seg.p->tot_len - new_seg.len - TCPH_HDRLEN_BYTES(new_seg.tcphdr)); - new_seg.p->tot_len = new_seg.p->len; - } -+ pcb->need_tso_send = 0; - } else - #endif - { -@@ -1647,6 +1649,7 @@ tcp_output(struct tcp_pcb *pcb) - #endif /* TCP_OVERSIZE */ - - output_done: -+ pcb->need_tso_send = 0; - if (pcb->unsent == NULL) - pcb->last_unsent = NULL; - tcp_clear_flags(pcb, TF_NAGLEMEMERR); -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 0b65b01..2fc683d 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -409,6 +409,8 @@ struct tcp_pcb { - u8_t snd_scale; - u8_t rcv_scale; - #endif -+ -+ u8_t need_tso_send; - }; - - #if TCP_PCB_HASH --- -2.33.0 - diff --git a/0052-lwip_fnctl-only-support-F_SETFL-F_GETFL.patch b/0052-lwip_fnctl-only-support-F_SETFL-F_GETFL.patch deleted file mode 100644 index 02af140..0000000 --- a/0052-lwip_fnctl-only-support-F_SETFL-F_GETFL.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 40bd7d38bd7a15d22459c4b35cfc7480205a57d9 Mon Sep 17 00:00:00 2001 -From: jiangheng12 -Date: Wed, 22 Feb 2023 20:20:35 +0800 -Subject: [PATCH] lwip_cnctl only support F_SETFL,F_GETFL, other opt return 0 - for compitable - ---- - src/api/sockets.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 9b3f514..2cb6f22 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -4107,7 +4107,12 @@ lwip_fcntl(int s, int cmd, int val) - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); -+#if USE_LIBOS -+ sock_set_errno(sock, 0); /* not yet implemented, but we return 0 for compatilbe with app */ -+ ret = 0; -+#else - sock_set_errno(sock, ENOSYS); /* not yet implemented */ -+#endif - break; - } - done_socket(sock); --- -2.23.0 - diff --git a/0053-cleancode-improve-lwipopts.h-readability.patch b/0053-cleancode-improve-lwipopts.h-readability.patch deleted file mode 100644 index 6996746..0000000 --- a/0053-cleancode-improve-lwipopts.h-readability.patch +++ /dev/null @@ -1,2252 +0,0 @@ -From b42299206a917ed5876c27617de59fb71f8437a7 Mon Sep 17 00:00:00 2001 -From: Lemmy Huang -Date: Thu, 9 Mar 2023 10:57:16 +0800 -Subject: [PATCH] cleancode: improve lwipopts.h readability - -Signed-off-by: Lemmy Huang ---- - src/api/api_msg.c | 12 +- - src/api/sockets.c | 66 ++++----- - src/api/tcpip.c | 18 +-- - src/core/ipv4/etharp.c | 4 +- - src/core/ipv4/icmp.c | 2 +- - src/core/ipv4/ip4.c | 6 +- - src/core/ipv4/ip4_frag.c | 4 +- - src/core/memp.c | 4 +- - src/core/pbuf.c | 8 +- - src/core/tcp.c | 66 ++++----- - src/core/tcp_in.c | 46 +++--- - src/core/tcp_out.c | 36 ++--- - src/core/timeouts.c | 4 +- - src/include/arch/sys_arch.h | 2 +- - src/include/dpdk_cksum.h | 4 +- - src/include/hlist.h | 4 +- - src/include/lwip/api.h | 10 +- - src/include/lwip/ip.h | 4 +- - src/include/lwip/memp.h | 10 +- - src/include/lwip/opt.h | 8 +- - src/include/lwip/pbuf.h | 6 +- - src/include/lwip/priv/memp_std.h | 4 +- - src/include/lwip/priv/tcp_priv.h | 24 ++-- - src/include/lwip/sockets.h | 30 ++-- - src/include/lwip/tcp.h | 16 +-- - src/include/lwip/timeouts.h | 4 +- - src/include/lwiplog.h | 4 +- - src/include/lwipopts.h | 240 +++++++++++++++++-------------- - src/include/lwipsock.h | 8 +- - src/netif/ethernet.c | 2 +- - 30 files changed, 339 insertions(+), 317 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 3a4a473..1840c9d 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -54,7 +54,7 @@ - #include "lwip/mld6.h" - #include "lwip/priv/tcpip_priv.h" - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include "lwip/sockets.h" - #include "lwipsock.h" - #include "posix_api.h" -@@ -341,7 +341,7 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) - #if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - add_recv_list(conn->socket); - LWIP_UNUSED_ARG(len); - #else -@@ -477,7 +477,7 @@ err_tcp(void *arg, err_t err) - if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, mbox_msg); --#if USE_LIBOS -+#if GAZELLE_ENABLE - add_recv_list(conn->socket); - #endif - } -@@ -609,7 +609,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - LWIP_DEBUGF(API_MSG_DEBUG, ("libos incoming connection established\n")); - SET_CONN_TYPE_LIBOS(newconn); - #endif -@@ -1333,7 +1333,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - return ERR_VAL; - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - gazelle_connected_callback(conn); - #endif - -@@ -1738,7 +1738,7 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) - } else { - write_more = 0; - } --#if USE_LIBOS -+#if GAZELLE_ENABLE - /* vector->ptr is private arg sock */ - LWIP_UNUSED_ARG(dataptr); - write_more = 0; -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 2cb6f22..356e345 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -62,7 +62,7 @@ - #include - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include - #include "lwipsock.h" - #include "posix_api.h" -@@ -92,7 +92,7 @@ - #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) - - #if LWIP_IPV4 --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ - (sin)->sin_family = AF_INET; \ - (sin)->sin_port = lwip_htons((port)); \ -@@ -105,7 +105,7 @@ - (sin)->sin_port = lwip_htons((port)); \ - inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ - memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ - inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ - (port) = lwip_ntohs((sin)->sin_port); }while(0) -@@ -271,12 +271,12 @@ static void lwip_socket_drop_registered_mld6_memberships(int s); - #endif /* LWIP_IPV6_MLD */ - - /** The global array of available sockets */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - uint32_t sockets_num; - struct lwip_sock *sockets; - #else - static struct lwip_sock sockets[NUM_SOCKETS]; --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL - #if LWIP_TCPIP_CORE_LOCKING -@@ -431,11 +431,11 @@ tryget_socket_unconn_nouse(int fd) - { - int s = fd - LWIP_SOCKET_OFFSET; - --#if USE_LIBOS -+#if GAZELLE_ENABLE - if ((s < 0) || (s >= sockets_num)) - #else - if ((s < 0) || (s >= NUM_SOCKETS)) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - { - LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); - return NULL; -@@ -500,13 +500,13 @@ tryget_socket(int fd) - * @param fd externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - struct lwip_sock * - get_socket(int fd) - #else - static struct lwip_sock * - get_socket(int fd) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - { - struct lwip_sock *sock = tryget_socket(fd); - if (!sock) { -@@ -519,7 +519,7 @@ get_socket(int fd) - return sock; - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - /** - * Map a externally used socket index to the internal socket representation. - * -@@ -535,7 +535,7 @@ get_socket_by_fd(int fd) - } - return &sockets[fd - LWIP_SOCKET_OFFSET]; - } --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /** - * Allocate a new socket for a given netconn. -@@ -553,7 +553,7 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - SYS_ARCH_DECL_PROTECT(lev); - LWIP_UNUSED_ARG(accepted); - --#if USE_LIBOS -+#if GAZELLE_ENABLE - int type, protocol = 0, domain = AF_INET; - switch (NETCONNTYPE_GROUP(newconn->type)) { - case NETCONN_RAW: -@@ -615,7 +615,7 @@ err: - posix_api->close_fn(i); - SYS_ARCH_UNPROTECT(lev); - return -1; --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - - /* allocate a new socket identifier */ - for (i = 0; i < NUM_SOCKETS; ++i) { -@@ -649,7 +649,7 @@ err: - } - return -1; - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - } - - /** Free a socket (under lock) -@@ -773,12 +773,12 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - done_socket(sock); - return -1; - } --#if USE_LIBOS -+#if GAZELLE_ENABLE - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < sockets_num + LWIP_SOCKET_OFFSET)); - gazelle_init_sock(newsock); - #else - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; - - /* See event_callback: If data comes in right away after an accept, even -@@ -816,13 +816,13 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - } - - IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; - } - #else - *addrlen = LWIP_MIN(*addrlen, sizeof(tempaddr)); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - MEMCPY(addr, &tempaddr, *addrlen); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); -@@ -993,10 +993,10 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) - return -1; - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - LWIP_DEBUGF(SOCKETS_DEBUG, ("libos connect succeed fd=%d\n",s)); - SET_CONN_TYPE_LIBOS(sock->conn); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); - sock_set_errno(sock, 0); -@@ -1065,7 +1065,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - apiflags |= NETCONN_DONTBLOCK; - } - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - do { - struct pbuf *p; - err_t err; -@@ -1146,13 +1146,13 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - } while ((recv_left > 0) && !(flags & MSG_PEEK)); - - lwip_recv_tcp_done: --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - LWIP_UNUSED_ARG(recv_left); - recvd = read_lwip_data(sock, flags, apiflags); - if (recvd <= 0) { - return recvd; - } --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - if (apiflags & NETCONN_NOAUTORCVD) { - if ((recvd > 0) && !(flags & MSG_PEEK)) { - /* ensure window update after copying all data */ -@@ -1188,7 +1188,7 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, - #endif /* LWIP_IPV4 && LWIP_IPV6 */ - - IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - if (*fromlen < saddr.sa.sa_len) { - truncated = 1; - } else if (*fromlen > saddr.sa.sa_len) { -@@ -2692,7 +2692,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - if (sock->rcvevent > 1) { - check_waiters = 0; - } --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (conn->acceptmbox != NULL && !sys_mbox_empty(conn->acceptmbox)) { - add_sock_event(sock, POLLIN); - } -@@ -2714,7 +2714,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; --#if USE_LIBOS -+#if GAZELLE_ENABLE - add_sock_event(sock, EPOLLERR); - #endif - break; -@@ -2911,7 +2911,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) - ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - if (*namelen > saddr.sa.sa_len) { - *namelen = saddr.sa.sa_len; - } -@@ -3052,7 +3052,7 @@ lwip_sockopt_to_ipopt(int optname) - return SOF_KEEPALIVE; - case SO_REUSEADDR: - return SOF_REUSEADDR; --#if USE_LIBOS -+#if GAZELLE_ENABLE - case SO_REUSEPORT: - return SO_REUSEPORT; - #endif -@@ -3928,7 +3928,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ - return err; - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - int - lwip_ioctl(int s, long cmd, ...) - { -@@ -3963,7 +3963,7 @@ lwip_ioctl(int s, long cmd, void *argp) - if (!sock) { - return -1; - } --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - switch (cmd) { - #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE -@@ -4107,7 +4107,7 @@ lwip_fcntl(int s, int cmd, int val) - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); --#if USE_LIBOS -+#if GAZELLE_ENABLE - sock_set_errno(sock, 0); /* not yet implemented, but we return 0 for compatilbe with app */ - ret = 0; - #else -@@ -4375,7 +4375,7 @@ lwip_socket_drop_registered_mld6_memberships(int s) - } - #endif /* LWIP_IPV6_MLD */ - --#if USE_LIBOS -+#if GAZELLE_ENABLE - void lwip_sock_init(void) - { - if (sockets_num == 0) { -@@ -4400,6 +4400,6 @@ void lwip_exit(void) - return; - } - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #endif /* LWIP_SOCKET */ -diff --git a/src/api/tcpip.c b/src/api/tcpip.c -index d3d0b55..fe7a7bd 100644 ---- a/src/api/tcpip.c -+++ b/src/api/tcpip.c -@@ -123,13 +123,13 @@ again: - * - * @param arg unused argument - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - __attribute__((unused)) static void - tcpip_thread(void *arg) - #else - static void - tcpip_thread(void *arg) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - { - struct tcpip_msg *msg; - LWIP_UNUSED_ARG(arg); -@@ -247,7 +247,7 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) - #if LWIP_TCPIP_CORE_LOCKING_INPUT - err_t ret; - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); --#if USE_LIBOS && LWIP_TIMERS -+#if GAZELLE_ENABLE && LWIP_TIMERS - sys_timer_run(); - #endif - LOCK_TCPIP_CORE(); -@@ -329,7 +329,7 @@ tcpip_callback(tcpip_callback_fn function, void *ctx) - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - --#if USE_LIBOS && LWIP_TIMER -+#if GAZELLE_ENABLE && LWIP_TIMER - sys_timer_run(); - #endif - sys_mbox_post(&tcpip_mbox, msg); -@@ -368,7 +368,7 @@ tcpip_try_callback(tcpip_callback_fn function, void *ctx) - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - --#if USE_LIBOS && LWIP_TIMER -+#if GAZELLE_ENABLE && LWIP_TIMER - sys_timer_run(); - #endif - if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { -@@ -452,7 +452,7 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) - { - #if LWIP_TCPIP_CORE_LOCKING - LWIP_UNUSED_ARG(sem); --#if USE_LIBOS && LWIP_TIMERS -+#if GAZELLE_ENABLE && LWIP_TIMERS - sys_timer_run(); - #endif - LOCK_TCPIP_CORE(); -@@ -492,7 +492,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) - #if LWIP_TCPIP_CORE_LOCKING - err_t err; - LOCK_TCPIP_CORE(); --#if USE_LIBOS && LWIP_TIMERS -+#if GAZELLE_ENABLE && LWIP_TIMERS - sys_timer_run(); - #endif - err = fn(call); -@@ -558,7 +558,7 @@ tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - --#if USE_LIBOS && LWIP_TIMER -+#if GAZELLE_ENABLE && LWIP_TIMER - sys_timer_run(); - #endif - return (struct tcpip_callback_msg *)msg; -@@ -638,7 +638,7 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg) - } - #endif /* LWIP_TCPIP_CORE_LOCKING */ - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); - #endif - } -diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c -index f1903e4..5a1a834 100644 ---- a/src/core/ipv4/etharp.c -+++ b/src/core/ipv4/etharp.c -@@ -482,7 +482,7 @@ etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct et - struct pbuf *p = arp_table[i].q; - arp_table[i].q = NULL; - #endif /* ARP_QUEUEING */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - struct pbuf *tmp = p->next; - while (tmp != NULL) { - tmp->ref--; -@@ -1034,7 +1034,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) - } else { - /* referencing the old pbuf is enough */ - p = q; --#if USE_LIBOS -+#if GAZELLE_ENABLE - struct pbuf *tmp = p; - while (tmp != NULL) { - pbuf_ref(tmp); -diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c -index c58ae25..402ba69 100644 ---- a/src/core/ipv4/icmp.c -+++ b/src/core/ipv4/icmp.c -@@ -51,7 +51,7 @@ - - #include - --#if USE_LIBOS && CHECKSUM_GEN_IP_HW -+#if GAZELLE_ENABLE && CHECKSUM_GEN_IP_HW - #include "dpdk_cksum.h" - #endif - -diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c -index d823491..1b70bb5 100644 ---- a/src/core/ipv4/ip4.c -+++ b/src/core/ipv4/ip4.c -@@ -59,7 +59,7 @@ - - #include - --#if USE_LIBOS && (CHECKSUM_CHECK_IP_HW || CHECKSUM_GEN_IP_HW) -+#if GAZELLE_ENABLE && (CHECKSUM_CHECK_IP_HW || CHECKSUM_GEN_IP_HW) - #include "dpdk_cksum.h" - #endif - -@@ -1034,13 +1034,13 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d - #endif /* ENABLE_LOOPBACK */ - #if IP_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (!(get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO)) { - #endif - if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip4_frag(p, netif, dest); - } --#if USE_LIBOS -+#if GAZELLE_ENABLE - } - #endif - #endif /* IP_FRAG */ -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index c60523d..f15b798 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -51,7 +51,7 @@ - - #include - --#if USE_LIBOS && CHECKSUM_GEN_IP_HW -+#if GAZELLE_ENABLE && CHECKSUM_GEN_IP_HW - #include "dpdk_cksum.h" - #endif - -@@ -115,7 +115,7 @@ PACK_STRUCT_END - IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 - - /* global variables */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - static PER_THREAD struct ip_reassdata *reassdatagrams; - static PER_THREAD u16_t ip_reass_pbufcount; - #else -diff --git a/src/core/memp.c b/src/core/memp.c -index 454ba32..fca1b0c 100644 ---- a/src/core/memp.c -+++ b/src/core/memp.c -@@ -78,14 +78,14 @@ - #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) - #include "lwip/priv/memp_std.h" - --#if USE_LIBOS -+#if GAZELLE_ENABLE - PER_THREAD struct memp_desc* memp_pools[MEMP_MAX] = {NULL}; - #else - const struct memp_desc *const memp_pools[MEMP_MAX] = { - #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, - #include "lwip/priv/memp_std.h" - }; --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index ad75aa6..dd71519 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -83,7 +83,7 @@ - #if LWIP_CHECKSUM_ON_COPY - #include "lwip/inet_chksum.h" - #endif --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include - #endif - -@@ -284,7 +284,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - } - - /* If pbuf is to be allocated in RAM, allocate memory for it. */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - /* alloc mbuf avoid send copy */ - p = lwip_alloc_pbuf(layer, length, type); - #else -@@ -753,7 +753,7 @@ pbuf_free(struct pbuf *p) - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (p->next) - rte_prefetch0(p->next); - #endif -@@ -1027,7 +1027,7 @@ pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_ - len_calc = p_to->len - offset_to; - } - --#if USE_LIBOS && (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW) -+#if GAZELLE_ENABLE && (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW) - p_to->l2_len = p_from->l2_len; - p_to->l3_len = p_from->l3_len; - p_to->ol_flags = p_from->ol_flags; -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 3171c5e..69a39f6 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -183,7 +183,7 @@ PER_THREAD struct tcp_pcb *tcp_tw_pcbs; - /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ - PER_THREAD struct tcp_pcb ** tcp_pcb_lists[NUM_TCP_PCB_LISTS] = {NULL, NULL, NULL, NULL}; - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - #define INIT_TCP_HTABLE(ht_ptr) \ - do { \ - int _i; \ -@@ -203,7 +203,7 @@ PER_THREAD u8_t tcp_active_pcbs_changed; - /** Timer counter to handle calling slow-timer from tcp_tmr() */ - static PER_THREAD u8_t tcp_timer; - static PER_THREAD u8_t tcp_timer_ctr; --#if USE_LIBOS -+#if GAZELLE_ENABLE - static u16_t tcp_new_port(struct tcp_pcb *pcb); - #else - static u16_t tcp_new_port(void); -@@ -214,7 +214,7 @@ static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); - static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - static u8_t port_state[TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START + 1] = {0}; - void release_port(u16_t port) - { -@@ -238,7 +238,7 @@ tcp_init(void) - tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); - #endif /* LWIP_RAND */ - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - tcp_active_htable = (struct tcp_hash_table*)mem_malloc(sizeof(struct tcp_hash_table)); - LWIP_ASSERT("malloc tcp_active_htable mem failed.", tcp_active_htable != NULL); - INIT_TCP_HTABLE(tcp_active_htable); -@@ -249,7 +249,7 @@ tcp_init(void) - void - tcp_free(struct tcp_pcb *pcb) - { --#if USE_LIBOS -+#if GAZELLE_ENABLE - vdev_unreg_done(pcb); - release_port(pcb->local_port); - #endif -@@ -405,7 +405,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) - pcb->local_port, pcb->remote_port); - - tcp_pcb_purge(pcb); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_RMV_ACTIVE_HASH(pcb); - #endif - TCP_RMV_ACTIVE(pcb); -@@ -442,7 +442,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) - tcp_free_listen(pcb); - break; - case SYN_SENT: --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_PCB_REMOVE_ACTIVE_HASH(pcb); - #endif - TCP_PCB_REMOVE_ACTIVE(pcb); -@@ -650,7 +650,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) - } else { - send_rst = reset; - local_port = pcb->local_port; --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_PCB_REMOVE_ACTIVE_HASH(pcb); - #endif - TCP_PCB_REMOVE_ACTIVE(pcb); -@@ -761,7 +761,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - if (port == 0) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - port = tcp_new_port(pcb); - #else - port = tcp_new_port(); -@@ -773,7 +773,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - /* Check if the address already is in use (on all lists) */ - for (i = 0; i < max_pcb_list; i++) { - for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - continue; - #else - if (cpcb->local_port == port) { -@@ -927,7 +927,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - goto done; - } - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - struct tcp_pcb_listen *first_same_port_pcb = NULL; - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if ((lpcb->local_port == pcb->local_port) && -@@ -952,9 +952,9 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - } - } - } --#endif /* REUSE_IPPORT */ -+#endif /* GAZELLE_TCP_REUSE_IPPORT */ - --#if USE_LIBOS -+#if GAZELLE_ENABLE - vdev_reg_done(REG_RING_TCP_LISTEN, pcb); - #endif - -@@ -972,7 +972,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - lpcb->connect_num = 0; - lpcb->next_same_port_pcb = NULL; - -@@ -992,7 +992,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - /* copy over ext_args to listening pcb */ - memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args)); - #endif --#if USE_LIBOS -+#if GAZELLE_ENABLE - /* pcb transfer to lpcb and reg into tcp_listen_pcbs. freeing pcb shouldn't release sock table in here. - * local_port=0 avoid to release sock table in tcp_free */ - pcb->local_port = 0; -@@ -1006,7 +1006,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - tcp_backlog_set(lpcb, backlog); - #endif /* TCP_LISTEN_BACKLOG */ - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - if (first_same_port_pcb != NULL) { - TCP_REG_SAMEPORT((struct tcp_pcb_listen *)first_same_port_pcb, (struct tcp_pcb_listen *)lpcb); - } else -@@ -1109,7 +1109,7 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) - * - * @return a new (free) local TCP port number - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - static u16_t - tcp_new_port(struct tcp_pcb *pcb) - #else -@@ -1128,7 +1128,7 @@ tcp_new_port(void) - } - - if (__atomic_load_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (port_in_stack_queue(pcb->remote_ip.addr, pcb->local_ip.addr, pcb->remote_port, tcp_port)) { - tmp_port = tcp_port; - __atomic_store_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); -@@ -1231,7 +1231,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - - old_local_port = pcb->local_port; - if (pcb->local_port == 0) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - pcb->local_port = tcp_new_port(pcb); - #else - pcb->local_port = tcp_new_port(); -@@ -1289,7 +1289,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - /* Send a SYN together with the MSS option. */ - ret = tcp_enqueue_flags(pcb, TCP_SYN); - if (ret == ERR_OK) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - vdev_reg_done(REG_RING_TCP_CONNECT, pcb); - #endif - -@@ -1298,7 +1298,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - if (old_local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_REG_ACTIVE_HASH(pcb); - #endif - TCP_REG_ACTIVE(pcb); -@@ -1516,7 +1516,7 @@ tcp_slowtmr_start: - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); - prev->next = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pcb->next) - pcb->next->prev = prev; - //dont set next NULL, it will be used below -@@ -1526,14 +1526,14 @@ tcp_slowtmr_start: - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); - tcp_active_pcbs = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pcb->next) - pcb->next->prev = NULL; - //dont set next NULL, it will be used below - pcb->prev = NULL; - #endif - } --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_RMV_ACTIVE_HASH(pcb); - #endif - -@@ -1546,7 +1546,7 @@ tcp_slowtmr_start: - last_state = pcb->state; - pcb2 = pcb; - pcb = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - pcb2->next = NULL; - #endif - tcp_free(pcb2); -@@ -1600,7 +1600,7 @@ tcp_slowtmr_start: - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); - prev->next = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pcb->next) - pcb->next->prev = prev; - //dont set next NULL, it will be used below -@@ -1610,7 +1610,7 @@ tcp_slowtmr_start: - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); - tcp_tw_pcbs = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pcb->next) - pcb->next->prev = NULL; - //dont set next NULL, it will be used below -@@ -1619,7 +1619,7 @@ tcp_slowtmr_start: - } - pcb2 = pcb; - pcb = pcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - pcb2->next = NULL; - #endif - tcp_free(pcb2); -@@ -1790,7 +1790,7 @@ tcp_seg_free(struct tcp_seg *seg) - seg->p = NULL; - #endif /* TCP_DEBUG */ - } --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - memp_free(MEMP_TCP_SEG, seg); - #endif - } -@@ -1828,7 +1828,7 @@ tcp_seg_copy(struct tcp_seg *seg) - - LWIP_ASSERT("tcp_seg_copy: invalid seg", seg != NULL); - --#if USE_LIBOS -+#if GAZELLE_ENABLE - cseg = (struct tcp_seg *)((uint8_t *)seg->p + sizeof(struct pbuf_custom)); - #else - cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); -@@ -2371,7 +2371,7 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - #endif /* TCP_QUEUE_OOSEQ */ - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - vdev_unreg_done(pcb); - release_port(pcb->local_port); - #endif -@@ -2383,13 +2383,13 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) - LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); - } - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - void - tcp_pcb_remove_hash(struct tcp_hash_table *htb, struct tcp_pcb *pcb) - { - TCP_RMV_HASH(htb, pcb); - } --#endif /* TCP_PCB_HASH */ -+#endif /* GAZELLE_TCP_PCB_HASH */ - - /** - * Calculates a new initial sequence number for new connections. -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 9f5c34a..dd83260 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -58,13 +58,13 @@ - #if LWIP_ND6_TCP_REACHABILITY_HINTS - #include "lwip/nd6.h" - #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include "lwip/api.h" - #endif - - #include - --#if USE_LIBOS && CHECKSUM_CHECK_TCP_HW -+#if GAZELLE_ENABLE && CHECKSUM_CHECK_TCP_HW - #include - #endif /* CHECKSUM_CHECK_TCP_HW */ - -@@ -134,7 +134,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - u8_t hdrlen_bytes; - err_t err; - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - u32_t idx; - struct hlist_head *head; - struct hlist_node *node; -@@ -277,7 +277,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - for an active connection. */ - prev = NULL; - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - idx = TUPLE4_HASH_FN( ip_current_dest_addr()->addr, tcphdr->dest, - ip_current_src_addr()->addr, tcphdr->src) & - (tcp_active_htable->size - 1); -@@ -301,7 +301,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { --#if !TCP_PCB_HASH -+#if !GAZELLE_TCP_PCB_HASH - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ -@@ -317,7 +317,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - #endif - break; - } --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - pcb = NULL; - #else - prev = pcb; -@@ -356,7 +356,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - } - } - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - struct tcp_pcb_listen *min_cnts_lpcb = NULL; - #endif - /* Finally, if we still did not get a match, we check all PCBs that -@@ -382,7 +382,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { - if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { - /* found an exact match */ --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - // check master fd - struct tcp_pcb_listen *tmp_lpcb = lpcb; - u8_t have_master_fd = 0; -@@ -395,7 +395,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - - tmp_lpcb = lpcb; - min_cnts_lpcb = lpcb; -- u16_t min_conn_num = MAX_CONN_NUM_PER_THREAD; -+ u16_t min_conn_num = GAZELLE_TCP_MAX_CONN_PER_THREAD; - while (tmp_lpcb != NULL) { - if (!have_master_fd || tmp_lpcb->master_lpcb) { - if (tmp_lpcb->connect_num < min_conn_num) { -@@ -434,13 +434,13 @@ tcp_input(struct pbuf *p, struct netif *inp) - arrivals). */ - if (prev != NULL) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (lpcb->next) - lpcb->next->prev = (struct tcp_pcb_listen *)prev; - #endif - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; --#if USE_LIBOS -+#if GAZELLE_ENABLE - lpcb->prev = NULL; - #endif - /* put this listening pcb at the head of the listening list */ -@@ -455,7 +455,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - tcphdr_opt1len, tcphdr_opt2, p) == ERR_OK) - #endif - { --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - tcp_listen_input(min_cnts_lpcb); - min_cnts_lpcb->connect_num++; - #else -@@ -528,7 +528,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - application that the connection is dead before we - deallocate the PCB. */ - TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - tcp_pcb_remove_hash(tcp_active_htable, pcb); - #endif - tcp_pcb_remove(&tcp_active_pcbs, pcb); -@@ -710,7 +710,7 @@ tcp_input_delayed_close(struct tcp_pcb *pcb) - ensure the application doesn't continue using the PCB. */ - TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); - } --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - tcp_pcb_remove_hash(tcp_active_htable, pcb); - #endif - tcp_pcb_remove(&tcp_active_pcbs, pcb); -@@ -799,12 +799,12 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - npcb->netif_idx = pcb->netif_idx; - /* Register the new PCB so that we can begin receiving segments - for it. */ --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_REG_ACTIVE_HASH(npcb); - #endif - TCP_REG_ACTIVE(npcb); - --#if USE_LIBOS -+#if GAZELLE_ENABLE - vdev_reg_done(REG_RING_TCP_CONNECT, npcb); - #endif - -@@ -1102,7 +1102,7 @@ tcp_process(struct tcp_pcb *pcb) - if (recv_flags & TF_GOT_FIN) { - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; --#if USE_LIBOS -+#if GAZELLE_ENABLE - API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); - #endif - } -@@ -1120,7 +1120,7 @@ tcp_process(struct tcp_pcb *pcb) - if (recv_flags & TF_GOT_FIN) { /* passive close */ - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; --#if USE_LIBOS -+#if GAZELLE_ENABLE - API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); - #endif - } -@@ -1134,7 +1134,7 @@ tcp_process(struct tcp_pcb *pcb) - ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_RMV_ACTIVE_HASH(pcb); - #endif - TCP_RMV_ACTIVE(pcb); -@@ -1155,7 +1155,7 @@ tcp_process(struct tcp_pcb *pcb) - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_RMV_ACTIVE_HASH(pcb); - #endif - TCP_RMV_ACTIVE(pcb); -@@ -1168,7 +1168,7 @@ tcp_process(struct tcp_pcb *pcb) - if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_pcb_purge(pcb); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - TCP_RMV_ACTIVE_HASH(pcb); - #endif - TCP_RMV_ACTIVE(pcb); -@@ -1377,7 +1377,7 @@ tcp_receive(struct tcp_pcb *pcb) - if (pcb->lastack == ackno) { - found_dataack = 1; - ++pcb->dataacks; -- if (pcb->dataacks > MAX_DATA_ACK_NUM) { -+ if (pcb->dataacks > GAZELLE_TCP_MAX_DATA_ACK_NUM) { - if (tcp_rexmit(pcb) == ERR_OK) { - pcb->rtime = 0; - pcb->dataacks = 0; -@@ -1775,7 +1775,7 @@ tcp_receive(struct tcp_pcb *pcb) - recv_flags |= TF_GOT_FIN; - if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ - pcb->state = CLOSE_WAIT; --#if USE_LIBOS -+#if GAZELLE_ENABLE - API_EVENT(((struct netconn *)pcb->callback_arg), NETCONN_EVT_ERROR, 0); - #endif - } -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index bf23381..1b3c5af 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -80,7 +80,7 @@ - - #include - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include "lwipsock.h" - #include - #if CHECKSUM_GEN_TCP_HW -@@ -162,7 +162,7 @@ tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) - * The TCP header is filled in except ackno and wnd. - * p is freed on failure. - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - void tcp_init_segment(struct tcp_seg *seg, const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, - u32_t seqno, u8_t optflags) - { -@@ -515,7 +515,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - * pos records progress as data is segmented. - */ - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; -@@ -631,9 +631,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - pcb->unsent_oversize == 0); - #endif /* TCP_OVERSIZE */ - } --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - last_unsent = pcb->last_unsent; --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /* - * Phase 3: Create new segments. -@@ -651,7 +651,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - u8_t chksum_swapped = 0; - #endif /* TCP_CHECKSUM_ON_COPY */ - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ -@@ -698,13 +698,13 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(p/*header*/, p2/*data*/); - } --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - p = write_lwip_data((struct lwip_sock *)arg, len - pos, &apiflags); - if (p == NULL) { - break; - } - seglen = p->tot_len; --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - queuelen += pbuf_clen(p); - -@@ -714,7 +714,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", - queuelen, (int)TCP_SND_QUEUELEN)); --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pos > 0) { - queuelen -= pbuf_clen(p); - break; -@@ -726,7 +726,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - } - - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (pos > 0) { - queuelen -= pbuf_clen(p); - break; -@@ -759,7 +759,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; --#if USE_LIBOS -+#if GAZELLE_ENABLE - write_lwip_over((struct lwip_sock*)arg); - #endif - } -@@ -847,7 +847,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - /* - * Finally update the pcb state. - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - if (queue) { - pcb->last_unsent = prev_seg; - } -@@ -876,7 +876,7 @@ memerr: - tcp_set_flags(pcb, TF_NAGLEMEMERR); - TCP_STATS_INC(tcp.memerr); - --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - if (concat_p != NULL) { - pbuf_free(concat_p); - } -@@ -1307,7 +1307,7 @@ tcp_build_wnd_scale_option(u32_t *opts) - } - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg, struct tcp_seg *useg) - { - if (TCP_TCPLEN(seg) > 0) { -@@ -1472,7 +1472,7 @@ tcp_output(struct tcp_pcb *pcb) - /* data available and window allows it to be sent? */ - - u32_t send_len = 0; --#if USE_LIBOS -+#if GAZELLE_ENABLE - if ((get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) && pcb->need_tso_send) { - while(seg && send_len < 0xffff) { - /** -@@ -1485,7 +1485,7 @@ tcp_output(struct tcp_pcb *pcb) - struct pbuf *pre_pbuf = NULL; - u8_t pbuf_chain_len = 0; - u32_t next_seqno = lwip_ntohl(seg->tcphdr->seqno); -- while (seg != NULL && pbuf_chain_len < MAX_PBUF_CHAIN_LEN) { -+ while (seg != NULL && pbuf_chain_len < GAZELLE_TCP_MAX_PBUF_CHAIN_LEN) { - u32_t seg_seqno = lwip_ntohl(seg->tcphdr->seqno); - if (seg_seqno - pcb->lastack + seg->len > wnd) { - if (first_pbuf) -@@ -1501,7 +1501,7 @@ tcp_output(struct tcp_pcb *pcb) - goto output_done; - } - -- if (seg->len < TCP_MSS || next_seqno != seg_seqno || pbuf_chain_len >= MAX_PBUF_CHAIN_LEN) { -+ if (seg->len < TCP_MSS || next_seqno != seg_seqno || pbuf_chain_len >= GAZELLE_TCP_MAX_PBUF_CHAIN_LEN) { - break; - } - if (first_pbuf == NULL && (seg->next == NULL || seg->next->len < TCP_MSS)) { -@@ -1771,7 +1771,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - } - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - /* pbuf into mbuf. ref dpdk_common.h */ - rte_prefetch0((uint8_t *)(seg->p) - sizeof(struct rte_mbuf) - sizeof(uint64_t) * 2); - #endif -diff --git a/src/core/timeouts.c b/src/core/timeouts.c -index 0542a32..2b80b0a 100644 ---- a/src/core/timeouts.c -+++ b/src/core/timeouts.c -@@ -442,7 +442,7 @@ sys_timeouts_sleeptime(void) - } - } - --#if USE_LIBOS -+#if GAZELLE_ENABLE - void sys_timer_run(void) - { - u32_t sleeptime; -@@ -452,7 +452,7 @@ void sys_timer_run(void) - sys_check_timeouts(); - } - } --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ - /* Satisfy the TCP code which calls this function */ -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -index fc4a9fd..04e3192 100644 ---- a/src/include/arch/sys_arch.h -+++ b/src/include/arch/sys_arch.h -@@ -76,7 +76,7 @@ int sys_mbox_empty(struct sys_mbox *); - struct sys_thread; - typedef struct sys_thread *sys_thread_t; - --#if USE_LIBOS -+#if GAZELLE_ENABLE - extern int eth_dev_poll(void); - #include - -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index 83c9c38..df2e2a5 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -34,7 +34,7 @@ - #define __DPDK_CKSUM_H__ - - #include "lwipopts.h" --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include - - #if CHECKSUM_OFFLOAD_ALL -@@ -103,5 +103,5 @@ static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, - } - #endif /* CHECKSUM_GEN_TCP_HW */ - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #endif /* __DPDK_CKSUM_H__ */ -diff --git a/src/include/hlist.h b/src/include/hlist.h -index 7059488..988b017 100644 ---- a/src/include/hlist.h -+++ b/src/include/hlist.h -@@ -35,7 +35,7 @@ - - #include "list.h" - --//#if TCP_PCB_HASH -+//#if GAZELLE_TCP_PCB_HASH - struct hlist_node { - /** - * @pprev: point the previous node's next pointer -@@ -228,6 +228,6 @@ static inline void hlist_ctl_add_after(struct hlist_node *n, struct hlist_node * - ctl->tail.end = next; - } - } --//#endif /* TCP_PCB_HASH */ -+//#endif /* GAZELLE_TCP_PCB_HASH */ - - #endif /* __HLIST_H__ */ -diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h -index 430a7a0..197faef 100644 ---- a/src/include/lwip/api.h -+++ b/src/include/lwip/api.h -@@ -141,16 +141,16 @@ enum netconn_type { - , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ - #endif /* LWIP_IPV6 */ - --#if USE_LIBOS -+#if GAZELLE_ENABLE - /*here must bigger than 0xff, because (type & 0xff) is for lwip inner use*/ - , NETCONN_LIBOS = 0x100 - , NETCONN_HOST = 0x200 - , NETCONN_INPRG = 0x400 - , NETCONN_STACK = NETCONN_LIBOS | NETCONN_HOST | NETCONN_INPRG --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - }; - --#ifdef USE_LIBOS -+#ifdef GAZELLE_ENABLE - #define SET_CONN_TYPE_LIBOS_OR_HOST(conn) do { \ - conn->type &= ~(NETCONN_STACK); \ - conn->type |= (NETCONN_LIBOS | NETCONN_HOST); } while (0) -@@ -175,7 +175,7 @@ enum netconn_type { - #define CONN_TYPE_HAS_LIBOS_AND_HOST(conn) (0) - #define CONN_TYPE_HAS_LIBOS(conn) (0) - #define CONN_TYPE_HAS_HOST(conn) (0) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /** Current state of the netconn. Non-TCP netconns are always - * in state NETCONN_NONE! */ -@@ -319,7 +319,7 @@ struct netconn { - /** A callback function that is informed about events for this netconn */ - netconn_callback callback; - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - u8_t is_master_fd; - #endif - }; -diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h -index 7f55fb3..1c6988b 100644 ---- a/src/include/lwip/ip.h -+++ b/src/include/lwip/ip.h -@@ -97,7 +97,7 @@ struct ip_pcb { - /* - * Option flags per-socket. These are the same like SO_XXX in sockets.h - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define SOF_REUSEADDR 0x02U /* allow local address reuse */ - #define SOF_KEEPALIVE 0x09U /* keep connections alive */ - #define SOF_BROADCAST 0x06U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -@@ -105,7 +105,7 @@ struct ip_pcb { - #define SOF_REUSEADDR 0x04U /* allow local address reuse */ - #define SOF_KEEPALIVE 0x08U /* keep connections alive */ - #define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ - #define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) -diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h -index 64d8f31..1763836 100644 ---- a/src/include/lwip/memp.h -+++ b/src/include/lwip/memp.h -@@ -58,11 +58,11 @@ typedef enum { - #include "lwip/priv/memp_priv.h" - #include "lwip/stats.h" - --#if USE_LIBOS -+#if GAZELLE_ENABLE - extern PER_THREAD struct memp_desc* memp_pools[MEMP_MAX]; - #else - extern const struct memp_desc* const memp_pools[MEMP_MAX]; --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /** - * @ingroup mempool -@@ -96,7 +96,7 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX]; - * To relocate a pool, declare it as extern in cc.h. Example for GCC: - * extern u8_t \_\_attribute\_\_((section(".onchip_mem"))) memp_memory_my_private_pool_base[]; - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ - PER_THREAD struct memp_desc memp_ ## name = {0}; \ - PER_THREAD char memp_desc_ ## name[] = desc; \ -@@ -106,7 +106,7 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX]; - PER_THREAD struct memp *memp_tab_ ## name = NULL; \ - LWIP_DECLARE_MEMP_BASE_ALIGNED(name, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); - --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - - #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ - LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ -@@ -124,7 +124,7 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX]; - &memp_tab_ ## name \ - }; - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #endif /* MEMP_MEM_MALLOC */ - - /** -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 718816b..0376f60 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -3525,7 +3525,7 @@ - /** - * EPOLL_DEBUG: Enable debugging in epoll.c. - */ --#if !defined EPOLL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#if !defined EPOLL_DEBUG || defined __DOXYGEN__ && GAZELLE_ENABLE - #define EPOLL_DEBUG LWIP_DBG_OFF - #endif - /** -@@ -3535,7 +3535,7 @@ - /** - * ETHDEV_DEBUG: Enable debugging in ethdev.c. - */ --#if !defined ETHDEV_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#if !defined ETHDEV_DEBUG || defined __DOXYGEN__ && GAZELLE_ENABLE - #define ETHDEV_DEBUG LWIP_DBG_OFF - #endif - /** -@@ -3545,7 +3545,7 @@ - /** - * ETHDEV_DEBUG: Enable debugging in ethdev.c. - */ --#if !defined SYSCALL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#if !defined SYSCALL_DEBUG || defined __DOXYGEN__ && GAZELLE_ENABLE - #define SYSCALL_DEBUG LWIP_DBG_OFF - #endif - /** -@@ -3555,7 +3555,7 @@ - /** - * CONTROL_DEBUG: Enable debugging in control_plane.c. - */ --#if !defined CONTROL_DEBUG || defined __DOXYGEN__ && USE_LIBOS -+#if !defined CONTROL_DEBUG || defined __DOXYGEN__ && GAZELLE_ENABLE - #define CONTROL_DEBUG LWIP_DBG_ON - #endif - /** -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 1124408..a2e8e01 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -220,7 +220,7 @@ struct pbuf { - /** For incoming packets, this contains the input netif's index */ - u8_t if_idx; - --#if USE_LIBOS && CHECKSUM_OFFLOAD_ALL -+#if GAZELLE_ENABLE && CHECKSUM_OFFLOAD_ALL - /** checksum offload ol_flags */ - u64_t ol_flags; - /* < L2 (MAC) Header Length for non-tunneling pkt. */ -@@ -234,7 +234,7 @@ struct pbuf { - u8_t in_write; - u8_t head; - struct pbuf *last; --#endif /* USE_LIBOS CHECKSUM_OFFLOAD_SWITCH */ -+#endif /* GAZELLE_ENABLE CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ - LWIP_PBUF_CUSTOM_DATA -@@ -287,7 +287,7 @@ void pbuf_free_ooseq(void); - - /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ - #define pbuf_init() --#if USE_LIBOS -+#if GAZELLE_ENABLE - struct pbuf *lwip_alloc_pbuf(pbuf_layer layer, uint16_t length, pbuf_type type); - #endif - struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); -diff --git a/src/include/lwip/priv/memp_std.h b/src/include/lwip/priv/memp_std.h -index 395ac0c..66d7e4e 100644 ---- a/src/include/lwip/priv/memp_std.h -+++ b/src/include/lwip/priv/memp_std.h -@@ -122,13 +122,13 @@ LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), - #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #if !LWIP_NETCONN_SEM_PER_THREAD - LWIP_MEMPOOL(SYS_SEM, MEMP_NUM_SYS_SEM, sizeof(struct sys_sem), "SYS_SEM") - #endif - - LWIP_MEMPOOL(SYS_MBOX, MEMP_NUM_SYS_MBOX, sizeof(struct sys_mbox), "SYS_MBOX") --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - /* - * A list of pools of pbuf's used by LWIP. - * -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index 97f799e..ddae3fd 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -340,7 +340,7 @@ extern PER_THREAD struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in T - #define NUM_TCP_PCB_LISTS 4 - extern PER_THREAD struct tcp_pcb ** tcp_pcb_lists[NUM_TCP_PCB_LISTS]; - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include "reg_sock.h" - static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pcb *pcb) - { -@@ -353,7 +353,7 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - qtuple.dst_ip = pcb->remote_ip.addr; - qtuple.dst_port = lwip_htons(pcb->remote_port); - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - if (reg_type == REG_RING_TCP_CONNECT_CLOSE) { - struct tcp_pcb_listen* lpcb = pcb->listener; - if (lpcb != NULL) { -@@ -389,7 +389,7 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - #define TCP_DEBUG_PCB_LISTS 0 - #endif - #if TCP_DEBUG_PCB_LISTS --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define TCP_REG(pcbs, npcb) do {\ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ -@@ -432,7 +432,7 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ - } while(0) - --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - #define TCP_REG(pcbs, npcb) do {\ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %"U16_F"\n", (void *)(npcb), (npcb)->local_port)); \ -@@ -465,10 +465,10 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (void *)(npcb), (void *)(*(pcbs)))); \ - } while(0) - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #else /* LWIP_DEBUG */ - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - #define TCP_REG_HASH(pcbs, npcb) \ - do { \ - u32_t idx; \ -@@ -496,9 +496,9 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - do { \ - hlist_del_init(&(npcb)->tcp_node); \ - } while (0) --#endif /* TCP_PCB_HASH */ -+#endif /* GAZELLE_TCP_PCB_HASH */ - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define TCP_REG(pcbs, npcb) \ - do { \ - if (*pcbs) \ -@@ -529,7 +529,7 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - (npcb)->next = NULL; \ - } while(0) - --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - #define TCP_REG(pcbs, npcb) \ - do { \ - (npcb)->next = *pcbs; \ -@@ -556,11 +556,11 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - (npcb)->next = NULL; \ - } while(0) - --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #endif /* LWIP_DEBUG */ - - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - #define TCP_REG_ACTIVE_HASH(npcb) \ - do { \ - TCP_REG_HASH(tcp_active_htable, npcb); \ -@@ -580,7 +580,7 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - } while (0) - - void tcp_pcb_remove_hash(struct tcp_hash_table *htb, struct tcp_pcb *pcb); --#endif /* TCP_PCB_HASH */ -+#endif /* GAZELLE_TCP_PCB_HASH */ - - #define TCP_REG_ACTIVE(npcb) \ - do { \ -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index 3c5b87b..58acf0f 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -57,7 +57,7 @@ extern "C" { - - /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED - to prevent this code from redefining it. */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define SA_FAMILY_T_DEFINED - typedef u16_t sa_family_t; - #endif -@@ -74,7 +74,7 @@ typedef u16_t in_port_t; - #if LWIP_IPV4 - /* members are in network byte order */ - struct sockaddr_in { --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - u8_t sin_len; - #endif - sa_family_t sin_family; -@@ -97,7 +97,7 @@ struct sockaddr_in6 { - #endif /* LWIP_IPV6 */ - - struct sockaddr { --#if !USE_LIBOS -+#if !GAZELLE_ENABLE - u8_t sa_len; - #endif - sa_family_t sa_family; -@@ -198,7 +198,7 @@ struct ifreq { - #define SOCK_DGRAM 2 - #define SOCK_RAW 3 - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #include - #else - /* -@@ -236,7 +236,7 @@ struct ifreq { - * Level number for (get/set)sockopt() to apply to socket itself. - */ - #define SOL_SOCKET 0xfff /* options for socket level */ --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /* - * Structure used for manipulating linger option. -@@ -289,20 +289,20 @@ struct linger { - /* - * Options for level IPPROTO_TCP - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - /* come from netinet/tcp.h */ - #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ - #define TCP_KEEPALIVE 0x24 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ - #define TCP_KEEPIDLE 0x04 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ - #define TCP_KEEPINTVL 0x05 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ - #define TCP_KEEPCNT 0x06 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ - #define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ - #define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ - #define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ - #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - #endif /* LWIP_TCP */ - - #if LWIP_IPV6 -@@ -505,13 +505,13 @@ typedef struct fd_set - unsigned char fd_bits [(FD_SETSIZE+7)/8]; - } fd_set; - --#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) && !USE_LIBOS -+#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) && !GAZELLE_ENABLE - #error "external FD_SETSIZE too small for number of sockets" - #else - #define LWIP_SELECT_MAXNFDS FD_SETSIZE - #endif /* FD_SET */ - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #if !defined(POLLIN) && !defined(POLLOUT) - /* come from bits/poll.h */ - #define POLLIN 0x001 -@@ -526,7 +526,7 @@ typedef struct fd_set - #define POLLWRBAND 0x200 - #define POLLHUP 0x010 - #endif --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #if LWIP_SOCKET_POLL - /* poll-related defines and types */ -@@ -664,13 +664,13 @@ int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptse - int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - int lwip_ioctl(int s, long cmd, ...); - int lwip_fcntl(int s, int cmd, int val); - #else - int lwip_ioctl(int s, long cmd, void *argp); - int lwip_fcntl(int s, int cmd, int val); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); - int lwip_inet_pton(int af, const char *src, void *dst); -@@ -740,7 +740,7 @@ int lwip_inet_pton(int af, const char *src, void *dst); - /** @ingroup socket */ - #define close(s) lwip_close(s) - --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define fcntl(s,cmd...) lwip_fcntl(s,cmd) - #define ioctl(s,cmd...) lwip_ioctl(s,cmd) - #else -@@ -748,7 +748,7 @@ int lwip_inet_pton(int af, const char *src, void *dst); - #define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) - /** @ingroup socket */ - #define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ - #endif /* LWIP_COMPAT_SOCKETS != 2 */ -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index c2018cb..b822f40 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -51,7 +51,7 @@ - #include "lwip/ip6.h" - #include "lwip/ip6_addr.h" - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - #include "lwip/sys.h" - #include "hlist.h" - #endif -@@ -214,7 +214,7 @@ typedef u16_t tcpflags_t; - /** - * members common to struct tcp_pcb and struct tcp_listen_pcb - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - #define TCP_PCB_COMMON(type) \ - type *next; /* for the linked list */ \ - type *prev; /* for the linked list */ \ -@@ -225,7 +225,7 @@ typedef u16_t tcpflags_t; - /* ports are in host byte order */ \ - u16_t local_port - --#else /* USE_LIBOS */ -+#else /* GAZELLE_ENABLE */ - #define TCP_PCB_COMMON(type) \ - type *next; /* for the linked list */ \ - void *callback_arg; \ -@@ -234,7 +234,7 @@ typedef u16_t tcpflags_t; - u8_t prio; \ - /* ports are in host byte order */ \ - u16_t local_port --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - /** the TCP protocol control block for listening pcbs */ - struct tcp_pcb_listen { -@@ -253,7 +253,7 @@ struct tcp_pcb_listen { - u8_t accepts_pending; - #endif /* TCP_LISTEN_BACKLOG */ - --#if REUSE_IPPORT -+#if GAZELLE_TCP_REUSE_IPPORT - struct tcp_pcb_listen* next_same_port_pcb; - u16_t connect_num; - int socket_fd; -@@ -269,7 +269,7 @@ struct tcp_pcb { - IP_PCB; - /** protocol specific PCB members */ - TCP_PCB_COMMON(struct tcp_pcb); --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - struct hlist_node tcp_node; - #endif - -@@ -421,7 +421,7 @@ struct tcp_pcb { - u8_t need_tso_send; - }; - --#if TCP_PCB_HASH -+#if GAZELLE_TCP_PCB_HASH - #define TCP_HTABLE_SIZE MEMP_NUM_NETCONN*12 - - struct tcp_hashbucket -@@ -471,7 +471,7 @@ static inline unsigned int jhash_3words(unsigned int a, unsigned int b, unsigned - #define tcppcb_hlist_for_each(tcppcb, node, list) \ - hlist_for_each_entry(tcppcb, node, list, tcp_node) - --#endif /* TCP_PCB_HASH */ -+#endif /* GAZELLE_TCP_PCB_HASH */ - - #if LWIP_EVENT_API - -diff --git a/src/include/lwip/timeouts.h b/src/include/lwip/timeouts.h -index b451554..f7ffc5e 100644 ---- a/src/include/lwip/timeouts.h -+++ b/src/include/lwip/timeouts.h -@@ -119,9 +119,9 @@ struct sys_timeo** sys_timeouts_get_next_timeout(void); - void lwip_cyclic_timer(void *arg); - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - void sys_timer_run(void); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - #endif /* LWIP_TIMERS */ - -diff --git a/src/include/lwiplog.h b/src/include/lwiplog.h -index 011ed21..f278ff4 100644 ---- a/src/include/lwiplog.h -+++ b/src/include/lwiplog.h -@@ -41,7 +41,7 @@ - - #include "lwipopts.h" - --#if USE_DPDK_LOG -+#if GAZELLE_USE_DPDK_LOG - - #define LWIP_LOG_WARN LWIP_DBG_LEVEL_WARNING - #define LWIP_LOG_ERROR LWIP_DBG_LEVEL_SERIOUS -@@ -75,6 +75,6 @@ do { LWIP_PLATFORM_LOG(LWIP_LOG_FATAL, "Assertion \"%s\" failed at line %d in %s - - #define LWIP_PLATFORM_LOG(debug, message) - --#endif /* USE_DPDK_LOG */ -+#endif /* GAZELLE_USE_DPDK_LOG */ - - #endif /* __LWIPLOG_H__ */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index be58ec3..9cc93bc 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -33,182 +33,204 @@ - #ifndef __LWIPOPTS_H__ - #define __LWIPOPTS_H__ - --#define LWIP_TCPIP_CORE_LOCKING 1 -- --#define LWIP_NETCONN_SEM_PER_THREAD 0 -- --#define LWIP_TCP 1 -- --#define LWIP_SO_SENTIMEO 0 -- --#define LIP_SO_LINGER 0 -- --#define MEMP_USE_CUSTOM_POOLS 0 --#define MEM_USE_POOLS 0 -- --#define PER_TCP_PCB_BUFFER (16 * 128) -- --#define MAX_CLIENTS (20000) -- --#define RESERVED_CLIENTS (2000) -- --#define MEMP_NUM_TCP_PCB (MAX_CLIENTS + RESERVED_CLIENTS) -- --/* we use PBUF_POOL instead of PBUF_RAM in tcp_write, so reduce PBUF_RAM size, -- * and do NOT let PBUF_POOL_BUFSIZE less then TCP_MSS -+/* -+ ------------------------------------- -+ ---------- gazelle options ---------- -+ ------------------------------------- - */ --#define MEM_SIZE (((PER_TCP_PCB_BUFFER + 128) * MEMP_NUM_TCP_SEG) >> 2) -+#define LWIP_PERF 1 -+#define LWIP_RECORD_PERF 0 - --#define MEMP_NUM_TCP_PCB_LISTEN 3000 -+//#define LWIP_DEBUG 1 -+#define GAZELLE_USE_DPDK_LOG 1 - --#define MEMP_NUM_TCP_SEG (128 * 128 * 2) -+#define GAZELLE_ENABLE 1 -+#define PER_THREAD __thread - --#define MEMP_NUM_NETCONN (MAX_CLIENTS + RESERVED_CLIENTS) -+#define FRAME_MTU 1500 - --#define MEMP_NUM_SYS_SEM (MAX_CLIENTS + RESERVED_CLIENTS) -+#define GAZELLE_TCP_PCB_HASH 1 - --#define MEMP_NUM_SYS_MBOX (MAX_CLIENTS + RESERVED_CLIENTS) -+#define GAZELLE_TCP_MAX_DATA_ACK_NUM 256 - --#define PBUF_POOL_SIZE (MAX_CLIENTS * 2) -+#define GAZELLE_TCP_MAX_PBUF_CHAIN_LEN 40 - --#define MEMP_MEM_MALLOC 0 -+/* -+ ---------------------------------- -+ ---------- NIC offloads ---------- -+ ---------------------------------- -+*/ -+#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 /* checksum ability check before checksum*/ - --#define LWIP_ARP 1 -+// rx cksum -+#define CHECKSUM_CHECK_IP 1 /* master switch */ -+#define CHECKSUM_CHECK_TCP 1 /* master switch */ -+// tx cksum -+#define CHECKSUM_GEN_IP 1 /* master switch */ -+#define CHECKSUM_GEN_TCP 1 /* master switch */ - --#define ETHARP_SUPPORT_STATIC_ENTRIES 1 -+// rx offload cksum -+#define CHECKSUM_CHECK_IP_HW (1 && CHECKSUM_CHECK_IP) /* hardware switch */ -+#define CHECKSUM_CHECK_TCP_HW (1 && CHECKSUM_CHECK_TCP) /* hardware switch */ -+// tx offload cksum -+#define CHECKSUM_GEN_IP_HW (1 && CHECKSUM_GEN_IP) /* hardware switch */ -+#define CHECKSUM_GEN_TCP_HW (1 && CHECKSUM_GEN_TCP) /* hardware switch */ - --#define LWIP_IPV4 1 -+#define CHECKSUM_OFFLOAD_ALL (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW || CHECKSUM_CHECK_IP_HW || CHECKSUM_CHECK_TCP_HW) - --#define IP_FORWARD 0 - --#define IP_REASSEMBLY 1 -+/* -+ --------------------------------------- -+ ---------- lwIP APIs options ---------- -+ --------------------------------------- -+*/ -+#define LWIP_TCPIP_CORE_LOCKING 1 - --#define LWIP_UDP 0 -+#define LWIP_TCPIP_TIMEOUT 0 - --#define LWIP_TCP 1 -+#define TCPIP_MBOX_SIZE (MEMP_NUM_TCPIP_MSG_API) - --#define IP_HLEN 20 -+#define LWIP_NETCONN 1 - --#define TCP_HLEN 20 -+#define LWIP_NETCONN_SEM_PER_THREAD 0 - --#define FRAME_MTU 1500 -+#define LWIP_STATS 1 - --#define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) -+#define LWIP_STATS_DISPLAY 1 - --#define TCP_WND (2500 * TCP_MSS) -+#define LWIP_TIMERS 1 - --#define TCP_SND_BUF (2500 * TCP_MSS) -+#define LWIP_TIMEVAL_PRIVATE 0 - --#define TCP_SND_QUEUELEN (8191) - --#define TCP_SNDLOWAT (TCP_SND_BUF / 5) -+/* -+ ------------------------------------------------ -+ ---------- Internal Memory Pool Sizes ---------- -+ ------------------------------------------------ -+*/ -+#define GAZELLE_MAX_CLIENTS (20000) -+#define GAZELLE_RESERVED_CLIENTS (2000) - --#define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5) -+#define LWIP_SUPPORT_CUSTOM_PBUF 1 - --#define TCP_LISTEN_BACKLOG 1 -+#define MEMP_MEM_MALLOC 0 -+#define MEM_LIBC_MALLOC 0 -+#define MEM_USE_POOLS 0 -+#define MEMP_USE_CUSTOM_POOLS 0 - --#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -+#define MEMP_NUM_TCP_PCB_LISTEN 3000 - --#define TCP_OVERSIZE 0 -+#define MEMP_NUM_TCP_PCB (GAZELLE_MAX_CLIENTS + GAZELLE_RESERVED_CLIENTS) - --#define LWIP_NETIF_API 1 -+#define MEMP_NUM_NETCONN (GAZELLE_MAX_CLIENTS + GAZELLE_RESERVED_CLIENTS) - --#define DEFAULT_TCP_RECVMBOX_SIZE 4096 -+#define MEMP_NUM_SYS_SEM (GAZELLE_MAX_CLIENTS + GAZELLE_RESERVED_CLIENTS) - --#define DEFAULT_ACCEPTMBOX_SIZE 1024 -+#define MEMP_NUM_SYS_MBOX (GAZELLE_MAX_CLIENTS + GAZELLE_RESERVED_CLIENTS) - --#define LWIP_NETCONN 1 -+#define PBUF_POOL_SIZE (GAZELLE_MAX_CLIENTS * 2) - --#define LWIP_TCPIP_TIMEOUT 0 -+/* we use PBUF_POOL instead of PBUF_RAM in tcp_write, so reduce PBUF_RAM size, -+ * and do NOT let PBUF_POOL_BUFSIZE less then TCP_MSS -+*/ -+#define MEMP_NUM_TCP_SEG (128 * 128 * 2) -+#define PER_TCP_PCB_BUFFER (16 * 128) -+#define MEM_SIZE (((PER_TCP_PCB_BUFFER + 128) * MEMP_NUM_TCP_SEG) >> 2) - --#define LWIP_SOCKET 1 - --#define LWIP_TCP_KEEPALIVE 1 -+/* -+ --------------------------------- -+ ---------- ARP options ---------- -+ --------------------------------- -+*/ -+#define LWIP_ARP 1 - --#define LWIP_STATS 1 -+#define ARP_TABLE_SIZE 512 - --#define LWIP_STATS_DISPLAY 1 -+#define ARP_QUEUEING 1 - --#define LWIP_TIMEVAL_PRIVATE 0 -+#define ARP_QUEUE_LEN 32 - --#define USE_LIBOS 1 -+#define ETHARP_SUPPORT_STATIC_ENTRIES 1 - --//#define LWIP_DEBUG 1 - --#define LWIP_PERF 1 -+/* -+ --------------------------------- -+ ---------- IP options ---------- -+ --------------------------------- -+*/ -+#define LWIP_IPV4 1 - --#define LWIP_RECORD_PERF 0 -+#define IP_FORWARD 0 - --#define LWIP_SOCKET_POLL 0 -+#define IP_REASSEMBLY 1 - --#define USE_LIBOS_ZC_RING 0 -+#define IP_HLEN 20 - --#define REUSE_IPPORT 1 - --#define MAX_CONN_NUM_PER_THREAD 65535 -+/* -+ --------------------------------- -+ ---------- UDP options ---------- -+ --------------------------------- -+*/ -+#define LWIP_UDP 0 - --#define SO_REUSE 1 - --#define SIOCSHIWAT 1 -+/* -+ --------------------------------- -+ ---------- TCP options ---------- -+ --------------------------------- -+*/ -+#define LWIP_TCP 1 - --#define O_NONBLOCK 04000 /* same as define in bits/fcntl-linux.h */ -+#define TCP_HLEN 20 - --#define O_NDELAY O_NONBLOCK -+#define DEFAULT_ACCEPTMBOX_SIZE 1024 -+#define DEFAULT_TCP_RECVMBOX_SIZE 4096 - --#define FIONBIO 0x5421 /* same as define in asm-generic/ioctls.h */ -+#define TCP_LISTEN_BACKLOG 1 -+#define TCP_DEFAULT_LISTEN_BACKLOG 0xff - --#define LWIP_SUPPORT_CUSTOM_PBUF 1 -+#define TCP_OVERSIZE 0 -+#define LWIP_NETIF_TX_SINGLE_PBUF 0 - --#define MEM_LIBC_MALLOC 0 -+#define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) - --#define LWIP_TIMERS 1 -+#define TCP_WND (2500 * TCP_MSS) - --#define TCPIP_MBOX_SIZE (MEMP_NUM_TCPIP_MSG_API) -+#define TCP_SND_BUF (2500 * TCP_MSS) - --#define TCP_PCB_HASH 1 -+#define TCP_SND_QUEUELEN (8191) - --#define USE_DPDK_LOG 1 -+#define TCP_SNDLOWAT (TCP_SND_BUF / 5) - --#define LWIP_EPOOL_WAIT_MAX_EVENTS 30 -+#define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5) - --#define ARP_TABLE_SIZE 512 -+#define LWIP_TCP_KEEPALIVE 1 - --#define ARP_QUEUEING 1 -+#define GAZELLE_TCP_MAX_CONN_PER_THREAD 65535 -+#define GAZELLE_TCP_REUSE_IPPORT 1 - --#define ARP_QUEUE_LEN 32 - --#define MAX_PBUF_CHAIN_LEN 40 -+/* -+ ------------------------------------ -+ ---------- Socket options ---------- -+ ------------------------------------ -+*/ -+#define LWIP_SOCKET 1 - --#define MIN_TSO_SEG_LEN 256 -+#define LWIP_SOCKET_POLL 0 - --#define MAX_DATA_ACK_NUM 256 -+#define LWIP_SO_SNDTIMEO 0 - --/* --------------------------------------- -- * ------- NIC offloads -------- -- * --------------------------------------- -- */ --#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 /* checksum ability check before checksum*/ -+#define LWIP_SO_LINGER 0 - --// rx cksum --#define CHECKSUM_CHECK_IP 1 /* master switch */ --#define CHECKSUM_CHECK_TCP 1 /* master switch */ --// tx cksum --#define CHECKSUM_GEN_IP 1 /* master switch */ --#define CHECKSUM_GEN_TCP 1 /* master switch */ -+#define SO_REUSE 1 - --// rx offload cksum --#define CHECKSUM_CHECK_IP_HW (1 && CHECKSUM_CHECK_IP) /* hardware switch */ --#define CHECKSUM_CHECK_TCP_HW (1 && CHECKSUM_CHECK_TCP) /* hardware switch */ --// tx offload cksum --#define CHECKSUM_GEN_IP_HW (1 && CHECKSUM_GEN_IP) /* hardware switch */ --#define CHECKSUM_GEN_TCP_HW (1 && CHECKSUM_GEN_TCP) /* hardware switch */ -+#define FIONBIO 0x5421 /* same as define in asm-generic/ioctls.h */ - --#define CHECKSUM_OFFLOAD_ALL (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW || CHECKSUM_CHECK_IP_HW || CHECKSUM_CHECK_TCP_HW) -+#define O_NONBLOCK 04000 /* same as define in bits/fcntl-linux.h */ - --#if USE_LIBOS --#define PER_THREAD __thread --#else --#define PER_THREAD --#endif -+#define SIOCSHIWAT 1 - - #endif /* __LWIPOPTS_H__ */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index a807e3e..f78c9cf 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -59,7 +59,7 @@ union lwip_sock_lastdata { - struct pbuf *pbuf; - }; - --#if USE_LIBOS -+#if GAZELLE_ENABLE - struct protocol_stack; - struct wakeup_poll; - struct rte_ring; -@@ -92,7 +92,7 @@ struct lwip_sock { - #define LWIP_SOCK_FD_FREE_FREE 2 - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - char pad0 __rte_cache_aligned; - /* app thread use */ - struct pbuf *recv_lastdata; /* unread data in one pbuf */ -@@ -131,7 +131,7 @@ struct lwip_sock { - * --------------- LIBNET references ---------------- - * -------------------------------------------------- - */ --#if USE_LIBOS -+#if GAZELLE_ENABLE - extern uint32_t sockets_num; - extern struct lwip_sock *sockets; - extern void gazelle_connected_callback(struct netconn *conn); -@@ -141,7 +141,7 @@ extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size - extern void gazelle_init_sock(int32_t fd); - extern void gazelle_clean_sock(int32_t fd); - extern void write_lwip_over(struct lwip_sock *sock); --#endif /* USE_LIBOS */ -+#endif /* GAZELLE_ENABLE */ - - struct lwip_sock *get_socket(int s); - struct lwip_sock *get_socket_by_fd(int s); -diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c -index ab976a8..fd13f00 100644 ---- a/src/netif/ethernet.c -+++ b/src/netif/ethernet.c -@@ -56,7 +56,7 @@ - #include "netif/ppp/pppoe.h" - #endif /* PPPOE_SUPPORT */ - --#if USE_LIBOS && (CHECKSUM_GEN_TCP_HW || CHECKSUM_GEN_IP_HW) -+#if GAZELLE_ENABLE && (CHECKSUM_GEN_TCP_HW || CHECKSUM_GEN_IP_HW) - #include "dpdk_cksum.h" - #endif - --- -2.33.0 - diff --git a/0054-reduce-cpu-usage-when-send.patch b/0054-reduce-cpu-usage-when-send.patch deleted file mode 100644 index 94f394f..0000000 --- a/0054-reduce-cpu-usage-when-send.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d3d6f7fa6e755992fd4b75b56681b5e14aa8ba14 Mon Sep 17 00:00:00 2001 -From: jiangheng12 -Date: Fri, 10 Mar 2023 19:32:48 +0800 -Subject: [PATCH] reduce cpu usage when send - ---- - src/include/lwipsock.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index f78c9cf..810e98f 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -33,6 +33,7 @@ - #ifndef __LWIPSOCK_H__ - #define __LWIPSOCK_H__ - -+#include - #include "lwip/opt.h" - #include "lwip/api.h" - -@@ -110,6 +111,7 @@ struct lwip_sock { - struct list_node send_list; - struct pbuf *send_lastdata; - struct pbuf *send_pre_del; -+ sem_t snd_ring_sem; - - char pad3 __rte_cache_aligned; - /* nerver change */ --- -2.23.0 - diff --git a/0055-add-pbuf-lock-when-aggregate-pbuf.patch b/0055-add-pbuf-lock-when-aggregate-pbuf.patch deleted file mode 100644 index 7df6243..0000000 --- a/0055-add-pbuf-lock-when-aggregate-pbuf.patch +++ /dev/null @@ -1,46 +0,0 @@ -From a9906aabda21b9d2912377352ef0058eb4fb76e0 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Mon, 13 Mar 2023 10:00:12 +0800 -Subject: [PATCH] add pbuf lock when aggregate pbuf - ---- - src/include/lwip/pbuf.h | 3 ++- - src/include/lwipsock.h | 3 +-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index a2e8e01..8807a49 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -231,9 +231,10 @@ struct pbuf { - u64_t l4_len:8; - u8_t header_off; - u8_t rexmit; -- u8_t in_write; -+ volatile u8_t allow_in; - u8_t head; - struct pbuf *last; -+ pthread_spinlock_t pbuf_lock; - #endif /* GAZELLE_ENABLE CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 810e98f..7e16ec8 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -104,11 +104,10 @@ struct lwip_sock { - - char pad1 __rte_cache_aligned; - /* app and stack thread all use */ -- uint32_t in_send; /* avoid sock too much send rpc msg*/ -+ uint32_t call_num; /* avoid sock too much send rpc msg*/ - char pad2 __rte_cache_aligned; - /* stack thread all use */ - struct list_node recv_list; -- struct list_node send_list; - struct pbuf *send_lastdata; - struct pbuf *send_pre_del; - sem_t snd_ring_sem; --- -2.29.0.windows.1 - diff --git a/0056-fix-tso-small-packet-drop-in-kernel-server.patch b/0056-fix-tso-small-packet-drop-in-kernel-server.patch deleted file mode 100644 index 997c865..0000000 --- a/0056-fix-tso-small-packet-drop-in-kernel-server.patch +++ /dev/null @@ -1,325 +0,0 @@ -From abeef0770f76cd0eff8e5c6e50de0b280079d7f0 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Mon, 13 Mar 2023 19:25:42 +0800 -Subject: [PATCH] fix tso small packet drop in kernel server - ---- - src/core/tcp_out.c | 254 +++++++++++++++++++++-------------------- - src/include/lwipopts.h | 2 + - 2 files changed, 130 insertions(+), 126 deletions(-) - -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 8a0d653..b1c317d 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1312,60 +1312,33 @@ tcp_build_wnd_scale_option(u32_t *opts) - #endif - - #if GAZELLE_ENABLE --static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg, struct tcp_seg *useg) --{ -- if (TCP_TCPLEN(seg) > 0) { -- seg->next = NULL; -- if (useg == NULL) { -- pcb->unacked = seg; -- pcb->last_unacked = seg; -- useg = seg; -- } else { -- if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { -- /* add segment to before tail of unacked list, keeping the list sorted */ -- struct tcp_seg **cur_seg = &(pcb->unacked); -- while (*cur_seg && -- TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { -- cur_seg = &((*cur_seg)->next ); -- } -- seg->next = (*cur_seg); -- (*cur_seg) = seg; -- } else { -- /* add segment to tail of unacked list */ -- useg->next = seg; -- useg = seg; -- pcb->last_unacked = seg; -- } -- } -- } else { -- tcp_seg_free(seg); -- } -- -- return useg; --} --static err_t tcp_output_seg(struct tcp_pcb *pcb, struct tcp_seg *seg, struct netif *netif, u32_t snd_nxt) --{ -- if (pcb->state != SYN_SENT) { -- TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); -- } -- -- err_t err = tcp_output_segment(seg, pcb, netif); -- if (err != ERR_OK) { -- /* segment could not be sent, for whatever reason */ -- tcp_set_flags(pcb, TF_NAGLEMEMERR); -- return err; -- } -- -- if (pcb->state != SYN_SENT) { -- tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); -- } -- -- if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { -- pcb->snd_nxt = snd_nxt; -- } -- -- return ERR_OK; --} -+u32_t start_seqno = 0; -+#define TCP_INIT_SEGMENT(tem_seg, _pcb, _p, _hdrflags, _seqno, _optflags) \ -+do { \ -+ struct tcp_seg *_seg = tem_seg; \ -+ u8_t _optlen; \ -+ rte_prefetch2(_p); \ -+ \ -+ _optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(_optflags, _pcb); \ -+ _seg->flags = _optflags; \ -+ _seg->next = NULL; \ -+ _seg->p = _p; \ -+ _seg->len = _p->tot_len - _optlen; \ -+ /* build TCP header */ \ -+ pbuf_add_header(_p, TCP_HLEN); \ -+ _seg->tcphdr = (struct tcp_hdr *)_seg->p->payload; \ -+ _seg->tcphdr->src = lwip_htons(_pcb->local_port); \ -+ _seg->tcphdr->dest = lwip_htons(_pcb->remote_port); \ -+ /* _seg->tcphdr->src = lwip_htons(_pcb->local_port); \ */ \ -+ /* _seg->tcphdr->dest = lwip_htons(_pcb->remote_port); \ */ \ -+ _seg->tcphdr->seqno = lwip_htonl(_seqno); \ -+ \ -+ if (start_seqno == 0) {\ -+ start_seqno = _seqno; \ -+ } \ -+ TCPH_HDRLEN_FLAGS_SET(_seg->tcphdr, (5 + _optlen / 4), _hdrflags); \ -+ _seg->tcphdr->urgp = 0; \ -+} while(0) - #endif - /** - * @ingroup tcp_raw -@@ -1471,97 +1444,127 @@ tcp_output(struct tcp_pcb *pcb) - pcb->persist_backoff = 0; - - /* useg should point to last segment on unacked queue */ -- useg = pcb->last_unacked; -+ useg = pcb->unacked; -+ if (useg != NULL) { -+ for (; useg->next != NULL; useg = useg->next); -+ } - - /* data available and window allows it to be sent? */ -- -- u32_t send_len = 0; - #if GAZELLE_ENABLE - if ((get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) && pcb->need_tso_send) { -- while(seg && send_len < 0xffff) { -- /** -- * 1) walk unsent queue, find all seg witch wait to send. chain buf in these segs. -- * 2) create new segment, send and free new segment. -- * 3) update snd_nxt, unacked queue, and unsent queue -- */ -- struct tcp_seg *start_seg = seg; -- struct pbuf *first_pbuf = NULL; -- struct pbuf *pre_pbuf = NULL; -- u8_t pbuf_chain_len = 0; -- u32_t next_seqno = lwip_ntohl(seg->tcphdr->seqno); -- while (seg != NULL && pbuf_chain_len < GAZELLE_TCP_MAX_PBUF_CHAIN_LEN) { -+ uint16_t send_pkt = 0; -+ -+ do { -+ struct tcp_seg * start_seg = seg; -+ struct pbuf *new_pbuf = NULL; -+ -+ struct pbuf *tmp_pbuf = NULL; - u32_t seg_seqno = lwip_ntohl(seg->tcphdr->seqno); -- if (seg_seqno - pcb->lastack + seg->len > wnd) { -- if (first_pbuf) -- break; -- else -- goto output_done; -+ u32_t last_seg_seqno = seg_seqno; -+ -+ struct tcp_seg *last_seg = NULL; -+ u16_t last_seg_len = 0; -+ u8_t pbuf_chain_len = 0; -+ while (seg != NULL && seg_seqno - pcb->lastack + seg->len <= wnd && pbuf_chain_len < GAZELLE_TCP_MAX_PBUF_CHAIN_LEN) { -+ if (last_seg_len != 0 && (last_seg_len + seg->len < 1460) && seg->len < GAZELLE_TCP_MIN_TSO_SEG_LEN) { -+ break; -+ } -+ -+ if ((tcp_do_output_nagle(pcb) == 0) && -+ ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { -+ break; -+ } -+ if (last_seg_seqno + last_seg_len == seg_seqno) { -+ pbuf_remove_header(seg->p, seg->p->tot_len - seg->len); -+ if (new_pbuf == NULL) { -+ new_pbuf = seg->p; -+ tmp_pbuf = new_pbuf; -+ } else { -+ new_pbuf->tot_len += seg->p->len; -+ tmp_pbuf->next = seg->p; -+ tmp_pbuf = tmp_pbuf->next; -+ } -+ } else { -+ break; -+ } -+ -+ last_seg = seg; -+ last_seg_len = seg->len; -+ last_seg_seqno = seg_seqno; -+ seg = seg->next; -+ seg_seqno = (seg != NULL) ? lwip_ntohl(seg->tcphdr->seqno) : seg_seqno; -+ pbuf_chain_len++; - } - -- if ((tcp_do_output_nagle(pcb) == 0) && ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { -- if (first_pbuf) -- break; -- else -- goto output_done; -+ // tcp_do_output_nagle, break -+ if (new_pbuf == NULL) { -+ goto end_loop; - } - -- if (seg->len < TCP_MSS || next_seqno != seg_seqno || pbuf_chain_len >= GAZELLE_TCP_MAX_PBUF_CHAIN_LEN) { -- break; -- } -- if (first_pbuf == NULL && (seg->next == NULL || seg->next->len < TCP_MSS)) { -- break; -- } -+ struct tcp_seg new_seg; -+ TCP_INIT_SEGMENT(&new_seg, pcb, new_pbuf, 0, lwip_ntohl(start_seg->tcphdr->seqno), 0); - -- pbuf_remove_header(seg->p, seg->p->tot_len - seg->len); -- if (first_pbuf == NULL) { -- first_pbuf = seg->p; -- } else { -- first_pbuf->tot_len += seg->p->len; -- pre_pbuf->next = seg->p; -+ if (pcb->state != SYN_SENT) { -+ TCPH_SET_FLAG(new_seg.tcphdr, TCP_ACK); - } - -- send_len += seg->len; -- pre_pbuf = seg->p; -- next_seqno = seg_seqno + TCP_TCPLEN(seg); -- seg = seg->next; -- pcb->unsent = seg; -- pbuf_chain_len++; -- } -- -- if (first_pbuf == NULL) { -- err = tcp_output_seg(pcb, seg, netif, next_seqno + seg->len); -+ err = tcp_output_segment(&new_seg, pcb, netif); - if (err != ERR_OK) { -- if (pcb->unsent == NULL) -- pcb->last_unsent = NULL; -- pcb->need_tso_send = 0; -- return err; -+ /* segment could not be sent, for whatever reason */ -+ tcp_set_flags(pcb, TF_NAGLEMEMERR); -+ return err; - } -- pcb->unsent = seg->next; -- useg = tcp_output_over(pcb, seg, useg); -- seg = pcb->unsent; -- continue; -- } -- -- struct tcp_seg new_seg; -- tcp_init_segment(&new_seg, pcb, first_pbuf, 0, lwip_ntohl(start_seg->tcphdr->seqno), 0); - -- err = tcp_output_seg(pcb, &new_seg, netif, next_seqno); -+ pcb->unsent = last_seg->next; -+ if (pcb->state != SYN_SENT) { -+ tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); -+ } - -- for (u32_t i = 0; i < pbuf_chain_len; i++) { -- struct tcp_seg *next_seg = start_seg->next; -- start_seg->p->next = NULL; -- useg = tcp_output_over(pcb, start_seg, useg); -- start_seg = next_seg; -- } -+ snd_nxt = last_seg_seqno + TCP_TCPLEN(last_seg); -+ if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { -+ pcb->snd_nxt = snd_nxt; -+ } - -- pbuf_remove_header(new_seg.p, new_seg.p->tot_len - new_seg.len - TCPH_HDRLEN_BYTES(new_seg.tcphdr)); -- new_seg.p->tot_len = new_seg.p->len; -- } -- pcb->need_tso_send = 0; -+ pbuf_remove_header(new_seg.p, new_seg.p->tot_len - new_seg.len - TCP_HLEN); -+ new_seg.p->tot_len = new_seg.p->len; -+ -+ for (int start = pbuf_chain_len; start > 0; start--) { -+ struct tcp_seg *tmp_seg = start_seg; -+ start_seg = start_seg->next; -+ tmp_seg->p->next = NULL; -+ if (TCP_TCPLEN(tmp_seg) > 0) { -+ tmp_seg->next = NULL; -+ if (pcb->unacked == NULL) { -+ pcb->unacked = tmp_seg; -+ useg = tmp_seg; -+ } else { -+ if (TCP_SEQ_LT(lwip_ntohl(tmp_seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { -+ /* add segment to before tail of unacked list, keeping the list sorted */ -+ struct tcp_seg **cur_seg = &(pcb->unacked); -+ while (*cur_seg && -+ TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(tmp_seg->tcphdr->seqno))) { -+ cur_seg = &((*cur_seg)->next ); -+ } -+ tmp_seg->next = (*cur_seg); -+ (*cur_seg) = tmp_seg; -+ } else { -+ /* add segment to tail of unacked list */ -+ useg->next = tmp_seg; -+ useg = useg->next; -+ } -+ } -+ } else { -+ tcp_seg_free(tmp_seg); -+ } -+ } -+ } while(seg != NULL && lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd && send_pkt++ < 10); -+end_loop: -+ pcb->need_tso_send = 0; - } else - #endif - { -- while (seg != NULL && send_len < 0xffff && -+ uint16_t send_pkt = 0; -+ while (seg != NULL && send_pkt++ < 10 && - lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); -@@ -1576,7 +1579,6 @@ tcp_output(struct tcp_pcb *pcb) - ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { - break; - } -- send_len += seg->len; - #if TCP_CWND_DEBUG - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 742b4a9..0d2a6d9 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -55,6 +55,8 @@ - - #define GAZELLE_TCP_MAX_PBUF_CHAIN_LEN 40 - -+#define GAZELLE_TCP_MIN_TSO_SEG_LEN 256 -+ - /* - ---------------------------------- - ---------- NIC offloads ---------- --- -2.33.0 - diff --git a/0057-same-node-gazellectl-a.patch b/0057-same-node-gazellectl-a.patch deleted file mode 100644 index 0061f5d..0000000 --- a/0057-same-node-gazellectl-a.patch +++ /dev/null @@ -1,456 +0,0 @@ -From 8a68ee510f5da20edf7fa06da701713ef10db930 Mon Sep 17 00:00:00 2001 -From: jiangheng12 -Date: Thu, 16 Mar 2023 19:59:26 +0800 -Subject: [PATCH] same node & gazellectl -a - ---- - src/api/sockets.c | 21 +++++++++++++++++++++ - src/core/ipv4/ip4_frag.c | 4 ++++ - src/core/netif.c | 7 ++++--- - src/core/pbuf.c | 6 ++++++ - src/core/tcp.c | 39 +++++++++++++++++++++++++++++++++++++++ - src/core/tcp_in.c | 6 ++++++ - src/core/tcp_out.c | 11 +++++++++++ - src/include/lwip/pbuf.h | 3 +++ - src/include/lwip/tcp.h | 10 ++++++++++ - src/include/lwipopts.h | 7 +++++++ - src/include/lwipsock.h | 37 +++++++++++++++++++++++++++++++++++++ - 11 files changed, 148 insertions(+), 3 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 356e345..7a5da26 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -605,6 +605,10 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - * (unless it has been created by accept()). */ - sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); - sockets[i].errevent = 0; -+ sockets[i].same_node_rx_ring = NULL; -+ sockets[i].same_node_rx_ring_mz = NULL; -+ sockets[i].same_node_tx_ring = NULL; -+ sockets[i].same_node_tx_ring_mz = NULL; - return i + LWIP_SOCKET_OFFSET; - } else { - lwip_close(i); -@@ -716,6 +720,11 @@ free_socket(struct lwip_sock *sock, int is_tcp) - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - -+#if GAZELLE_ENABLE -+ /* remove sock from same_node_recv_lit */ -+ list_del_node_null(&sock->recv_list); -+#endif -+ - freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); - SYS_ARCH_UNPROTECT(lev); - /* don't use 'sock' after this line, as another task might have allocated it */ -@@ -780,6 +789,18 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); - #endif /* GAZELLE_ENABLE */ - nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; -+#if GAZELLE_ENABLE -+ struct tcp_pcb *pcb = newconn->pcb.tcp; -+ if (pcb->client_rx_ring != NULL && pcb->client_tx_ring != NULL) { -+ if (find_same_node_memzone(pcb, nsock) != 0) { -+ netconn_delete(newconn); -+ free_socket(nsock, 1); -+ sock_set_errno(sock, ENOTCONN); -+ done_socket(sock); -+ return -1; -+ } -+ } -+#endif - - /* See event_callback: If data comes in right away after an accept, even - * though the server task might not have created a new socket yet. -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index f15b798..e01ea51 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -729,6 +729,7 @@ ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref *p) - - /** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -+#if !GAZELLE_ENABLE - static void - ipfrag_free_pbuf_custom(struct pbuf *p) - { -@@ -740,6 +741,7 @@ ipfrag_free_pbuf_custom(struct pbuf *p) - } - ip_frag_free_pbuf_custom_ref(pcr); - } -+#endif - #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - - /** -@@ -851,7 +853,9 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) - } - pbuf_ref(p); - pcr->original = p; -+#if !GAZELLE_ENABLE - pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; -+#endif - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. -diff --git a/src/core/netif.c b/src/core/netif.c -index 70392cb..86b74a0 100644 ---- a/src/core/netif.c -+++ b/src/core/netif.c -@@ -1065,7 +1065,7 @@ netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callb - } - #endif /* LWIP_NETIF_LINK_CALLBACK */ - --#if ENABLE_LOOPBACK -+#if !GAZELLE_ENABLE - /** - * @ingroup netif - * Send an IP packet to be received on the same netif (loopif-like). -@@ -1184,6 +1184,7 @@ netif_loop_output(struct netif *netif, struct pbuf *p) - - return ERR_OK; - } -+#endif - - #if LWIP_HAVE_LOOPIF - #if LWIP_IPV4 -@@ -1205,7 +1206,7 @@ netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ad - #endif /* LWIP_IPV6 */ - #endif /* LWIP_HAVE_LOOPIF */ - -- -+#if !GAZELLE_ENABLE - /** - * Call netif_poll() in the main loop of your application. This is to prevent - * reentering non-reentrant functions like tcp_input(). Packets passed to -@@ -1277,6 +1278,7 @@ netif_poll(struct netif *netif) - } - SYS_ARCH_UNPROTECT(lev); - } -+#endif - - #if !LWIP_NETIF_LOOPBACK_MULTITHREADING - /** -@@ -1292,7 +1294,6 @@ netif_poll_all(void) - } - } - #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ --#endif /* ENABLE_LOOPBACK */ - - #if LWIP_NUM_NETIF_CLIENT_DATA > 0 - /** -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index dd71519..2385e57 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -69,6 +69,7 @@ - */ - - #include "lwip/opt.h" -+#include "lwipsock.h" - - #include "lwip/pbuf.h" - #include "lwip/stats.h" -@@ -189,6 +190,7 @@ pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, - p->flags = flags; - p->ref = 1; - p->if_idx = NETIF_NO_INDEX; -+ p->pcb = NULL; - } - - /** -@@ -777,9 +779,13 @@ pbuf_free(struct pbuf *p) - #if LWIP_SUPPORT_CUSTOM_PBUF - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { -+#if GAZELLE_ENABLE -+ gazelle_free_pbuf(p); -+#else - struct pbuf_custom *pc = (struct pbuf_custom *)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); - pc->custom_free_function(p); -+#endif - } else - #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - { -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 69a39f6..538a664 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -116,6 +116,8 @@ - #include - #include - -+#include "lwipsock.h" -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -250,6 +252,18 @@ void - tcp_free(struct tcp_pcb *pcb) - { - #if GAZELLE_ENABLE -+ if (pcb->free_ring == 1) { -+ struct netconn *netconn = NULL; -+ struct lwip_sock *sock = NULL; -+ rte_ring_free(pcb->client_rx_ring); -+ rte_ring_free(pcb->client_tx_ring); -+ netconn = (struct netconn *)pcb->callback_arg; -+ sock = get_socket(netconn->socket); -+ rte_memzone_free(sock->same_node_rx_ring->mz); -+ rte_memzone_free(sock->same_node_rx_ring_mz); -+ rte_memzone_free(sock->same_node_tx_ring->mz); -+ rte_memzone_free(sock->same_node_tx_ring_mz); -+ } - vdev_unreg_done(pcb); - release_port(pcb->local_port); - #endif -@@ -996,6 +1010,15 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - /* pcb transfer to lpcb and reg into tcp_listen_pcbs. freeing pcb shouldn't release sock table in here. - * local_port=0 avoid to release sock table in tcp_free */ - pcb->local_port = 0; -+ -+ char name[RING_NAME_LEN]; -+ snprintf(name, sizeof(name), "listen_rx_ring_%u", lpcb->local_port); -+ if (rte_ring_lookup(name) != NULL) { -+ /* port reuse */ -+ lpcb->listen_rx_ring = NULL; -+ } else { -+ same_node_ring_create(&lpcb->listen_rx_ring, SAME_NODE_RING_SIZE, lpcb->local_port, "listen", "rx"); -+ } - #endif - tcp_free(pcb); - #if LWIP_CALLBACK_API -@@ -1262,6 +1285,16 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, - #endif /* SO_REUSE */ - } - -+#if GAZELLE_ENABLE -+ /* communication between processes on the same node */ -+ if (ip_addr_cmp(&pcb->local_ip, &pcb->remote_ip)) { -+ ret = create_same_node_ring(pcb); -+ if (ret != 0) { -+ return ret; -+ } -+ } -+#endif -+ - iss = tcp_next_iss(pcb); - pcb->rcv_nxt = 0; - pcb->snd_nxt = iss; -@@ -2090,7 +2123,13 @@ tcp_alloc(u8_t prio) - pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; - pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; - #endif /* LWIP_TCP_KEEPALIVE */ -+#if GAZELLE_ENABLE -+ pcb->client_rx_ring = NULL; -+ pcb->client_tx_ring = NULL; -+ pcb->free_ring = 0; -+#endif - } -+ - return pcb; - } - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index dd83260..719cf04 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -42,6 +42,7 @@ - */ - - #include "lwip/opt.h" -+#include "lwipsock.h" - - #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -@@ -806,6 +807,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - - #if GAZELLE_ENABLE - vdev_reg_done(REG_RING_TCP_CONNECT, npcb); -+ if (ip_addr_cmp(&npcb->local_ip, &npcb->remote_ip)) { -+ if (find_same_node_ring(npcb) != 0) { -+ return; -+ } -+ } - #endif - - /* Parse any options in the SYN. */ -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 8100e18..b1c317d 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -725,6 +725,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - goto memerr; - } - -+#if GAZELLE_ENABLE -+ lstack_calculate_aggregate(2, p->tot_len); -+#endif -+ - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { - #if GAZELLE_ENABLE - if (pos > 0) { -@@ -1705,6 +1709,10 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - int seg_chksum_was_swapped = 0; - #endif - -+#if USE_LIBOS -+ lstack_calculate_aggregate(1, seg->len); -+#endif -+ - LWIP_ASSERT("tcp_output_segment: invalid seg", seg != NULL); - LWIP_ASSERT("tcp_output_segment: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_output_segment: invalid netif", netif != NULL); -@@ -1899,6 +1907,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - PERF_START(PERF_LAYER_IP, PERF_POINT_IP_SEND); - - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); -+ -+ seg->p->pcb = pcb; - err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); - NETIF_RESET_HINTS(netif); -@@ -2236,6 +2246,7 @@ tcp_output_control_segment(struct tcp_pcb *pcb, struct pbuf *p, - err_t err; - struct netif *netif; - -+ p->pcb = pcb; - LWIP_ASSERT("tcp_output_control_segment: invalid pbuf", p != NULL); - - if (pcb == NULL || pcb->pcb_if == NULL) { -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 6c4ca44..9321afc 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -235,6 +235,7 @@ struct pbuf { - u8_t head; - struct pbuf *last; - pthread_spinlock_t pbuf_lock; -+ struct tcp_pcb *pcb; - #endif /* GAZELLE_ENABLE CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -@@ -263,7 +264,9 @@ struct pbuf_custom { - /** The actual pbuf */ - struct pbuf pbuf; - /** This function is called when pbuf_free deallocates this pbuf(_custom) */ -+#if !GAZELLE_ENABLE - pbuf_free_custom_fn custom_free_function; -+#endif - }; - #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index b822f40..e13099c 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -260,6 +260,9 @@ struct tcp_pcb_listen { - u8_t master_lpcb; - #endif - -+#if GAZELLE_ENABLE -+ struct rte_ring *listen_rx_ring; -+#endif - }; - - -@@ -418,6 +421,13 @@ struct tcp_pcb { - u8_t rcv_scale; - #endif - -+#if GAZELLE_ENABLE -+#define SAME_NODE_RING_SIZE 512 -+ struct rte_ring *client_rx_ring; -+ struct rte_ring *client_tx_ring; -+ u8_t free_ring; -+#endif -+ - u8_t need_tso_send; - }; - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 414ead4..0d2a6d9 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -235,4 +235,11 @@ - - #define SIOCSHIWAT 1 - -+/* -+ ------------------------------------ -+ ---------- Netif options ---------- -+ ------------------------------------ -+*/ -+#define LWIP_NETIF_LOOPBACK 1 -+ - #endif /* __LWIPOPTS_H__ */ -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index 7e16ec8..f917d8a 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -65,7 +65,19 @@ struct protocol_stack; - struct wakeup_poll; - struct rte_ring; - #include -+#include -+ -+// 8M -+#define SAME_NODE_RING_LEN (unsigned long long)(8388608) -+#define SAME_NODE_RING_MASK (unsigned long long)(8388608 - 1) -+#define RING_NAME_LEN 32 -+struct same_node_ring { -+ const struct rte_memzone *mz; -+ unsigned long long sndbegin; -+ unsigned long long sndend; -+}; - #endif -+ - /** Contains all internal pointers and states used for a socket */ - struct lwip_sock { - /** sockets currently are built on netconns, each socket has one netconn */ -@@ -120,9 +132,25 @@ struct lwip_sock { - struct protocol_stack *stack; - struct rte_ring *recv_ring; - struct rte_ring *send_ring; -+ -+ /* same node send data ring */ -+ struct same_node_ring *same_node_rx_ring; -+ const struct rte_memzone *same_node_rx_ring_mz; -+ struct same_node_ring *same_node_tx_ring; -+ const struct rte_memzone *same_node_tx_ring_mz; - #endif - }; - -+#if GAZELLE_ENABLE -+static inline unsigned same_node_ring_count(struct lwip_sock *sock) -+{ -+ const unsigned long long cur_begin = __atomic_load_n(&sock->same_node_rx_ring->sndbegin, __ATOMIC_RELAXED); -+ const unsigned long long cur_end = __atomic_load_n(&sock->same_node_rx_ring->sndend, __ATOMIC_RELAXED); -+ -+ return cur_end - cur_begin; -+} -+#endif -+ - #ifndef set_errno - #define set_errno(err) do { if (err) { errno = (err); } } while(0) - #endif -@@ -142,6 +170,15 @@ extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size - extern void gazelle_init_sock(int32_t fd); - extern void gazelle_clean_sock(int32_t fd); - extern void write_lwip_over(struct lwip_sock *sock); -+extern void netif_poll(struct netif *netif); -+extern err_t netif_loop_output(struct netif *netif, struct pbuf *p); -+extern err_t find_same_node_memzone(struct tcp_pcb *pcb, struct lwip_sock *nsock); -+extern err_t same_node_memzone_create(const struct rte_memzone **zone, int size, int port, char *name, char *); -+extern err_t same_node_ring_create(struct rte_ring **ring, int size, int port, char *name, char *rx); -+extern err_t create_same_node_ring(struct tcp_pcb *pcb); -+extern err_t find_same_node_ring(struct tcp_pcb *pcb); -+extern void gazelle_free_pbuf(struct pbuf *pbuf); -+extern void lstack_calculate_aggregate(int type, uint32_t len); - #endif /* GAZELLE_ENABLE */ - - struct lwip_sock *get_socket(int s); --- -2.23.0 - diff --git a/0058-lwip-send-recv-thread-bind-numa.patch b/0058-lwip-send-recv-thread-bind-numa.patch deleted file mode 100644 index 070b327..0000000 --- a/0058-lwip-send-recv-thread-bind-numa.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0e16f4ec71b0794f48cb7b9e99712c36e40d4d48 Mon Sep 17 00:00:00 2001 -From: kircher -Date: Wed, 22 Mar 2023 15:16:04 +0800 -Subject: [PATCH] lwip-send-recv-thread-bind-numa - ---- - src/include/lwipsock.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index f917d8a..f8480c5 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -138,6 +138,7 @@ struct lwip_sock { - const struct rte_memzone *same_node_rx_ring_mz; - struct same_node_ring *same_node_tx_ring; - const struct rte_memzone *same_node_tx_ring_mz; -+ uint8_t already_bind_numa; - #endif - }; - --- -2.33.0 - diff --git a/0059-fix-last_unsent-last_unacked.patch b/0059-fix-last_unsent-last_unacked.patch deleted file mode 100644 index e51d645..0000000 --- a/0059-fix-last_unsent-last_unacked.patch +++ /dev/null @@ -1,114 +0,0 @@ -From f1692b0c380241699f70adbf7796cb2c7b3a5c94 Mon Sep 17 00:00:00 2001 -From: jiangheng12 -Date: Sat, 1 Apr 2023 16:59:28 +0800 -Subject: [PATCH] fix last_unsent/last_unacked - ---- - src/core/tcp_in.c | 25 +++++++++++++------------ - src/core/tcp_out.c | 18 +++++++++++++----- - 2 files changed, 26 insertions(+), 17 deletions(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 719cf04..7e7d70a 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -1375,18 +1375,19 @@ tcp_receive(struct tcp_pcb *pcb) - } - } - } -- } -- /* fast rexmit when receive too many acks with data */ -- if (TCP_SEQ_LT(ackno + 1, pcb->snd_nxt)) { -- if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { -- if (pcb->rtime >= 0) { -- if (pcb->lastack == ackno) { -- found_dataack = 1; -- ++pcb->dataacks; -- if (pcb->dataacks > GAZELLE_TCP_MAX_DATA_ACK_NUM) { -- if (tcp_rexmit(pcb) == ERR_OK) { -- pcb->rtime = 0; -- pcb->dataacks = 0; -+ } else { -+ /* fast rexmit when receive too many acks with data */ -+ if (TCP_SEQ_LT(ackno + 1, pcb->snd_nxt)) { -+ if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { -+ if (pcb->rtime >= 0) { -+ if (pcb->lastack == ackno) { -+ found_dataack = 1; -+ ++pcb->dataacks; -+ if ((pcb->dataacks > GAZELLE_TCP_MAX_DATA_ACK_NUM) && (pcb->nrtx < (TCP_MAXRTX / 2))) { -+ if (tcp_rexmit(pcb) == ERR_OK) { -+ pcb->rtime = 0; -+ pcb->dataacks = 0; -+ } - } - } - } -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index b1c317d..6250e6b 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1444,10 +1444,7 @@ tcp_output(struct tcp_pcb *pcb) - pcb->persist_backoff = 0; - - /* useg should point to last segment on unacked queue */ -- useg = pcb->unacked; -- if (useg != NULL) { -- for (; useg->next != NULL; useg = useg->next); -- } -+ useg = pcb->last_unacked; - - /* data available and window allows it to be sent? */ - #if GAZELLE_ENABLE -@@ -1515,7 +1512,11 @@ tcp_output(struct tcp_pcb *pcb) - return err; - } - -+ if (pcb->last_unsent == pcb->unsent) { -+ pcb->last_unsent = last_seg->next; -+ } - pcb->unsent = last_seg->next; -+ - if (pcb->state != SYN_SENT) { - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } -@@ -1535,6 +1536,7 @@ tcp_output(struct tcp_pcb *pcb) - if (TCP_TCPLEN(tmp_seg) > 0) { - tmp_seg->next = NULL; - if (pcb->unacked == NULL) { -+ pcb->last_unacked = tmp_seg; - pcb->unacked = tmp_seg; - useg = tmp_seg; - } else { -@@ -1550,6 +1552,9 @@ tcp_output(struct tcp_pcb *pcb) - } else { - /* add segment to tail of unacked list */ - useg->next = tmp_seg; -+ if (pcb->last_unacked == useg) { -+ pcb->last_unacked = tmp_seg; -+ } - useg = useg->next; - } - } -@@ -1603,6 +1608,9 @@ end_loop: - #if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; - #endif /* TCP_OVERSIZE_DBGCHECK */ -+ if (pcb->last_unsent == pcb->unsent) { -+ pcb->last_unsent = seg->next; -+ } - pcb->unsent = seg->next; - if (pcb->state != SYN_SENT) { - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); -@@ -1709,7 +1717,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - int seg_chksum_was_swapped = 0; - #endif - --#if USE_LIBOS -+#if GAZELLE_ENABLE - lstack_calculate_aggregate(1, seg->len); - #endif - --- -2.23.0 - diff --git a/0060-lwip-add-udp-multicast.patch b/0060-lwip-add-udp-multicast.patch deleted file mode 100644 index 94e4e30..0000000 --- a/0060-lwip-add-udp-multicast.patch +++ /dev/null @@ -1,337 +0,0 @@ -From d9ef907e03f44c30e26190b0c5ad895de716ac5c Mon Sep 17 00:00:00 2001 -From: kircher -Date: Fri, 12 May 2023 20:54:51 +0800 -Subject: [PATCH] add udp multicast in support - ---- - src/api/api_msg.c | 5 +++++ - src/api/sockets.c | 21 ++++++++++++++++++++- - src/core/dir.mk | 2 +- - src/core/udp.c | 28 +++++++++++++++++++++++++--- - src/include/dpdk_cksum.h | 4 ++++ - src/include/lwip/opt.h | 5 +++-- - src/include/lwip/pbuf.h | 4 ++++ - src/include/lwip/sockets.h | 15 +++++++++++++++ - src/include/lwipopts.h | 2 +- - 9 files changed, 78 insertions(+), 8 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 1840c9d..0287c06 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -282,8 +282,13 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - #if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ -+#if GAZELLE_ENABLE -+ add_recv_list(conn->socket); -+ LWIP_UNUSED_ARG(len); -+#else - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); -+#endif - } - } - #endif /* LWIP_UDP */ -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 7a5da26..a0f9d50 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -54,6 +54,7 @@ - #include "lwip/netif.h" - #include "lwip/priv/tcpip_priv.h" - #include "lwip/mld6.h" -+#include "lwip/api.h" - #if LWIP_CHECKSUM_ON_COPY - #include "lwip/inet_chksum.h" - #endif -@@ -1187,7 +1188,7 @@ lwip_recv_tcp_done: - #endif - - /* Convert a netbuf's address data to struct sockaddr */ --static int -+int - lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, - struct sockaddr *from, socklen_t *fromlen) - { -@@ -1274,6 +1275,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - apiflags = 0; - } - -+#if !GAZELLE_ENABLE - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); - /* Check if there is data left from the last recv operation. */ - buf = sock->lastdata.netbuf; -@@ -1361,6 +1363,18 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - sock->lastdata.netbuf = NULL; - netbuf_delete(buf); - } -+#else /* GAZELLE_ENABLE */ -+ LWIP_UNUSED_ARG(copylen); -+ LWIP_UNUSED_ARG(buf); -+ LWIP_UNUSED_ARG(err); -+ LWIP_UNUSED_ARG(copied); -+ LWIP_UNUSED_ARG(i); -+ buflen = read_lwip_data(sock, flags, apiflags); -+ if (buflen <= 0) { -+ return ERR_BUF; -+ } -+ -+#endif /* GAZELLE_ENABLE */ - if (datagram_len) { - *datagram_len = buflen; - } -@@ -1409,6 +1423,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, - done_socket(sock); - return -1; - } -+ - ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); - if (fromlen) { - *fromlen = msg.msg_namelen; -@@ -3956,6 +3971,10 @@ lwip_ioctl(int s, long cmd, ...) - struct lwip_sock *sock = posix_api->get_socket(s); - u8_t val; - -+#if LWIP_SO_RCVBUF -+ int recv_avail; -+#endif /* LWIP_SO_RCVBUF */ -+ - int ret = -1; - void *argp; - va_list ap; -diff --git a/src/core/dir.mk b/src/core/dir.mk -index ebc01a5..57a9670 100644 ---- a/src/core/dir.mk -+++ b/src/core/dir.mk -@@ -1,6 +1,6 @@ - SRC = def.c inet_chksum.c init.c ip.c mem.c memp.c netif.c pbuf.c \ - raw.c tcp.c tcp_in.c tcp_out.c timeouts.c udp.c stats.c\ - ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4_frag.c ipv4/etharp.c \ -- ipv4/ip4.c -+ ipv4/ip4.c ipv4/igmp.c - - $(eval $(call register_dir, core, $(SRC))) -diff --git a/src/core/udp.c b/src/core/udp.c -index a5f76b9..1398537 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -65,6 +65,12 @@ - - #include - -+#if GAZELLE_ENABLE -+#include "lwipsock.h" -+#include -+#include "dpdk_cksum.h" -+#endif -+ - #ifndef UDP_LOCAL_PORT_RANGE_START - /* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -@@ -210,7 +216,7 @@ udp_input(struct pbuf *p, struct netif *inp) - #if LWIP_RECORD_PERF - PERF_START(PERF_LAYER_UDP, PERF_POINT_UDP); - #else -- PERF_START; -+ //PERF_START; - #endif - - UDP_STATS_INC(udp.recv); -@@ -435,7 +441,7 @@ end: - #if LWIP_RECORD_PERF - PERF_STOP_INCREASE_COUNT("udp_input", PERF_LAYER_UDP); - #else -- PERF_STOP("udp_input"); -+ //PERF_STOP("udp_input"); - #endif - - return; -@@ -451,7 +457,7 @@ chkerr: - #if LWIP_RECORD_PERF - PERF_STOP_INCREASE_COUNT("udp_input", PERF_LAYER_UDP); - #else -- PERF_STOP("udp_input"); -+ //PERF_STOP("udp_input"); - #endif - - #endif /* CHECKSUM_CHECK_UDP */ -@@ -608,11 +614,26 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } -+ uint8_t apiflags = 0; -+ -+ struct pbuf *udp_pbuf = write_lwip_data((struct lwip_sock *)(p->payload), p->tot_len, &apiflags); -+ write_lwip_over((struct lwip_sock *)(p->payload)); -+ -+ pbuf_free(p); -+ p = udp_pbuf; -+ if (p == NULL) { -+ return ERR_MEM; -+ } -+ -+ if (p->port) { -+ return udp_sendto_if(pcb, p, &(p->addr), p->port, netif); -+ } else { - #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); - #else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); - #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -+ } - } - - /** -@@ -905,6 +926,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); - /* output to IP */ - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); -+ udph_cksum_set(q, UDP_HLEN); - err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); - NETIF_RESET_HINTS(netif); - -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index df2e2a5..e41644b 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -82,6 +82,10 @@ static inline void tcph_cksum_set(struct pbuf *p, u16_t len) { - p->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; - } - -+static inline void udph_cksum_set(struct pbuf *p, u16_t len) { -+ p->l4_len = len; -+} -+ - static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dst) - { -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 0376f60..38c6e9b 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -133,6 +133,7 @@ - * MEMCPY: override this if you have a faster implementation at hand than the - * one included in your C library - */ -+//#include - #if !defined MEMCPY || defined __DOXYGEN__ - #define MEMCPY(dst,src,len) memcpy(dst,src,len) - #endif -@@ -1083,7 +1084,7 @@ - * LWIP_IGMP==1: Turn on IGMP module. - */ - #if !defined LWIP_IGMP || defined __DOXYGEN__ --#define LWIP_IGMP 0 -+#define LWIP_IGMP 1 - #endif - #if !LWIP_IPV4 - #undef LWIP_IGMP -@@ -2030,7 +2031,7 @@ - * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. - */ - #if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ --#define LWIP_SO_RCVBUF 0 -+#define LWIP_SO_RCVBUF 1 - #endif - - /** -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 9321afc..fb21134 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -40,6 +40,8 @@ - - #include "lwip/opt.h" - #include "lwip/err.h" -+#include "lwip/ip_addr.h" -+#include "lwip/ip6_addr.h" - - #ifdef __cplusplus - extern "C" { -@@ -236,6 +238,8 @@ struct pbuf { - struct pbuf *last; - pthread_spinlock_t pbuf_lock; - struct tcp_pcb *pcb; -+ ip_addr_t addr; -+ u16_t port; - #endif /* GAZELLE_ENABLE CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index 58acf0f..36a47eb 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -48,6 +48,7 @@ - #include "lwip/err.h" - #include "lwip/inet.h" - #include "lwip/errno.h" -+#include "lwip/api.h" - - #include - -@@ -323,20 +324,31 @@ struct linger { - - - #if LWIP_MULTICAST_TX_OPTIONS -+#if GAZELLE_ENABLE -+#define IP_MULTICAST_IF 32 -+#define IP_MULTICAST_TTL 33 -+#define IP_MULTICAST_LOOP 34 -+#else - /* - * Options and types for UDP multicast traffic handling - */ - #define IP_MULTICAST_TTL 5 - #define IP_MULTICAST_IF 6 - #define IP_MULTICAST_LOOP 7 -+#endif /* GAZELLE_ENABLE */ - #endif /* LWIP_MULTICAST_TX_OPTIONS */ - - #if LWIP_IGMP -+#if GAZELLE_ENABLE -+#define IP_ADD_MEMBERSHIP 35 -+#define IP_DROP_MEMBERSHIP 36 -+#else - /* - * Options and types related to multicast membership - */ - #define IP_ADD_MEMBERSHIP 3 - #define IP_DROP_MEMBERSHIP 4 -+#endif /* GAZELLE_ENABLE */ - - typedef struct ip_mreq { - struct in_addr imr_multiaddr; /* IP multicast address of group */ -@@ -656,6 +668,7 @@ ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, - int lwip_socket(int domain, int type, int protocol); - ssize_t lwip_write(int s, const void *dataptr, size_t size); - ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); -+ - #if LWIP_SOCKET_SELECT - int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout); -@@ -667,6 +680,8 @@ int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); - #if GAZELLE_ENABLE - int lwip_ioctl(int s, long cmd, ...); - int lwip_fcntl(int s, int cmd, int val); -+int lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, -+ struct sockaddr *from, socklen_t *fromlen); - #else - int lwip_ioctl(int s, long cmd, void *argp); - int lwip_fcntl(int s, int cmd, int val); -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 0d2a6d9..bcb0879 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -175,7 +175,7 @@ - ---------- UDP options ---------- - --------------------------------- - */ --#define LWIP_UDP 0 -+#define LWIP_UDP 1 - - - /* --- -2.33.0 - diff --git a/0061-fix-pbuf-leak-in-udp-connection.patch b/0061-fix-pbuf-leak-in-udp-connection.patch deleted file mode 100644 index a75e3fd..0000000 --- a/0061-fix-pbuf-leak-in-udp-connection.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 21f7f9a5bdfd5d2f592af19e73647a48fdbb7bf1 Mon Sep 17 00:00:00 2001 -From: kircher -Date: Tue, 16 May 2023 19:07:42 +0800 -Subject: [PATCH] fix pbuf leak in udp connection - ---- - src/core/udp.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/core/udp.c b/src/core/udp.c -index 1398537..9c3cdaa 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -933,8 +933,11 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - /* @todo: must this be increased even if error occurred? */ - MIB2_STATS_INC(mib2.udpoutdatagrams); - -+#if !GAZELLE_ENABLE - /* did we chain a separate header pbuf earlier? */ -- if (q != p) { -+ if (q != p) -+#endif -+ { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; --- -2.33.0 - diff --git a/0062-drop-netbuf-in-recv_udp-to-fix-mem-overflow.patch b/0062-drop-netbuf-in-recv_udp-to-fix-mem-overflow.patch deleted file mode 100644 index 7022817..0000000 --- a/0062-drop-netbuf-in-recv_udp-to-fix-mem-overflow.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 2e51934e230013c9df58971df53a08dad108becf Mon Sep 17 00:00:00 2001 -From: kircher -Date: Mon, 29 May 2023 19:58:52 +0800 -Subject: [PATCH] drop-netbuf-in-recv_udp-to-fix-mem-overflow - ---- - src/api/api_lib.c | 14 ++++++++++++++ - src/api/api_msg.c | 15 ++++++++++++--- - src/api/sockets.c | 6 +++--- - src/core/udp.c | 8 ++++++++ - src/include/lwip/api.h | 3 +++ - src/include/lwip/pbuf.h | 4 ++++ - src/include/lwip/sockets.h | 8 ++++---- - src/include/lwipopts.h | 4 ++++ - 8 files changed, 52 insertions(+), 10 deletions(-) - -diff --git a/src/api/api_lib.c b/src/api/api_lib.c -index ffa14d6..afdfc11 100644 ---- a/src/api/api_lib.c -+++ b/src/api/api_lib.c -@@ -655,7 +655,11 @@ netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) - #if (LWIP_UDP || LWIP_RAW) - { - LWIP_ASSERT("buf != NULL", buf != NULL); -+#if GAZELLE_UDP_ENABLE -+ len = ((struct pbuf *)buf)->tot_len; -+#else /* GAZELLE_UDP_ENABLE */ - len = netbuf_len((struct netbuf *)buf); -+#endif /* GAZELLE_UDP_ENABLE */ - } - #endif /* (LWIP_UDP || LWIP_RAW) */ - -@@ -827,6 +831,16 @@ netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) - return netconn_recv_data(conn, (void **)new_buf, 0); - } - -+#if GAZELLE_UDP_ENABLE -+err_t -+netconn_recv_udp_raw_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) -+{ -+ LWIP_ERROR("netconn_recv_udp_raw_pbuf: invalid conn", (conn != NULL) && -+ NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); -+ return netconn_recv_data(conn, (void **)new_buf, apiflags); -+} -+#endif /* GAZELLE_UDP_ENABLE */ -+ - /** - * Receive data (in form of a netbuf) from a UDP or RAW netconn - * -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 30929be..b82ebf2 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -253,6 +253,14 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - return; - } - -+#if GAZELLE_UDP_ENABLE -+ LWIP_UNUSED_ARG(buf); -+ ip_addr_set(&p->addr, addr); -+ p->port = port; -+ len = p->tot_len; -+ if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { -+ return; -+#else /* GAZELLE_UDP_ENABLE */ - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - pbuf_free(p); -@@ -277,17 +285,18 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { - netbuf_delete(buf); - return; -+#endif /* GAZELLE_UDP_ENABLE */ - } else { - #if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ --#if GAZELLE_ENABLE -+#if GAZELLE_UDP_ENABLE - add_recv_list(conn->socket); - LWIP_UNUSED_ARG(len); --#else -+#else /* GAZELLE_UDP_ENABLE */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); --#endif -+#endif /* GAZELLE_UDP_ENABLE */ - } - } - #endif /* LWIP_UDP */ -diff --git a/src/api/sockets.c b/src/api/sockets.c -index dee9230..17691f7 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1179,7 +1179,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - apiflags = 0; - } - --#if !GAZELLE_ENABLE -+#if !GAZELLE_UDP_ENABLE - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); - /* Check if there is data left from the last recv operation. */ - buf = sock->lastdata.netbuf; -@@ -1267,7 +1267,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - sock->lastdata.netbuf = NULL; - netbuf_delete(buf); - } --#else /* GAZELLE_ENABLE */ -+#else /* GAZELLE_UDP_ENABLE */ - LWIP_UNUSED_ARG(copylen); - LWIP_UNUSED_ARG(buf); - LWIP_UNUSED_ARG(err); -@@ -1278,7 +1278,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - return ERR_BUF; - } - --#endif /* GAZELLE_ENABLE */ -+#endif /* GAZELLE_UDP_ENABLE */ - if (datagram_len) { - *datagram_len = buflen; - } -diff --git a/src/core/udp.c b/src/core/udp.c -index 170c911..1eb459d 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -599,6 +599,7 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } -+#if GAZELLE_UDP_ENABLE - uint8_t apiflags = 0; - - struct pbuf *udp_pbuf = write_lwip_data((struct lwip_sock *)(p->payload), p->tot_len, &apiflags); -@@ -611,14 +612,21 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - } - - if (p->port) { -+#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -+ return udp_sendto_if_chksum(pcb, p, &(p->addr), p->port, netif, have_chksum, chksum); -+#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - return udp_sendto_if(pcb, p, &(p->addr), p->port, netif); -+#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - } else { -+#endif /* GAZELLE_UDP_ENABLE */ - #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); - #else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); - #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -+#if GAZELLE_UDP_ENABLE - } -+#endif /* GAZELLE_UDP_ENABLE */ - } - - /** -diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h -index d3c4f02..6090cab 100644 ---- a/src/include/lwip/api.h -+++ b/src/include/lwip/api.h -@@ -338,6 +338,9 @@ err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); - err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); - err_t netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf); - err_t netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags); -+#if GAZELLE_UDP_ENABLE -+err_t netconn_recv_udp_raw_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags); -+#endif /* GAZELLE_UDP_ENABLE */ - err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); - err_t netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags); - err_t netconn_tcp_recvd(struct netconn *conn, size_t len); -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 728c5e4..4747f39 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -40,8 +40,10 @@ - - #include "lwip/opt.h" - #include "lwip/err.h" -+#if GAZELLE_UDP_ENABLE - #include "lwip/ip_addr.h" - #include "lwip/ip6_addr.h" -+#endif /* GAZELLE_UDP_ENABLE */ - - #ifdef __cplusplus - extern "C" { -@@ -238,8 +240,10 @@ struct pbuf { - struct pbuf *last; - pthread_spinlock_t pbuf_lock; - struct tcp_pcb *pcb; -+#if GAZELLE_UDP_ENABLE - ip_addr_t addr; - u16_t port; -+#endif /* GAZELLE_UDP_ENABLE */ - #endif /* GAZELLE_ENABLE CHECKSUM_OFFLOAD_SWITCH */ - - /** In case the user needs to store data custom data on a pbuf */ -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index 643093a..2b6e6be 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -330,7 +330,7 @@ struct linger { - - - #if LWIP_MULTICAST_TX_OPTIONS --#if GAZELLE_ENABLE -+#if GAZELLE_UDP_ENABLE - #define IP_MULTICAST_IF 32 - #define IP_MULTICAST_TTL 33 - #define IP_MULTICAST_LOOP 34 -@@ -341,11 +341,11 @@ struct linger { - #define IP_MULTICAST_TTL 5 - #define IP_MULTICAST_IF 6 - #define IP_MULTICAST_LOOP 7 --#endif /* GAZELLE_ENABLE */ -+#endif /* GAZELLE_UDP_ENABLE */ - #endif /* LWIP_MULTICAST_TX_OPTIONS */ - - #if LWIP_IGMP --#if GAZELLE_ENABLE -+#if GAZELLE_UDP_ENABLE - #define IP_ADD_MEMBERSHIP 35 - #define IP_DROP_MEMBERSHIP 36 - #else -@@ -354,7 +354,7 @@ struct linger { - */ - #define IP_ADD_MEMBERSHIP 3 - #define IP_DROP_MEMBERSHIP 4 --#endif /* GAZELLE_ENABLE */ -+#endif /* GAZELLE_UDP_ENABLE */ - - typedef struct ip_mreq { - struct in_addr imr_multiaddr; /* IP multicast address of group */ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 6b5a2d1..9804aed 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -63,6 +63,10 @@ - - #define GAZELLE_TCP_MIN_TSO_SEG_LEN 256 - -+ -+#define GAZELLE_UDP_ENABLE 1 -+ -+ - /* - ---------------------------------- - ---------- NIC offloads ---------- --- -2.33.0 - diff --git a/0063-optimize-avoid-too-many-empty-acks-in-tcp_input.patch b/0063-optimize-avoid-too-many-empty-acks-in-tcp_input.patch deleted file mode 100644 index 0fa456e..0000000 --- a/0063-optimize-avoid-too-many-empty-acks-in-tcp_input.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 30f5815c847060c5ad4075e81581771b8d0cbb72 Mon Sep 17 00:00:00 2001 -From: Lemmy Huang -Date: Thu, 8 Jun 2023 15:15:07 +0800 -Subject: [PATCH] optimize: avoid too many empty acks in tcp_input - -Signed-off-by: Lemmy Huang ---- - src/core/tcp_in.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 7e7d70ab..0abee303 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -1807,11 +1807,7 @@ tcp_receive(struct tcp_pcb *pcb) - - - /* Acknowledge the segment(s). */ -- if (flags & TCP_PSH) { -- tcp_ack_now(pcb); -- } else { -- tcp_ack(pcb); -- } -+ tcp_ack(pcb); - - #if LWIP_TCP_SACK_OUT - if (LWIP_TCP_SACK_VALID(pcb, 0)) { --- -2.22.0.windows.1 - diff --git a/0064-fix-udp-send-recv-in-multiple-queue.patch b/0064-fix-udp-send-recv-in-multiple-queue.patch deleted file mode 100644 index 1b5139f..0000000 --- a/0064-fix-udp-send-recv-in-multiple-queue.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 71d82a830005540ef92b2bcd7c121c9ff85beb64 Mon Sep 17 00:00:00 2001 -From: j00660176 -Date: Mon, 12 Jun 2023 20:21:23 +0800 -Subject: [PATCH] fix udp send/recv in multiple queue - ---- - src/core/udp.c | 73 +++++++++++++++++++++++++++++++++++++++--- - src/include/lwip/udp.h | 4 +++ - 2 files changed, 73 insertions(+), 4 deletions(-) - -diff --git a/src/core/udp.c b/src/core/udp.c -index fba645b..0b1fa65 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -65,10 +65,12 @@ - - #include - --#if GAZELLE_ENABLE --#include "lwipsock.h" -+#if GAZELLE_UDP_ENABLE -+#include - #include -+#include "lwipsock.h" - #include "dpdk_cksum.h" -+#include "reg_sock.h" - #endif - - #ifndef UDP_LOCAL_PORT_RANGE_START -@@ -81,10 +83,24 @@ - - /* last local UDP port */ - static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; -+#if GAZELLE_UDP_ENABLE -+static pthread_mutex_t g_udp_port_mutex = PTHREAD_MUTEX_INITIALIZER; -+static u8_t port_state[UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START + 1] = {0}; -+static void udp_release_port(u16_t port) -+{ -+ if (port >= UDP_LOCAL_PORT_RANGE_START && port <= UDP_LOCAL_PORT_RANGE_END) { -+ port_state[port - UDP_LOCAL_PORT_RANGE_START] = 0; -+ } -+} -+#endif - - /* The list of UDP PCBs */ - /* exported in udp.h (was static) */ -+#if GAZELLE_UDP_ENABLE -+PER_THREAD struct udp_pcb *udp_pcbs; -+#else - struct udp_pcb *udp_pcbs; -+#endif - - /** - * Initialize this module. -@@ -102,6 +118,37 @@ udp_init(void) - * - * @return a new (free) local UDP port number - */ -+#if GAZELLE_UDP_ENABLE -+static u16_t -+udp_new_port(struct udp_pcb *dst_pcb) -+{ -+ u16_t n = 0; -+ u16_t tmp_port = 0; -+ -+ pthread_mutex_lock(&g_udp_port_mutex); -+ do { -+ if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { -+ udp_port = UDP_LOCAL_PORT_RANGE_START; -+ } -+ -+ if (__atomic_load_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { -+ if (port_in_stack_queue(dst_pcb->remote_ip.addr, dst_pcb->local_ip.addr, dst_pcb->remote_port, udp_port)) { -+ tmp_port = udp_port; -+ __atomic_store_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); -+ break; -+ } -+ } -+ n++; -+ if (n > UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START) { -+ break; -+ } -+ } while (tmp_port == 0); -+ -+ pthread_mutex_unlock(&g_udp_port_mutex); -+ -+ return tmp_port; -+} -+#else - static u16_t - udp_new_port(void) - { -@@ -123,6 +170,7 @@ again: - } - return udp_port; - } -+#endif - - /** Common code to see if the current input packet matches the pcb - * (current input packet is accessed via ip(4/6)_current_* macros) -@@ -789,7 +837,21 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - /* if the PCB is not yet bound to a port, bind it here */ - if (pcb->local_port == 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); -+#if GAZELLE_UDP_ENABLE -+ ip_addr_t tmp_local_ip = pcb->local_ip; -+ ip_addr_t tmp_remote_ip = pcb->remote_ip; -+ u16_t tmp_remote_port = pcb->remote_port; -+ -+ pcb->local_ip = netif->ip_addr; -+ pcb->remote_port = dst_port; -+ pcb->remote_ip = *dst_ip; -+#endif - err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); -+#if GAZELLE_UDP_ENABLE -+ pcb->local_ip = tmp_local_ip; -+ pcb->remote_ip = tmp_remote_ip; -+ pcb->remote_port = tmp_remote_port; -+#endif - if (err != ERR_OK) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); - return err; -@@ -941,7 +1003,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - /* @todo: must this be increased even if error occurred? */ - MIB2_STATS_INC(mib2.udpoutdatagrams); - --#if !GAZELLE_ENABLE -+#if !GAZELLE_UDP_ENABLE - /* did we chain a separate header pbuf earlier? */ - if (q != p) - #endif -@@ -1026,7 +1088,7 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) - - /* no port specified? */ - if (port == 0) { -- port = udp_new_port(); -+ port = udp_new_port(pcb); - if (port == 0) { - /* no more ports available in local range */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); -@@ -1252,6 +1314,9 @@ udp_remove(struct udp_pcb *pcb) - } - } - } -+#if GAZELLE_UDP_ENABLE -+ udp_release_port(pcb->local_port); -+#endif - memp_free(MEMP_UDP_PCB, pcb); - } - -diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h -index b1c78e5..f588d90 100644 ---- a/src/include/lwip/udp.h -+++ b/src/include/lwip/udp.h -@@ -112,7 +112,11 @@ struct udp_pcb { - void *recv_arg; - }; - /* udp_pcbs export for external reference (e.g. SNMP agent) */ -+#if GAZELLE_UDP_ENABLE -+extern PER_THREAD struct udp_pcb *udp_pcbs; -+#else - extern struct udp_pcb *udp_pcbs; -+#endif - - /* The following functions is the application layer interface to the - UDP code. */ --- -2.33.0 - diff --git a/0065-fix-udp-recvmbox-size-not-set.patch b/0065-fix-udp-recvmbox-size-not-set.patch deleted file mode 100644 index e8e5663..0000000 --- a/0065-fix-udp-recvmbox-size-not-set.patch +++ /dev/null @@ -1,24 +0,0 @@ -From b94a7024bc7dc4984039b4f54aff3dbdcd21d8b8 Mon Sep 17 00:00:00 2001 -From: jiangheng12 -Date: Wed, 14 Jun 2023 18:34:12 +0800 -Subject: [PATCH] fix udp recvmbox size not set - ---- - src/include/lwipopts.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 6b5c769..f0df0e3 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -180,6 +180,7 @@ - --------------------------------- - */ - #define LWIP_UDP 1 -+#define DEFAULT_UDP_RECVMBOX_SIZE 4096 - - - /* --- -2.23.0 - diff --git a/0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch b/0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch deleted file mode 100644 index ebd81af..0000000 --- a/0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch +++ /dev/null @@ -1,144 +0,0 @@ -From a8ca1b0361d5b31e437fd70d17860248dd44ddf7 Mon Sep 17 00:00:00 2001 -From: Lemmy Huang -Date: Thu, 15 Jun 2023 09:06:58 +0800 -Subject: [PATCH] adapt to dpdk-19.11 and dpdk-21.11 - -Signed-off-by: Lemmy Huang ---- - src/Makefile | 3 +++ - src/include/arch/sys_arch.h | 1 + - src/include/dpdk_cksum.h | 3 +++ - src/include/dpdk_version.h | 52 +++++++++++++++++++++++++++++++++++++ - src/include/eventpoll.h | 1 + - src/include/reg_sock.h | 2 ++ - 6 files changed, 62 insertions(+) - create mode 100644 src/include/dpdk_version.h - -diff --git a/src/Makefile b/src/Makefile -index f445601b..480470fb 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -19,6 +19,9 @@ ARFLAGS = crDP - ifeq ($(shell $(CC) -dumpmachine | cut -d"-" -f1), x86_64) - CFLAGS += -mssse3 - endif -+ifeq ($(DPDK_VERSION_1911), 1) -+ CFLAGS += -DDPDK_VERSION_1911=1 -+endif - - SRCS = - DIRS = api core netif -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -index 04e3192a..5e95f3d3 100644 ---- a/src/include/arch/sys_arch.h -+++ b/src/include/arch/sys_arch.h -@@ -79,6 +79,7 @@ typedef struct sys_thread *sys_thread_t; - #if GAZELLE_ENABLE - extern int eth_dev_poll(void); - #include -+#include "dpdk_version.h" - - /* - gazelle custom rte ring interface -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index e41644b5..b48c9267 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -34,8 +34,11 @@ - #define __DPDK_CKSUM_H__ - - #include "lwipopts.h" -+ - #if GAZELLE_ENABLE -+#include - #include -+#include "dpdk_version.h" - - #if CHECKSUM_OFFLOAD_ALL - #include -diff --git a/src/include/dpdk_version.h b/src/include/dpdk_version.h -new file mode 100644 -index 00000000..43b254a8 ---- /dev/null -+++ b/src/include/dpdk_version.h -@@ -0,0 +1,52 @@ -+/* -+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without modification, -+ * are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ * -+ * This file is part of the lwIP TCP/IP stack. -+ * -+ * Author: Huawei Technologies -+ * -+ */ -+ -+#ifndef __DPDK_VERSION_H__ -+#define __DPDK_VERSION_H__ -+ -+#if DPDK_VERSION_1911 -+#define __rte_ring_enqueue_elems(r, prod_head, obj_table, esize, n) \ -+ ENQUEUE_PTRS(r, &r[1], prod_head, (obj_table), n, void *) -+ -+#define __rte_ring_dequeue_elems(r, cons_head, obj_table, esize, n) \ -+ DEQUEUE_PTRS(r, &r[1], cons_head, (obj_table), n, void *) -+ -+#define RTE_MBUF_F_RX_IP_CKSUM_BAD PKT_RX_IP_CKSUM_BAD -+#define RTE_MBUF_F_RX_L4_CKSUM_BAD PKT_RX_L4_CKSUM_BAD -+#define RTE_MBUF_F_TX_IPV4 PKT_TX_IPV4 -+#define RTE_MBUF_F_TX_IP_CKSUM PKT_TX_IP_CKSUM -+#define RTE_MBUF_F_TX_TCP_CKSUM PKT_TX_TCP_CKSUM -+#define RTE_MBUF_F_TX_TCP_SEG PKT_TX_TCP_SEG -+ -+#endif /* DPDK_VERSION_1911 */ -+ -+#endif /* __DPDK_VERSION_H__ */ -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -index a10c84bf..dd65a4d5 100644 ---- a/src/include/eventpoll.h -+++ b/src/include/eventpoll.h -@@ -35,6 +35,7 @@ - - #include - -+#include "arch/sys_arch.h" - #include "lwip/api.h" - #include "list.h" - -diff --git a/src/include/reg_sock.h b/src/include/reg_sock.h -index e349e854..5d5710d7 100644 ---- a/src/include/reg_sock.h -+++ b/src/include/reg_sock.h -@@ -33,6 +33,8 @@ - #ifndef __REG_SOCK_H__ - #define __REG_SOCK_H__ - -+#include -+ - enum reg_ring_type { - REG_RING_TCP_LISTEN = 0, - REG_RING_TCP_LISTEN_CLOSE, --- -2.22.0.windows.1 - diff --git a/0067-fix-null-pointer-when-all-zero-address-listen.patch b/0067-fix-null-pointer-when-all-zero-address-listen.patch deleted file mode 100644 index aa58a8f..0000000 --- a/0067-fix-null-pointer-when-all-zero-address-listen.patch +++ /dev/null @@ -1,100 +0,0 @@ -From b4a2b2799c199fb2955ecaae72e7b7dbe79e593b Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Thu, 15 Jun 2023 21:42:04 +0800 -Subject: [PATCH] fix null pointer when all zero address listen - ---- - src/core/tcp_in.c | 58 ++++++++++++++++++++++++++++------------------- - 1 file changed, 35 insertions(+), 23 deletions(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 0abee30..c20c9b5 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -114,6 +114,36 @@ static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); - #endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ - #endif /* LWIP_TCP_SACK_OUT */ - -+#if GAZELLE_TCP_REUSE_IPPORT -+struct tcp_pcb_listen *min_cnts_lpcb_get(struct tcp_pcb_listen *lpcb) -+{ -+ struct tcp_pcb_listen *min_cnts_lpcb; -+ struct tcp_pcb_listen *tmp_lpcb = lpcb; -+ u16_t min_conn_num = GAZELLE_TCP_MAX_CONN_PER_THREAD; -+ u8_t have_master_fd = 0; -+ -+ while (tmp_lpcb != NULL) { -+ if (tmp_lpcb->master_lpcb) { -+ have_master_fd = 1; -+ } -+ tmp_lpcb = tmp_lpcb->next_same_port_pcb; -+ } -+ -+ tmp_lpcb = lpcb; -+ min_cnts_lpcb = lpcb; -+ while (tmp_lpcb != NULL) { -+ if (!have_master_fd || tmp_lpcb->master_lpcb) { -+ if (tmp_lpcb->connect_num < min_conn_num) { -+ min_cnts_lpcb = tmp_lpcb; -+ min_conn_num = tmp_lpcb->connect_num; -+ } -+ tmp_lpcb = tmp_lpcb->next_same_port_pcb; -+ } -+ } -+ return min_cnts_lpcb; -+} -+#endif -+ - /** - * The initial input processing of TCP. It verifies the TCP header, demultiplexes - * the segment between the PCBs and passes it on to tcp_process(), which implements -@@ -384,33 +414,15 @@ tcp_input(struct pbuf *p, struct netif *inp) - if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { - /* found an exact match */ - #if GAZELLE_TCP_REUSE_IPPORT -- // check master fd -- struct tcp_pcb_listen *tmp_lpcb = lpcb; -- u8_t have_master_fd = 0; -- while (tmp_lpcb != NULL) { -- if (tmp_lpcb->master_lpcb) { -- have_master_fd = 1; -- } -- tmp_lpcb = tmp_lpcb->next_same_port_pcb; -- } -- -- tmp_lpcb = lpcb; -- min_cnts_lpcb = lpcb; -- u16_t min_conn_num = GAZELLE_TCP_MAX_CONN_PER_THREAD; -- while (tmp_lpcb != NULL) { -- if (!have_master_fd || tmp_lpcb->master_lpcb) { -- if (tmp_lpcb->connect_num < min_conn_num) { -- min_cnts_lpcb = tmp_lpcb; -- min_conn_num = tmp_lpcb->connect_num; -- } -- } -- tmp_lpcb = tmp_lpcb->next_same_port_pcb; -- } -+ min_cnts_lpcb = min_cnts_lpcb_get(lpcb); - #endif - break; - } else if (ip_addr_isany(&lpcb->local_ip)) { - /* found an ANY-match */ - #if SO_REUSE -+#if GAZELLE_TCP_REUSE_IPPORT -+ min_cnts_lpcb = min_cnts_lpcb_get(lpcb); -+#endif - lpcb_any = lpcb; - lpcb_prev = prev; - #else /* SO_REUSE */ -@@ -458,7 +470,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - { - #if GAZELLE_TCP_REUSE_IPPORT - tcp_listen_input(min_cnts_lpcb); -- min_cnts_lpcb->connect_num++; -+ min_cnts_lpcb->connect_num++; - #else - tcp_listen_input(lpcb); - #endif --- -2.27.0 - diff --git a/0068-enable-UDP-CKSUM-in-lwip.patch b/0068-enable-UDP-CKSUM-in-lwip.patch deleted file mode 100644 index 9f5d0d9..0000000 --- a/0068-enable-UDP-CKSUM-in-lwip.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 73d78d322ba8bb997d74c92727d1ec8b8640607f Mon Sep 17 00:00:00 2001 -From: kircher -Date: Wed, 21 Jun 2023 16:59:34 +0800 -Subject: [PATCH] enable UDP CKSUM in lwip - ---- - src/include/dpdk_cksum.h | 1 + - src/include/lwipopts.h | 6 ++++++ - 2 files changed, 7 insertions(+) - -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index b48c926..2c5b31e 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -87,6 +87,7 @@ static inline void tcph_cksum_set(struct pbuf *p, u16_t len) { - - static inline void udph_cksum_set(struct pbuf *p, u16_t len) { - p->l4_len = len; -+ p->ol_flags |= RTE_MBUF_F_TX_UDP_CKSUM; - } - - static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index f0df0e3..2ba1e4c 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -180,6 +180,12 @@ - --------------------------------- - */ - #define LWIP_UDP 1 -+ -+#define UDP_HLEN 8 -+ -+#define MEMP_NUM_UDP_PCB 16 -+#define MEMP_NUM_IGMP_GROUP 16 -+ - #define DEFAULT_UDP_RECVMBOX_SIZE 4096 - - --- -2.33.0 - diff --git a/0069-add-error-check-in-hugepage_init-and-sys_mbox_free.patch b/0069-add-error-check-in-hugepage_init-and-sys_mbox_free.patch deleted file mode 100644 index 55710e8..0000000 --- a/0069-add-error-check-in-hugepage_init-and-sys_mbox_free.patch +++ /dev/null @@ -1,72 +0,0 @@ -From cbeb07ef6238a719a2bb84837835ebc228ac4fde Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 20 Jun 2023 14:56:28 +0800 -Subject: [PATCH] add error check in hugepage_init and sys_mbox_free - ---- - src/api/sys_arch.c | 8 ++++++-- - src/include/memp_def.h | 13 ++++++++++++- - 2 files changed, 18 insertions(+), 3 deletions(-) - -diff --git a/src/api/sys_arch.c b/src/api/sys_arch.c -index f93a00e..1bc3aee 100644 ---- a/src/api/sys_arch.c -+++ b/src/api/sys_arch.c -@@ -124,8 +124,12 @@ err_t sys_mbox_new(struct sys_mbox **mb, int size) - void sys_mbox_free(struct sys_mbox **mb) - { - struct sys_mbox *mbox = *mb; -- rte_ring_free(mbox->ring); -+ if (mbox->ring != NULL) { -+ rte_ring_free(mbox->ring); -+ mbox->ring = NULL; -+ } - memp_free(MEMP_SYS_MBOX, mbox); -+ sys_mbox_set_invalid(mb); - } - - err_t sys_mbox_trypost(struct sys_mbox **mb, void *msg) -@@ -371,7 +375,7 @@ uint8_t *sys_hugepage_malloc(const char *name, uint32_t size) - - mz = rte_memzone_reserve(name, size, rte_socket_id(), 0); - if (mz == NULL) { -- rte_exit(EXIT_FAILURE, "failed to reserver memory for mempool[%s]\n", name); -+ LWIP_DEBUGF(SYS_DEBUG, ("sys_hugepage_malloc: failed to reserve memory for mempool\n")); - return NULL; - } - -diff --git a/src/include/memp_def.h b/src/include/memp_def.h -index 082f685..3408c60 100644 ---- a/src/include/memp_def.h -+++ b/src/include/memp_def.h -@@ -52,15 +52,26 @@ - #include - #undef LWIP_MEMPOOL - --static inline void hugepage_init(void) -+extern PER_THREAD uint8_t *ram_heap; -+static inline int hugepage_init(void) - { - #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_BASE_INIT(name) - #include "lwip/priv/memp_std.h" -+ u16_t i; -+ for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) { -+ if (memp_pools[i]->base == NULL) { -+ return -1; -+ } -+ } - - #if !MEM_LIBC_MALLOC - LWIP_MEM_MEMORY_DECLARE(ram_heap) - LWIP_MEM_MEMORY_INIT(ram_heap) -+ if (ram_heap == NULL) { -+ return -1; -+ } - #endif /* MEM_LIBC_MALLOC */ -+ return 0; - } - - #endif /* __MEMP_DEF_H__ */ --- -2.27.0 - diff --git a/0070-add-CHECKSUM_UDP-when-not-support-OFFLOAD_UDP_CHECKS.patch b/0070-add-CHECKSUM_UDP-when-not-support-OFFLOAD_UDP_CHECKS.patch deleted file mode 100644 index 55b1779..0000000 --- a/0070-add-CHECKSUM_UDP-when-not-support-OFFLOAD_UDP_CHECKS.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 4ea38ff354eb4dad54be3c056b884ff7920135da Mon Sep 17 00:00:00 2001 -From: kircher -Date: Tue, 27 Jun 2023 11:18:58 +0800 -Subject: [PATCH] add CHECKSUM_UDP when not support OFFLOAD_UDP_CHECKSUM - ---- - src/core/tcp_in.c | 2 +- - src/core/udp.c | 26 +++++++++++++++++++++++++- - src/include/dpdk_cksum.h | 16 ++++++++++------ - src/include/dpdk_version.h | 1 + - src/include/lwipopts.h | 8 ++++++-- - 5 files changed, 43 insertions(+), 10 deletions(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 62a6511..5014a21 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -210,7 +210,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - #if CHECKSUM_CHECK_TCP_HW - u64_t ret; - if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_TCP_CKSUM) { -- ret = is_cksum_tcpbad(p); -+ ret = is_cksum_bad(p); - } else { - ret = (u64_t)ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - ip_current_src_addr(), ip_current_dest_addr()); -diff --git a/src/core/udp.c b/src/core/udp.c -index 0b1fa65..d9db535 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -412,9 +412,21 @@ udp_input(struct pbuf *p, struct netif *inp) - #endif /* LWIP_UDPLITE */ - { - if (udphdr->chksum != 0) { -+#if CHECKSUM_CHECK_UDP_HW -+ u64_t ret = 0; -+ if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_UDP_CKSUM) { -+ ret = is_cksum_bad(p); -+ } else { -+ ret = ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, -+ ip_current_src_addr(), -+ ip_current_dest_addr()); -+ } -+ if (ret != 0) { -+#else /* CHECKSUM_CHECK_UDP_HW */ - if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, - ip_current_src_addr(), - ip_current_dest_addr()) != 0) { -+#endif /* CHECKSUM_CHECK_UDP_HW */ - goto chkerr; - } - } -@@ -970,8 +982,18 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - } else - #endif /* LWIP_CHECKSUM_ON_COPY */ - { -+#if CHECKSUM_GEN_UDP_HW -+ if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_UDP_CKSUM) { -+ udph_cksum_set(q, UDP_HLEN); -+ udpchksum = ip_chksum_pseudo_offload(IP_PROTO_UDP, q->tot_len, &pcb->local_ip, &pcb->remote_ip); -+ } else { -+ udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, -+ src_ip, dst_ip); -+ } -+#else /* CHECKSUM_GEN_UDP_HW */ - udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, - src_ip, dst_ip); -+#endif /* CHECKSUM_GEN_UDP_HW */ - } - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ -@@ -996,7 +1018,9 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); - /* output to IP */ - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); -- udph_cksum_set(q, UDP_HLEN); -+#if GAZELLE_UDP_ENABLE -+ q->l4_len = UDP_HLEN; -+#endif /* GAZELLE_UDP_ENABLE */ - err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); - NETIF_RESET_HINTS(netif); - -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index 2c5b31e..d092a1d 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -54,12 +54,12 @@ static inline u64_t is_cksum_ipbad(struct pbuf *p) { - } - #endif /* CHECKSUM_CHECK_IP_HW */ - --#if CHECKSUM_CHECK_TCP_HW --// for tcp_input --static inline u64_t is_cksum_tcpbad(struct pbuf *p) { -+#if (CHECKSUM_CHECK_TCP_HW || CHECKSUM_CHECK_UDP_HW) -+// for tcp_input and udp_input -+static inline u64_t is_cksum_bad(struct pbuf *p) { - return p->ol_flags & (RTE_MBUF_F_RX_L4_CKSUM_BAD); - } --#endif /* CHECKSUM_CHECK_TCP_HW */ -+#endif /* (CHECKSUM_CHECK_TCP_HW || CHECKSUM_CHECK_UDP_HW) */ - - #if CHECKSUM_GEN_IP_HW - static inline void ethh_cksum_set(struct pbuf *p, u16_t len) { -@@ -77,18 +77,22 @@ static inline void iph_cksum_set(struct pbuf *p, u16_t len, bool do_ipcksum) { - #endif /* CHECKSUM_GEN_IP_HW */ - - // replace ip_chksum_pseudo --#if CHECKSUM_GEN_TCP_HW -+#if (CHECKSUM_GEN_TCP_HW || CHECKSUM_GEN_UDP_HW) - #include - -+#if CHECKSUM_GEN_TCP_HW - static inline void tcph_cksum_set(struct pbuf *p, u16_t len) { - p->l4_len = len; - p->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; - } -+#endif /* CHECKSUM_GEN_TCP_HW */ - -+#if CHECKSUM_GEN_UDP_HW - static inline void udph_cksum_set(struct pbuf *p, u16_t len) { - p->l4_len = len; - p->ol_flags |= RTE_MBUF_F_TX_UDP_CKSUM; - } -+#endif /* CHECKSUM_GEN_UDP_HW */ - - static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dst) -@@ -109,7 +113,7 @@ static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, - - return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); - } --#endif /* CHECKSUM_GEN_TCP_HW */ -+#endif /* (CHECKSUM_GEN_TCP_HW || CHECKSUM_GEN_UDP_HW) */ - - #endif /* GAZELLE_ENABLE */ - #endif /* __DPDK_CKSUM_H__ */ -diff --git a/src/include/dpdk_version.h b/src/include/dpdk_version.h -index 43b254a..c90ddb8 100644 ---- a/src/include/dpdk_version.h -+++ b/src/include/dpdk_version.h -@@ -46,6 +46,7 @@ - #define RTE_MBUF_F_TX_IP_CKSUM PKT_TX_IP_CKSUM - #define RTE_MBUF_F_TX_TCP_CKSUM PKT_TX_TCP_CKSUM - #define RTE_MBUF_F_TX_TCP_SEG PKT_TX_TCP_SEG -+#define RTE_MBUF_F_TX_UDP_CKSUM PKT_TX_UDP_CKSUM - - #endif /* DPDK_VERSION_1911 */ - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 2ba1e4c..5ba123f 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -71,18 +71,22 @@ - // rx cksum - #define CHECKSUM_CHECK_IP 1 /* master switch */ - #define CHECKSUM_CHECK_TCP 1 /* master switch */ -+#define CHECKSUM_CHECK_UDP 1 /* master switch */ - // tx cksum - #define CHECKSUM_GEN_IP 1 /* master switch */ --#define CHECKSUM_GEN_TCP 1 /* master switch */ -+#define CHECKSUM_GEN_TCP 1 /* master switch */ -+#define CHECKSUM_GEN_UDP 1 /* master switch */ - - // rx offload cksum - #define CHECKSUM_CHECK_IP_HW (1 && CHECKSUM_CHECK_IP) /* hardware switch */ - #define CHECKSUM_CHECK_TCP_HW (1 && CHECKSUM_CHECK_TCP) /* hardware switch */ -+#define CHECKSUM_CHECK_UDP_HW (1 && CHECKSUM_CHECK_UDP) /* hardware switch */ - // tx offload cksum - #define CHECKSUM_GEN_IP_HW (1 && CHECKSUM_GEN_IP) /* hardware switch */ - #define CHECKSUM_GEN_TCP_HW (1 && CHECKSUM_GEN_TCP) /* hardware switch */ -+#define CHECKSUM_GEN_UDP_HW (1 && CHECKSUM_GEN_UDP) /* hardware switch */ - --#define CHECKSUM_OFFLOAD_ALL (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW || CHECKSUM_CHECK_IP_HW || CHECKSUM_CHECK_TCP_HW) -+#define CHECKSUM_OFFLOAD_ALL (CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW || CHECKSUM_CHECK_IP_HW || CHECKSUM_CHECK_TCP_HW || CHECKSUM_CHECK_UDP_HW || CHECKSUM_GEN_UDP_HW) - - - /* --- -2.28.0.windows.1 - diff --git a/0071-fix-pbuf-tot_len-incorrect-after-pbuf_split_64k-is-c.patch b/0071-fix-pbuf-tot_len-incorrect-after-pbuf_split_64k-is-c.patch deleted file mode 100644 index 7bf4711..0000000 --- a/0071-fix-pbuf-tot_len-incorrect-after-pbuf_split_64k-is-c.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 339ad47548236f2b11ee6161a419db8aa664138c Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 15 Sep 2023 09:33:56 +0800 -Subject: [PATCH] fix pbuf->tot_len incorrect after pbuf_split_64k is called - ---- - src/core/pbuf.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 2385e57..8a55463 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -1194,7 +1194,7 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) - if (r != NULL) { - /* Update the tot_len field in the first part */ - for (i = p; i != NULL; i = i->next) { -- i->tot_len = tot_len_front; -+ i->tot_len = (u16_t)(i->tot_len - r->tot_len); - LWIP_ASSERT("tot_len/len mismatch in last pbuf", - (i->next != NULL) || (i->tot_len == i->len)); - } -@@ -1205,9 +1205,6 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) - /* tot_len field in rest does not need modifications */ - /* reference counters do not need modifications */ - *rest = r; -- r->tot_len = r->len; -- }else{ -- p->tot_len = tot_len_front; - } - } - } --- -2.27.0 - diff --git a/0072-add-O_NONBLOCK-and-FIONBIO-when-not-defined.patch b/0072-add-O_NONBLOCK-and-FIONBIO-when-not-defined.patch deleted file mode 100644 index d4dda8b..0000000 --- a/0072-add-O_NONBLOCK-and-FIONBIO-when-not-defined.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 5ba123f..baf739e 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -244,9 +244,13 @@ - - #define SO_REUSE 1 - -+#ifndef FIONBIO - #define FIONBIO 0x5421 /* same as define in asm-generic/ioctls.h */ -+#endif - -+#ifndef O_NONBLOCK - #define O_NONBLOCK 04000 /* same as define in bits/fcntl-linux.h */ -+#endif - - #define SIOCSHIWAT 1 - diff --git a/0073-lstack_lwip-external-api-start-with-do_lwip_-prefix.patch b/0073-lstack_lwip-external-api-start-with-do_lwip_-prefix.patch deleted file mode 100644 index a6b8741..0000000 --- a/0073-lstack_lwip-external-api-start-with-do_lwip_-prefix.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 39f06e9ef0929da16282b23ec606c3893f394b1e Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Mon, 25 Sep 2023 15:23:51 +0800 -Subject: [PATCH] lstack_lwip: external api start with do_lwip_ prefix - ---- - src/api/api_msg.c | 8 ++++---- - src/api/sockets.c | 8 ++++---- - src/core/pbuf.c | 4 ++-- - src/core/tcp_out.c | 4 ++-- - src/core/udp.c | 4 ++-- - src/include/lwip/pbuf.h | 3 ++- - src/include/lwipsock.h | 19 +++++++++++-------- - 7 files changed, 27 insertions(+), 23 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 869d6bc..3e982ab 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -292,7 +292,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ - #if GAZELLE_UDP_ENABLE -- add_recv_list(conn->socket); -+ do_lwip_add_recvlist(conn->socket); - LWIP_UNUSED_ARG(len); - #else /* GAZELLE_UDP_ENABLE */ - /* Register event with callback */ -@@ -356,7 +356,7 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) - SYS_ARCH_INC(conn->recv_avail, len); - #endif /* LWIP_SO_RCVBUF */ - #if GAZELLE_ENABLE -- add_recv_list(conn->socket); -+ do_lwip_add_recvlist(conn->socket); - LWIP_UNUSED_ARG(len); - #else - /* Register event with callback */ -@@ -492,7 +492,7 @@ err_tcp(void *arg, err_t err) - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, mbox_msg); - #if GAZELLE_ENABLE -- add_recv_list(conn->socket); -+ do_lwip_add_recvlist(conn->socket); - #endif - } - /* pass error message to acceptmbox to wake up pending accept */ -@@ -1348,7 +1348,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) - } - - #if GAZELLE_ENABLE -- gazelle_connected_callback(conn); -+ do_lwip_connected_callback(conn); - #endif - - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); -diff --git a/src/api/sockets.c b/src/api/sockets.c -index f9b7a8f..8d573aa 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -613,7 +613,7 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - return i + LWIP_SOCKET_OFFSET; - } else { - lwip_close(i); -- gazelle_clean_sock(i); -+ do_lwip_clean_sock(i); - } - - err: -@@ -785,7 +785,7 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - } - #if GAZELLE_ENABLE - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < sockets_num + LWIP_SOCKET_OFFSET)); -- gazelle_init_sock(newsock); -+ do_lwip_init_sock(newsock); - #else - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); - #endif /* GAZELLE_ENABLE */ -@@ -1170,7 +1170,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - lwip_recv_tcp_done: - #else /* GAZELLE_ENABLE */ - LWIP_UNUSED_ARG(recv_left); -- recvd = read_lwip_data(sock, flags, apiflags); -+ recvd = do_lwip_read_from_lwip(sock, flags, apiflags); - if (recvd <= 0) { - return recvd; - } -@@ -1369,7 +1369,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 - LWIP_UNUSED_ARG(err); - LWIP_UNUSED_ARG(copied); - LWIP_UNUSED_ARG(i); -- buflen = read_lwip_data(sock, flags, apiflags); -+ buflen = do_lwip_read_from_lwip(sock, flags, apiflags); - if (buflen <= 0) { - return ERR_BUF; - } -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 8a55463..975e240 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -288,7 +288,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - /* If pbuf is to be allocated in RAM, allocate memory for it. */ - #if GAZELLE_ENABLE - /* alloc mbuf avoid send copy */ -- p = lwip_alloc_pbuf(layer, length, type); -+ p = do_lwip_alloc_pbuf(layer, length, type); - #else - p = (struct pbuf *)mem_malloc(alloc_len); - if (p == NULL) { -@@ -780,7 +780,7 @@ pbuf_free(struct pbuf *p) - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { - #if GAZELLE_ENABLE -- gazelle_free_pbuf(p); -+ do_lwip_free_pbuf(p); - #else - struct pbuf_custom *pc = (struct pbuf_custom *)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 6250e6b..547d01e 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -699,7 +699,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - pbuf_cat(p/*header*/, p2/*data*/); - } - #else /* GAZELLE_ENABLE */ -- p = write_lwip_data((struct lwip_sock *)arg, len - pos, &apiflags); -+ p = do_lwip_get_from_sendring((struct lwip_sock *)arg, len - pos, &apiflags); - if (p == NULL) { - break; - } -@@ -764,7 +764,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - - pos += seglen; - #if GAZELLE_ENABLE -- write_lwip_over((struct lwip_sock*)arg); -+ do_lwip_get_from_sendring_over((struct lwip_sock*)arg); - #endif - } - -diff --git a/src/core/udp.c b/src/core/udp.c -index d9db535..5c6dadb 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -677,8 +677,8 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - #if GAZELLE_UDP_ENABLE - uint8_t apiflags = 0; - -- struct pbuf *udp_pbuf = write_lwip_data((struct lwip_sock *)(p->payload), p->tot_len, &apiflags); -- write_lwip_over((struct lwip_sock *)(p->payload)); -+ struct pbuf *udp_pbuf = do_lwip_get_from_sendring((struct lwip_sock *)(p->payload), p->tot_len, &apiflags); -+ do_lwip_get_from_sendring_over((struct lwip_sock *)(p->payload)); - - pbuf_free(p); - p = udp_pbuf; -diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h -index 2639b37..e1f2e50 100644 ---- a/src/include/lwip/pbuf.h -+++ b/src/include/lwip/pbuf.h -@@ -300,7 +300,8 @@ void pbuf_free_ooseq(void); - /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ - #define pbuf_init() - #if GAZELLE_ENABLE --struct pbuf *lwip_alloc_pbuf(pbuf_layer layer, uint16_t length, pbuf_type type); -+extern struct pbuf *do_lwip_alloc_pbuf(pbuf_layer layer, uint16_t length, pbuf_type type); -+extern void do_lwip_free_pbuf(struct pbuf *pbuf); - #endif - struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); - struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); -diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h -index f8480c5..ccc8c43 100644 ---- a/src/include/lwipsock.h -+++ b/src/include/lwipsock.h -@@ -164,13 +164,17 @@ static inline unsigned same_node_ring_count(struct lwip_sock *sock) - #if GAZELLE_ENABLE - extern uint32_t sockets_num; - extern struct lwip_sock *sockets; --extern void gazelle_connected_callback(struct netconn *conn); --extern void add_recv_list(int32_t fd); --extern ssize_t read_lwip_data(struct lwip_sock *sock, int32_t flags, u8_t apiflags); --extern struct pbuf *write_lwip_data(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); --extern void gazelle_init_sock(int32_t fd); --extern void gazelle_clean_sock(int32_t fd); --extern void write_lwip_over(struct lwip_sock *sock); -+ -+extern void do_lwip_init_sock(int32_t fd); -+extern void do_lwip_clean_sock(int32_t fd); -+extern void do_lwip_connected_callback(struct netconn *conn); -+ -+extern struct pbuf *do_lwip_get_from_sendring(struct lwip_sock *sock, uint16_t remain_size, uint8_t *apiflags); -+extern void do_lwip_get_from_sendring_over(struct lwip_sock *sock); -+extern ssize_t do_lwip_read_from_lwip(struct lwip_sock *sock, int32_t flags, u8_t apiflags); -+ -+extern void do_lwip_add_recvlist(int32_t fd); -+ - extern void netif_poll(struct netif *netif); - extern err_t netif_loop_output(struct netif *netif, struct pbuf *p); - extern err_t find_same_node_memzone(struct tcp_pcb *pcb, struct lwip_sock *nsock); -@@ -178,7 +182,6 @@ extern err_t same_node_memzone_create(const struct rte_memzone **zone, int size, - extern err_t same_node_ring_create(struct rte_ring **ring, int size, int port, char *name, char *rx); - extern err_t create_same_node_ring(struct tcp_pcb *pcb); - extern err_t find_same_node_ring(struct tcp_pcb *pcb); --extern void gazelle_free_pbuf(struct pbuf *pbuf); - extern void lstack_calculate_aggregate(int type, uint32_t len); - #endif /* GAZELLE_ENABLE */ - --- -2.27.0 - diff --git a/0074-gazelle-offloads-are-registered-to-lwip.patch b/0074-gazelle-offloads-are-registered-to-lwip.patch deleted file mode 100644 index 0bef4d8..0000000 --- a/0074-gazelle-offloads-are-registered-to-lwip.patch +++ /dev/null @@ -1,241 +0,0 @@ -From cc35c455bb52f78546d7b7216b30203863c017fb Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 24 Oct 2023 17:32:17 +0800 -Subject: [PATCH] gazelle offloads are registered to lwip - ---- - src/core/ipv4/icmp.c | 2 +- - src/core/ipv4/ip4.c | 6 +++--- - src/core/ipv4/ip4_frag.c | 4 ++-- - src/core/netif.c | 20 ++++++++++++++++++++ - src/core/tcp_in.c | 2 +- - src/core/tcp_out.c | 6 +++--- - src/core/udp.c | 4 ++-- - src/include/dpdk_cksum.h | 2 -- - src/include/lwip/netif.h | 20 ++++++++++++++++++++ - 9 files changed, 52 insertions(+), 14 deletions(-) - -diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c -index 402ba69..c3a877c 100644 ---- a/src/core/ipv4/icmp.c -+++ b/src/core/ipv4/icmp.c -@@ -241,7 +241,7 @@ icmp_input(struct pbuf *p, struct netif *inp) - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { - #if CHECKSUM_GEN_IP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_txol_flags(inp) & DEV_TX_OFFLOAD_IPV4_CKSUM) { - iph_cksum_set(p, hlen, 1); - } else { - iph_cksum_set(p, hlen, 0); -diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c -index 1b70bb5..1e3690f 100644 ---- a/src/core/ipv4/ip4.c -+++ b/src/core/ipv4/ip4.c -@@ -509,7 +509,7 @@ ip4_input(struct pbuf *p, struct netif *inp) - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) { - #if CHECKSUM_CHECK_IP_HW - u64_t ret; -- if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_rxol_flags(inp) & DEV_RX_OFFLOAD_IPV4_CKSUM) { - ret = is_cksum_ipbad(p); - } else { - ret = (u64_t)inet_chksum(iphdr, iphdr_hlen); -@@ -986,7 +986,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { - #if CHECKSUM_GEN_IP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_IPV4_CKSUM) { - iph_cksum_set(p, ip_hlen, 1); - } else { - iph_cksum_set(p, ip_hlen, 0); -@@ -1035,7 +1035,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d - #if IP_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ - #if GAZELLE_ENABLE -- if (!(get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO)) { -+ if (!(netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_TCP_TSO)) { - #endif - if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip4_frag(p, netif, dest); -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index e01ea51..f63a99e 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -642,7 +642,7 @@ ip4_reass(struct pbuf *p) - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { - #if CHECKSUM_GEN_IP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_txol_flags(ip_current_input_netif()) & DEV_TX_OFFLOAD_IPV4_CKSUM) { - iph_cksum_set(p, IP_HLEN, 1); - } else { - iph_cksum_set(p, IP_HLEN, 0); -@@ -885,7 +885,7 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) - #if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { - #if CHECKSUM_GEN_IP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_IPV4_CKSUM) { - iph_cksum_set(p, IP_HLEN, 1); - } else { - iph_cksum_set(p, IP_HLEN, 0); -diff --git a/src/core/netif.c b/src/core/netif.c -index 86b74a0..eb59fbc 100644 ---- a/src/core/netif.c -+++ b/src/core/netif.c -@@ -1049,6 +1049,26 @@ netif_set_link_down(struct netif *netif) - } - } - -+#if GAZELLE_ENABLE -+void -+netif_set_rtc_mode(struct netif *netif) -+{ -+ if (!(netif->flags & NETIF_FLAG_RTC_MODE)) { -+ netif_set_flags(netif, NETIF_FLAG_RTC_MODE); -+ } -+} -+void -+netif_set_rxol_flags(struct netif *netif, u64_t flags) -+{ -+ netif->rxol_flags |= flags; -+} -+void -+netif_set_txol_flags(struct netif *netif, u64_t flags) -+{ -+ netif->txol_flags |= flags; -+} -+#endif -+ - #if LWIP_NETIF_LINK_CALLBACK - /** - * @ingroup netif -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 736845c..07203e5 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -209,7 +209,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - /* Verify TCP checksum. */ - #if CHECKSUM_CHECK_TCP_HW - u64_t ret; -- if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_TCP_CKSUM) { -+ if (netif_get_rxol_flags(inp) & DEV_RX_OFFLOAD_TCP_CKSUM) { - ret = is_cksum_bad(p); - } else { - ret = (u64_t)ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 547d01e..e2c9d63 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1448,7 +1448,7 @@ tcp_output(struct tcp_pcb *pcb) - - /* data available and window allows it to be sent? */ - #if GAZELLE_ENABLE -- if ((get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) && pcb->need_tso_send) { -+ if ((netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_TCP_TSO) && pcb->need_tso_send) { - uint16_t send_pkt = 0; - - do { -@@ -1831,7 +1831,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif - #if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - #if CHECKSUM_GEN_TCP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -+ if (netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_TCP_CKSUM) { - tcph_cksum_set(seg->p, TCPH_HDRLEN_BYTES(seg->tcphdr)); - seg->tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP,seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); - } else { -@@ -2273,7 +2273,7 @@ tcp_output_control_segment(struct tcp_pcb *pcb, struct pbuf *p, - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; - #if CHECKSUM_GEN_TCP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) { -+ if (netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_TCP_CKSUM) { - tcph_cksum_set(p, TCPH_HDRLEN_BYTES(tcphdr)); - tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP, p->tot_len, src, dst); - } else { -diff --git a/src/core/udp.c b/src/core/udp.c -index 5c6dadb..937a045 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -414,7 +414,7 @@ udp_input(struct pbuf *p, struct netif *inp) - if (udphdr->chksum != 0) { - #if CHECKSUM_CHECK_UDP_HW - u64_t ret = 0; -- if (get_eth_params_rx_ol() & DEV_RX_OFFLOAD_UDP_CKSUM) { -+ if (netif_get_txol_flags(inp) & DEV_RX_OFFLOAD_UDP_CKSUM) { - ret = is_cksum_bad(p); - } else { - ret = ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, -@@ -983,7 +983,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d - #endif /* LWIP_CHECKSUM_ON_COPY */ - { - #if CHECKSUM_GEN_UDP_HW -- if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_UDP_CKSUM) { -+ if (netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_UDP_CKSUM) { - udph_cksum_set(q, UDP_HLEN); - udpchksum = ip_chksum_pseudo_offload(IP_PROTO_UDP, q->tot_len, &pcb->local_ip, &pcb->remote_ip); - } else { -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index 5b1b6f6..b8056f9 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -45,8 +45,6 @@ - #include "lwip/pbuf.h" - #endif - --extern uint64_t get_eth_params_rx_ol(void); --extern uint64_t get_eth_params_tx_ol(void); - #if CHECKSUM_CHECK_IP_HW - // for ip4_input - static inline u64_t is_cksum_ipbad(struct pbuf *p) { -diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h -index 057c51f..75f8d50 100644 ---- a/src/include/lwip/netif.h -+++ b/src/include/lwip/netif.h -@@ -106,6 +106,11 @@ extern "C" { - * Set by the netif driver in its init function. */ - #define NETIF_FLAG_MLD6 0x40U - -+#if GAZELLE_ENABLE -+/** If set, use run to completion mode */ -+#define NETIF_FLAG_RTC_MODE 0x80U -+#endif -+ - /** - * @} - */ -@@ -343,6 +348,10 @@ struct netif { - u8_t hwaddr_len; - /** flags (@see @ref netif_flags) */ - u8_t flags; -+#if GAZELLE_ENABLE -+ u64_t rxol_flags; -+ u64_t txol_flags; -+#endif - /** descriptive abbreviation */ - char name[2]; - /** number of this interface. Used for @ref if_api and @ref netifapi_netif, -@@ -464,6 +473,17 @@ void netif_set_down(struct netif *netif); - */ - #define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) - -+#if GAZELLE_ENABLE -+#define netif_is_rtc_mode(netif) (((netif)->flags & NETIF_FLAG_RTC_MODE) ? (u8_t)1 : (u8_t)0) -+#define netif_get_rxol_flags(netif) ((netif)->rxol_flags) -+#define netif_get_txol_flags(netif) ((netif)->txol_flags) -+ -+void netif_set_rtc_mode(struct netif *netif); -+void netif_set_rxol_flags(struct netif *netif, u64_t flags); -+void netif_set_txol_flags(struct netif *netif, u64_t flags); -+ -+#endif -+ - #if LWIP_NETIF_STATUS_CALLBACK - void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); - #endif /* LWIP_NETIF_STATUS_CALLBACK */ --- -2.27.0 - diff --git a/0075-adapt-read-write-for-rtc-mode.patch b/0075-adapt-read-write-for-rtc-mode.patch deleted file mode 100644 index 9da5656..0000000 --- a/0075-adapt-read-write-for-rtc-mode.patch +++ /dev/null @@ -1,457 +0,0 @@ -From be56e9eed8acf82a862d19ef4f890f309018ddde Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Sat, 28 Oct 2023 17:21:46 +0800 -Subject: [PATCH] adapt read/write for rtc mode - ---- - src/api/api_msg.c | 14 ++-- - src/api/sockets.c | 21 ++--- - src/core/init.c | 2 +- - src/core/pbuf.c | 7 ++ - src/core/tcp_out.c | 171 +++++++++++++++++++++++++++++++++-------- - src/core/udp.c | 2 +- - src/include/lwip/tcp.h | 4 + - src/include/lwipopts.h | 6 +- - 8 files changed, 174 insertions(+), 53 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 3e982ab..d8b99ee 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -1753,11 +1753,15 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) - write_more = 0; - } - #if GAZELLE_ENABLE -- /* vector->ptr is private arg sock */ -- LWIP_UNUSED_ARG(dataptr); -- write_more = 0; -- err = tcp_write(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags); -- conn->current_msg->msg.w.len = len; -+ if (netif_is_rtc_mode(netif_default)) { -+ err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); -+ } else { -+ /* vector->ptr is private arg sock */ -+ LWIP_UNUSED_ARG(dataptr); -+ write_more = 0; -+ err = tcp_write_from_stack(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags); -+ conn->current_msg->msg.w.len = len; -+ } - conn->pcb.tcp->need_tso_send = 1; - #else - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 8d573aa..e374f96 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1087,7 +1087,15 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - apiflags |= NETCONN_DONTBLOCK; - } - --#if !GAZELLE_ENABLE -+#if GAZELLE_ENABLE -+ if (!netif_is_rtc_mode(netif_default)) { -+ LWIP_UNUSED_ARG(recv_left); -+ recvd = do_lwip_read_from_lwip(sock, flags, apiflags); -+ if (recvd <= 0) { -+ return recvd; -+ } -+ } else { -+#endif - do { - struct pbuf *p; - err_t err; -@@ -1166,15 +1174,10 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) - apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; - /* @todo: do we need to support peeking more than one pbuf? */ - } while ((recv_left > 0) && !(flags & MSG_PEEK)); -- --lwip_recv_tcp_done: --#else /* GAZELLE_ENABLE */ -- LWIP_UNUSED_ARG(recv_left); -- recvd = do_lwip_read_from_lwip(sock, flags, apiflags); -- if (recvd <= 0) { -- return recvd; -+#if GAZELLE_ENABLE - } --#endif /* GAZELLE_ENABLE */ -+#endif -+lwip_recv_tcp_done: - if (apiflags & NETCONN_NOAUTORCVD) { - if ((recvd > 0) && !(flags & MSG_PEEK)) { - /* ensure window update after copying all data */ -diff --git a/src/core/init.c b/src/core/init.c -index 7b6214f..60e1c68 100644 ---- a/src/core/init.c -+++ b/src/core/init.c -@@ -306,7 +306,7 @@ PACK_STRUCT_END - #if TCP_SNDLOWAT >= TCP_SND_BUF - #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." - #endif --#if TCP_SNDLOWAT >= (0xFFFFFFFF - (4 * TCP_MSS)) -+#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) - #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" - #endif - #if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN -diff --git a/src/core/pbuf.c b/src/core/pbuf.c -index 975e240..61690ff 100644 ---- a/src/core/pbuf.c -+++ b/src/core/pbuf.c -@@ -117,6 +117,7 @@ pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset); - volatile u8_t pbuf_free_ooseq_pending; - #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() - -+#if !GAZELLE_ENABLE - /** - * Attempt to reclaim some memory from queued out-of-sequence TCP segments - * if we run out of pool pbufs. It's better to give priority to new packets -@@ -176,6 +177,7 @@ pbuf_pool_is_empty(void) - } - #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ - } -+#endif /* GAZELLE_ENABLE */ - #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ - - /* Initialize members of struct pbuf after allocation */ -@@ -238,6 +240,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - p = pbuf_alloc_reference(NULL, length, type); - break; - case PBUF_POOL: { -+#if GAZELLE_ENABLE -+ // alloc from pktmbuf pool, one pbuf is enough -+ p = do_lwip_alloc_pbuf(layer, length, type); -+#else - struct pbuf *q, *last; - u16_t rem_len; /* remaining length */ - p = NULL; -@@ -273,6 +279,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) - rem_len = (u16_t)(rem_len - qlen); - offset = 0; - } while (rem_len > 0); -+#endif /* GAZELLE_ENABLE */ - break; - } - case PBUF_RAM: { -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index e2c9d63..073d989 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -515,15 +515,18 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - * pos records progress as data is segmented. - */ - --#if !GAZELLE_ENABLE - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; - u16_t unsent_optlen; - -+#if GAZELLE_ENABLE -+ last_unsent = pcb->last_unsent; -+#else - /* @todo: this could be sped up by keeping last_unsent in the pcb */ - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); -+#endif - - /* Usable space at the end of the last unsent segment */ - unsent_optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(last_unsent->flags, pcb); -@@ -631,9 +634,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - pcb->unsent_oversize == 0); - #endif /* TCP_OVERSIZE */ - } --#else /* GAZELLE_ENABLE */ -- last_unsent = pcb->last_unsent; --#endif /* GAZELLE_ENABLE */ - - /* - * Phase 3: Create new segments. -@@ -651,7 +651,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - u8_t chksum_swapped = 0; - #endif /* TCP_CHECKSUM_ON_COPY */ - --#if !GAZELLE_ENABLE - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ -@@ -698,13 +697,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(p/*header*/, p2/*data*/); - } --#else /* GAZELLE_ENABLE */ -- p = do_lwip_get_from_sendring((struct lwip_sock *)arg, len - pos, &apiflags); -- if (p == NULL) { -- break; -- } -- seglen = p->tot_len; --#endif /* GAZELLE_ENABLE */ - - queuelen += pbuf_clen(p); - -@@ -714,14 +706,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", - queuelen, (int)TCP_SND_QUEUELEN)); --#if GAZELLE_ENABLE -- if (pos > 0) { -- queuelen -= pbuf_clen(p); -- break; -- } --#else - pbuf_free(p); --#endif - goto memerr; - } - -@@ -730,12 +715,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - #endif - - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { --#if GAZELLE_ENABLE -- if (pos > 0) { -- queuelen -= pbuf_clen(p); -- break; -- } --#endif - goto memerr; - } - #if TCP_OVERSIZE_DBGCHECK -@@ -763,9 +742,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; --#if GAZELLE_ENABLE -- do_lwip_get_from_sendring_over((struct lwip_sock*)arg); --#endif - } - - /* -@@ -855,12 +831,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) - if (queue) { - pcb->last_unsent = prev_seg; - } -- pcb->snd_lbb += pos; -- pcb->snd_buf -= pos; --#else -+#endif - pcb->snd_lbb += len; - pcb->snd_buf -= len; --#endif - pcb->snd_queuelen = queuelen; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", -@@ -880,14 +853,12 @@ memerr: - tcp_set_flags(pcb, TF_NAGLEMEMERR); - TCP_STATS_INC(tcp.memerr); - --#if !GAZELLE_ENABLE - if (concat_p != NULL) { - pbuf_free(concat_p); - } - if (queue != NULL) { - tcp_segs_free(queue); - } --#endif - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); -@@ -896,6 +867,137 @@ memerr: - return ERR_MEM; - } - -+#if GAZELLE_ENABLE -+err_t -+tcp_write_from_stack(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) -+{ -+ struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; -+ u16_t pos = 0; /* position in 'arg' data */ -+ u16_t queuelen; -+ u8_t optlen; -+ u8_t optflags = 0; -+ err_t err; -+ u16_t mss_local; -+ -+ /* don't allocate segments bigger than half the maximum window we ever received */ -+ mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2)); -+ mss_local = mss_local ? mss_local : pcb->mss; -+ -+ err = tcp_write_checks(pcb, len); -+ if (err != ERR_OK) { -+ return err; -+ } -+ queuelen = pcb->snd_queuelen; -+ -+ optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); -+ -+ last_unsent = pcb->last_unsent; -+ -+ /* -+ * get pbuf from sendring and create new segments. -+ */ -+ while (pos < len) { -+ struct pbuf *p; -+ u16_t left = len - pos; -+ u16_t max_len = mss_local - optlen; -+ u16_t seglen = LWIP_MIN(left, max_len); -+ -+ p = do_lwip_get_from_sendring((struct lwip_sock *)arg, len - pos, &apiflags); -+ if (p == NULL) { -+ break; -+ } -+ seglen = p->tot_len; -+ -+ queuelen += pbuf_clen(p); -+ -+ /* Now that there are more segments queued, we check again if the -+ * length of the queue exceeds the configured maximum or -+ * overflows. */ -+ if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { -+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", -+ queuelen, (int)TCP_SND_QUEUELEN)); -+ if (pos > 0) { -+ queuelen -= pbuf_clen(p); -+ break; -+ } -+ goto memerr; -+ } -+ -+ lstack_calculate_aggregate(2, p->tot_len); -+ -+ if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { -+ if (pos > 0) { -+ queuelen -= pbuf_clen(p); -+ break; -+ } -+ goto memerr; -+ } -+ -+ /* first segment of to-be-queued data? */ -+ if (queue == NULL) { -+ queue = seg; -+ } else { -+ /* Attach the segment to the end of the queued segments */ -+ LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); -+ prev_seg->next = seg; -+ } -+ /* remember last segment of to-be-queued data for next iteration */ -+ prev_seg = seg; -+ -+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", -+ lwip_ntohl(seg->tcphdr->seqno), -+ lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); -+ -+ pos += seglen; -+ do_lwip_get_from_sendring_over((struct lwip_sock*)arg); -+ } -+ -+ /* -+ * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that -+ * is harmless -+ */ -+ if (last_unsent == NULL) { -+ pcb->unsent = queue; -+ } else { -+ last_unsent->next = queue; -+ } -+ -+ /* -+ * Finally update the pcb state. -+ */ -+ if (queue) { -+ pcb->last_unsent = prev_seg; -+ } -+ pcb->snd_lbb += pos; -+ pcb->snd_buf -= pos; -+ pcb->snd_queuelen = queuelen; -+ -+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", -+ pcb->snd_queuelen)); -+ if (pcb->snd_queuelen != 0) { -+ LWIP_ASSERT("tcp_write: valid queue length", -+ pcb->unacked != NULL || pcb->unsent != NULL); -+ } -+ -+ /* Set the PSH flag in the last segment that we enqueued. */ -+ if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE) == 0)) { -+ TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); -+ } -+ -+ return ERR_OK; -+memerr: -+ tcp_set_flags(pcb, TF_NAGLEMEMERR); -+ TCP_STATS_INC(tcp.memerr); -+ -+ if (pcb->snd_queuelen != 0) { -+ LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || -+ pcb->unsent != NULL); -+ } -+ LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); -+ return ERR_MEM; -+} -+#endif -+ - /** - * Split segment on the head of the unsent queue. If return is not - * ERR_OK, existing head remains intact -@@ -2095,6 +2197,7 @@ tcp_rexmit(struct tcp_pcb *pcb) - - /* Don't take any rtt measurements after retransmitting. */ - pcb->rttest = 0; -+ pcb->need_tso_send = 1; - - /* Do the actual retransmission. */ - MIB2_STATS_INC(mib2.tcpretranssegs); -diff --git a/src/core/udp.c b/src/core/udp.c -index 937a045..828a489 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -414,7 +414,7 @@ udp_input(struct pbuf *p, struct netif *inp) - if (udphdr->chksum != 0) { - #if CHECKSUM_CHECK_UDP_HW - u64_t ret = 0; -- if (netif_get_txol_flags(inp) & DEV_RX_OFFLOAD_UDP_CKSUM) { -+ if (netif_get_rxol_flags(inp) & DEV_RX_OFFLOAD_UDP_CKSUM) { - ret = is_cksum_bad(p); - } else { - ret = ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index e13099c..959df3e 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -567,6 +567,10 @@ err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); - - err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags); -+#if GAZELLE_ENABLE -+err_t tcp_write_from_stack (struct tcp_pcb *pcb, const void *dataptr, u16_t len, -+ u8_t apiflags); -+#endif - - void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index baf739e..fdd4f87 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -208,8 +208,8 @@ - #define TCP_LISTEN_BACKLOG 1 - #define TCP_DEFAULT_LISTEN_BACKLOG 0xff - --#define TCP_OVERSIZE 0 --#define LWIP_NETIF_TX_SINGLE_PBUF 0 -+#define TCP_OVERSIZE TCP_MSS -+#define LWIP_NETIF_TX_SINGLE_PBUF 1 - - #define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) - -@@ -219,7 +219,7 @@ - - #define TCP_SND_QUEUELEN (8191) - --#define TCP_SNDLOWAT (TCP_SND_BUF / 5) -+#define TCP_SNDLOWAT (32768) - - #define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5) - --- -2.27.0 - diff --git a/0076-fix-recvmsg-return-EINVAL.patch b/0076-fix-recvmsg-return-EINVAL.patch deleted file mode 100644 index 32c2830..0000000 --- a/0076-fix-recvmsg-return-EINVAL.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 92091a697ae8dac4026fd75a421ad9464aaa253e Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Wed, 25 Oct 2023 15:44:19 +0800 -Subject: [PATCH 76/77] fix recvmsg return EINVAL - ---- - src/api/sockets.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index b6c7b05..1d71427 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1492,9 +1492,21 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) - /* check for valid vectors */ - buflen = 0; - for (i = 0; i < message->msg_iovlen; i++) { -+#if GAZELLE_ENABLE -+ /* msg_iov[i].iov_len == 0 dont return ERRVAL -+ * According to the Single Unix Specification we should return EINVAL if an elment length is < 0 -+ * when cast to ssize_t -+ */ -+ if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len < 0) || -+#else - if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || -+#endif - ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || -+#if GAZELLE_ENABLE -+ ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) < 0)) { -+#else - ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { -+#endif - sock_set_errno(sock, err_to_errno(ERR_VAL)); - done_socket(sock); - return -1; --- -2.27.0 - diff --git a/0077-adpat-event-for-rtc-mode.patch b/0077-adpat-event-for-rtc-mode.patch deleted file mode 100644 index 32bfd22..0000000 --- a/0077-adpat-event-for-rtc-mode.patch +++ /dev/null @@ -1,123 +0,0 @@ -From e719fde7f90a1dff8daeb23170febb5ff38903c9 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 27 Oct 2023 19:19:42 +0800 -Subject: [PATCH 77/77] adpat event for rtc mode - ---- - src/api/api_msg.c | 8 ++------ - src/api/sockets.c | 33 ++++++++++++++++++++++++++++++--- - src/include/eventpoll.h | 4 ++++ - 3 files changed, 36 insertions(+), 9 deletions(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 9a8992a..5e09505 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -293,11 +293,9 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - #endif /* LWIP_SO_RCVBUF */ - #if GAZELLE_UDP_ENABLE - do_lwip_add_recvlist(conn->socket); -- LWIP_UNUSED_ARG(len); --#else /* GAZELLE_UDP_ENABLE */ -+#endif /* GAZELLE_UDP_ENABLE */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); --#endif /* GAZELLE_UDP_ENABLE */ - } - } - #endif /* LWIP_UDP */ -@@ -357,11 +355,9 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) - #endif /* LWIP_SO_RCVBUF */ - #if GAZELLE_ENABLE - do_lwip_add_recvlist(conn->socket); -- LWIP_UNUSED_ARG(len); --#else -+#endif - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); --#endif - } - - return ERR_OK; -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 1d71427..d62290d 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2744,29 +2744,56 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - check_waiters = 0; - } - #if GAZELLE_ENABLE -- if (conn->acceptmbox != NULL && !sys_mbox_empty(conn->acceptmbox)) { -- add_sock_event(sock, POLLIN); -+ if (netif_is_rtc_mode(netif_default)) { -+ if (sock->rcvevent == 1) { -+ add_sock_event_nolock(sock, POLLIN); -+ } -+ } else { -+ if (conn->acceptmbox != NULL && !sys_mbox_empty(conn->acceptmbox)) { -+ add_sock_event(sock, POLLIN); -+ } - } - #endif - break; - case NETCONN_EVT_RCVMINUS: - sock->rcvevent--; - check_waiters = 0; -+#if GAZELLE_ENABLE -+ if (netif_is_rtc_mode(netif_default)) { -+ if (sock->rcvevent == 0) { -+ del_sock_event_nolock(sock, POLLIN); -+ } -+ } -+#endif - break; - case NETCONN_EVT_SENDPLUS: - if (sock->sendevent) { - check_waiters = 0; - } - sock->sendevent = 1; -+#if GAZELLE_ENABLE -+ if (netif_is_rtc_mode(netif_default)) { -+ add_sock_event_nolock(sock, POLLOUT); -+ } -+#endif - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; - check_waiters = 0; -+#if GAZELLE_ENABLE -+ if (netif_is_rtc_mode(netif_default)) { -+ del_sock_event_nolock(sock, POLLOUT); -+ } -+#endif - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; - #if GAZELLE_ENABLE -- add_sock_event(sock, EPOLLERR); -+ if (netif_is_rtc_mode(netif_default)) { -+ add_sock_event_nolock(sock, EPOLLERR); -+ } else { -+ add_sock_event(sock, EPOLLERR); -+ } - #endif - break; - default: -diff --git a/src/include/eventpoll.h b/src/include/eventpoll.h -index dd65a4d..5bc5206 100644 ---- a/src/include/eventpoll.h -+++ b/src/include/eventpoll.h -@@ -66,6 +66,10 @@ struct libos_epoll { - - struct lwip_sock; - extern void add_sock_event(struct lwip_sock *sock, uint32_t event); -+extern void add_sock_event_nolock(struct lwip_sock *sock, uint32_t event); -+extern void del_sock_event(struct lwip_sock *sock, uint32_t event); -+extern void del_sock_event_nolock(struct lwip_sock *sock, uint32_t event); -+ - extern int32_t lstack_epoll_close(int32_t); - - #endif /* __EVENTPOLL_H__ */ --- -2.27.0 - diff --git a/0078-posix_api-support-select.patch b/0078-posix_api-support-select.patch deleted file mode 100644 index 93cb177..0000000 --- a/0078-posix_api-support-select.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 189022c0a2438f099caa6cbfcac1a7ca76cf1e71 Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Fri, 3 Nov 2023 14:55:15 +0800 -Subject: [PATCH] posix_api: support select - ---- - src/api/posix_api.c | 1 + - src/include/posix_api.h | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/src/api/posix_api.c b/src/api/posix_api.c -index b7334da..0dc6ad1 100644 ---- a/src/api/posix_api.c -+++ b/src/api/posix_api.c -@@ -114,6 +114,7 @@ int posix_api_init(void) - CHECK_DLSYM_RET_RETURN(posix_api->sigaction_fn = dlsym(handle, "sigaction")); - CHECK_DLSYM_RET_RETURN(posix_api->poll_fn = dlsym(handle, "poll")); - CHECK_DLSYM_RET_RETURN(posix_api->ioctl_fn = dlsym(handle, "ioctl")); -+ CHECK_DLSYM_RET_RETURN(posix_api->select_fn = dlsym(handle, "select")); - - /* lstack helper api */ - posix_api->get_socket = get_socket; -diff --git a/src/include/posix_api.h b/src/include/posix_api.h -index a73e2ec..cde37e3 100644 ---- a/src/include/posix_api.h -+++ b/src/include/posix_api.h -@@ -78,6 +78,7 @@ typedef struct { - int (*sigaction_fn)(int signum, const struct sigaction *act, struct sigaction *oldact); - int (*poll_fn)(struct pollfd *fds, nfds_t nfds, int timeout); - int (*ioctl_fn)(int fd, int cmd, ...); -+ int (*select_fn)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); - - int ues_posix; - } posix_api_t; --- -2.23.0 - diff --git a/0079-enable-vlan-define.patch b/0079-enable-vlan-define.patch deleted file mode 100644 index da751bf..0000000 --- a/0079-enable-vlan-define.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a7be70b7c210fbe17d4b6a90b8c8a155dd489035 Mon Sep 17 00:00:00 2001 -From: compile_success <980965867@qq.com> -Date: Sat, 4 Nov 2023 14:16:06 +0000 -Subject: [PATCH] enable vlan define - ---- - src/include/lwipopts.h | 3 +++ - src/netif/ethernet.c | 4 ++++ - 2 files changed, 7 insertions(+) - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index fdd4f87..a18179e 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -261,4 +261,7 @@ - */ - #define LWIP_NETIF_LOOPBACK 1 - -+#define ETHARP_SUPPORT_VLAN 1 -+#define LWIP_VLAN_PCP 1 -+ - #endif /* __LWIPOPTS_H__ */ -diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c -index cbe298e..d411892 100644 ---- a/src/netif/ethernet.c -+++ b/src/netif/ethernet.c -@@ -321,7 +321,11 @@ ethernet_output(struct netif * netif, struct pbuf * p, - ("ethernet_output: sending packet %p\n", (void *)p)); - - #if CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW -+#if LWIP_VLAN_PCP -+ ethh_cksum_set(p, sizeof(*ethhdr)+SIZEOF_VLAN_HDR); -+#else - ethh_cksum_set(p, sizeof(*ethhdr)); -+#endif - #endif - - /* send the packet */ --- -2.33.0 - diff --git a/0080-enable-ipv6.patch b/0080-enable-ipv6.patch deleted file mode 100644 index 1b75b4a..0000000 --- a/0080-enable-ipv6.patch +++ /dev/null @@ -1,425 +0,0 @@ -From 5d9613fe21e2e02863517dbd9d5db539336351b9 Mon Sep 17 00:00:00 2001 -From: zhengjiebing -Date: Fri, 17 Nov 2023 20:37:56 +0800 -Subject: [PATCH] enable ipv6 - ---- - src/api/sockets.c | 12 +++++++++++- - src/core/dir.mk | 4 +++- - src/core/init.c | 2 ++ - src/core/ipv6/ip6.c | 18 ++++++++++++++++-- - src/core/ipv6/ip6_frag.c | 4 ++++ - src/core/tcp.c | 2 +- - src/core/tcp_in.c | 4 ++-- - src/core/tcp_out.c | 2 ++ - src/core/udp.c | 2 +- - src/include/dpdk_cksum.h | 12 ++++++------ - src/include/dpdk_version.h | 1 + - src/include/lwip/priv/tcp_priv.h | 27 ++++++++++++++++++++------- - src/include/lwip/sockets.h | 2 ++ - src/include/lwip/tcp.h | 21 ++++++++++++++++++++- - src/include/lwipopts.h | 11 ++++++++++- - src/include/reg_sock.h | 7 ++++++- - 16 files changed, 107 insertions(+), 24 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 6cff4cb..62052f2 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -113,6 +113,14 @@ - #endif /* LWIP_IPV4 */ - - #if LWIP_IPV6 -+#if GAZELLE_ENABLE -+#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ -+ (sin6)->sin6_family = AF_INET6; \ -+ (sin6)->sin6_port = lwip_htons((port)); \ -+ (sin6)->sin6_flowinfo = 0; \ -+ inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ -+ (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) -+#else - #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ - (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ - (sin6)->sin6_family = AF_INET6; \ -@@ -120,6 +128,7 @@ - (sin6)->sin6_flowinfo = 0; \ - inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ - (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) -+#endif /* GAZELLE_ENABLE */ - #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ - inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ - if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ -@@ -555,7 +564,8 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - LWIP_UNUSED_ARG(accepted); - - #if GAZELLE_ENABLE -- int type, protocol = 0, domain = AF_INET; -+ int type, protocol = 0; -+ int domain = NETCONNTYPE_ISIPV6(newconn->type) ? AF_INET6 : AF_INET; - switch (NETCONNTYPE_GROUP(newconn->type)) { - case NETCONN_RAW: - type = SOCK_RAW; -diff --git a/src/core/dir.mk b/src/core/dir.mk -index 57a9670..69b43d1 100644 ---- a/src/core/dir.mk -+++ b/src/core/dir.mk -@@ -1,6 +1,8 @@ - SRC = def.c inet_chksum.c init.c ip.c mem.c memp.c netif.c pbuf.c \ - raw.c tcp.c tcp_in.c tcp_out.c timeouts.c udp.c stats.c\ - ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4_frag.c ipv4/etharp.c \ -- ipv4/ip4.c ipv4/igmp.c -+ ipv4/ip4.c ipv4/igmp.c ipv6/icmp6.c ipv6/ip6_addr.c ipv6/ip6_frag.c \ -+ ipv6/ethip6.c ipv6/ip6.c ipv6/dhcp6.c ipv6/inet6.c \ -+ ipv6/mld6.c ipv6/nd6.c - - $(eval $(call register_dir, core, $(SRC))) -diff --git a/src/core/init.c b/src/core/init.c -index 60e1c68..6880fd3 100644 ---- a/src/core/init.c -+++ b/src/core/init.c -@@ -347,7 +347,9 @@ lwip_init(void) - mem_init(); - memp_init(); - pbuf_init(); -+#if !GAZELLE_ENABLE - netif_init(); -+#endif /* GAZELLE_ENABLE */ - #if LWIP_IPV4 - ip_init(); - #if LWIP_ARP -diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c -index 9d904ec..101e599 100644 ---- a/src/core/ipv6/ip6.c -+++ b/src/core/ipv6/ip6.c -@@ -60,6 +60,10 @@ - #include "lwip/debug.h" - #include "lwip/stats.h" - -+#if GAZELLE_ENABLE && (CHECKSUM_CHECK_IP_HW || CHECKSUM_GEN_IP_HW) -+#include "dpdk_cksum.h" -+#endif -+ - #ifdef LWIP_HOOK_FILENAME - #include LWIP_HOOK_FILENAME - #endif -@@ -1232,6 +1236,10 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - /* src cannot be NULL here */ - ip6_addr_copy_to_packed(ip6hdr->src, *src); - -+#if CHECKSUM_GEN_IP_HW -+ iph_cksum_set(p, IP6_HLEN, 0); -+#endif /* CHECKSUM_GEN_IP_HW */ -+ - } else { - /* IP header already included in p */ - ip6hdr = (struct ip6_hdr *)p->payload; -@@ -1270,9 +1278,15 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - #endif /* ENABLE_LOOPBACK */ - #if LWIP_IPV6_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ -- if (netif_mtu6(netif) && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { -- return ip6_frag(p, netif, dest); -+#if GAZELLE_ENABLE -+ if (!(netif_get_txol_flags(netif) & DEV_TX_OFFLOAD_TCP_TSO)) { -+#endif -+ if (netif_mtu6(netif) && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { -+ return ip6_frag(p, netif, dest); -+ } -+#if GAZELLE_ENABLE - } -+#endif - #endif /* LWIP_IPV6_FRAG */ - - LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); -diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c -index 8b352f5..67e36bf 100644 ---- a/src/core/ipv6/ip6_frag.c -+++ b/src/core/ipv6/ip6_frag.c -@@ -689,6 +689,7 @@ ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) - memp_free(MEMP_FRAG_PBUF, p); - } - -+#if !GAZELLE_ENABLE - /** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ - static void -@@ -702,6 +703,7 @@ ip6_frag_free_pbuf_custom(struct pbuf *p) - } - ip6_frag_free_pbuf_custom_ref(pcr); - } -+#endif /* !GAZELLE_ENABLE */ - #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - - /** -@@ -816,7 +818,9 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) - } - pbuf_ref(p); - pcr->original = p; -+#if !GAZELLE_ENABLE - pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; -+#endif /* !GAZELLE_ENABLE */ - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. -diff --git a/src/core/tcp.c b/src/core/tcp.c -index c44664e..963b8a4 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -1155,7 +1155,7 @@ tcp_new_port(void) - - if (__atomic_load_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { - #if GAZELLE_ENABLE -- if (port_in_stack_queue(pcb->remote_ip.addr, pcb->local_ip.addr, pcb->remote_port, tcp_port)) { -+ if (port_in_stack_queue(pcb->remote_ip, pcb->local_ip, pcb->remote_port, tcp_port)) { - tmp_port = tcp_port; - __atomic_store_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); - break; -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index ecbd616..7154659 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -309,8 +309,8 @@ tcp_input(struct pbuf *p, struct netif *inp) - prev = NULL; - - #if GAZELLE_TCP_PCB_HASH -- idx = TUPLE4_HASH_FN( ip_current_dest_addr()->addr, tcphdr->dest, -- ip_current_src_addr()->addr, tcphdr->src) & -+ idx = TUPLE4_HASH_FN( ip_current_dest_addr(), tcphdr->dest, -+ ip_current_src_addr(), tcphdr->src) & - (tcp_active_htable->size - 1); - head = &tcp_active_htable->array[idx].chain; - tcppcb_hlist_for_each(pcb, node, head) { -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 073d989..137e3cf 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -139,7 +139,9 @@ static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct - static struct netif * - tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) - { -+#if LWIP_IPV6 - LWIP_UNUSED_ARG(src); /* in case IPv4-only and source-based routing is disabled */ -+#endif /* LWIP_IPV6 */ - - if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { - return netif_get_by_index(pcb->netif_idx); -diff --git a/src/core/udp.c b/src/core/udp.c -index 828a489..727a705 100644 ---- a/src/core/udp.c -+++ b/src/core/udp.c -@@ -132,7 +132,7 @@ udp_new_port(struct udp_pcb *dst_pcb) - } - - if (__atomic_load_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { -- if (port_in_stack_queue(dst_pcb->remote_ip.addr, dst_pcb->local_ip.addr, dst_pcb->remote_port, udp_port)) { -+ if (port_in_stack_queue(dst_pcb->remote_ip, dst_pcb->local_ip, dst_pcb->remote_port, udp_port)) { - tmp_port = udp_port; - __atomic_store_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); - break; -diff --git a/src/include/dpdk_cksum.h b/src/include/dpdk_cksum.h -index b8056f9..38cfb96 100644 ---- a/src/include/dpdk_cksum.h -+++ b/src/include/dpdk_cksum.h -@@ -66,7 +66,7 @@ static inline void ethh_cksum_set(struct pbuf *p, u16_t len) { - - // replaces IPH_CHKSUM_SET - static inline void iph_cksum_set(struct pbuf *p, u16_t len, bool do_ipcksum) { -- p->ol_flags |= RTE_MBUF_F_TX_IPV4; -+ p->ol_flags |= ((len == IP_HLEN) ? RTE_MBUF_F_TX_IPV4 : RTE_MBUF_F_TX_IPV6); - if (do_ipcksum) { - p->ol_flags |= RTE_MBUF_F_TX_IP_CKSUM; - } -@@ -95,16 +95,16 @@ static inline void udph_cksum_set(struct pbuf *p, u16_t len) { - static inline u16_t ip_chksum_pseudo_offload(u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dst) - { -- struct ipv4_psd_header { -- uint32_t src_addr; /* IP address of source host. */ -- uint32_t dst_addr; /* IP address of destination host. */ -+ struct ip_psd_header { -+ ip_addr_t src_addr; /* IP address of source host. */ -+ ip_addr_t dst_addr; /* IP address of destination host. */ - uint8_t zero; /* zero. */ - uint8_t proto; /* L4 protocol type. */ - uint16_t len; /* L4 length. */ - } psd_hdr; - -- psd_hdr.src_addr = ip4_addr_get_u32(src); -- psd_hdr.dst_addr = ip4_addr_get_u32(dst); -+ ip_addr_copy(psd_hdr.src_addr, *src); -+ ip_addr_copy(psd_hdr.dst_addr, *dst); - psd_hdr.proto = proto; - psd_hdr.len = lwip_htons(proto_len); - psd_hdr.zero = 0; -diff --git a/src/include/dpdk_version.h b/src/include/dpdk_version.h -index c90ddb8..e61d0b3 100644 ---- a/src/include/dpdk_version.h -+++ b/src/include/dpdk_version.h -@@ -43,6 +43,7 @@ - #define RTE_MBUF_F_RX_IP_CKSUM_BAD PKT_RX_IP_CKSUM_BAD - #define RTE_MBUF_F_RX_L4_CKSUM_BAD PKT_RX_L4_CKSUM_BAD - #define RTE_MBUF_F_TX_IPV4 PKT_TX_IPV4 -+#define RTE_MBUF_F_TX_IPV6 PKT_TX_IPV6 - #define RTE_MBUF_F_TX_IP_CKSUM PKT_TX_IP_CKSUM - #define RTE_MBUF_F_TX_TCP_CKSUM PKT_TX_TCP_CKSUM - #define RTE_MBUF_F_TX_TCP_SEG PKT_TX_TCP_SEG -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index ddae3fd..9b1341c 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -347,11 +347,24 @@ static inline int vdev_reg_done(enum reg_ring_type reg_type, const struct tcp_pc - LWIP_ASSERT("Invalid parameter", pcb != NULL); - - struct gazelle_quintuple qtuple; -- qtuple.protocol = 0; -- qtuple.src_ip = pcb->local_ip.addr; -- qtuple.src_port = lwip_htons(pcb->local_port); -- qtuple.dst_ip = pcb->remote_ip.addr; -- qtuple.dst_port = lwip_htons(pcb->remote_port); -+ if (IP_IS_V4_VAL(pcb->local_ip)) { -+ qtuple.protocol = 0; -+ qtuple.src_ip = ip_2_ip4(&pcb->local_ip)->addr; -+ qtuple.src_port = lwip_htons(pcb->local_port); -+ qtuple.dst_ip = ip_2_ip4(&pcb->remote_ip)->addr; -+ qtuple.dst_port = lwip_htons(pcb->remote_port); -+ } else { -+#if LWIP_IPV6 -+ qtuple.protocol = 1; -+ qtuple.src_port = lwip_htons(pcb->local_port); -+ qtuple.dst_port = lwip_htons(pcb->remote_port); -+ -+ for (int i = 0; i < 4; i++) { -+ qtuple.src_ip6[i] = pcb->local_ip.u_addr.ip6.addr[i]; -+ qtuple.dst_ip6[i] = pcb->remote_ip.u_addr.ip6.addr[i]; -+ } -+#endif -+ } - - #if GAZELLE_TCP_REUSE_IPPORT - if (reg_type == REG_RING_TCP_CONNECT_CLOSE) { -@@ -474,8 +487,8 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb) - u32_t idx; \ - struct hlist_head *hd; \ - struct tcp_hash_table *htb = pcbs; \ -- idx = TUPLE4_HASH_FN((npcb)->local_ip.addr, (npcb)->local_port, \ -- (npcb)->remote_ip.addr, (npcb)->remote_port) & \ -+ idx = TUPLE4_HASH_FN(&((npcb)->local_ip), (npcb)->local_port, \ -+ &((npcb)->remote_ip), (npcb)->remote_port) & \ - (htb->size - 1); \ - hd = &htb->array[idx].chain; \ - hlist_add_head(&(npcb)->tcp_node, hd); \ -diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h -index cfec6a5..5715df4 100644 ---- a/src/include/lwip/sockets.h -+++ b/src/include/lwip/sockets.h -@@ -88,7 +88,9 @@ struct sockaddr_in { - - #if LWIP_IPV6 - struct sockaddr_in6 { -+#if !GAZELLE_ENABLE - u8_t sin6_len; /* length of this structure */ -+#endif /* GAZELLE_ENABLE */ - sa_family_t sin6_family; /* AF_INET6 */ - in_port_t sin6_port; /* Transport layer port # */ - u32_t sin6_flowinfo; /* IPv6 flow information */ -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 959df3e..91a86c9 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -476,7 +476,26 @@ static inline unsigned int jhash_3words(unsigned int a, unsigned int b, unsigned - return c; - } - --#define TUPLE4_HASH_FN(laddr, lport, faddr, fport) jhash_3words(laddr, faddr,lport|(fport<<16)) -+static inline unsigned int jhash_3words6(unsigned int *a, unsigned int *b, unsigned int c) -+{ -+ for (int i = 0; i < 4; i++) { -+ unsigned int e = *((unsigned int *)a + i) + JHASH_INITVAL; -+ unsigned int f = *((unsigned int *)b + i) + JHASH_INITVAL; -+ -+ __jhash_final(e, f, c); -+ } -+ -+ return c; -+} -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+#define TUPLE4_HASH_FN(laddr, lport, faddr, fport) \ -+ (IP_IS_V4(laddr) ? jhash_3words(ip_2_ip4(laddr)->addr, ip_2_ip4(faddr)->addr, lport|(fport<<16)) \ -+ : jhash_3words6(ip_2_ip6(laddr)->addr, ip_2_ip6(faddr)->addr, lport|(fport<<16))) -+#elif LWIP_IPV4 -+#define TUPLE4_HASH_FN(laddr, lport, faddr, fport) \ -+ jhash_3words(ip_2_ip4(laddr)->addr, ip_2_ip4(faddr)->addr, lport|(fport<<16)) -+#endif - - #define tcppcb_hlist_for_each(tcppcb, node, list) \ - hlist_for_each_entry(tcppcb, node, list, tcp_node) -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index a18179e..9ab5cde 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -178,6 +178,14 @@ - #define IP_HLEN 20 - - -+/* -+ ------------------------------------- -+ ----------- IPv6 options ----------- -+ ------------------------------------- -+*/ -+#define LWIP_IPV6 1 -+#define IP6_HLEN 40 -+ - /* - --------------------------------- - ---------- UDP options ---------- -@@ -211,7 +219,7 @@ - #define TCP_OVERSIZE TCP_MSS - #define LWIP_NETIF_TX_SINGLE_PBUF 1 - --#define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN) -+#define TCP_MSS (FRAME_MTU - IP6_HLEN - TCP_HLEN - VLAN_LEN) - - #define TCP_WND (2500 * TCP_MSS) - -@@ -263,5 +271,6 @@ - - #define ETHARP_SUPPORT_VLAN 1 - #define LWIP_VLAN_PCP 1 -+#define VLAN_LEN 4 - - #endif /* __LWIPOPTS_H__ */ -diff --git a/src/include/reg_sock.h b/src/include/reg_sock.h -index 5d5710d..5a5e971 100644 ---- a/src/include/reg_sock.h -+++ b/src/include/reg_sock.h -@@ -34,6 +34,7 @@ - #define __REG_SOCK_H__ - - #include -+#include "lwip/ip_addr.h" - - enum reg_ring_type { - REG_RING_TCP_LISTEN = 0, -@@ -50,6 +51,10 @@ struct gazelle_quintuple { - uint16_t dst_port; - uint32_t src_ip; - uint32_t dst_ip; -+#if LWIP_IPV6 -+ uint32_t src_ip6[4]; -+ uint32_t dst_ip6[4]; -+#endif - }; - - struct reg_ring_msg { -@@ -60,6 +65,6 @@ struct reg_ring_msg { - }; - - extern int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); --extern bool port_in_stack_queue(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); -+extern bool port_in_stack_queue(ip_addr_t src_ip, ip_addr_t dst_ip, uint16_t src_port, uint16_t dst_port); - - #endif /* __REG_SOCK_H__ */ --- -2.27.0 - diff --git a/0081-ip6-hdr.patch b/0081-ip6-hdr.patch deleted file mode 100644 index a35fe54..0000000 --- a/0081-ip6-hdr.patch +++ /dev/null @@ -1,354 +0,0 @@ -diff -Nur lwip-ipv6/src/core/ipv6/ip6.c lwip-ipv6-hdr/src/core/ipv6/ip6.c ---- lwip-ipv6/src/core/ipv6/ip6.c 2023-11-15 19:48:02.864481010 +0800 -+++ lwip-ipv6-hdr/src/core/ipv6/ip6.c 2023-11-15 20:05:30.388481010 +0800 -@@ -367,7 +367,7 @@ - * @param inp the netif on which this packet was received - */ - static void --ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) -+ip6_forward(struct pbuf *p, struct ip6hdr *iphdr, struct netif *inp) - { - struct netif *netif; - -@@ -512,7 +512,7 @@ - err_t - ip6_input(struct pbuf *p, struct netif *inp) - { -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - struct netif *netif; - const u8_t *nexth; - u16_t hlen, hlen_tot; /* the current header length */ -@@ -531,7 +531,7 @@ - IP6_STATS_INC(ip6.recv); - - /* identify the IP header */ -- ip6hdr = (struct ip6_hdr *)p->payload; -+ ip6hdr = (struct ip6hdr *)p->payload; - if (IP6H_V(ip6hdr) != 6) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", - IP6H_V(ip6hdr))); -@@ -1015,7 +1015,7 @@ - - /* Returned p point to IPv6 header. - * Update all our variables and pointers and continue. */ -- ip6hdr = (struct ip6_hdr *)p->payload; -+ ip6hdr = (struct ip6hdr *)p->payload; - nexth = &IP6H_NEXTH(ip6hdr); - hlen = hlen_tot = IP6_HLEN; - pbuf_remove_header(p, IP6_HLEN); -@@ -1188,7 +1188,7 @@ - u8_t hl, u8_t tc, - u8_t nexth, struct netif *netif) - { -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - ip6_addr_t dest_addr; - - LWIP_ASSERT_CORE_LOCKED(); -@@ -1217,9 +1217,9 @@ - return ERR_BUF; - } - -- ip6hdr = (struct ip6_hdr *)p->payload; -- LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", -- (p->len >= sizeof(struct ip6_hdr))); -+ ip6hdr = (struct ip6hdr *)p->payload; -+ LWIP_ASSERT("check that first pbuf can hold struct ip6hdr", -+ (p->len >= sizeof(struct ip6hdr))); - - IP6H_HOPLIM_SET(ip6hdr, hl); - IP6H_NEXTH_SET(ip6hdr, nexth); -@@ -1242,7 +1242,7 @@ - - } else { - /* IP header already included in p */ -- ip6hdr = (struct ip6_hdr *)p->payload; -+ ip6hdr = (struct ip6hdr *)p->payload; - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - ip6_addr_assign_zone(&dest_addr, IP6_UNKNOWN, netif); - dest = &dest_addr; -@@ -1316,7 +1316,7 @@ - u8_t hl, u8_t tc, u8_t nexth) - { - struct netif *netif; -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - ip6_addr_t src_addr, dest_addr; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); -@@ -1325,7 +1325,7 @@ - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ -- ip6hdr = (struct ip6_hdr *)p->payload; -+ ip6hdr = (struct ip6hdr *)p->payload; - ip6_addr_copy_from_packed(src_addr, ip6hdr->src); - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - netif = ip6_route(&src_addr, &dest_addr); -@@ -1375,7 +1375,7 @@ - u8_t hl, u8_t tc, u8_t nexth, struct netif_hint *netif_hint) - { - struct netif *netif; -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - ip6_addr_t src_addr, dest_addr; - err_t err; - -@@ -1385,7 +1385,7 @@ - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ -- ip6hdr = (struct ip6_hdr *)p->payload; -+ ip6hdr = (struct ip6hdr *)p->payload; - ip6_addr_copy_from_packed(src_addr, ip6hdr->src); - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - netif = ip6_route(&src_addr, &dest_addr); -@@ -1476,7 +1476,7 @@ - void - ip6_debug_print(struct pbuf *p) - { -- struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; -+ struct ip6hdr *ip6hdr = (struct ip6hdr *)p->payload; - - LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); -diff -Nur lwip-ipv6/src/core/ipv6/ip6_frag.c lwip-ipv6-hdr/src/core/ipv6/ip6_frag.c ---- lwip-ipv6/src/core/ipv6/ip6_frag.c 2023-11-15 19:48:02.864481010 +0800 -+++ lwip-ipv6-hdr/src/core/ipv6/ip6_frag.c 2023-11-15 20:01:41.668481010 +0800 -@@ -551,7 +551,7 @@ - - if (valid) { - /* All fragments have been received */ -- struct ip6_hdr* iphdr_ptr; -+ struct ip6hdr* iphdr_ptr; - - /* chain together the pbufs contained within the ip6_reassdata list. */ - iprh = (struct ip6_reass_helper*) ipr->p->payload; -@@ -565,7 +565,7 @@ - pbuf_remove_header(next_pbuf, IP6_FRAG_HLEN); - #if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { -- /* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ -+ /* hide the extra bytes borrowed from ip6hdr for struct ip6_reass_helper */ - u8_t hdrerr = pbuf_remove_header(next_pbuf, IPV6_FRAG_REQROOM); - LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); -@@ -610,7 +610,7 @@ - (size_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr)); - - /* This is where the IPv6 header is now. */ -- iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->iphdr + -+ iphdr_ptr = (struct ip6hdr*)((u8_t*)ipr->iphdr + - sizeof(struct ip6_frag_hdr)); - - /* Adjust datagram length by adding header lengths. */ -@@ -721,8 +721,8 @@ - err_t - ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) - { -- struct ip6_hdr *original_ip6hdr; -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *original_ip6hdr; -+ struct ip6hdr *ip6hdr; - struct ip6_frag_hdr *frag_hdr; - struct pbuf *rambuf; - #if !LWIP_NETIF_TX_SINGLE_PBUF -@@ -740,7 +740,7 @@ - - identification++; - -- original_ip6hdr = (struct ip6_hdr *)p->payload; -+ original_ip6hdr = (struct ip6hdr *)p->payload; - - /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ - LWIP_ASSERT("p->tot_len >= IP6_HLEN", p->tot_len >= IP6_HLEN); -@@ -769,7 +769,7 @@ - } - /* fill in the IP header */ - SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); -- ip6hdr = (struct ip6_hdr *)rambuf->payload; -+ ip6hdr = (struct ip6hdr *)rambuf->payload; - frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); - #else - /* When not using a static buffer, create a chain of pbufs. -@@ -785,7 +785,7 @@ - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len >= (IP6_HLEN))); - SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); -- ip6hdr = (struct ip6_hdr *)rambuf->payload; -+ ip6hdr = (struct ip6hdr *)rambuf->payload; - frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); - - /* Can just adjust p directly for needed offset. */ -diff -Nur lwip-ipv6/src/core/ipv6/nd6.c lwip-ipv6-hdr/src/core/ipv6/nd6.c ---- lwip-ipv6/src/core/ipv6/nd6.c 2023-11-15 19:48:02.864481010 +0800 -+++ lwip-ipv6-hdr/src/core/ipv6/nd6.c 2023-11-15 20:06:47.036481010 +0800 -@@ -895,7 +895,7 @@ - case ICMP6_TYPE_PTB: /* Packet too big */ - { - struct icmp6_hdr *icmp6hdr; /* Packet too big message */ -- struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ -+ struct ip6hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ - u32_t pmtu; - ip6_addr_t destination_address; - -@@ -909,7 +909,7 @@ - } - - icmp6hdr = (struct icmp6_hdr *)p->payload; -- ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); -+ ip6hdr = (struct ip6hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); - - /* Create an aligned, zoned copy of the destination address. */ - ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); -@@ -2187,7 +2187,7 @@ - static void - nd6_send_q(s8_t i) - { -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - ip6_addr_t dest; - #if LWIP_ND6_QUEUEING - struct nd6_q_entry *q; -@@ -2204,7 +2204,7 @@ - /* pop first item off the queue */ - neighbor_cache[i].q = q->next; - /* Get ipv6 header. */ -- ip6hdr = (struct ip6_hdr *)(q->p->payload); -+ ip6hdr = (struct ip6hdr *)(q->p->payload); - /* Create an aligned copy. */ - ip6_addr_copy_from_packed(dest, ip6hdr->dest); - /* Restore the zone, if applicable. */ -@@ -2219,7 +2219,7 @@ - #else /* LWIP_ND6_QUEUEING */ - if (neighbor_cache[i].q != NULL) { - /* Get ipv6 header. */ -- ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); -+ ip6hdr = (struct ip6hdr *)(neighbor_cache[i].q->payload); - /* Create an aligned copy. */ - ip6_addr_copy_from_packed(dest, ip6hdr->dest); - /* Restore the zone, if applicable. */ -diff -Nur lwip-ipv6/src/core/raw.c lwip-ipv6-hdr/src/core/raw.c ---- lwip-ipv6/src/core/raw.c 2023-11-15 19:48:02.860481010 +0800 -+++ lwip-ipv6-hdr/src/core/raw.c 2023-11-15 19:49:53.468481010 +0800 -@@ -146,7 +146,7 @@ - if (IP_HDR_GET_VERSION(p->payload) == 6) - #endif /* LWIP_IPV4 */ - { -- struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; -+ struct ip6hdr *ip6hdr = (struct ip6hdr *)p->payload; - proto = IP6H_NEXTH(ip6hdr); - } - #if LWIP_IPV4 -diff -Nur lwip-ipv6/src/include/lwip/ip6_frag.h lwip-ipv6-hdr/src/include/lwip/ip6_frag.h ---- lwip-ipv6/src/include/lwip/ip6_frag.h 2023-11-15 19:48:02.864481010 +0800 -+++ lwip-ipv6-hdr/src/include/lwip/ip6_frag.h 2023-11-15 20:13:40.008481010 +0800 -@@ -90,7 +90,7 @@ - struct ip6_reassdata { - struct ip6_reassdata *next; - struct pbuf *p; -- struct ip6_hdr *iphdr; /* pointer to the first (original) IPv6 header */ -+ struct ip6hdr *iphdr; /* pointer to the first (original) IPv6 header */ - #if IPV6_FRAG_COPYHEADER - ip6_addr_p_t src; /* copy of the source address in the IP header */ - ip6_addr_p_t dest; /* copy of the destination address in the IP header */ -diff -Nur lwip-ipv6/src/include/lwip/ip.h lwip-ipv6-hdr/src/include/lwip/ip.h ---- lwip-ipv6/src/include/lwip/ip.h 2023-11-15 19:48:02.864481010 +0800 -+++ lwip-ipv6-hdr/src/include/lwip/ip.h 2023-11-15 20:12:42.796481010 +0800 -@@ -123,7 +123,7 @@ - #endif /* LWIP_IPV4 */ - #if LWIP_IPV6 - /** Header of the input IPv6 packet currently being processed. */ -- struct ip6_hdr *current_ip6_header; -+ struct ip6hdr *current_ip6_header; - #endif /* LWIP_IPV6 */ - /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ - u16_t current_ip_header_tot_len; -@@ -159,7 +159,7 @@ - /** Get the IPv6 header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ --#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) -+#define ip6_current_header() ((const struct ip6hdr*)(ip_data.current_ip6_header)) - /** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ - #define ip_current_is_v6() (ip6_current_header() != NULL) - /** Source IPv6 address of current_header */ -@@ -201,7 +201,7 @@ - /** Get the IPv6 header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ --#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) -+#define ip6_current_header() ((const struct ip6hdr*)(ip_data.current_ip6_header)) - /** Always returns TRUE when only supporting IPv6 only */ - #define ip_current_is_v6() 1 - /** Get the transport layer protocol */ -diff -Nur lwip-ipv6/src/include/lwip/prot/ip6.h lwip-ipv6-hdr/src/include/lwip/prot/ip6.h ---- lwip-ipv6/src/include/lwip/prot/ip6.h 2023-11-15 19:48:02.868481010 +0800 -+++ lwip-ipv6-hdr/src/include/lwip/prot/ip6.h 2023-11-17 13:24:56.832481010 +0800 -@@ -79,7 +79,7 @@ - # include "arch/bpstruct.h" - #endif - PACK_STRUCT_BEGIN --struct ip6_hdr { -+struct ip6hdr { - /** version / traffic class / flow label */ - PACK_STRUCT_FIELD(u32_t _v_tc_fl); - /** payload length */ -diff -Nur lwip-ipv6/src/netif/lowpan6.c lwip-ipv6-hdr/src/netif/lowpan6.c ---- lwip-ipv6/src/netif/lowpan6.c 2023-11-15 19:48:02.868481010 +0800 -+++ lwip-ipv6-hdr/src/netif/lowpan6.c 2023-11-15 20:16:23.836481010 +0800 -@@ -570,12 +570,12 @@ - struct lowpan6_link_addr src, dest; - #if LWIP_6LOWPAN_INFER_SHORT_ADDRESS - ip6_addr_t ip6_src; -- struct ip6_hdr *ip6_hdr; -+ struct ip6hdr *ip6_hdr; - #endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - - #if LWIP_6LOWPAN_INFER_SHORT_ADDRESS - /* Check if we can compress source address (use aligned copy) */ -- ip6_hdr = (struct ip6_hdr *)q->payload; -+ ip6_hdr = (struct ip6hdr *)q->payload; - ip6_addr_copy_from_packed(ip6_src, ip6_hdr->src); - ip6_addr_assign_zone(&ip6_src, IP6_UNICAST, netif); - if (lowpan6_get_address_mode(&ip6_src, &short_mac_addr) == 3) { -diff -Nur lwip-ipv6/src/netif/lowpan6_common.c lwip-ipv6-hdr/src/netif/lowpan6_common.c ---- lwip-ipv6/src/netif/lowpan6_common.c 2023-11-15 19:48:02.868481010 +0800 -+++ lwip-ipv6-hdr/src/netif/lowpan6_common.c 2023-11-15 20:15:44.460481010 +0800 -@@ -137,7 +137,7 @@ - u8_t lowpan6_header_len; - u8_t hidden_header_len = 0; - s8_t i; -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - ip_addr_t ip6src, ip6dst; - - LWIP_ASSERT("netif != NULL", netif != NULL); -@@ -160,7 +160,7 @@ - } - - /* Point to ip6 header and align copies of src/dest addresses. */ -- ip6hdr = (struct ip6_hdr *)inptr; -+ ip6hdr = (struct ip6hdr *)inptr; - ip_addr_copy_from_ip6_packed(ip6dst, ip6hdr->dest); - ip6_addr_assign_zone(ip_2_ip6(&ip6dst), IP6_UNKNOWN, netif); - ip_addr_copy_from_ip6_packed(ip6src, ip6hdr->src); -@@ -396,7 +396,7 @@ - struct lowpan6_link_addr *src, struct lowpan6_link_addr *dest) - { - u16_t lowpan6_offset; -- struct ip6_hdr *ip6hdr; -+ struct ip6hdr *ip6hdr; - s8_t i; - u32_t header_temp; - u16_t ip6_offset = IP6_HLEN; -@@ -408,7 +408,7 @@ - LWIP_ASSERT("hdr_size_comp != NULL", hdr_size_comp != NULL); - LWIP_ASSERT("dehdr_size_decompst != NULL", hdr_size_decomp != NULL); - -- ip6hdr = (struct ip6_hdr *)decomp_buffer; -+ ip6hdr = (struct ip6hdr *)decomp_buffer; - if (decomp_bufsize < IP6_HLEN) { - return ERR_MEM; - } diff --git a/0082-add-vlanid-in-netif.patch b/0082-add-vlanid-in-netif.patch deleted file mode 100644 index 49bffd3..0000000 --- a/0082-add-vlanid-in-netif.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff -Nur lwip-org/src/core/netif.c lwip-vlan/src/core/netif.c ---- lwip-org/src/core/netif.c 2023-11-24 17:38:29.428481010 +0800 -+++ lwip-vlan/src/core/netif.c 2023-11-27 18:35:00.172481010 +0800 -@@ -355,6 +355,11 @@ - netif->input = input; - - NETIF_RESET_HINTS(netif); -+ -+#if GAZELLE_ENABLE -+ netif->vlan_enable=false; -+#endif -+ - #if ENABLE_LOOPBACK - netif->loop_first = NULL; - netif->loop_last = NULL; -@@ -441,6 +446,15 @@ - return netif; - } - -+#if GAZELLE_ENABLE -+void -+netif_set_vlan_tci(struct netif *netif, u16_t vlan_tci) -+{ -+ netif->vlan_enable = true; -+ netif->vlan_tci = vlan_tci; -+} -+#endif -+ - static void - netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) - { -diff -Nur lwip-org/src/core/tcp.c lwip-vlan/src/core/tcp.c ---- lwip-org/src/core/tcp.c 2023-11-24 17:38:29.448481010 +0800 -+++ lwip-vlan/src/core/tcp.c 2023-11-27 10:42:33.228481010 +0800 -@@ -987,7 +987,9 @@ - lpcb->tos = pcb->tos; - - #if LWIP_VLAN_PCP -+#if !GAZELLE_ENABLE - lpcb->netif_hints.tci = pcb->netif_hints.tci; -+#endif - #endif /* LWIP_VLAN_PCP */ - #if GAZELLE_TCP_REUSE_IPPORT - lpcb->connect_num = 0; -diff -Nur lwip-org/src/core/tcp_in.c lwip-vlan/src/core/tcp_in.c ---- lwip-org/src/core/tcp_in.c 2023-11-24 17:38:29.448481010 +0800 -+++ lwip-vlan/src/core/tcp_in.c 2023-11-27 10:42:33.228481010 +0800 -@@ -808,7 +808,9 @@ - npcb->listener = pcb; - #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ - #if LWIP_VLAN_PCP -+#if !GAZELLE_ENABLE - npcb->netif_hints.tci = pcb->netif_hints.tci; -+#endif - #endif /* LWIP_VLAN_PCP */ - /* inherit socket options */ - npcb->so_options = pcb->so_options & SOF_INHERITED; -diff -Nur lwip-org/src/include/lwip/netif.h lwip-vlan/src/include/lwip/netif.h ---- lwip-org/src/include/lwip/netif.h 2023-11-24 17:38:29.440481010 +0800 -+++ lwip-vlan/src/include/lwip/netif.h 2023-11-27 18:33:07.936481010 +0800 -@@ -45,6 +45,10 @@ - - #include "lwip/ip_addr.h" - -+#if GAZELLE_ENABLE -+#include -+#endif -+ - #include "lwip/def.h" - #include "lwip/pbuf.h" - #include "lwip/stats.h" -@@ -357,6 +361,10 @@ - #if GAZELLE_ENABLE - u64_t rxol_flags; - u64_t txol_flags; -+ bool vlan_enable; -+ /** vlan id is an attribute of NIC. The variable 'netif_hints' is not used because it is assigned by pcb, -+ * while non transport layers without pcb cannot be enabled */ -+ u16_t vlan_tci; - #endif - /** descriptive abbreviation */ - char name[2]; -@@ -484,6 +492,7 @@ - #define netif_get_rxol_flags(netif) ((netif)->rxol_flags) - #define netif_get_txol_flags(netif) ((netif)->txol_flags) - -+void netif_set_vlan_tci(struct netif *netif, u16_t vlan_tci); - void netif_set_rtc_mode(struct netif *netif); - void netif_set_rxol_flags(struct netif *netif, u64_t flags); - void netif_set_txol_flags(struct netif *netif, u64_t flags); -diff -Nur lwip-org/src/netif/ethernet.c lwip-vlan/src/netif/ethernet.c ---- lwip-org/src/netif/ethernet.c 2023-11-24 17:38:29.444481010 +0800 -+++ lwip-vlan/src/netif/ethernet.c 2023-11-27 11:07:48.464481010 +0800 -@@ -283,9 +283,15 @@ - vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); - #elif LWIP_VLAN_PCP - vlan_prio_vid = -1; -+#if !GAZELLE_ENABLE - if (netif->hints && (netif->hints->tci >= 0)) { - vlan_prio_vid = (u16_t)netif->hints->tci; - } -+#else -+ if (netif->vlan_enable) { -+ vlan_prio_vid = netif->vlan_tci; -+ } -+#endif /* GAZELLE_ENABLE */ - #endif - if (vlan_prio_vid >= 0) { - struct eth_vlan_hdr *vlanhdr; diff --git a/0083-lwipopts-add-lwip-debug-log-macro.patch b/0083-lwipopts-add-lwip-debug-log-macro.patch deleted file mode 100644 index d6fda4f..0000000 --- a/0083-lwipopts-add-lwip-debug-log-macro.patch +++ /dev/null @@ -1,75 +0,0 @@ -From afa156f10bdabe937e37080918f669937343eb54 Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Tue, 28 Nov 2023 09:22:34 +0800 -Subject: [PATCH] lwipopts: add lwip debug log macro - ---- - src/include/lwiplog.h | 15 ++++++++------- - src/include/lwipopts.h | 10 +++++++++- - 2 files changed, 17 insertions(+), 8 deletions(-) - -diff --git a/src/include/lwiplog.h b/src/include/lwiplog.h -index f278ff4..80ed0fc 100644 ---- a/src/include/lwiplog.h -+++ b/src/include/lwiplog.h -@@ -43,21 +43,22 @@ - - #if GAZELLE_USE_DPDK_LOG - --#define LWIP_LOG_WARN LWIP_DBG_LEVEL_WARNING --#define LWIP_LOG_ERROR LWIP_DBG_LEVEL_SERIOUS --#define LWIP_LOG_FATAL LWIP_DBG_LEVEL_SEVERE -+#define LWIP_LOG_WARN LWIP_DBG_LEVEL_WARNING -+#define LWIP_LOG_ERROR LWIP_DBG_LEVEL_SERIOUS -+#define LWIP_LOG_FATAL LWIP_DBG_LEVEL_SEVERE -+#define RTE_LOGTYPE_LWIP RTE_LOGTYPE_USER2 - - #define LWIP_PLATFORM_LOG(level, fmt, ...) \ - do { \ - if ((level) & LWIP_LOG_FATAL) { \ -- RTE_LOG(ERR, EAL, fmt, ##__VA_ARGS__); \ -+ RTE_LOG(ERR, LWIP, fmt, ##__VA_ARGS__); \ - abort(); \ - } else if ((level) & LWIP_LOG_ERROR) { \ -- RTE_LOG(ERR, EAL, fmt, ##__VA_ARGS__); \ -+ RTE_LOG(ERR, LWIP, fmt, ##__VA_ARGS__); \ - } else if ((level) & LWIP_LOG_WARN) { \ -- RTE_LOG(WARNING, EAL, fmt, ##__VA_ARGS__); \ -+ RTE_LOG(WARNING, LWIP, fmt, ##__VA_ARGS__); \ - } else { \ -- RTE_LOG(INFO, EAL, fmt, ##__VA_ARGS__); \ -+ RTE_LOG(INFO, LWIP, fmt, ##__VA_ARGS__); \ - } \ - } while(0) - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 9ab5cde..06b3ae5 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -41,7 +41,6 @@ - #define LWIP_PERF 1 - #define LWIP_RECORD_PERF 0 - --//#define LWIP_DEBUG 1 - #define GAZELLE_USE_DPDK_LOG 1 - - #define GAZELLE_ENABLE 1 -@@ -262,6 +261,15 @@ - - #define SIOCSHIWAT 1 - -+/* -+ ------------------------------------ -+ --------- Debug log options -------- -+ ------------------------------------ -+*/ -+#define LWIP_DEBUG 1 -+ -+#define GAZELLE_DEBUG LWIP_DBG_ON -+ - /* - ------------------------------------ - ---------- Netif options ---------- --- -2.23.0 - diff --git a/0084-add-tcpslowtmr-log-and-tcpfasttmr-cnt.patch b/0084-add-tcpslowtmr-log-and-tcpfasttmr-cnt.patch deleted file mode 100644 index c28c2a3..0000000 --- a/0084-add-tcpslowtmr-log-and-tcpfasttmr-cnt.patch +++ /dev/null @@ -1,135 +0,0 @@ -From d0edabb1ebfe0cc1f32e91834589b16b209dcfc9 Mon Sep 17 00:00:00 2001 -From: hantwofish -Date: Tue, 28 Nov 2023 04:34:02 +0800 -Subject: [PATCH] add tcpslowtmr log and tcpfasttmr cnt - ---- - src/core/tcp.c | 18 +++++++++++------- - src/include/lwip/stats.h | 3 +++ - src/include/lwipopts.h | 3 +++ - 3 files changed, 17 insertions(+), 7 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 9f1e636..c1b64a3 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -1393,16 +1393,17 @@ tcp_slowtmr_start: - - if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max SYN retries reached loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else if (pcb->nrtx >= TCP_MAXRTX) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max DATA retries reached loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else { - if (pcb->persist_backoff > 0) { - LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); - LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); - if (pcb->persist_probe >= TCP_MAXRTX) { - ++pcb_remove; /* max probes reached */ -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: persist_probe is greater TCP_MAXRTX loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else { - u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; - if (pcb->persist_cnt < backoff_cnt) { -@@ -1486,7 +1487,7 @@ tcp_slowtmr_start: - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2 loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - } -@@ -1497,7 +1498,7 @@ tcp_slowtmr_start: - (pcb->state == CLOSE_WAIT))) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(TCP_DEBUG, ("\n")); - -@@ -1519,7 +1520,7 @@ tcp_slowtmr_start: - #if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL && - (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { -- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: dropping OOSEQ queued data loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - tcp_free_ooseq(pcb); - } - #endif /* TCP_QUEUE_OOSEQ */ -@@ -1529,7 +1530,7 @@ tcp_slowtmr_start: - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - -@@ -1537,7 +1538,7 @@ tcp_slowtmr_start: - if (pcb->state == LAST_ACK) { - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in LAST-ACK loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - -@@ -1691,6 +1692,7 @@ tcp_fasttmr_start: - /* send delayed ACKs */ - if (pcb->flags & TF_ACK_DELAY) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); -+ MIB2_STATS_INC(mib2.tcpdelayackcnt); - tcp_ack_now(pcb); - tcp_output(pcb); - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); -@@ -1698,6 +1700,7 @@ tcp_fasttmr_start: - /* send pending FIN */ - if (pcb->flags & TF_CLOSEPEND) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); -+ MIB2_STATS_INC(mib2.tcpfinackcnt); - tcp_clear_flags(pcb, TF_CLOSEPEND); - tcp_close_shutdown_fin(pcb); - } -@@ -1707,6 +1710,7 @@ tcp_fasttmr_start: - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - tcp_active_pcbs_changed = 0; -+ MIB2_STATS_INC(mib2.tcpredusedcnt); - tcp_process_refused_data(pcb); - if (tcp_active_pcbs_changed) { - /* application callback has changed the pcb list: restart the loop */ -diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h -index 4470531..5953a74 100644 ---- a/src/include/lwip/stats.h -+++ b/src/include/lwip/stats.h -@@ -150,6 +150,9 @@ struct stats_mib2 { - u32_t tcpinsegs; - u32_t tcpinerrs; - u32_t tcpoutrsts; -+ u32_t tcpfinackcnt; -+ u32_t tcpdelayackcnt; -+ u32_t tcpredusedcnt; - - /* UDP */ - u32_t udpindatagrams; -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 06b3ae5..5fe647f 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -269,6 +269,9 @@ - #define LWIP_DEBUG 1 - - #define GAZELLE_DEBUG LWIP_DBG_ON -+#define GAZELLE_DEBUG_WARNING (LWIP_DBG_ON | LWIP_DBG_LEVEL_WARNING) -+#define GAZELLE_DEBUG_SERIOUS (LWIP_DBG_ON | LWIP_DBG_LEVEL_SERIOUS) -+#define GAZELLE_DEBUG_SEVERE (LWIP_DBG_ON | LWIP_DBG_LEVEL_SEVERE) - - /* - ------------------------------------ --- -2.33.0 - diff --git a/0085-add-lwip-log-tcp_rst-tcp_abandon-tcp_abort.patch b/0085-add-lwip-log-tcp_rst-tcp_abandon-tcp_abort.patch deleted file mode 100644 index 0785dbf..0000000 --- a/0085-add-lwip-log-tcp_rst-tcp_abandon-tcp_abort.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 4ab4406f6e59ee09d893e31104236518fc81e991 Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Tue, 28 Nov 2023 16:11:09 +0800 -Subject: [PATCH] add lwip log: tcp_rst & tcp_abandon & tcp_abort - ---- - src/core/tcp.c | 24 ++++++++++++++++-------- - src/core/tcp_in.c | 19 +++++++++++++++++-- - src/include/lwip/debug.h | 4 ++-- - 3 files changed, 35 insertions(+), 12 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 963b8a4..a4f82a3 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -415,6 +415,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) - - /* don't call tcp_abort here: we must not deallocate the pcb since - that might not be expected when calling tcp_close */ -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -+ ("tcp_close_shutdown: Not all data received by app, send RST, local_port=%d, remote_port=%d\n", -+ pcb->local_port, pcb->remote_port)); - tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - -@@ -682,7 +685,8 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) - #endif /* TCP_QUEUE_OOSEQ */ - tcp_backlog_accepted(pcb); - if (send_rst) { -- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); -+ LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_abandon: send RST, local port=%d, remote port=%d\n", local_port, pcb->remote_port)); - tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); - } - last_state = pcb->state; -@@ -1574,6 +1578,9 @@ tcp_slowtmr_start: - #endif - - if (pcb_reset) { -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -+ ("tcp_slowtmr: KEEPALIVE timeout, send RST, local port=%d, remote port=%d\n", -+ pcb->local_port, pcb->remote_port)); - tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - } -@@ -1941,8 +1948,8 @@ tcp_kill_prio(u8_t prio) - } - } - if (inactive != NULL) { -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", -- (void *)inactive, inactivity)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_kill_prio: killing oldest PCB (%"S32_F")\n", inactivity)); - tcp_abort(inactive); - } - } -@@ -1972,8 +1979,8 @@ tcp_kill_state(enum tcp_state state) - } - } - if (inactive != NULL) { -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", -- tcp_state_str[state], (void *)inactive, inactivity)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_kill_closing: killing oldest %s PCB (%"S32_F")\n", tcp_state_str[state], inactivity)); - /* Don't send a RST, since no data is lost. */ - tcp_abandon(inactive, 0); - } -@@ -1999,8 +2006,8 @@ tcp_kill_timewait(void) - } - } - if (inactive != NULL) { -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", -- (void *)inactive, inactivity)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_kill_timewait: killing oldest TIME-WAIT PCB (%"S32_F")\n", inactivity)); - tcp_abort(inactive); - } - } -@@ -2540,7 +2547,8 @@ tcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb - ) { - /* this connection must be aborted */ - struct tcp_pcb *next = pcb->next; -- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); -+ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE | GAZELLE_DEBUG_SERIOUS, -+ ("netif_set_ipaddr: aborting TCP\n")); - tcp_abort(pcb); - pcb = next; - } else { -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 7154659..700a64c 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -592,6 +592,7 @@ tcp_input(struct pbuf *p, struct netif *inp) - pbuf_free(rest); - } - #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_input: received data although already closed, send RST\n")); - tcp_abort(pcb); - goto aborted; - } -@@ -683,10 +684,12 @@ aborted: - } else { - /* If no matching PCB was found, send a TCP RST (reset) to the - sender. */ -- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); - if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { - TCP_STATS_INC(tcp.proterr); - TCP_STATS_INC(tcp.drop); -+ LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_input: no PCB match found, send RST, dest port=%d, src port=%d\n", -+ lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); - tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } -@@ -761,7 +764,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - if (flags & TCP_ACK) { - /* For incoming segments with the ACK flag set, respond with a - RST. */ -- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); -+ LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ ("tcp_listen_input: ACK in LISTEN, send reset, dest port=%d, src port=%d\n", -+ lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { -@@ -852,6 +857,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - /* Send a SYN|ACK together with the MSS option. */ - rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); - if (rc != ERR_OK) { -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_listen_input: send SYN or ACK failed\n")); - tcp_abandon(npcb, 0); - PERF_RESUME(PERF_LAYER_TCP, PERF_POINT_TCP_SYN_RECV); - return; -@@ -892,6 +898,9 @@ tcp_timewait_input(struct tcp_pcb *pcb) - should be sent in reply */ - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { - /* If the SYN is in the window it is an error, send a reset */ -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -+ ("tcp_timewait_input: SYN in TIME_WAIT, send RST, dest port=%d, src port=%d\n", -+ lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - return; -@@ -1060,6 +1069,8 @@ tcp_process(struct tcp_pcb *pcb) - /* received ACK? possibly a half-open connection */ - else if (flags & TCP_ACK) { - /* send a RST to bring the other side in a non-synchronized state. */ -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_process: ACK in SYN_SENT, send RST, dest port=%d, src port=%d\n", -+ lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - /* Resend SYN immediately (don't wait for rto timeout) to establish -@@ -1102,6 +1113,7 @@ tcp_process(struct tcp_pcb *pcb) - * the connection. */ - /* Already aborted? */ - if (err != ERR_ABRT) { -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_process: accept function returns with an error %d, send RST\n", err)); - tcp_abort(pcb); - } - return ERR_ABRT; -@@ -1129,6 +1141,9 @@ tcp_process(struct tcp_pcb *pcb) - } - } else { - /* incorrect ACK number, send RST */ -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -+ ("tcp_process: incorrect ACK number in SYN_RCVD, send RST, ackno=%d, lastack=%d, snd_nxt=%d, dest port=%d, src port=%d\n", -+ ackno, pcb->lastack, pcb->snd_nxt, lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } -diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h -index f47cbfe..6abed9f 100644 ---- a/src/include/lwip/debug.h -+++ b/src/include/lwip/debug.h -@@ -56,12 +56,12 @@ - /** Debug level: Serious. memory allocation failures, ... */ - #define LWIP_DBG_LEVEL_SERIOUS 0x02 - /** Debug level: Severe */ --#define LWIP_DBG_LEVEL_SEVERE 0x03 -+#define LWIP_DBG_LEVEL_SEVERE 0x04 - /** - * @} - */ - --#define LWIP_DBG_MASK_LEVEL 0x03 -+#define LWIP_DBG_MASK_LEVEL 0x07 - /* compatibility define only */ - #define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL - --- -2.23.0 - diff --git a/0086-log-add-errevent-log-and-tcp-exception-statistics.patch b/0086-log-add-errevent-log-and-tcp-exception-statistics.patch deleted file mode 100644 index 17cba3b..0000000 --- a/0086-log-add-errevent-log-and-tcp-exception-statistics.patch +++ /dev/null @@ -1,77 +0,0 @@ -From d7b0ffc7604075639f3eedbfe63fc0f12b87d23f Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Tue, 28 Nov 2023 16:34:16 +0800 -Subject: [PATCH] log: add errevent log and tcp exception statistics - ---- - src/api/api_msg.c | 1 + - src/api/sockets.c | 3 ++- - src/core/tcp_in.c | 2 ++ - src/include/lwip/stats.h | 3 +++ - 4 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 8d98be6..531da40 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -613,6 +613,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) - sys_mbox_free(&newconn->recvmbox); - sys_mbox_set_invalid(&newconn->recvmbox); - netconn_free(newconn); -+ MIB2_STATS_INC(mib2.tcpacceptmboxfull); - return ERR_MEM; - } else { - /* Register event with callback */ -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 62052f2..65c69d4 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2797,9 +2797,10 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - #endif - break; - case NETCONN_EVT_ERROR: -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d\n", conn->pending_err)); - sock->errevent = 1; - #if GAZELLE_ENABLE -- if (netif_is_rtc_mode(netif_default)) { -+ if (netif_is_rtc_mode(netif_default)) { - add_sock_event_nolock(sock, EPOLLERR); - } else { - add_sock_event(sock, EPOLLERR); -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 1076f20..03b9942 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -770,6 +770,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - #if TCP_LISTEN_BACKLOG - if (pcb->accepts_pending >= pcb->backlog) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); -+ MIB2_STATS_INC(mib2.tcplistendrops); - return; - } - #endif /* TCP_LISTEN_BACKLOG */ -@@ -1845,6 +1846,7 @@ tcp_receive(struct tcp_pcb *pcb) - - } else { - /* We get here if the incoming segment is out-of-sequence. */ -+ MIB2_STATS_INC(mib2.tcpoutofseq); - - #if TCP_QUEUE_OOSEQ - /* We queue the segment on the ->ooseq queue. */ -diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h -index 5953a74..805836c 100644 ---- a/src/include/lwip/stats.h -+++ b/src/include/lwip/stats.h -@@ -153,6 +153,9 @@ struct stats_mib2 { - u32_t tcpfinackcnt; - u32_t tcpdelayackcnt; - u32_t tcpredusedcnt; -+ u32_t tcpoutofseq; -+ u32_t tcpacceptmboxfull; -+ u32_t tcplistendrops; - - /* UDP */ - u32_t udpindatagrams; --- -2.27.0 - diff --git a/0087-support-vlan-offload.patch b/0087-support-vlan-offload.patch deleted file mode 100644 index 756db5d..0000000 --- a/0087-support-vlan-offload.patch +++ /dev/null @@ -1,56 +0,0 @@ -diff -Nur lwip-82/src/include/dpdk_version.h lwip-offload/src/include/dpdk_version.h ---- lwip-82/src/include/dpdk_version.h 2023-11-28 14:17:02.432481010 +0800 -+++ lwip-offload/src/include/dpdk_version.h 2023-11-28 14:34:21.208481010 +0800 -@@ -48,6 +48,7 @@ - #define RTE_MBUF_F_TX_TCP_CKSUM PKT_TX_TCP_CKSUM - #define RTE_MBUF_F_TX_TCP_SEG PKT_TX_TCP_SEG - #define RTE_MBUF_F_TX_UDP_CKSUM PKT_TX_UDP_CKSUM -+#define RTE_MBUF_F_TX_VLAN PKT_TX_VLAN_PKT - - #endif /* DPDK_VERSION_1911 */ - -diff -Nur lwip-82/src/include/lwip/pbuf.h lwip-offload/src/include/lwip/pbuf.h ---- lwip-82/src/include/lwip/pbuf.h 2023-11-28 14:17:02.408481010 +0800 -+++ lwip-offload/src/include/lwip/pbuf.h 2023-11-28 14:41:31.580481010 +0800 -@@ -240,6 +240,7 @@ - struct pbuf *last; - pthread_spinlock_t pbuf_lock; - struct tcp_pcb *pcb; -+ u16_t vlan_tci; - #if GAZELLE_UDP_ENABLE - ip_addr_t addr; - u16_t port; -diff -Nur lwip-82/src/netif/ethernet.c lwip-offload/src/netif/ethernet.c ---- lwip-82/src/netif/ethernet.c 2023-11-28 14:17:02.440481010 +0800 -+++ lwip-offload/src/netif/ethernet.c 2023-11-28 16:35:36.536481010 +0800 -@@ -289,7 +289,12 @@ - } - #else - if (netif->vlan_enable) { -- vlan_prio_vid = netif->vlan_tci; -+ if (netif->txol_flags & DEV_TX_OFFLOAD_VLAN_INSERT) { -+ p->ol_flags |= RTE_MBUF_F_TX_VLAN; -+ p->vlan_tci = netif->vlan_tci; -+ } else { -+ vlan_prio_vid = netif->vlan_tci; -+ } - } - #endif /* GAZELLE_ENABLE */ - #endif -@@ -327,11 +332,11 @@ - ("ethernet_output: sending packet %p\n", (void *)p)); - - #if CHECKSUM_GEN_IP_HW || CHECKSUM_GEN_TCP_HW --#if LWIP_VLAN_PCP -- ethh_cksum_set(p, sizeof(*ethhdr)+SIZEOF_VLAN_HDR); --#else -- ethh_cksum_set(p, sizeof(*ethhdr)); --#endif -+ if (netif->vlan_enable && !(netif->txol_flags & DEV_TX_OFFLOAD_VLAN_INSERT)) { -+ ethh_cksum_set(p, sizeof(*ethhdr) + SIZEOF_VLAN_HDR); -+ } else { -+ ethh_cksum_set(p, sizeof(*ethhdr)); -+ } - #endif - - /* send the packet */ diff --git a/0088-modify-log-info-err.patch b/0088-modify-log-info-err.patch deleted file mode 100644 index 43bafbf..0000000 --- a/0088-modify-log-info-err.patch +++ /dev/null @@ -1,82 +0,0 @@ -From f1b954fd737ca0e7571019f88b18a926ce849e6b Mon Sep 17 00:00:00 2001 -From: hantwofish -Date: Tue, 5 Dec 2023 10:57:46 +0800 -Subject: [PATCH] modify log info err - ---- - src/core/tcp.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index 3c7bbd0..2cfee11 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -1397,17 +1397,17 @@ tcp_slowtmr_start: - - if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max SYN retries reached loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max SYN retries reached local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else if (pcb->nrtx >= TCP_MAXRTX) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max DATA retries reached loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: max DATA retries reached local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else { - if (pcb->persist_backoff > 0) { - LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); - LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); - if (pcb->persist_probe >= TCP_MAXRTX) { - ++pcb_remove; /* max probes reached */ -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: persist_probe is greater TCP_MAXRTX loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: persist_probe is greater TCP_MAXRTX local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } else { - u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; - if (pcb->persist_cnt < backoff_cnt) { -@@ -1491,7 +1491,7 @@ tcp_slowtmr_start: - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2 loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2 local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - } -@@ -1502,7 +1502,7 @@ tcp_slowtmr_start: - (pcb->state == CLOSE_WAIT))) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(TCP_DEBUG, ("\n")); - -@@ -1524,7 +1524,7 @@ tcp_slowtmr_start: - #if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL && - (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: dropping OOSEQ queued data loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: dropping OOSEQ queued data local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - tcp_free_ooseq(pcb); - } - #endif /* TCP_QUEUE_OOSEQ */ -@@ -1534,7 +1534,7 @@ tcp_slowtmr_start: - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - -@@ -1542,7 +1542,7 @@ tcp_slowtmr_start: - if (pcb->state == LAST_ACK) { - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; -- LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in LAST-ACK loac_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_slowtmr: removing pcb stuck in LAST-ACK local_port=%u, remote_port=%u\n", pcb->local_port, pcb->remote_port)); - } - } - --- -2.33.0 - diff --git a/0089-add-struct-gz-addr.patch b/0089-add-struct-gz-addr.patch deleted file mode 100644 index 09729fd..0000000 --- a/0089-add-struct-gz-addr.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff -Nur lwip-org/src/core/tcp.c lwip-gz-addr/src/core/tcp.c ---- lwip-org/src/core/tcp.c 2023-12-04 14:10:25.364481010 +0800 -+++ lwip-gz-addr/src/core/tcp.c 2023-12-04 14:33:31.712481010 +0800 -@@ -1161,7 +1161,7 @@ - - if (__atomic_load_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { - #if GAZELLE_ENABLE -- if (port_in_stack_queue(pcb->remote_ip, pcb->local_ip, pcb->remote_port, tcp_port)) { -+ if (port_in_stack_queue((gz_addr_t *)&pcb->remote_ip, (gz_addr_t *)&pcb->local_ip, pcb->remote_port, tcp_port)) { - tmp_port = tcp_port; - __atomic_store_n(&port_state[tcp_port - TCP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); - break; -diff -Nur lwip-org/src/core/udp.c lwip-gz-addr/src/core/udp.c ---- lwip-org/src/core/udp.c 2023-12-04 14:10:25.364481010 +0800 -+++ lwip-gz-addr/src/core/udp.c 2023-12-04 14:19:58.832481010 +0800 -@@ -132,7 +132,7 @@ - } - - if (__atomic_load_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], __ATOMIC_ACQUIRE) == 0) { -- if (port_in_stack_queue(dst_pcb->remote_ip, dst_pcb->local_ip, dst_pcb->remote_port, udp_port)) { -+ if (port_in_stack_queue((gz_addr_t *)&dst_pcb->remote_ip, (gz_addr_t *)&dst_pcb->local_ip, dst_pcb->remote_port, udp_port)) { - tmp_port = udp_port; - __atomic_store_n(&port_state[udp_port - UDP_LOCAL_PORT_RANGE_START], 1, __ATOMIC_RELEASE); - break; -diff -Nur lwip-org/src/include/lwipopts.h lwip-gz-addr/src/include/lwipopts.h ---- lwip-org/src/include/lwipopts.h 2023-12-04 14:10:25.368481010 +0800 -+++ lwip-gz-addr/src/include/lwipopts.h 2023-12-06 19:29:24.520481010 +0800 -@@ -184,6 +184,7 @@ - */ - #define LWIP_IPV6 1 - #define IP6_HLEN 40 -+#define LWIP_IPV6_SCOPES 1 - - /* - --------------------------------- -diff -Nur lwip-org/src/include/reg_sock.h lwip-gz-addr/src/include/reg_sock.h ---- lwip-org/src/include/reg_sock.h 2023-12-04 14:10:25.368481010 +0800 -+++ lwip-gz-addr/src/include/reg_sock.h 2023-12-06 19:41:19.792481010 +0800 -@@ -34,7 +34,35 @@ - #define __REG_SOCK_H__ - - #include --#include "lwip/ip_addr.h" -+ -+#include "lwipopts.h" -+ -+/* compatible with ip4_addr_t */ -+struct gz_ip4 { -+ uint32_t addr; -+}; -+ -+/* compatible with ip6_addr_t */ -+#if LWIP_IPV6 -+struct gz_ip6 { -+ uint32_t addr[4]; -+#if LWIP_IPV6_SCOPES -+ uint8_t zone; -+#endif /* LWIP_IPV6_SCOPES */ -+}; -+#endif /* LWIP_IPV6 */ -+ -+/* gazelle ip address, compatible with ip_addr_t */ -+typedef struct gz_addr { -+ union { -+#if LWIP_IPV6 -+ struct gz_ip6 ip6; -+#endif /* LWIP_IPV6 */ -+ struct gz_ip4 ip4; -+ } u_addr; -+ /** @ref lwip_ip_addr_type */ -+ uint8_t type; -+} gz_addr_t; - - enum reg_ring_type { - REG_RING_TCP_LISTEN = 0, -@@ -45,10 +73,12 @@ - }; - - struct gazelle_quintuple { -- uint32_t protocol; -+ uint32_t protocol; - /* net byte order */ - uint16_t src_port; - uint16_t dst_port; -+ -+ /* TODO: replace with gz_addr_t */ - uint32_t src_ip; - uint32_t dst_ip; - #if LWIP_IPV6 -@@ -65,6 +95,6 @@ - }; - - extern int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); --extern bool port_in_stack_queue(ip_addr_t src_ip, ip_addr_t dst_ip, uint16_t src_port, uint16_t dst_port); -+extern bool port_in_stack_queue(gz_addr_t *src_ip, gz_addr_t *dst_ip, uint16_t src_port, uint16_t dst_port); - - #endif /* __REG_SOCK_H__ */ diff --git a/0090-frag-fix-coredump-when-get-netif.patch b/0090-frag-fix-coredump-when-get-netif.patch deleted file mode 100644 index e5159c4..0000000 --- a/0090-frag-fix-coredump-when-get-netif.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5e5195ad88819a77d59038ec49004d1e11801d08 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Fri, 8 Dec 2023 11:14:15 +0800 -Subject: [PATCH] frag: fix coredump when get netif - ---- - src/core/ipv4/ip4_frag.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c -index f63a99e..b4a183a 100644 ---- a/src/core/ipv4/ip4_frag.c -+++ b/src/core/ipv4/ip4_frag.c -@@ -640,9 +640,9 @@ ip4_reass(struct pbuf *p) - IPH_CHKSUM_SET(fraghdr, 0); - /* @todo: do we need to set/calculate the correct checksum? */ - #if CHECKSUM_GEN_IP -- IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { -+ IF__NETIF_CHECKSUM_ENABLED(netif_default, NETIF_CHECKSUM_GEN_IP) { - #if CHECKSUM_GEN_IP_HW -- if (netif_get_txol_flags(ip_current_input_netif()) & DEV_TX_OFFLOAD_IPV4_CKSUM) { -+ if (netif_get_txol_flags(netif_default) & DEV_TX_OFFLOAD_IPV4_CKSUM) { - iph_cksum_set(p, IP_HLEN, 1); - } else { - iph_cksum_set(p, IP_HLEN, 0); --- -2.27.0 - diff --git a/0091-add-fd-log-info-and-fix-wrong-port-log-info.patch b/0091-add-fd-log-info-and-fix-wrong-port-log-info.patch deleted file mode 100644 index a2a8f9d..0000000 --- a/0091-add-fd-log-info-and-fix-wrong-port-log-info.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 9ef6e86cbbd7bff2d1980f9b88f3b6f9ec1457b5 Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Wed, 6 Dec 2023 08:43:23 +0800 -Subject: [PATCH] add fd log info and fix wrong port log info - ---- - src/api/sockets.c | 2 +- - src/core/tcp_in.c | 20 ++++++++++---------- - 2 files changed, 11 insertions(+), 11 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 65c69d4..d488b5b 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2797,7 +2797,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - #endif - break; - case NETCONN_EVT_ERROR: -- LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d\n", conn->pending_err)); -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d, fd=%d\n", conn->pending_err, conn->socket)); - sock->errevent = 1; - #if GAZELLE_ENABLE - if (netif_is_rtc_mode(netif_default)) { -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 8ed91b5..24706c1 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -688,8 +688,8 @@ aborted: - TCP_STATS_INC(tcp.proterr); - TCP_STATS_INC(tcp.drop); - LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -- ("tcp_input: no PCB match found, send RST, dest port=%d, src port=%d\n", -- lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); -+ ("tcp_input: no PCB match found, send RST, local_port=%d, remote_port=%d\n", -+ tcphdr->src, tcphdr->dest)); - tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } -@@ -765,8 +765,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - /* For incoming segments with the ACK flag set, respond with a - RST. */ - LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -- ("tcp_listen_input: ACK in LISTEN, send reset, dest port=%d, src port=%d\n", -- lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); -+ ("tcp_listen_input: ACK in LISTEN, send reset, local_port=%d, remote_port=%d\n", -+ tcphdr->src, tcphdr->dest)); - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { -@@ -902,8 +902,8 @@ tcp_timewait_input(struct tcp_pcb *pcb) - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { - /* If the SYN is in the window it is an error, send a reset */ - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -- ("tcp_timewait_input: SYN in TIME_WAIT, send RST, dest port=%d, src port=%d\n", -- lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); -+ ("tcp_timewait_input: SYN in TIME_WAIT, send RST, local_port=%d, remote_port=%d\n", -+ tcphdr->src, tcphdr->dest)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - return; -@@ -1072,8 +1072,8 @@ tcp_process(struct tcp_pcb *pcb) - /* received ACK? possibly a half-open connection */ - else if (flags & TCP_ACK) { - /* send a RST to bring the other side in a non-synchronized state. */ -- LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_process: ACK in SYN_SENT, send RST, dest port=%d, src port=%d\n", -- lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_process: ACK in SYN_SENT, send RST, local_port=%d, remote_port=%d\n", -+ tcphdr->src, tcphdr->dest)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - /* Resend SYN immediately (don't wait for rto timeout) to establish -@@ -1145,8 +1145,8 @@ tcp_process(struct tcp_pcb *pcb) - } else { - /* incorrect ACK number, send RST */ - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, -- ("tcp_process: incorrect ACK number in SYN_RCVD, send RST, ackno=%d, lastack=%d, snd_nxt=%d, dest port=%d, src port=%d\n", -- ackno, pcb->lastack, pcb->snd_nxt, lwip_ntohs(tcphdr->dest), lwip_ntohs(tcphdr->src))); -+ ("tcp_process: incorrect ACK number in SYN_RCVD, send RST, ackno=%d, lastack=%d, snd_nxt=%d, local_port=%d, remote_port=%d\n", -+ ackno, pcb->lastack, pcb->snd_nxt, tcphdr->src, tcphdr->dest)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } --- -2.33.0 - diff --git a/0092-fix-the-coredump-issue-when-UDP-traffic-is-sent.patch b/0092-fix-the-coredump-issue-when-UDP-traffic-is-sent.patch deleted file mode 100644 index 5da5819..0000000 --- a/0092-fix-the-coredump-issue-when-UDP-traffic-is-sent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From defef8f57ee35b510c4a542e54237f664ac31d5d Mon Sep 17 00:00:00 2001 -From: root -Date: Sat, 9 Dec 2023 16:54:47 +0800 -Subject: [PATCH] fix the coredump issue when UDP traffic is sent - ---- - src/api/sockets.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index d488b5b..a9d39ae 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -1865,7 +1865,13 @@ lwip_sendto(int s, const void *data, size_t size, int flags, - } else - #endif /* LWIP_CHECKSUM_ON_COPY */ - { -+#if GAZELLE_ENABLE -+ /* In the gazelle scenario, the payload is stored in send_ring, -+ and the payload stores the sock pointer information. */ -+ buf.p->payload = (void *)sock; -+#else - MEMCPY(buf.p->payload, data, short_size); -+#endif - } - err = ERR_OK; - } --- -2.30.0 - diff --git a/0093-modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening.patch b/0093-modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening.patch deleted file mode 100644 index df7ee1c..0000000 --- a/0093-modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening.patch +++ /dev/null @@ -1,37 +0,0 @@ -From dcdd7d73c6083a63fe966a68f11eddcafa3fd743 Mon Sep 17 00:00:00 2001 -From: hantwofish -Date: Thu, 14 Dec 2023 14:51:37 +0800 -Subject: [PATCH] resove null pointer - ---- - src/api/sockets.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index a9d39ae..0b3e4ea 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -801,15 +801,17 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - #endif /* GAZELLE_ENABLE */ - nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; - #if GAZELLE_ENABLE -+ int ret = 0; - struct tcp_pcb *pcb = newconn->pcb.tcp; -- if (pcb->client_rx_ring != NULL && pcb->client_tx_ring != NULL) { -- if (find_same_node_memzone(pcb, nsock) != 0) { -+ if (pcb != NULL && pcb->client_rx_ring != NULL && pcb->client_tx_ring != NULL) { -+ ret = find_same_node_memzone(pcb, nsock); -+ } -+ if (pcb == NULL || ret != 0) { - netconn_delete(newconn); - free_socket(nsock, 1); - sock_set_errno(sock, ENOTCONN); - done_socket(sock); - return -1; -- } - } - #endif - --- -2.33.0 - diff --git a/0094-lwip-log-fix-reversed-port-in-tcp_input.patch b/0094-lwip-log-fix-reversed-port-in-tcp_input.patch deleted file mode 100644 index 1168db7..0000000 --- a/0094-lwip-log-fix-reversed-port-in-tcp_input.patch +++ /dev/null @@ -1,61 +0,0 @@ -From ce3debdf4c4cd6701cdb323377477539a5fd13fa Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Fri, 15 Dec 2023 17:21:54 +0800 -Subject: [PATCH] lwip log: fix reversed port in tcp_input - ---- - src/core/tcp_in.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 24706c1..c76c114 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -689,7 +689,7 @@ aborted: - TCP_STATS_INC(tcp.drop); - LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, - ("tcp_input: no PCB match found, send RST, local_port=%d, remote_port=%d\n", -- tcphdr->src, tcphdr->dest)); -+ tcphdr->dest, tcphdr->src)); - tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } -@@ -766,7 +766,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - RST. */ - LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, - ("tcp_listen_input: ACK in LISTEN, send reset, local_port=%d, remote_port=%d\n", -- tcphdr->src, tcphdr->dest)); -+ tcphdr->dest, tcphdr->src)); - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { -@@ -903,7 +903,7 @@ tcp_timewait_input(struct tcp_pcb *pcb) - /* If the SYN is in the window it is an error, send a reset */ - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, - ("tcp_timewait_input: SYN in TIME_WAIT, send RST, local_port=%d, remote_port=%d\n", -- tcphdr->src, tcphdr->dest)); -+ tcphdr->dest, tcphdr->src)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - return; -@@ -1073,7 +1073,7 @@ tcp_process(struct tcp_pcb *pcb) - else if (flags & TCP_ACK) { - /* send a RST to bring the other side in a non-synchronized state. */ - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("tcp_process: ACK in SYN_SENT, send RST, local_port=%d, remote_port=%d\n", -- tcphdr->src, tcphdr->dest)); -+ tcphdr->dest, tcphdr->src)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - /* Resend SYN immediately (don't wait for rto timeout) to establish -@@ -1146,7 +1146,7 @@ tcp_process(struct tcp_pcb *pcb) - /* incorrect ACK number, send RST */ - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, - ("tcp_process: incorrect ACK number in SYN_RCVD, send RST, ackno=%d, lastack=%d, snd_nxt=%d, local_port=%d, remote_port=%d\n", -- ackno, pcb->lastack, pcb->snd_nxt, tcphdr->src, tcphdr->dest)); -+ ackno, pcb->lastack, pcb->snd_nxt, tcphdr->dest, tcphdr->src)); - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } --- -2.33.0 - diff --git a/0095-event_callback-del-errevent-log-if-err-is-ERR_OK.patch b/0095-event_callback-del-errevent-log-if-err-is-ERR_OK.patch deleted file mode 100644 index 9260abc..0000000 --- a/0095-event_callback-del-errevent-log-if-err-is-ERR_OK.patch +++ /dev/null @@ -1,27 +0,0 @@ -From db1929c5698a672200bf96d7ece992f10a98a80c Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Wed, 20 Dec 2023 17:37:42 +0800 -Subject: [PATCH] event_callback: del errevent log if err is ERR_OK - ---- - src/api/sockets.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index 0b3e4ea..f5b8ea6 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2805,7 +2805,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - #endif - break; - case NETCONN_EVT_ERROR: -- LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d, fd=%d\n", conn->pending_err, conn->socket)); -+ if (conn->pending_err != ERR_OK) { -+ LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d, fd=%d\n", conn->pending_err, conn->socket)); -+ } - sock->errevent = 1; - #if GAZELLE_ENABLE - if (netif_is_rtc_mode(netif_default)) { --- -2.33.0 - diff --git a/0096-tcp_send_fin-add-the-fin-to-the-last-unsent-segment.patch b/0096-tcp_send_fin-add-the-fin-to-the-last-unsent-segment.patch deleted file mode 100644 index 2e77f0e..0000000 --- a/0096-tcp_send_fin-add-the-fin-to-the-last-unsent-segment.patch +++ /dev/null @@ -1,27 +0,0 @@ -From c91f1d05c65526fe250cf5e5c32f9038721bc1d5 Mon Sep 17 00:00:00 2001 -From: yangchen -Date: Mon, 25 Dec 2023 12:39:56 +0800 -Subject: [PATCH] tcp_send_fin: add the fin to the last unsent segment - ---- - src/core/tcp_out.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c -index 137e3cf..e5c407e 100644 ---- a/src/core/tcp_out.c -+++ b/src/core/tcp_out.c -@@ -1195,8 +1195,8 @@ tcp_send_fin(struct tcp_pcb *pcb) - LWIP_ASSERT("tcp_send_fin: invalid pcb", pcb != NULL); - - /* first, try to add the fin to the last unsent segment */ -- if (pcb->unsent != NULL) { -- struct tcp_seg *last_unsent = pcb->unsent; -+ if (pcb->last_unsent != NULL) { -+ struct tcp_seg *last_unsent = pcb->last_unsent; - - if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { - /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ --- -2.33.0 - diff --git a/0097-Mod-the-issue-that-2w-connection-unable-to-establish.patch b/0097-Mod-the-issue-that-2w-connection-unable-to-establish.patch deleted file mode 100644 index 764a155..0000000 --- a/0097-Mod-the-issue-that-2w-connection-unable-to-establish.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 212198780662639e0422419a25d28ff2bb0d421e Mon Sep 17 00:00:00 2001 -From: hantwofish -Date: Mon, 25 Dec 2023 15:36:45 +0800 -Subject: [PATCH] Mod the issue that 2w connection unable to establish in - Redis. - ---- - src/api/api_lib.c | 2 +- - src/api/api_msg.c | 2 +- - src/api/sockets.c | 19 ++++++++++++------- - src/core/init.c | 4 ++-- - src/core/tcp.c | 4 ++-- - src/core/tcp_in.c | 2 +- - src/include/lwip/api.h | 2 +- - src/include/lwip/opt.h | 2 +- - src/include/lwip/priv/api_msg.h | 2 +- - src/include/lwip/tcp.h | 8 ++++---- - src/include/lwipopts.h | 4 ++-- - 11 files changed, 28 insertions(+), 23 deletions(-) - -diff --git a/src/api/api_lib.c b/src/api/api_lib.c -index e73b81e..30e3422 100644 ---- a/src/api/api_lib.c -+++ b/src/api/api_lib.c -@@ -431,7 +431,7 @@ netconn_disconnect(struct netconn *conn) - * don't return any error (yet?)) - */ - err_t --netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) -+netconn_listen_with_backlog(struct netconn *conn, u16_t backlog) - { - #if LWIP_TCP - API_MSG_VAR_DECLARE(msg); -diff --git a/src/api/api_msg.c b/src/api/api_msg.c -index 531da40..91b8590 100644 ---- a/src/api/api_msg.c -+++ b/src/api/api_msg.c -@@ -1499,7 +1499,7 @@ lwip_netconn_do_listen(void *m) - /* connection is not closed, cannot listen */ - err = ERR_VAL; - } else { -- u8_t backlog; -+ u16_t backlog; - #if TCP_LISTEN_BACKLOG - backlog = msg->msg.lb.backlog; - #else /* TCP_LISTEN_BACKLOG */ -diff --git a/src/api/sockets.c b/src/api/sockets.c -index f5b8ea6..b7ee304 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -447,7 +447,7 @@ tryget_socket_unconn_nouse(int fd) - if ((s < 0) || (s >= NUM_SOCKETS)) - #endif /* GAZELLE_ENABLE */ - { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tryget_socket_unconn(%d): invalid\n", fd)); - return NULL; - } - return &sockets[s]; -@@ -521,7 +521,7 @@ get_socket(int fd) - struct lwip_sock *sock = tryget_socket(fd); - if (!sock) { - if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("get_socket(%d): invalid\n", fd)); - } - set_errno(EBADF); - return NULL; -@@ -588,6 +588,7 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - SYS_ARCH_PROTECT(lev); - i = posix_api->socket_fn(domain, type, protocol); - if (i == -1) { -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("posix_api->socket_fn fail socket is -1")); - goto err; - } - -@@ -596,6 +597,7 @@ alloc_socket(struct netconn *newconn, int accepted, int flags) - } - - if ((i < LWIP_SOCKET_OFFSET) || (i >= sockets_num + LWIP_SOCKET_OFFSET)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("posix_api->socket_fn socket is %d, illegal\n", i)); - goto err; - } - -@@ -767,13 +769,14 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - - sock = get_socket(s); - if (!sock) { -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("get_socket sock is null\n")); - return -1; - } - - /* wait for a new connection */ - err = netconn_accept(sock->conn, &newconn); - if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); - } else if (err == ERR_CLSD) { -@@ -788,6 +791,7 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - - newsock = alloc_socket(newconn, 1, flags); - if (newsock == -1) { -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("alloc_socket fail newsock is -1\n")); - netconn_delete(newconn); - sock_set_errno(sock, ENFILE); - done_socket(sock); -@@ -807,6 +811,7 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - ret = find_same_node_memzone(pcb, nsock); - } - if (pcb == NULL || ret != 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("alloc_socket fail pcb null flag=%u, ret=%d \n", (pcb == NULL), ret)); - netconn_delete(newconn); - free_socket(nsock, 1); - sock_set_errno(sock, ENOTCONN); -@@ -842,7 +847,7 @@ lwip_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) - /* get the IP address and port of the remote host */ - err = netconn_peer(newconn, &naddr, &port); - if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); -+ LWIP_DEBUGF(SOCKETS_DEBUG | GAZELLE_DEBUG_SERIOUS, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); - free_socket(nsock, 1); - sock_set_errno(sock, err_to_errno(err)); - done_socket(sock); -@@ -1059,10 +1064,10 @@ lwip_listen(int s, int backlog) - return -1; - } - -- /* limit the "backlog" parameter to fit in an u8_t */ -- backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); -+ /* limit the "backlog" parameter to fit in an u16_t */ -+ backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xffff); - -- err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); -+ err = netconn_listen_with_backlog(sock->conn, (u16_t)backlog); - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); -diff --git a/src/core/init.c b/src/core/init.c -index 6880fd3..8c59a7c 100644 ---- a/src/core/init.c -+++ b/src/core/init.c -@@ -160,8 +160,8 @@ PACK_STRUCT_END - #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) - #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" - #endif --#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))) --#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" -+#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xffff))) -+#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u16_t" - #endif - #if (LWIP_TCP && LWIP_TCP_SACK_OUT && !TCP_QUEUE_OOSEQ) - #error "To use LWIP_TCP_SACK_OUT, TCP_QUEUE_OOSEQ needs to be enabled" -diff --git a/src/core/tcp.c b/src/core/tcp.c -index ca70a85..76f0ffd 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -903,7 +903,7 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) - * tpcb = tcp_listen_with_backlog(tpcb, backlog); - */ - struct tcp_pcb * --tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) -+tcp_listen_with_backlog(struct tcp_pcb *pcb, u16_t backlog) - { - LWIP_ASSERT_CORE_LOCKED(); - return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); -@@ -926,7 +926,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) - * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); - */ - struct tcp_pcb * --tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) -+tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u16_t backlog, err_t *err) - { - struct tcp_pcb_listen *lpcb = NULL; - err_t res; -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index c76c114..e9ab96f 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -785,7 +785,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - SYN at a time when we have more memory available. */ - if (npcb == NULL) { - err_t err; -- LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); -+ LWIP_DEBUGF(TCP_DEBUG | GAZELLE_DEBUG_SERIOUS, ("tcp_listen_input: could not allocate PCB\n")); - TCP_STATS_INC(tcp.memerr); - TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); - LWIP_UNUSED_ARG(err); /* err not useful here */ -diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h -index ed237c7..a986cd4 100644 ---- a/src/include/lwip/api.h -+++ b/src/include/lwip/api.h -@@ -366,7 +366,7 @@ err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); - err_t netconn_bind_if(struct netconn *conn, u8_t if_idx); - err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); - err_t netconn_disconnect (struct netconn *conn); --err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); -+err_t netconn_listen_with_backlog(struct netconn *conn, u16_t backlog); - /** @ingroup netconn_tcp */ - #define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) - err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 57a1a53..6332d51 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -1428,7 +1428,7 @@ - * 0xff is the maximum (u8_t). - */ - #if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ --#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -+#define TCP_DEFAULT_LISTEN_BACKLOG 0xffff - #endif - - /** -diff --git a/src/include/lwip/priv/api_msg.h b/src/include/lwip/priv/api_msg.h -index 9e8ffc9..b36f00a 100644 ---- a/src/include/lwip/priv/api_msg.h -+++ b/src/include/lwip/priv/api_msg.h -@@ -145,7 +145,7 @@ struct api_msg { - #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - #if TCP_LISTEN_BACKLOG - struct { -- u8_t backlog; -+ u16_t backlog; - } lb; - #endif /* TCP_LISTEN_BACKLOG */ - } msg; -diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h -index 91a86c9..741e58f 100644 ---- a/src/include/lwip/tcp.h -+++ b/src/include/lwip/tcp.h -@@ -249,8 +249,8 @@ struct tcp_pcb_listen { - #endif /* LWIP_CALLBACK_API */ - - #if TCP_LISTEN_BACKLOG -- u8_t backlog; -- u8_t accepts_pending; -+ u16_t backlog; -+ u16_t accepts_pending; - #endif /* TCP_LISTEN_BACKLOG */ - - #if GAZELLE_TCP_REUSE_IPPORT -@@ -575,8 +575,8 @@ void tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); - err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, - u16_t port, tcp_connected_fn connected); - --struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); --struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); -+struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u16_t backlog, err_t *err); -+struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u16_t backlog); - /** @ingroup tcp_raw */ - #define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) - -diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h -index 82cf881..44ed80f 100644 ---- a/src/include/lwipopts.h -+++ b/src/include/lwipopts.h -@@ -210,11 +210,11 @@ - - #define TCP_HLEN 20 - --#define DEFAULT_ACCEPTMBOX_SIZE 1024 -+#define DEFAULT_ACCEPTMBOX_SIZE 4096 - #define DEFAULT_TCP_RECVMBOX_SIZE 4096 - - #define TCP_LISTEN_BACKLOG 1 --#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -+#define TCP_DEFAULT_LISTEN_BACKLOG 0xffff - - #define TCP_OVERSIZE TCP_MSS - #define LWIP_NETIF_TX_SINGLE_PBUF 1 --- -2.33.0 - diff --git a/0098-remove-duplicate-lwip-log.patch b/0098-remove-duplicate-lwip-log.patch deleted file mode 100644 index 16a847d..0000000 --- a/0098-remove-duplicate-lwip-log.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 2d01f8467027e5a640ee6c7ed72d64d8e0247829 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Wed, 27 Dec 2023 10:40:54 +0800 -Subject: [PATCH] remove duplicate log - ---- - src/core/tcp_in.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index e9ab96f..69dcd26 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -764,7 +764,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - if (flags & TCP_ACK) { - /* For incoming segments with the ACK flag set, respond with a - RST. */ -- LWIP_DEBUGF(TCP_RST_DEBUG | GAZELLE_DEBUG_SERIOUS, -+ LWIP_DEBUGF(TCP_RST_DEBUG, - ("tcp_listen_input: ACK in LISTEN, send reset, local_port=%d, remote_port=%d\n", - tcphdr->dest, tcphdr->src)); - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), --- -2.27.0 - diff --git a/0099-fix-rte_ring_create-time-consuming.patch b/0099-fix-rte_ring_create-time-consuming.patch deleted file mode 100644 index c544b2a..0000000 --- a/0099-fix-rte_ring_create-time-consuming.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 01be1587c5e6771da95d6cf8d387c0b5ba15c275 Mon Sep 17 00:00:00 2001 -From: jiangheng -Date: Wed, 27 Dec 2023 10:19:34 +0800 -Subject: [PATCH] fix rte_ring_create time consuming - ---- - src/api/sockets.c | 2 +- - src/api/sys_arch.c | 63 ++++++++++++++++++++++++++++--------- - src/include/arch/sys_arch.h | 4 +++ - 3 files changed, 54 insertions(+), 15 deletions(-) - -diff --git a/src/api/sockets.c b/src/api/sockets.c -index b7ee304..15053b3 100644 ---- a/src/api/sockets.c -+++ b/src/api/sockets.c -@@ -2810,7 +2810,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) - #endif - break; - case NETCONN_EVT_ERROR: -- if (conn->pending_err != ERR_OK) { -+ if ((conn->pending_err != ERR_OK) && (conn->pending_err != ERR_RST)) { - LWIP_DEBUGF(GAZELLE_DEBUG_SERIOUS, ("event_callback: have errevent, err=%d, fd=%d\n", conn->pending_err, conn->socket)); - } - sock->errevent = 1; -diff --git a/src/api/sys_arch.c b/src/api/sys_arch.c -index 1bc3aee..332d460 100644 ---- a/src/api/sys_arch.c -+++ b/src/api/sys_arch.c -@@ -37,6 +37,7 @@ - #include - - #include -+#include - - #include "lwip/err.h" - #include "lwip/mem.h" -@@ -89,9 +90,50 @@ static int mbox_wait_func(void) - return eth_dev_poll(); - } - -+struct rte_ring *gazelle_ring_create_fast(const char *name, uint32_t size, uint32_t flags) -+{ -+ ssize_t ring_size; -+ char ring_name[RTE_MEMZONE_NAMESIZE] = {0}; -+ struct rte_ring *ring; -+ -+ ring_size = rte_ring_get_memsize_elem(sizeof(void *), size); -+ if (ring_size < 0) { -+ RTE_LOG(ERR, EAL, "rte_ring_get_memszie_elem failed\n"); -+ return NULL; -+ } -+ -+ /* -+ * rte_ring_create is not used because it calls memzone_lookup_thread_unsafe function -+ * time consuming when there are many rings -+ */ -+ ring = rte_malloc_socket(NULL, ring_size, RTE_CACHE_LINE_SIZE, rte_socket_id()); -+ if (ring == NULL) { -+ RTE_LOG(ERR, EAL, "cannot create rte_ring for mbox\n"); -+ return NULL; -+ } -+ -+ if (snprintf(ring_name, sizeof(ring_name), "%s""%"PRIXPTR, name, (uintptr_t)ring) < 0) { -+ rte_free(ring); -+ RTE_LOG(ERR, EAL, "snprintf failed\n"); -+ return NULL; -+ } -+ -+ if (rte_ring_init(ring, ring_name, size, flags) != 0) { -+ rte_free(ring); -+ RTE_LOG(ERR, EAL, "cannot init rte_ring for mbox\n"); -+ return NULL; -+ } -+ -+ return ring; -+} -+ -+void gazelle_ring_free_fast(struct rte_ring *ring) -+{ -+ rte_free(ring); -+} -+ - err_t sys_mbox_new(struct sys_mbox **mb, int size) - { -- int ret; - struct sys_mbox *mbox; - - mbox = (struct sys_mbox *)memp_malloc(MEMP_SYS_MBOX); -@@ -100,21 +142,14 @@ err_t sys_mbox_new(struct sys_mbox **mb, int size) - } - - mbox->flags = RING_F_SP_ENQ | RING_F_SC_DEQ; -- -- ret = snprintf(mbox->name, sizeof(mbox->name), MBOX_NAME_PREFIX"%"PRIXPTR, (uintptr_t)mbox); -- if (ret < 0) { -- memp_free(MEMP_SYS_MBOX, mbox); -- return ERR_VAL; -- } -- - mbox->size = size; - mbox->socket_id = rte_socket_id(); -- mbox->ring = rte_ring_create(mbox->name, mbox->size, mbox->socket_id, mbox->flags); -- if (!mbox->ring) { -- RTE_LOG(ERR, EAL, "cannot create rte_ring for mbox\n"); -- memp_free(MEMP_SYS_MBOX, mbox); -- return ERR_MEM; -+ -+ mbox->ring = gazelle_ring_create_fast(MBOX_NAME_PREFIX, mbox->size, mbox->flags); -+ if (mbox->ring == NULL) { -+ sys_mbox_free(&mbox); - } -+ - mbox->wait_fn = mbox_wait_func; - *mb = mbox; - -@@ -125,7 +160,7 @@ void sys_mbox_free(struct sys_mbox **mb) - { - struct sys_mbox *mbox = *mb; - if (mbox->ring != NULL) { -- rte_ring_free(mbox->ring); -+ gazelle_ring_free_fast(mbox->ring); - mbox->ring = NULL; - } - memp_free(MEMP_SYS_MBOX, mbox); -diff --git a/src/include/arch/sys_arch.h b/src/include/arch/sys_arch.h -index 5e95f3d..bf7e437 100644 ---- a/src/include/arch/sys_arch.h -+++ b/src/include/arch/sys_arch.h -@@ -123,6 +123,10 @@ static __rte_always_inline uint32_t gazelle_st_ring_dequeue_burst(struct rte_rin - - return n; - } -+ -+void gazelle_ring_free_fast(struct rte_ring *ring); -+struct rte_ring *gazelle_ring_create_fast(const char *name, uint32_t size, uint32_t flags); -+ - #endif - - void sys_calibrate_tsc(void); --- -2.33.0 - diff --git a/BUILD.gn b/BUILD.gn index 02f5c01..f2dd58b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -19,40 +19,40 @@ import("lwip.gni") ohos_shared_library("liblwip") { sources = [ "src/core/altcp_alloc.c", - "src/core/altcp_alloc.c", + "src/core/altcp.c", "src/core/altcp_tcp.c", "src/core/def.c", "src/core/dns.c", "src/core/inet_chksum.c", "src/core/init.c", "src/core/ip.c", + "src/core/ipv4/acd.c", "src/core/ipv4/autoip.c", "src/core/ipv4/dhcp.c", "src/core/ipv4/etharp.c", "src/core/ipv4/icmp.c", "src/core/ipv4/igmp.c", - "src/core/ipv4/ip4.c", "src/core/ipv4/ip4_addr.c", + "src/core/ipv4/ip4.c", "src/core/ipv4/ip4_frag.c", "src/core/ipv6/dhcp6.c", "src/core/ipv6/ethip6.c", "src/core/ipv6/icmp6.c", "src/core/ipv6/inet6.c", - "src/core/ipv6/ip6.c", "src/core/ipv6/ip6_addr.c", + "src/core/ipv6/ip6.c", "src/core/ipv6/ip6_frag.c", "src/core/ipv6/mld6.c", "src/core/ipv6/nd6.c", - "src/core/lowpower.c", "src/core/mem.c", "src/core/memp.c", - "src/core/net_group.c", "src/core/netif.c", "src/core/pbuf.c", "src/core/raw.c", "src/core/stats.c", "src/core/sys.c", "src/core/tcp.c", + "src/core/tcp_in.c", "src/core/tcp_out.c", "src/core/timeouts.c", "src/core/udp.c", diff --git a/BUILDING b/BUILDING new file mode 100644 index 0000000..a2adc62 --- /dev/null +++ b/BUILDING @@ -0,0 +1,119 @@ +Building lwIP +============= + +lwIP uses a CMake based build system. + +The CMake files in this project are designed to +be included into your own CMake files. They are +mainly variable definitions containing a list of +source files and predefined static libraries to +be linked against application code. + +1) lwIP sources: + src/Filelists.cmake provides file lists containing + the lwIP core library. + The file also contains two static libraries, lwipcore + and lwipallapps, where you can link your app against. + This is the file that is useful to all lwIP users. + +2) Example applications: + contrib/Filelists.cmake provides several file lists + containing the example applications. + The file also contains several static libraries + for these example apps. + This file is only useful for you, if you can use one + of the examples in your application, which is normally + not the case. + +3) OS/platform port: + Usually the OS port needs to be provided by the user. + If a port to Linux, Windows or MacOS is useful for + you, you can use + contrib/ports/{win32, unix}/Filelists.cmake + that contains file lists and libraries for + these operating systems. + +VARIABLES +========= +In all cases, you need to provide two variables. + +"LWIP_DIR" pointing to the lwIP directory +Example: +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/externals/lwip) + +"LWIP_INCLUDE_DIRS" that contains the include base paths +- for lwIP itself (${LWIP_DIR}/src/include) +- for lwIP contrib if you use it (${LWIP_DIR}/contrib) +- to a directory containing an OS port +- to a directory containing lwipopts.h + +Example: +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/src/include" + "${LWIP_DIR}/contrib" + "${LWIP_DIR}/contrib/ports/unix/port/include" + "${LWIP_DIR}/contrib/examples/example_app" +) + +Putting it all together +======================= +To get a working application, your CMake system +needs to provide the variables described above, e.g. +set (LWIP_DIR ) +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/src/include" + "${LWIP_DIR}/contrib" + "/include" + "" +) + +You may add some defines: +set (LWIP_DEFINITIONS LWIP_DEBUG=1) + +Then include the filelists you need: +include(${LWIP_DIR}/src/Filelists.cmake) +include(${LWIP_DIR}/contrib/Filelists.cmake) + +Then, declare you executable: +add_executable(my_app ) + +Add lwIP include dirs to your app: +target_include_directories(my_app PRIVATE ${LWIP_INCLUDE_DIRS}) + +Link your app against the lwIP libs from the filelists you need: +target_link_libraries(my_app lwipcontribapps lwipallapps lwipcore) + +Working example +=============== +Working build examples can be found in the +contrib/ports/{win32, unix}/example_app +subdirectory. +To use them, create a build directory and call cmake with +the lwIP root dir: + +- mkdir build +- cd build +- cmake .. +- cmake --build . + +The CMakeLists.txt will autoselect the correct port +for your system (supported: Linux, Windows, Darwin). + +To configure the example app to your needs, you need to copy the file + contrib/examples/example_app/lwipcfg.h.example +to + contrib/examples/example_app/lwipcfg.h +and edit to your needs. + +Makefile based build system +=========================== +lwIP also maintains file lists for Makefile-based +build systems. Look for Filelists.mk files +in the source tree. We try to maintain them, +but lwIP's mainly focused build system is CMake. + +MS Visual Studio +================ +lwIP also provides basic support for MSVS in the win32 port +folder under 'msvc'. We try to maintain these files, +but lwIP's mainly focused build system is CMake. diff --git a/CHANGELOG b/CHANGELOG index 5f797e7..90a5834 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,145 @@ HISTORY * [Enter new changes just after this line - do not remove this line] +(STABLE-2.2.1): + + ++ New features: + + 2023-10-11: Faidon Liambotis + * Add MEM_CUSTOM_ALLOCATOR and make LIBC a subset of it + + 2023-09-29: Jiri Findejs + * mqtt: support binary Will Message + + ++ Bugfixes: + + 2024-02-19: Simon Goldschmidt + * tcpip: fix that TCPIP_CORE_LOCK is not released for LWIP_TIMERS==0 + + 2024-01-09: Simon Goldschmidt + * snmp v3, ppp: prevent possible timing attacks by using a constant-runtime-memcmp when + checking credentials + + 2023-01-04: Simon Goldschmidt + * makefsdata: update tinydir.h to newest version (1.2.6) + + 2023-10-12: Borys Szefler + * dhcp: fix memory corruption when LWIP_DHCP_MAX_DNS_SERVERS > DNS_MAX_SERVERS + + 2023-10-11: Mazakazu + * sockets: fix socket leak when using setsockopt/getsockopt hook with LWIP_NETCONN_FULLDUPLEX==1 + + 2023-10-10: Simon Goldschmidt + * sockets: fix bug #63898: allow socket option IPV6_CHECKSUM for both IPPROTO_IPV6 and IPPROTO_RAW + + 2023-10-10: Simon Goldschmidt + * ipv6: fix ip6_current_header() after reassembly + + 2023-10-07: Simon Goldschmidt + * ipv6 reassembly: fix detecting holes in reassembled packets + + 2023-10-04: Simon Goldschmidt + * apps: http client: improve the HTTP client; ensure connection settings are passed + + 2023-10-03: Simon Goldschmidt + * ipv6: frag: fix bogus icmp6 response on reassembly timeout + + 2023-09-28: Szabolcs Szekelyi + * httpd: ensure headers are parsed case-insensitive + + 2023-09-28: Erik Ekman + * Fix ND6 Router Advertisement parsing when NETIF_MAX_HWADDR_LEN is above 6. + + 2023-09-27: Hardy Griech + * Fix iperf byte counting mode + +(STABLE-2.2.0): + + 2018-10-02: Dirk Ziegelmeier + * Integrate contrib repository into main lwIP repository + + ++ New features: + + 2022-04-05: David Cermak + * contrib/addons: Add example of using DHCP extra options hooks + + 2023-05-11: David Cermak + * dhcp: Add macro for appending extra client's request options + + 2023-05-11: xueyunfei + * dhcp: Enable custom config for timeouts, thresholds, backoff time + + 2021-04-26 + * test/unit: added more unit tests + + 2020-03-27: Simon Goldschmidt + * test/fuzz: improve fuzz test + + 2019-12-11: Simon Goldschmidt + * ip6addr_aton: support scoped address strings (via '%') + + 2019-08-28: Joan Lledó + * Contrib: Add kFreeBSD to the Unix port + + 2019-07-14: Joan Lledó + * Unix port: improve support for the Hurd + + ++ Bugfixes: + + 2019-12-11: David Girault + * altcp_tls: support for saving/restoring session information + + 2018-11-16: Craig McQUeen + * dns: allow a DNS look-up with a trailing dot in the name + + 2018-10-19: Timmy Brolin + * Add outgoing VLAN PCP support for Ethernet level QoS + + 2018-10-08: Ben Wijen + * apps/tftp: added TFTP client + + 2018-10-04: Jasper Verschueren + * Implement IPv4 ACD (Address Conflict Detection) + + 2023-05-10 + * altcp_tls_mbedtls: note which version of mbedtls we are compatible to + * altcp_tls_mbedtls: multiple compatibility fixes + + 2023-04-26: Jan Breuer, Harrold Spier, Ognjen Bjelica, Dirk Ziegelmeier, Simon Goldschmidt + * apps/snmp: multiple fixes and improvements to snmp + + 2022-01-12: Simon Goldschmidt + * httpd: clean up custom file handling + + 2021-11-25: quanjia + * ping: fix sockaddr len in ping_send() for PING_USE_SOCKETS==1 + + 2021-11-12: Bas Prins + * http_client: reset timeout when receiving data + + 2020-07-07: Erik Ekman + * Rename IP and Ethernet equality checkers from _cmp to _eq + + 2020-03-05: Simon Goldschmidt + * tcp: tighten up checks for received SYN + + 2020-01-30: Simon Goldschmidt, David Girault, David J. Fiddes, Tom Ferrin + * apps/sntp: multiple fixes and improvements for sntp + + 2020-01-30: Simon Goldschmidt + * ip_forward: fix IPv4 forwarding with multiple netifs/offloading + + 2019-06-11: David Girault, Giuseppe Modugno + * apps/mqtt: multiple fixes for mqtt + + 2019-05-19: Joan Lledó + * New function tcpip_callback_wait() + Call a function inside the tcpip thread and block the calling thread until + the callback finishes + + 2018-08-15: Jasper Verschueren, David Girault, Our Air Quality + * apps/mdns: greatly improved the mdns client + (STABLE-2.1.2): ++ Bugfixes: @@ -177,7 +316,7 @@ HISTORY 2017-01-20: Joel Cunningham * sockets: add interface name/index APIs (task #14314) - + 2017-01-08: David van Moolenbroek * Extensions to RAW API (patch #9208) - Connected RAW PCBs @@ -266,7 +405,7 @@ HISTORY 2017-08-02: Abroz Bizjak/Simon Goldschmidt * multiple fixes in IPv4 reassembly (leading to corrupted datagrams received) - + 2017-03-30: Simon Goldschmidt * dhcp.c: return ERR_VAL instead of asserting on offset-out-of-pbuf @@ -411,7 +550,7 @@ HISTORY 2016-11-14: Joel Cunningham * tcp_out.c: fixed bug #49533 (start persist timer when unsent seg can't fit - in window) + in window) 2016-11-16: Roberto Barbieri Carrera * autoip.c: fixed bug #49610 (sometimes AutoIP fails to reuse the same address) @@ -686,7 +825,7 @@ HISTORY implementation which is under a BSD-ish license. - Also switched to PolarSSL MD4,MD5,SHA1 implementations, which are meant to be used in embedded devices with reduced memory footprint. - - Removed PPP configuration file parsing support. + - Removed PPP configuration file parsing support. - Added macro definition EAP_SUPPORT to make EAP support optional. - Added macro definition CHAP_SUPPORT to make CHAP support optional. - Added macro definition MSCHAP_SUPPORT to make MSCHAP support optional. @@ -1218,7 +1357,7 @@ HISTORY 2012-03-25: Simon Goldschmidt (idea by Mason) * posix/*: added posix-compatibility include files posix/netdb.h and posix/sys/socket.h which are a simple wrapper to the correct lwIP include files. - + 2012-01-16: Simon Goldschmidt * opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP @@ -1300,10 +1439,10 @@ HISTORY 2012-03-22: Simon Goldschmidt * ip4.c: fixed bug #35927: missing refragmentaion in ip_forward - + 2012-03-20: Simon Goldschmidt (patch by Mason) * netdb.c: fixed bug #35907: lwip_gethostbyname_r returns an invalid h_addr_list - + 2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic) * ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, possible bug on little endian system @@ -1758,7 +1897,7 @@ HISTORY 2011-03-27: Simon Goldschmidt * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. - + 2011-03-27: Simon Goldschmidt * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route is present never times out) by starting retransmission timer before checking @@ -1811,7 +1950,7 @@ HISTORY 2010-11-23: Simon Goldschmidt * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after refusing 'refused_data' again. - + 2010-11-22: Simon Goldschmidt * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS after a successful nonblocking connection. @@ -1856,21 +1995,21 @@ HISTORY 2010-08-01: Simon Goldschmidt (patch by Greg Renda) * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big endian architectures) - + 2010-07-28: Simon Goldschmidt * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP disabled. - + 2010-07-27: Simon Goldschmidt * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no harm but never did anything - + 2010-07-21: Simon Goldschmidt * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not add IP options) 2010-07-16: Kieran Mansley - * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator + * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator 2010-07-10: Simon Goldschmidt * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options @@ -1974,7 +2113,7 @@ HISTORY 2010-03-05: Simon Goldschmidt * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split - into multiple calls to tcp_write. + into multiple calls to tcp_write. 2010-02-21: Simon Goldschmidt * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep @@ -2434,7 +2573,7 @@ HISTORY sent to mbox 2009-06-25 Kieran Mansley - * api_msg.c api.h: BUG26722: initialise netconn write variables + * api_msg.c api.h: BUG26722: initialise netconn write variables in netconn_alloc 2009-06-25 Kieran Mansley @@ -2442,7 +2581,7 @@ HISTORY 2009-06-25 Kieran Mansley * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct - simultaneous close behaviour, and make snd_nxt have the same meaning + simultaneous close behaviour, and make snd_nxt have the same meaning as in the RFCs. 2009-05-12 Simon Goldschmidt @@ -2578,7 +2717,7 @@ HISTORY * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping connections where no reset required (bug #25622) - * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes + * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes (bug #20779) 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) @@ -2614,7 +2753,7 @@ HISTORY out of pool pbufs. 2008-12-19 Simon Goldschmidt - * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 + * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 2008-12-10 Tamas Somogyi, Frédéric Bernon * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and @@ -2699,7 +2838,7 @@ HISTORY made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. 2008-01-22 Frédéric Bernon - * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in + * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. 2008-01-14 Frédéric Bernon @@ -2709,7 +2848,7 @@ HISTORY 2008-01-14 Frédéric Bernon, Marc Chaland * ip.c: Integrate patch #6369" ip_input : checking before realloc". - + 2008-01-12 Frédéric Bernon * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field netconn::sem per netconn::op_completed like suggested for the task #7490 @@ -2735,8 +2874,8 @@ HISTORY Introduce changes for task #7490 "Add return value to sys_mbox_post" with some modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which indicate the number of pointers query by the mailbox. There is three defines - in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the - netconn::acceptmbox. Port maintainers, you can decide to just add this new + in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the + netconn::acceptmbox. Port maintainers, you can decide to just add this new parameter in your implementation, but to ignore it to keep the previous behavior. The new sys_mbox_trypost function return a value to know if the mailbox is full or if the message is posted. Take a look to sys_arch.txt for more details. @@ -2860,7 +2999,7 @@ HISTORY Note that previous "copy" parameter for "write" APIs is now called "apiflags". 2007-10-24 Frédéric Bernon - * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than + * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than TCP_EVENT_xxx macros to get a code more readable. It could also help to remove some code (like we have talk in "patch #5919 : Create compile switch to remove select code"), but it could be done later. @@ -2880,7 +3019,7 @@ HISTORY all netifs (or ports) can use it. 2007-10-05 Frédéric Bernon - * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the + * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the common function to reduce a little bit the footprint (for all functions using only the "netif" parameter). @@ -2904,7 +3043,7 @@ HISTORY or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only - when it's queried (any direct call to "sysuptime" is changed by a call to + when it's queried (any direct call to "sysuptime" is changed by a call to snmp_get_sysuptime). 2007-09-09 Frédéric Bernon, Bill Florac @@ -2985,7 +3124,7 @@ HISTORY 2007-08-26 Marc Boucher * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL since they can under certain circumstances be called with an invalid conn - pointer after the connection has been closed (and conn has been freed). + pointer after the connection has been closed (and conn has been freed). 2007-08-25 Frédéric Bernon (Artem Migaev's Patch) * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". @@ -2997,11 +3136,11 @@ HISTORY 2007-08-22 Frédéric Bernon * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & - ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the + ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the name is tcpip_input (we keep the name of 1.2.0 function). 2007-08-17 Jared Grubb - * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool + * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool settings into new memp_std.h and optional user file lwippools.h. This adds more dynamic mempools, and allows the user to create an arbitrary number of mempools for mem_malloc. @@ -3208,32 +3347,32 @@ HISTORY snmp_set_sysname. 2007-03-28 Frédéric Bernon - * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to + * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to initialize a network interface's flag with. It tell this interface is an ethernet device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). 2007-03-26 Frédéric Bernon, Jonathan Larmour * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build - time if you only use PPP or SLIP. The default is enable. Note we don't have to call + time if you only use PPP or SLIP. The default is enable. Note we don't have to call etharp_init in your port's initilization sequence if you use tcpip.c, because this call is done in tcpip_init function. 2007-03-22 Frédéric Bernon * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in - your lwipopts.h. More, unused counters are not defined in the stats structs, and not + your lwipopts.h. More, unused counters are not defined in the stats structs, and not display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined but never used. Fix msg_in.c with the correct #if test for a stat display. 2007-03-21 Kieran Mansley - * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). + * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). Provides callback on netif up/down state change. 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, ip.c, netif.h, tcpip.c, opt.h: - New configuration option LWIP_IGMP to enable IGMP processing. Based on only one + New configuration option LWIP_IGMP to enable IGMP processing. Based on only one filter per all network interfaces. Declare a new function in netif to enable to control the MAC filter (to reduce lwIP traffic processing). @@ -3256,7 +3395,7 @@ HISTORY * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. 2007-03-06 Frédéric Bernon - * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: + * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: Implement SO_RCVTIMEO on UDP sockets/netconn. 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) @@ -3298,7 +3437,7 @@ HISTORY and/or warnings on some systems where mem_size_t and size_t differ. * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. - 2008-03-04 Kieran Mansley (contributions by others) + 2008-03-04 Kieran Mansley (contributions by others) * Numerous small compiler error/warning fixes from contributions to mailing list after 1.3.0 release candidate made. @@ -3415,7 +3554,7 @@ HISTORY type change. Any compiler should cause an error without any changes in yours netconn_peer calls (so, it can't be a "silent change"). It also reduce a little bit the footprint for socket layer (lwip_getpeername & - lwip_getsockname use now a common lwip_getaddrname function since + lwip_getsockname use now a common lwip_getaddrname function since netconn_peer & netconn_addr have the same parameters). 2007-09-20 Simon Goldschmidt @@ -3435,13 +3574,13 @@ HISTORY if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. 2007-08-30 Frédéric Bernon - * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, + * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, and fix some coding style. 2007-08-28 Frédéric Bernon * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any - kind of packets. These packets are considered like Ethernet packets (payload - pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets + kind of packets. These packets are considered like Ethernet packets (payload + pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets are considered like IP packets (payload pointing to iphdr). 2007-08-27 Frédéric Bernon @@ -3539,7 +3678,7 @@ HISTORY 2007-06-28 Frédéric Bernon * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications - in api_lib/api_msg (use pointers and not type with table, etc...) + in api_lib/api_msg (use pointers and not type with table, etc...) 2007-06-26 Simon Goldschmidt * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. @@ -3641,7 +3780,7 @@ HISTORY 2007-05-16 Frédéric Bernon * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work - with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in + with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in tcpip_init) because we have to be sure that network interfaces are already added (mac filter is updated only in igmp_init for the moment). @@ -3788,7 +3927,7 @@ HISTORY 2007-03-20 Frédéric Bernon * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, - tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with + tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with network interfaces. Also fix a compiler warning. 2007-03-20 Kieran Mansley @@ -3880,13 +4019,13 @@ HISTORY * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call interval. - 2007-02-28 Kieran Mansley + 2007-02-28 Kieran Mansley * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved outside the region of the pbuf by pbuf_header() - 2007-02-28 Kieran Mansley + 2007-02-28 Kieran Mansley * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero - when supplied timeout is also non-zero + when supplied timeout is also non-zero (STABLE-1.2.0) @@ -3970,7 +4109,7 @@ HISTORY in accept() by Kevin Lawson. 2006-05-26 Christiaan Simons - * api_lib.c: Removed conn->sem creation and destruction + * api_lib.c: Removed conn->sem creation and destruction from netconn_write() and added sys_sem_new to netconn_new_*. (STABLE-1_1_1) @@ -4040,7 +4179,7 @@ HISTORY * dhcp.c: Decline messages were not multicast but unicast. * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. Do not try hard to insert arbitrary packet's source address, - etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. + etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. etharp_query() now always DOES call ETHARP_TRY_HARD so that users querying an address will see it appear in the cache (DHCP could suffer from this when a server invalidly gave an in-use address.) diff --git a/CMakeLists.txt b/CMakeLists.txt index f05c0f6..62a2c10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,23 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.10) + +set (CMAKE_CONFIGURATION_TYPES "Debug;Release") project(lwIP) +# Example lwIP application set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -include(src/Filelists.cmake) -# Package generation +set (LWIP_DEFINITIONS LWIP_DEBUG=1) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + add_subdirectory(${LWIP_DIR}/contrib/ports/win32/example_app) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + add_subdirectory(${LWIP_DIR}/contrib/ports/unix/example_app) +else() + message(WARNING "Host ${CMAKE_SYSTEM_NAME} is not supported to build example_app") +endif() + +# Source package generation set(CPACK_SOURCE_GENERATOR "ZIP") set(CPACK_SOURCE_PACKAGE_DESCRIPTION_SUMMARY "lwIP lightweight IP stack") set(CPACK_PACKAGE_VERSION_MAJOR "${LWIP_VERSION_MAJOR}") @@ -15,6 +27,11 @@ set(CPACK_SOURCE_IGNORE_FILES "/build/;${CPACK_SOURCE_IGNORE_FILES};.git") set(CPACK_SOURCE_PACKAGE_FILE_NAME "lwip-${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}") include(CPack) -# Target for package generation -add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) -add_dependencies(dist lwipdocs) +# Generate docs before creating source package +include(src/Filelists.cmake) +if (NOT TARGET dist) + add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) + if (TARGET lwipdocs) + add_dependencies(dist lwipdocs) + endif() +endif() diff --git a/COPYING b/COPYING index a11d7c1..90465f5 100644 --- a/COPYING +++ b/COPYING @@ -1,12 +1,25 @@ -Copyright (c) 2010, Swedish Institute of Computer Science. +Copyright (c) 2001, 2002 Swedish Institute of Computer Science. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/FEATURES b/FEATURES index a50c5a5..87802d1 100644 --- a/FEATURES +++ b/FEATURES @@ -4,7 +4,7 @@ The focus of the lwIP TCP/IP implementation is to reduce resource usage while st Main features include: - Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE, 6LowPAN (via IEEE 802.15.4, BLE or ZEP; since v2.1.0) -- DHCP client, stateless DHCPv6 (since v2.1.0), DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3 (since v2.1.0), private MIB support & MIB compiler) +- DHCP client, stateless DHCPv6 (since v2.1.0), DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection), SNMP agent (v1, v2c, v3 (since v2.1.0), private MIB support & MIB compiler) - APIs: specialized APIs for enhanced performance & zero copy, optional Berkeley-alike socket API - Extended features: IP forwarding over multiple network interfaces - Extended TCP features: congestion control, RTT estimation and fast recovery/fast retransmit, sending SACKs (since v2.1.0), "altcp": nearly transparent TLS for any tcp pcb (since v2.1.0) diff --git a/FILES b/FILES index e6e0998..2a7086c 100644 --- a/FILES +++ b/FILES @@ -1,3 +1,4 @@ +contrib/ - lwIP examples, ports, and small apps (formerly http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git/) src/ - The source code for the lwIP TCP/IP stack. doc/ - The documentation for lwIP. test/ - Some code to test whether the sources do what they should. diff --git a/README b/README index b95f155..f831051 100644 --- a/README +++ b/README @@ -17,12 +17,13 @@ FEATURES multiple network interfaces * ICMP (Internet Control Message Protocol) for network maintenance and debugging * IGMP (Internet Group Management Protocol) for multicast traffic management - * MLD (Multicast listener discovery for IPv6). Aims to be compliant with + * MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2 * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration) - * DHCP, AutoIP/APIPA (Zeroconf) and (stateless) DHCPv6 + * DHCP, AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection) + and (stateless) DHCPv6 * UDP (User Datagram Protocol) including experimental UDP-lite extensions * TCP (Transmission Control Protocol) with congestion control, RTT estimation fast recovery/fast retransmit and sending SACKs @@ -63,37 +64,39 @@ help improve lwIP by use of Savannah's interface, Git and the mailing list. A core team of developers will commit changes to the Git source tree. -The lwIP TCP/IP stack is maintained in the 'lwip' Git module and -contributions (such as platform ports) are in the 'contrib' Git module. +The lwIP TCP/IP stack is maintained in the 'src' directory and +contributions (such as platform ports and applications) are in +the 'contrib' directory. See doc/savannah.txt for details on Git server access for users and developers. -The current Git trees are web-browsable: - http://git.savannah.gnu.org/cgit/lwip.git - http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git +The current Git tree is web-browsable: + https://git.savannah.gnu.org/cgit/lwip.git Submit patches and bugs via the lwIP project page: - http://savannah.nongnu.org/projects/lwip/ + https://savannah.nongnu.org/projects/lwip/ Continuous integration builds (GCC, clang): - https://travis-ci.org/yarrick/lwip-merged + https://github.com/lwip-tcpip/lwip/actions DOCUMENTATION Self documentation of the source code is regularly extracted from the current Git sources and is available from this web page: - http://www.nongnu.org/lwip/ - -There is now a constantly growing wiki about lwIP at - http://lwip.wikia.com/wiki/LwIP_Wiki + https://www.nongnu.org/lwip/ Also, there are mailing lists you can subscribe at - http://savannah.nongnu.org/mail/?group=lwip + https://savannah.nongnu.org/mail/?group=lwip plus searchable archives: - http://lists.nongnu.org/archive/html/lwip-users/ - http://lists.nongnu.org/archive/html/lwip-devel/ + https://lists.nongnu.org/archive/html/lwip-users/ + https://lists.nongnu.org/archive/html/lwip-devel/ + +There is a wiki about lwIP at + https://lwip.wikia.com/wiki/LwIP_Wiki +You might get questions answered there, but unfortunately, it is not as +well maintained as it should be. lwIP was originally written by Adam Dunkels: http://dunkels.com/adam/ diff --git a/README.OpenSource b/README.OpenSource index 2a6bc2b..688ec96 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -1,11 +1,11 @@ [ { - "Name" : "openEuler:lwip", + "Name" : "lwip", "License" : "BSD 3-Clause License", "License File" : "COPYING", - "Version Number" : "2.1.3-102.oe2203sp3", - "Owner" : "wangmihu@huawei.com", - "Upstream URL" : "https://repo.openeuler.org/openEuler-22.03-LTS/update/source/Packages/lwip-2.1.3-39.oe2203sp1.src.rpm", + "Version Number" : "STABLE-2_2_1_RELEASE", + "Owner" : "heqianmo@huawei.com", + "Upstream URL" : "https://savannah.nongnu.org/projects/lwip/", "Description" : "lwIP is a small independent implementation of the TCP/IP protocol suite that has been initially developed by Adam Dunkels. The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM." } ] diff --git a/README_en.md b/README_en.md deleted file mode 100644 index 4f9c91c..0000000 --- a/README_en.md +++ /dev/null @@ -1,106 +0,0 @@ -# INTRODUCTION - -lwIP is a small independent implementation of the TCP/IP protocol suite. - -The focus of the lwIP TCP/IP implementation is to reduce the RAM usage -while still having a full scale TCP. This making lwIP suitable for use -in embedded systems with tens of kilobytes of free RAM and room for -around 40 kilobytes of code ROM. - -lwIP was originally developed by Adam Dunkels at the Computer and Networks -Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS) -and is now developed and maintained by a worldwide network of developers. - -# FEATURES - - * IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over - multiple network interfaces - * ICMP (Internet Control Message Protocol) for network maintenance and debugging - * IGMP (Internet Group Management Protocol) for multicast traffic management - * MLD (Multicast listener discovery for IPv6). Aims to be compliant with - RFC 2710. No support for MLDv2 - * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). - Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 - (Address autoconfiguration) - * DHCP, AutoIP/APIPA (Zeroconf) and (stateless) DHCPv6 - * UDP (User Datagram Protocol) including experimental UDP-lite extensions - * TCP (Transmission Control Protocol) with congestion control, RTT estimation - fast recovery/fast retransmit and sending SACKs - * raw/native API for enhanced performance - * Optional Berkeley-like socket API - * TLS: optional layered TCP ("altcp") for nearly transparent TLS for any - TCP-based protocol (ported to mbedTLS) (see changelog for more info) - * PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet) - * DNS (Domain name resolver incl. mDNS) - * 6LoWPAN (via IEEE 802.15.4, BLE or ZEP) - - -# APPLICATIONS - - * HTTP server with SSI and CGI (HTTPS via altcp) - * SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp - * SNTP (Simple network time protocol) - * NetBIOS name service responder - * MDNS (Multicast DNS) responder - * iPerf server implementation - * MQTT client (TLS support via altcp) - - -# LICENSE - -lwIP is freely available under a BSD license. - - -# DEVELOPMENT - -lwIP has grown into an excellent TCP/IP stack for embedded devices, -and developers using the stack often submit bug fixes, improvements, -and additions to the stack to further increase its usefulness. - -Development of lwIP is hosted on Savannah, a central point for -software development, maintenance and distribution. Everyone can -help improve lwIP by use of Savannah's interface, Git and the -mailing list. A core team of developers will commit changes to the -Git source tree. - -The lwIP TCP/IP stack is maintained in the 'lwip' Git module and -contributions (such as platform ports) are in the 'contrib' Git module. - -See doc/savannah.txt for details on Git server access for users and -developers. - -The current Git trees are web-browsable: - http://git.savannah.gnu.org/cgit/lwip.git - http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git - -Submit patches and bugs via the lwIP project page: - http://savannah.nongnu.org/projects/lwip/ - -Continuous integration builds (GCC, clang): - https://travis-ci.org/yarrick/lwip-merged - - -# DOCUMENTATION - -Self documentation of the source code is regularly extracted from the current -Git sources and is available from this web page: - http://www.nongnu.org/lwip/ - -There is now a constantly growing wiki about lwIP at - http://lwip.wikia.com/wiki/LwIP_Wiki - -Also, there are mailing lists you can subscribe at - http://savannah.nongnu.org/mail/?group=lwip -plus searchable archives: - http://lists.nongnu.org/archive/html/lwip-users/ - http://lists.nongnu.org/archive/html/lwip-devel/ - -lwIP was originally written by Adam Dunkels: - http://dunkels.com/adam/ - -Reading Adam's papers, the files in docs/, browsing the source code -documentation and browsing the mailing list archives is a good way to -become familiar with the design of lwIP. - -Adam Dunkels -Leon Woestenberg diff --git a/UPGRADING b/UPGRADING index 21ad8cc..ac77cf5 100644 --- a/UPGRADING +++ b/UPGRADING @@ -7,6 +7,17 @@ with newer versions. (git master) * [Enter new changes just after this line - do not remove this line] + * The eth_addr_cmp and ip_addr_cmp set of functions have been renamed to eth_addr_eq, ip_addr_eq + and so on, since they return non-zero on equality. Macros for the old names exist. + * The sio_write function used by PPP now takes the data argument as const. + * The prev field in the snmp_varbind struct has been removed. + +(2.2.0) + + ++ Repository changes: + + * The contrib repository has been added into the main repository in the subdirectory 'contrib' + (the old contrib repository remains online for reference but is not used any more) (2.1.0) diff --git a/backport-Add-outgoing-VLAN-PCP-support.patch b/backport-Add-outgoing-VLAN-PCP-support.patch deleted file mode 100644 index 7f89e9c..0000000 --- a/backport-Add-outgoing-VLAN-PCP-support.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 95aba99f41333ad430496eab2596bc8b489ae731 Mon Sep 17 00:00:00 2001 -From: Dirk Ziegelmeier -Date: Fri, 19 Oct 2018 22:30:17 +0200 -Subject: [PATCH] Implement task #11620: Add outgoing VLAN PCP support for - Ethernet level QoS - -Apply rebased patch from Timmy Brolin ---- - src/core/tcp.c | 29 ++++++++++++++++------------- - src/core/tcp_in.c | 3 +++ - src/include/lwip/netif.h | 22 ++++++++++++++-------- - src/include/lwip/opt.h | 34 +++++++++++++++++++++++----------- - src/netif/ethernet.c | 12 ++++++++++-- - 5 files changed, 66 insertions(+), 34 deletions(-) - -diff --git a/src/core/tcp.c b/src/core/tcp.c -index ce03c8161..1f91d24ba 100644 ---- a/src/core/tcp.c -+++ b/src/core/tcp.c -@@ -892,6 +892,9 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; - -+#if LWIP_VLAN_PCP -+ lpcb->netif_hints.tci = pcb->netif_hints.tci; -+#endif /* LWIP_VLAN_PCP */ - #if GAZELLE_TCP_REUSE_IPPORT - lpcb->connect_num = 0; - lpcb->next_same_port_pcb = NULL; -index 428a6f48d..d1fe067a4 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -690,6 +690,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) - #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG - npcb->listener = pcb; - #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ -+#if LWIP_VLAN_PCP -+ npcb->netif_hints.tci = pcb->netif_hints.tci; -+#endif /* LWIP_VLAN_PCP */ - /* inherit socket options */ - npcb->so_options = pcb->so_options & SOF_INHERITED; - npcb->netif_idx = pcb->netif_idx; -diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h -index 9e2007a64..013a69b5a 100644 ---- a/src/include/lwip/netif.h -+++ b/src/include/lwip/netif.h -@@ -248,14 +248,20 @@ typedef u8_t netif_addr_idx_t; - #define NETIF_ADDR_IDX_MAX 0x7F - #endif - -+#if LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP -+ #define LWIP_NETIF_USE_HINTS 1 -+ struct netif_hint { - #if LWIP_NETIF_HWADDRHINT --#define LWIP_NETIF_USE_HINTS 1 --struct netif_hint { -- netif_addr_idx_t addr_hint; --}; --#else /* LWIP_NETIF_HWADDRHINT */ --#define LWIP_NETIF_USE_HINTS 0 --#endif /* LWIP_NETIF_HWADDRHINT */ -+ u8_t addr_hint; -+#endif -+#if LWIP_VLAN_PCP -+ /** VLAN hader is set if this is >= 0 (but must be <= 0xFFFF) */ -+ s32_t tci; -+#endif -+ }; -+#else /* LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP */ -+ #define LWIP_NETIF_USE_HINTS 0 -+#endif /* LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP*/ - - /** Generic data structure used for all lwIP network interfaces. - * The following fields should be filled in by the initialization - #if LWIP_IPV6_AUTOCONFIG -diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h -index 90fce4f05..fb4b10c8b 100644 ---- a/src/include/lwip/opt.h -+++ b/src/include/lwip/opt.h -@@ -677,6 +677,18 @@ - #define ETHARP_SUPPORT_VLAN 0 - #endif - -+/** -+ * LWIP_VLAN_PCP==1: Enable outgoing VLAN taggning of frames on a per-PCB basis -+ * for QoS purposes. With this feature enabled, each PCB has a new variable: "tci". -+ * (Tag Control Identifier). The TCI contains three fields: VID, CFI and PCP. -+ * VID is the VLAN ID, which should be set to zero. -+ * The "CFI" bit is used to enable or disable VLAN tags for the PCB. -+ * PCP (Priority Code Point) is a 3 bit field used for Ethernet level QoS. -+ */ -+#ifndef LWIP_VLAN_PCP -+#define LWIP_VLAN_PCP 0 -+#endif -+ - /** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled - */ - #if !defined LWIP_ETHERNET || defined __DOXYGEN__ -@@ -1548,13 +1560,13 @@ - * link level header. The default is 14, the standard value for - * Ethernet. - */ --#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ --#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ --#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) --#else /* LWIP_HOOK_VLAN_SET */ --#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) --#endif /* LWIP_HOOK_VLAN_SET */ --#endif -+ #if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ -+#if (defined LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP) && !defined __DOXYGEN__ -+ #define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) -+#else /* LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP */ -+ #define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -+#endif /* LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP */ -+ #endif - - /** - * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated -diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c -index dd171e280..9e367f8cc 100644 ---- a/src/netif/ethernet.c -+++ b/src/netif/ethernet.c -@@ -273,8 +273,16 @@ ethernet_output(struct netif * netif, struct pbuf * p, - struct eth_hdr *ethhdr; - u16_t eth_type_be = lwip_htons(eth_type); - --#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) -- s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); -+#if ETHARP_SUPPORT_VLAN -+ s32_t vlan_prio_vid; -+#ifdef LWIP_HOOK_VLAN_SET -+ vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); -+#elif LWIP_VLAN_PCP -+ vlan_prio_vid = -1; -+ if (netif->hints && (netif->hints->tci >= 0)) { -+ vlan_prio_vid = (u16_t)netif->hints->tci; -+ } -+#endif - if (vlan_prio_vid >= 0) { - struct eth_vlan_hdr *vlanhdr; - - diff --git a/backport-fix-compiling-ETHARP_SUPPORT_VLAN.patch b/backport-fix-compiling-ETHARP_SUPPORT_VLAN.patch deleted file mode 100644 index d601427..0000000 --- a/backport-fix-compiling-ETHARP_SUPPORT_VLAN.patch +++ /dev/null @@ -1,33 +0,0 @@ -From f72227aadcc1d0d8c46a8b4fe62ba3d03ffa42c3 Mon Sep 17 00:00:00 2001 -From: Simon Goldschmidt -Date: Wed, 7 Nov 2018 10:49:06 +0100 -Subject: [PATCH] fix compiling ETHARP_SUPPORT_VLAN without LWIP_HOOK_VLAN_SET - and LWIP_VLAN_PCP - ---- - src/netif/ethernet.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c -index 9e367f8cc..6db434b46 100644 ---- a/src/netif/ethernet.c -+++ b/src/netif/ethernet.c -@@ -273,7 +273,7 @@ ethernet_output(struct netif * netif, struct pbuf * p, - struct eth_hdr *ethhdr; - u16_t eth_type_be = lwip_htons(eth_type); - --#if ETHARP_SUPPORT_VLAN -+#if ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) - s32_t vlan_prio_vid; - #ifdef LWIP_HOOK_VLAN_SET - vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); -@@ -297,7 +297,7 @@ ethernet_output(struct netif * netif, struct pbuf * p, - - eth_type_be = PP_HTONS(ETHTYPE_VLAN); - } else --#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ -+#endif /* ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) */ - { - if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) { - goto pbuf_header_failed; - diff --git a/backport-tcp-fix-sequence-number-comparison.patch b/backport-tcp-fix-sequence-number-comparison.patch deleted file mode 100644 index 5c0f960..0000000 --- a/backport-tcp-fix-sequence-number-comparison.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 003d34eebd223c16a3dbf6a970bb6e23cb7d1a24 Mon Sep 17 00:00:00 2001 -From: Simon Goldschmidt -Date: Fri, 27 Mar 2020 22:59:05 +0100 -Subject: [PATCH] tcp: fix sequence number comparison -This fixes both undefined behavior (see bug #51447) as well as a possible bug -where sequence numbers in 31 bit distance may come through. -Conflict: NA -Reference: https://git.savannah.gnu.org/cgit/lwip.git/commit/?id=003d34eebd223c16a3dbf6a970bb6e23cb7d1a24 ---- - src/include/lwip/priv/tcp_priv.h | 11 ++++------- - 1 file changed, 4 insertions(+), 7 deletions(-) -diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h -index 72f9126d..c84b5be8 100644 ---- a/src/include/lwip/priv/tcp_priv.h -+++ b/src/include/lwip/priv/tcp_priv.h -@@ -106,14 +106,11 @@ err_t tcp_process_refused_data(struct tcp_pcb *pcb); - #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) - - --#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) --#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) --#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) --#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) -+#define TCP_SEQ_LT(a,b) (((u32_t)((u32_t)(a) - (u32_t)(b)) & 0x80000000u) != 0) -+#define TCP_SEQ_LEQ(a,b) (!(TCP_SEQ_LT(b,a))) -+#define TCP_SEQ_GT(a,b) TCP_SEQ_LT(b,a) -+#define TCP_SEQ_GEQ(a,b) TCP_SEQ_LEQ(b,a) - /* is b<=a<=c? */ --#if 0 /* see bug #10548 */ --#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) --#endif - #define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) - - #ifndef TCP_TMR_INTERVAL --- -2.28.0.windows.1 diff --git a/backport-tcp-tighten-up-checks-for-received-SYN.patch b/backport-tcp-tighten-up-checks-for-received-SYN.patch deleted file mode 100644 index 0892cbf..0000000 --- a/backport-tcp-tighten-up-checks-for-received-SYN.patch +++ /dev/null @@ -1,58 +0,0 @@ -From adbc5b5f716d108966bcf606e61de60b83f525a5 Mon Sep 17 00:00:00 2001 -From: Simon Goldschmidt -Date: Thu, 5 Mar 2020 21:20:35 +0100 -Subject: [PATCH] tcp: tighten up checks for received SYN -Any malicous segment could contain a SYN up to now (no check). -A SYN in the wrong segment could break OOSEQ queueing. -Fix this by allowing SYN only in states where it is required. -See bug #56397: Assert "tcp_receive: ooseq tcplen > rcv_wnd" -Signed-off-by: Simon Goldschmidt -Conflict: NA -Reference: https://git.savannah.gnu.org/cgit/lwip.git/commit/?id=adbc5b5f716d108966bcf606e61de60b83f525a5 ---- - src/core/tcp_in.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) -diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c -index 4bfba85f..90061281 100644 ---- a/src/core/tcp_in.c -+++ b/src/core/tcp_in.c -@@ -852,6 +852,13 @@ tcp_process(struct tcp_pcb *pcb) - - tcp_parseopt(pcb); - -+ if (flags & TCP_SYN) { -+ /* accept SYN only in 2 states: */ -+ if ((pcb->state != SYN_SENT) && (pcb->state != SYN_RCVD)) { -+ return ERR_OK; -+ } -+ } -+ - /* Do different things depending on the TCP state. */ - switch (pcb->state) { - case SYN_SENT: -@@ -924,7 +931,12 @@ tcp_process(struct tcp_pcb *pcb) - } - break; - case SYN_RCVD: -- if (flags & TCP_ACK) { -+ if (flags & TCP_SYN) { -+ if (seqno == pcb->rcv_nxt - 1) { -+ /* Looks like another copy of the SYN - retransmit our SYN-ACK */ -+ tcp_rexmit(pcb); -+ } -+ } else if (flags & TCP_ACK) { - /* expected ACK number? */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { - pcb->state = ESTABLISHED; -@@ -975,9 +987,6 @@ tcp_process(struct tcp_pcb *pcb) - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } -- } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { -- /* Looks like another copy of the SYN - retransmit our SYN-ACK */ -- tcp_rexmit(pcb); - } - break; - case CLOSE_WAIT: --- -2.28.0.windows.1 diff --git a/codespell_changed_files.sh b/codespell_changed_files.sh new file mode 100644 index 0000000..638a18e --- /dev/null +++ b/codespell_changed_files.sh @@ -0,0 +1,26 @@ +# Copyright 2017 Kaspar Schleiser +# Copyright 2014 Ludwig Knüpfer +# Copyright 2014 Hinnerk van Bruinehsen +# Copyright 2020 Jonathan Demeyer +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +changed_files() { + : ${FILEREGEX:='\.([CcHh])$'} + : ${EXCLUDE:=''} + : ${DIFFFILTER:='ACMR'} + + DIFFFILTER="--diff-filter=${DIFFFILTER}" + + # select either all or only touched-in-branch files, filter through FILEREGEX + if [ -z "${BASE_BRANCH}" ]; then + FILES="$(git ls-tree -r --full-tree --name-only HEAD | grep -E ${FILEREGEX})" + else + FILES="$(git diff ${DIFFFILTER} --name-only ${BASE_BRANCH} | grep -E ${FILEREGEX})" + fi + + # filter out negatives + echo "${FILES}" | grep -v -E ${EXCLUDE} +} diff --git a/codespell_check.sh b/codespell_check.sh new file mode 100755 index 0000000..b3c2a16 --- /dev/null +++ b/codespell_check.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +# Copyright 2019 Alexandre Abadie +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +CODESPELL_CMD="codespell" + +if tput colors &> /dev/null && [ "$(tput colors)" -ge 8 ]; then + CERROR=$'\033[1;31m' + CRESET=$'\033[0m' +else + CERROR= + CRESET= +fi + +: "${LWIPBASE:=$(cd $(dirname $0)/; pwd)}" +cd $LWIPBASE + +: "${LWIPTOOLS:=${LWIPBASE}}" +. "${LWIPTOOLS}"/codespell_changed_files.sh + +FILEREGEX='\.([CcHh]|sh|py|md|txt)$' +EXCLUDE='^(./contrib/apps/LwipMibCompiler/Mibs)' +FILES=$(FILEREGEX=${FILEREGEX} EXCLUDE=${EXCLUDE} changed_files) + +if [ -z "${FILES}" ]; then + exit 0 +fi + +${CODESPELL_CMD} --version &> /dev/null || { + printf "%s%s: cannot execute \"%s\"!%s\n" "${CERROR}" "$0" "${CODESPELL_CMD}" "${CRESET}" + exit 1 +} + +CODESPELL_OPTS="-q 2" # Disable "WARNING: Binary file" +CODESPELL_OPTS+=" --check-hidden" +# Disable false positives "nd => and, 2nd", "ans => and", "tolen => token", +# "ofo => of", "WAN => WANT", "mut => must, mutt, moot" +CODESPELL_OPTS+=" --ignore-words-list=nd,ans,tolen,ofo,wan,mut,clen,useg,clos " +CODESPELL_OPTS+=" --ignore-words-list=devine,clinet,linz,garantie,explicite,numer " +CODESPELL_OPTS+=" --ignore-words-list=skool " +# propagate all options to codespell -> pass "-w" to this script to write changes +CODESPELL_OPTS+="$@" + +# Filter-out all false positive raising "disabled due to" messages. +ERRORS=$(${CODESPELL_CMD} ${CODESPELL_OPTS} ${FILES} | grep -ve "disabled due to") + +if [ -n "${ERRORS}" ] +then + printf "%sThere are typos in the following files:%s\n\n" "${CERROR}" "${CRESET}" + printf "%s\n" "${ERRORS}" + # TODO: return 1 when all typos are fixed + exit 0 +else + exit 0 +fi diff --git a/contrib/Coverity/coverity.c b/contrib/Coverity/coverity.c new file mode 100644 index 0000000..99bebae --- /dev/null +++ b/contrib/Coverity/coverity.c @@ -0,0 +1,106 @@ +typedef unsigned char err_t; +typedef unsigned int u32_t; +typedef unsigned short u16_t; +typedef unsigned char u8_t; +typedef void sys_sem_t; +typedef void sys_mutex_t; +typedef size_t mem_size_t; +typedef size_t memp_t; +struct pbuf; +struct netif; + +void* mem_malloc(mem_size_t size) +{ + __coverity_alloc__(size); +} +void mem_free(void* mem) +{ + __coverity_free__(mem); +} + +void* memp_malloc(memp_t type) +{ + __coverity_alloc_nosize__(); +} +void memp_free(memp_t type, void* mem) +{ + __coverity_free__(mem); +} + +void sys_mutex_lock(sys_mutex_t* mutex) +{ + __coverity_exclusive_lock_acquire__(mutex); +} +void sys_mutex_unlock(sys_mutex_t* mutex) +{ + __coverity_exclusive_lock_release__(mutex); +} + +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + __coverity_recursive_lock_acquire__(sem); +} +void sys_sem_signal(sys_sem_t *sem) +{ + __coverity_recursive_lock_release__(sem); +} + +err_t ethernet_input(struct pbuf *p, struct netif *inp) +{ + __coverity_tainted_string_sink_content__(p); +} +err_t tcpip_input(struct pbuf *p, struct netif *inp) +{ + __coverity_tainted_string_sink_content__(p); +} +err_t ip_input(struct pbuf *p, struct netif *inp) +{ + __coverity_tainted_string_sink_content__(p); +} +err_t ip4_input(struct pbuf *p, struct netif *inp) +{ + __coverity_tainted_string_sink_content__(p); +} +err_t ip6_input(struct pbuf *p, struct netif *inp) +{ + __coverity_tainted_string_sink_content__(p); +} + +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ + __coverity_tainted_string_argument__(buf); + __coverity_tainted_data_argument__(buf); +} +err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset) +{ + __coverity_tainted_string_argument__(buf); + __coverity_tainted_data_argument__(buf); +} +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) +{ + __coverity_tainted_data_transitive__(p_to, p_from); +} +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset) +{ + __coverity_tainted_string_argument__(dataptr); + __coverity_tainted_data_argument__(dataptr); +} +u8_t pbuf_get_at(struct pbuf* p, u16_t offset) +{ + __coverity_tainted_data_return__(); +} + +void abort(void) +{ + __coverity_panic__(); +} + +int check_path(char* path, size_t size) +{ + if (size) { + __coverity_tainted_data_sanitize__(path); + return 1; + } else { + return 0; + } +} diff --git a/contrib/Filelists.cmake b/contrib/Filelists.cmake new file mode 100644 index 0000000..a375dd2 --- /dev/null +++ b/contrib/Filelists.cmake @@ -0,0 +1,61 @@ +# This file is indended to be included in end-user CMakeLists.txt +# include(/path/to/Filelists.cmake) +# It assumes the variable LWIP_CONTRIB_DIR is defined pointing to the +# root path of lwIP/contrib sources. +# +# This file is NOT designed (on purpose) to be used as cmake +# subdir via add_subdirectory() +# The intention is to provide greater flexibility to users to +# create their own targets using the *_SRCS variables. + +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + +set(lwipcontribexamples_SRCS + ${LWIP_CONTRIB_DIR}/examples/httpd/fs_example/fs_example.c + ${LWIP_CONTRIB_DIR}/examples/httpd/https_example/https_example.c + ${LWIP_CONTRIB_DIR}/examples/httpd/ssi_example/ssi_example.c + ${LWIP_CONTRIB_DIR}/examples/lwiperf/lwiperf_example.c + ${LWIP_CONTRIB_DIR}/examples/mdns/mdns_example.c + ${LWIP_CONTRIB_DIR}/examples/mqtt/mqtt_example.c + ${LWIP_CONTRIB_DIR}/examples/ppp/pppos_example.c + ${LWIP_CONTRIB_DIR}/examples/snmp/snmp_private_mib/lwip_prvmib.c + ${LWIP_CONTRIB_DIR}/examples/snmp/snmp_v3/snmpv3_dummy.c + ${LWIP_CONTRIB_DIR}/examples/snmp/snmp_example.c + ${LWIP_CONTRIB_DIR}/examples/sntp/sntp_example.c + ${LWIP_CONTRIB_DIR}/examples/tftp/tftp_example.c +) +add_library(lwipcontribexamples EXCLUDE_FROM_ALL ${lwipcontribexamples_SRCS}) +target_compile_options(lwipcontribexamples PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipcontribexamples PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwipcontribexamples PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) + +set(lwipcontribapps_SRCS + ${LWIP_CONTRIB_DIR}/apps/httpserver/httpserver-netconn.c + ${LWIP_CONTRIB_DIR}/apps/chargen/chargen.c + ${LWIP_CONTRIB_DIR}/apps/udpecho/udpecho.c + ${LWIP_CONTRIB_DIR}/apps/tcpecho/tcpecho.c + ${LWIP_CONTRIB_DIR}/apps/shell/shell.c + ${LWIP_CONTRIB_DIR}/apps/udpecho_raw/udpecho_raw.c + ${LWIP_CONTRIB_DIR}/apps/tcpecho_raw/tcpecho_raw.c + ${LWIP_CONTRIB_DIR}/apps/netio/netio.c + ${LWIP_CONTRIB_DIR}/apps/ping/ping.c + ${LWIP_CONTRIB_DIR}/apps/socket_examples/socket_examples.c + ${LWIP_CONTRIB_DIR}/apps/rtp/rtp.c +) +add_library(lwipcontribapps EXCLUDE_FROM_ALL ${lwipcontribapps_SRCS}) +target_compile_options(lwipcontribapps PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipcontribapps PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwipcontribapps PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) + +set(lwipcontribaddons_SRCS + ${LWIP_CONTRIB_DIR}/addons/tcp_isn/tcp_isn.c + ${LWIP_CONTRIB_DIR}/addons/ipv6_static_routing/ip6_route_table.c +# ${LWIP_CONTRIB_DIR}/addons/netconn/external_resolve/dnssd.c +# ${LWIP_CONTRIB_DIR}/addons/tcp_md5/tcp_md5.c +) +add_library(lwipcontribaddons EXCLUDE_FROM_ALL ${lwipcontribaddons_SRCS}) +target_compile_options(lwipcontribaddons PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipcontribaddons PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwipcontribaddons PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/contrib/Filelists.mk b/contrib/Filelists.mk new file mode 100644 index 0000000..f0fb48b --- /dev/null +++ b/contrib/Filelists.mk @@ -0,0 +1,57 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +# CONTRIBAPPFILES: Contrib Applications. +CONTRIBAPPFILES=$(CONTRIBDIR)/apps/httpserver/httpserver-netconn.c \ + $(CONTRIBDIR)/apps/chargen/chargen.c \ + $(CONTRIBDIR)/apps/udpecho/udpecho.c \ + $(CONTRIBDIR)/apps/tcpecho/tcpecho.c \ + $(CONTRIBDIR)/apps/shell/shell.c \ + $(CONTRIBDIR)/apps/udpecho_raw/udpecho_raw.c \ + $(CONTRIBDIR)/apps/tcpecho_raw/tcpecho_raw.c \ + $(CONTRIBDIR)/apps/netio/netio.c \ + $(CONTRIBDIR)/apps/ping/ping.c \ + $(CONTRIBDIR)/apps/socket_examples/socket_examples.c \ + $(CONTRIBDIR)/apps/rtp/rtp.c \ + $(CONTRIBDIR)/examples/httpd/fs_example/fs_example.c \ + $(CONTRIBDIR)/examples/httpd/https_example/https_example.c \ + $(CONTRIBDIR)/examples/httpd/ssi_example/ssi_example.c \ + $(CONTRIBDIR)/examples/lwiperf/lwiperf_example.c \ + $(CONTRIBDIR)/examples/mdns/mdns_example.c \ + $(CONTRIBDIR)/examples/mqtt/mqtt_example.c \ + $(CONTRIBDIR)/examples/ppp/pppos_example.c \ + $(CONTRIBDIR)/examples/snmp/snmp_private_mib/lwip_prvmib.c \ + $(CONTRIBDIR)/examples/snmp/snmp_v3/snmpv3_dummy.c \ + $(CONTRIBDIR)/examples/snmp/snmp_example.c \ + $(CONTRIBDIR)/examples/sntp/sntp_example.c \ + $(CONTRIBDIR)/examples/tftp/tftp_example.c \ + $(CONTRIBDIR)/addons/tcp_isn/tcp_isn.c \ + $(CONTRIBDIR)/addons/ipv6_static_routing/ip6_route_table.c diff --git a/contrib/addons/dhcp_extra_opts/README b/contrib/addons/dhcp_extra_opts/README new file mode 100644 index 0000000..81a7ced --- /dev/null +++ b/contrib/addons/dhcp_extra_opts/README @@ -0,0 +1,5 @@ +A simple example of using LWIP_HOOK_DHCP_PARSE/APPEND_OPTION hooks to implement: +* DHCP_OPTION_MTU (option 26) to update the netif's MTU +* DHCP_OPTION_CLIENT_ID (option 61) to advertize client's HW id of LWIP_IANA_HWTYPE_ETHERNET type + +Please follow the instructions in dhcp_extra_opts.h to add the hooks, definitions in lwipopts.h and enabling the extra options. diff --git a/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.c b/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.c new file mode 100644 index 0000000..3e287bf --- /dev/null +++ b/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) Espressif Systems (Shanghai) CO LTD + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/netif.h" +#include "lwip/prot/iana.h" + + +void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset) +{ + LWIP_UNUSED_ARG(dhcp); + LWIP_UNUSED_ARG(state); + LWIP_UNUSED_ARG(option); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(offset); +#if LWIP_DHCP_ENABLE_MTU_UPDATE + if ((option == DHCP_OPTION_MTU) && + (state == DHCP_STATE_REBOOTING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_RENEWING || state == DHCP_STATE_REQUESTING)) { + u32_t mtu = 0; + struct netif *netif; + LWIP_ERROR("dhcp_parse_extra_opts(): MTU option's len != 2", len == 2, return;); + LWIP_ERROR("dhcp_parse_extra_opts(): extracting MTU option failed", + pbuf_copy_partial(p, &mtu, 2, offset) == 2, return;); + mtu = lwip_htons((u16_t)mtu); + NETIF_FOREACH(netif) { + /* find the netif related to this dhcp */ + if (dhcp == netif_dhcp_data(netif)) { + if (mtu < netif->mtu) { + netif->mtu = mtu; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_parse_extra_opts(): Negotiated netif MTU is %d\n", netif->mtu)); + } + return; + } + } + } /* DHCP_OPTION_MTU */ +#endif /* LWIP_DHCP_ENABLE_MTU_UPDATE */ +} + +void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(state); + LWIP_UNUSED_ARG(msg_out); + LWIP_UNUSED_ARG(options_out_len); +#if LWIP_DHCP_ENABLE_CLIENT_ID + if (state == DHCP_STATE_RENEWING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_REBOOTING || state == DHCP_STATE_OFF || + state == DHCP_STATE_REQUESTING || state == DHCP_STATE_BACKING_OFF || state == DHCP_STATE_SELECTING) { + size_t i; + u8_t *options = msg_out->options + *options_out_len; + LWIP_ERROR("dhcp_append(client_id): options_out_len + 3 + netif->hwaddr_len <= DHCP_OPTIONS_LEN", + *options_out_len + 3U + netif->hwaddr_len <= DHCP_OPTIONS_LEN, return;); + *options_out_len = *options_out_len + netif->hwaddr_len + 3; + *options++ = DHCP_OPTION_CLIENT_ID; + *options++ = netif->hwaddr_len + 1; /* option size */ + *options++ = LWIP_IANA_HWTYPE_ETHERNET; + for (i = 0; i < netif->hwaddr_len; i++) { + *options++ = netif->hwaddr[i]; + } + } +#endif /* LWIP_DHCP_ENABLE_CLIENT_ID */ +} diff --git a/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.h b/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.h new file mode 100644 index 0000000..959404d --- /dev/null +++ b/contrib/addons/dhcp_extra_opts/dhcp_extra_opts.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) Espressif Systems (Shanghai) CO LTD + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * To use these additional DHCP options, make sure this file is included in LWIP_HOOK_FILENAME + * and define these hooks: + * + * #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) \ + * do { LWIP_UNUSED_ARG(msg); \ + * dhcp_parse_extra_opts(dhcp, state, option, len, pbuf, offset); \ + * } while(0) + * + * #define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) \ + * dhcp_append_extra_opts(netif, state, msg, options_len_ptr); + * + * To enable (disable) these option, please set one or both of the below macros to 1 (0) + * #define LWIP_DHCP_ENABLE_MTU_UPDATE 1 + * #define LWIP_DHCP_ENABLE_CLIENT_ID 1 + */ + +#ifndef LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H +#define LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H + +/* Add standard integers so the header could be included before lwip */ +#include + +/* Forward declare lwip structs */ +struct dhcp; +struct pbuf; +struct dhcp; +struct netif; +struct dhcp_msg; + +/* Internal hook functions */ +void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset); +void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len); + +#endif /* LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H */ diff --git a/contrib/addons/ipv6_static_routing/README b/contrib/addons/ipv6_static_routing/README new file mode 100644 index 0000000..0c3b06c --- /dev/null +++ b/contrib/addons/ipv6_static_routing/README @@ -0,0 +1,43 @@ +A simple routing table implementation for addition, deletion and lookup of IPv6 routes.  + +APIs are: +1) s8_t ip6_add_route_entry(struct ip6_prefix *ip6_prefix, +                            struct netif *netif, +                            ip6_addr_t *gateway, +                            s8_t *index); + +2) err_t ip6_remove_route_entry(struct ip6_prefix *ip6_prefix); + +3) s8_t ip6_find_route_entry(ip6_addr_t *ip6_dest_addr); + +4) struct netif *ip6_static_route(ip6_addr_t *src, ip6_addr_t *dest); + +5) ip6_addr_t *ip6_get_gateway(struct netif *netif, ip6_addr_t *dest); + +6) struct ip6_route_entry *ip6_get_route_table(void); + +For route lookup from the table, The LWIP_HOOK_IP6_ROUTE hook in ip6_route(..) of ip6.c +could be assigned to the ip6_static_route() API of this implementation to return the +appropriate netif. + +-- The application can add routes using the API ip6_add_route_entry(..).  +   This API adds the ip6 prefix route into the static route table while +   keeping all entries sorted in decreasing order of prefix length. +   Subsequently, a linear search down the list can be performed to retrieve a +   matching route entry for a Longest Prefix Match. +   The prefix length is expected to be at an 8-bit boundary. While this is  +   a limitation, it would serve most practical purposes. + +-- The application can remove routes using the API ip6_remove_route_entry(..). + +-- The application can find a route entry for a specific address using the  +   ip6_find_route_entry() function which returns the index of the found entry.  +   This is used internally by the route lookup function ip6_static_route() API. + +-- To fetch the gateway IPv6 address for a specific destination IPv6  +   address and target netif, the application can call ip6_get_gateway(..). + This API could be assigned to the LWIP_HOOK_ND6_GET_GW() if a gateway has + been added as part of the ip6_add_route_entry(). + +-- To fetch a pointer to the head of the table, the application can call  +   ip6_get_route_table(). diff --git a/contrib/addons/ipv6_static_routing/ip6_route_table.c b/contrib/addons/ipv6_static_routing/ip6_route_table.c new file mode 100644 index 0000000..a92dd33 --- /dev/null +++ b/contrib/addons/ipv6_static_routing/ip6_route_table.c @@ -0,0 +1,248 @@ +/** + * @file + * IPv6 static route table. + */ + +/* + * Copyright (c) 2015 Nest Labs, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Pradip De + * + * + * Please coordinate changes and requests with Pradip De + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "ip6_route_table.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/nd6.h" +#include "lwip/debug.h" +#include "lwip/stats.h" + +#include "string.h" + +static struct ip6_route_entry static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES]; + +/** + * Add the ip6 prefix route and target netif into the static route table while + * keeping all entries sorted in decreasing order of prefix length. + * 1. Search from the last entry up to find the correct slot to insert while + * moving entries one position down to create room. + * 2. Insert into empty slot created. + * + * Subsequently, a linear search down the list can be performed to retrieve a + * matching route entry for a Longest Prefix Match. + * + * @param ip6_prefix the route prefix entry to add. + * @param netif pointer to target netif. + * @param gateway the gateway address to use to send through. Has to be link local. + * @param idx return value argument of index where route entry was added in table. + * @return ERR_OK if addition was successful. + * ERR_MEM if table is already full. + * ERR_ARG if passed argument is bad or route already exists in table. + */ +err_t +ip6_add_route_entry(const struct ip6_prefix *ip6_prefix, struct netif *netif, const ip6_addr_t *gateway, s8_t *idx) +{ + s8_t i = -1; + err_t retval = ERR_OK; + + if (!ip6_prefix_valid(ip6_prefix->prefix_len) || (netif == NULL)) { + retval = ERR_ARG; + goto exit; + } + + /* Check if an entry already exists with matching prefix; If so, replace it. */ + for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) { + if ((ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len) && + memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr, + ip6_prefix->prefix_len / 8) == 0) { + /* Prefix matches; replace the netif with the one being added. */ + goto insert; + } + } + + /* Check if the table is full */ + if (static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES - 1].netif != NULL) { + retval = ERR_MEM; + goto exit; + } + + /* Shift all entries down the table until slot is found */ + for (i = LWIP_IPV6_NUM_ROUTE_ENTRIES - 1; + i > 0 && (ip6_prefix->prefix_len > static_route_table[i - 1].prefix.prefix_len); i--) { + SMEMCPY(&static_route_table[i], &static_route_table[i - 1], sizeof(struct ip6_route_entry)); + } + +insert: + /* Insert into the slot selected */ + SMEMCPY(&static_route_table[i].prefix, ip6_prefix, sizeof(struct ip6_prefix)); + static_route_table[i].netif = netif; + + /* Add gateway to route table */ + static_route_table[i].gateway = gateway; + + if (idx != NULL) { + *idx = i; + } + +exit: + return retval; +} + +/** + * Removes the route entry from the static route table. + * + * @param ip6_prefix the route prefix entry to delete. + */ +void +ip6_remove_route_entry(const struct ip6_prefix *ip6_prefix) +{ + int i, pos = -1; + + for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) { + /* compare prefix to find position to delete */ + if (ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len && + memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr, + ip6_prefix->prefix_len / 8) == 0) { + pos = i; + break; + } + } + + if (pos >= 0) { + /* Shift everything beyond pos one slot up */ + for (i = pos; i < LWIP_IPV6_NUM_ROUTE_ENTRIES - 1; i++) { + SMEMCPY(&static_route_table[i], &static_route_table[i+1], sizeof(struct ip6_route_entry)); + if (static_route_table[i].netif == NULL) { + break; + } + } + /* Zero the remaining entries */ + for (; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) { + ip6_addr_set_zero((&static_route_table[i].prefix.addr)); + static_route_table[i].netif = NULL; + } + } +} + +/** + * Finds the appropriate route entry in the static route table corresponding to the given + * destination IPv6 address. Since the entries in the route table are kept sorted in decreasing + * order of prefix length, a linear search down the list is performed to retrieve a matching + * index. + * + * @param ip6_dest_addr the destination address to match + * @return the idx of the found route entry; -1 if not found. + */ +s8_t +ip6_find_route_entry(const ip6_addr_t *ip6_dest_addr) +{ + s8_t i, idx = -1; + + /* Search prefix in the sorted(decreasing order of prefix length) list */ + for(i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) { + if (memcmp(ip6_dest_addr, &static_route_table[i].prefix.addr, + static_route_table[i].prefix.prefix_len / 8) == 0) { + idx = i; + break; + } + } + + return idx; +} + +/** + * Finds the appropriate network interface for a given IPv6 address from a routing table with + * static IPv6 routes. + * + * @param src the source IPv6 address, if known + * @param dest the destination IPv6 address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip6_static_route(const ip6_addr_t *src, const ip6_addr_t *dest) +{ + int i; + + LWIP_UNUSED_ARG(src); + + /* Perform table lookup */ + i = ip6_find_route_entry(dest); + + if (i >= 0) { + return static_route_table[i].netif; + } else { + return NULL; + } +} + +/** + * Finds the gateway IP6 address for a given destination IPv6 address and target netif + * from a routing table with static IPv6 routes. + * + * @param netif the netif used for sending + * @param dest the destination IPv6 address + * @return the ip6 address of the gateway to forward packet to + */ +const ip6_addr_t * +ip6_get_gateway(struct netif *netif, const ip6_addr_t *dest) +{ + const ip6_addr_t *ret_gw = NULL; + const int i = ip6_find_route_entry(dest); + + LWIP_UNUSED_ARG(netif); + + if (i >= 0) { + if (static_route_table[i].gateway != NULL) { + ret_gw = static_route_table[i].gateway; + } + } + + return ret_gw; +} + +/** + * Returns the top of the route table. + * This should be used for debug printing only. + * + * @return the top of the route table. + */ +const struct ip6_route_entry * +ip6_get_route_table(void) +{ + return static_route_table; +} + +#endif /* LWIP_IPV6 */ diff --git a/contrib/addons/ipv6_static_routing/ip6_route_table.h b/contrib/addons/ipv6_static_routing/ip6_route_table.h new file mode 100644 index 0000000..478328e --- /dev/null +++ b/contrib/addons/ipv6_static_routing/ip6_route_table.h @@ -0,0 +1,94 @@ +/** + * @file + * + * IPv6 static route table. + */ + +/* + * Copyright (c) 2015 Nest Labs, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Pradip De + * + * + * Please coordinate changes and requests with Pradip De + * + */ + +#ifndef __LWIP_IP6_ROUTE_TABLE_H__ +#define __LWIP_IP6_ROUTE_TABLE_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netif; + +/** + * LWIP_IPV6_NUM_ROUTES: Number of IPV6 routes that can be kept in the static route table. + */ +#ifndef LWIP_IPV6_NUM_ROUTE_ENTRIES +#define LWIP_IPV6_NUM_ROUTE_ENTRIES (8) +#endif + +#define IP6_MAX_PREFIX_LEN (128) +#define IP6_PREFIX_ALLOWED_GRANULARITY (8) +/* Prefix length cannot be greater than 128 bits and needs to be at a byte boundary */ +#define ip6_prefix_valid(prefix_len) (((prefix_len) <= IP6_MAX_PREFIX_LEN) && \ + (((prefix_len) % IP6_PREFIX_ALLOWED_GRANULARITY) == 0)) + +struct ip6_prefix { + ip6_addr_t addr; + u8_t prefix_len; /* prefix length in bits at byte boundaries */ +}; + +struct ip6_route_entry { + struct ip6_prefix prefix; + struct netif *netif; + const ip6_addr_t *gateway; +}; + +err_t ip6_add_route_entry(const struct ip6_prefix *ip6_prefix, struct netif *netif, + const ip6_addr_t *gateway, s8_t *idx); +void ip6_remove_route_entry(const struct ip6_prefix *ip6_prefix); +s8_t ip6_find_route_entry(const ip6_addr_t *ip6_dest_addr); +struct netif *ip6_static_route(const ip6_addr_t *src, const ip6_addr_t *dest); +const ip6_addr_t *ip6_get_gateway(struct netif *netif, const ip6_addr_t *dest); +const struct ip6_route_entry *ip6_get_route_table(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_ROUTE_TABLE_H__ */ diff --git a/contrib/addons/netconn/external_resolve/dnssd.c b/contrib/addons/netconn/external_resolve/dnssd.c new file mode 100644 index 0000000..d26743b --- /dev/null +++ b/contrib/addons/netconn/external_resolve/dnssd.c @@ -0,0 +1,164 @@ +/** + * @file + * DNS-SD APIs used by LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE + * + * This implementation assumes the DNS-SD API implementation (most likely provided by + * mDNSResponder) is implemented in the same process space as LwIP and can directly + * invoke the callback for DNSServiceGetAddrInfo. This is the typical deployment in + * an embedded environment where as a traditional OS requires pumping the callback results + * through an IPC mechanism (see DNSServiceRefSockFD/DNSServiceProcessResult) + * + * @defgroup dnssd DNS-SD + * @ingroup dns + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Joel Cunningham + * + */ +#include "lwip/opt.h" + +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#include "dnssd.h" + +/* External headers */ +#include +#include + +/* This timeout should allow for multiple queries. +mDNSResponder has the following query timeline: + Query 1: time = 0s + Query 2: time = 1s + Query 3: time = 4s +*/ +#define GETADDR_TIMEOUT_MS 5000 +#define LOCAL_DOMAIN ".local" + +/* Only consume .local hosts */ +#ifndef CONSUME_LOCAL_ONLY +#define CONSUME_LOCAL_ONLY 1 +#endif + +struct addr_clbk_msg { + sys_sem_t sem; + struct sockaddr_storage addr; + err_t err; +}; + +static void addr_info_callback(DNSServiceRef ref, DNSServiceFlags flags, u32_t interface_index, + DNSServiceErrorType error_code, char const* hostname, + const struct sockaddr* address, u32_t ttl, void* context); + +int +lwip_dnssd_gethostbyname(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err) +{ + DNSServiceErrorType result; + DNSServiceRef ref; + struct addr_clbk_msg msg; + char *p; + + /* @todo: use with IPv6 */ + LWIP_UNUSED_ARG(addrtype); + +#if CONSUME_LOCAL_ONLY + /* check if this is a .local host. If it is, then we consume the query */ + p = strstr(name, LOCAL_DOMAIN); + if (p == NULL) { + return 0; /* not consumed */ + } + p += (sizeof(LOCAL_DOMAIN) - 1); + /* check to make sure .local isn't a substring (only allow .local\0 or .local.\0) */ + if ((*p != '.' && *p != '\0') || + (*p == '.' && *(p + 1) != '\0')) { + return 0; /* not consumed */ + } +#endif /* CONSUME_LOCAL_ONLY */ + + msg.err = sys_sem_new(&msg.sem, 0); + if (msg.err != ERR_OK) { + goto query_done; + } + + msg.err = ERR_TIMEOUT; + result = DNSServiceGetAddrInfo(&ref, 0, 0, kDNSServiceProtocol_IPv4, name, addr_info_callback, &msg); + if (result == kDNSServiceErr_NoError) { + sys_arch_sem_wait(&msg.sem, GETADDR_TIMEOUT_MS); + DNSServiceRefDeallocate(ref); + + /* We got a response */ + if (msg.err == ERR_OK) { + struct sockaddr_in* addr_in = (struct sockaddr_in *)&msg.addr; + if (addr_in->sin_family == AF_INET) { + inet_addr_to_ip4addr(ip_2_ip4(addr), &addr_in->sin_addr); + } else { + /* @todo add IPv6 support */ + msg.err = ERR_VAL; + } + } + } + sys_sem_free(&msg.sem); + +/* Query has been consumed and is finished */ +query_done: +*err = msg.err; +return 1; +} + +static void +addr_info_callback(DNSServiceRef ref, DNSServiceFlags flags, u32_t interface_index, + DNSServiceErrorType error_code, char const* hostname, + const struct sockaddr* address, u32_t ttl, void* context) +{ + struct addr_clbk_msg* msg = (struct addr_clbk_msg*)context; + struct sockaddr_in* addr_in = (struct sockaddr_in *)address; + + LWIP_UNUSED_ARG(ref); + LWIP_UNUSED_ARG(flags); + LWIP_UNUSED_ARG(interface_index); + LWIP_UNUSED_ARG(hostname); + LWIP_UNUSED_ARG(ttl); + LWIP_UNUSED_ARG(context); + + if ((error_code == kDNSServiceErr_NoError) && + (addr_in->sin_family == AF_INET)) { + MEMCPY(&msg->addr, addr_in, sizeof(*addr_in)); + msg->err = ERR_OK; + } + else { + /* @todo add IPv6 support */ + msg->err = ERR_VAL; + } + + sys_sem_signal(&msg->sem); +} /* addr_info_callback() */ diff --git a/contrib/addons/netconn/external_resolve/dnssd.h b/contrib/addons/netconn/external_resolve/dnssd.h new file mode 100644 index 0000000..e2d71d9 --- /dev/null +++ b/contrib/addons/netconn/external_resolve/dnssd.h @@ -0,0 +1,50 @@ +/** + * @file + * DNS-SD APIs used by LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE + * + * @defgroup dnssd DNS-SD + * @ingroup dns + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Joel Cunningham + * + */ +#include "lwip/opt.h" + +#ifndef LWIP_HDR_DNSSD_H +#define LWIP_HDR_DNSSD_H + +#include "lwip/err.h" +#include "lwip/ip_addr.h" + +int lwip_dnssd_gethostbyname(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err); + +#endif /* LWIP_HDR_DNSSD_H */ diff --git a/contrib/addons/tcp_isn/tcp_isn.c b/contrib/addons/tcp_isn/tcp_isn.c new file mode 100644 index 0000000..c161499 --- /dev/null +++ b/contrib/addons/tcp_isn/tcp_isn.c @@ -0,0 +1,182 @@ +/** + * @file + * + * Reference implementation of the TCP ISN algorithm standardized in RFC 6528. + * Produce TCP Initial Sequence Numbers by combining an MD5-generated hash + * based on the new TCP connection's identity and a stable secret, with the + * current time at 4-microsecond granularity. + * + * Specifically, the implementation uses MD5 to compute a hash of the input + * buffer, which contains both the four-tuple of the new TCP connection (local + * and remote IP address and port), as well as a 16-byte secret to make the + * results unpredictable to external parties. The secret must be given at + * initialization time and should ideally remain the same across system + * reboots. To be sure: the spoofing-resistance of the resulting ISN depends + * mainly on the strength of the supplied secret! + * + * The implementation takes 32 bits from the computed hash, and adds to it the + * current time, in 4-microsecond units. The current time is computed from a + * boot time given at initialization, and the current uptime as provided by + * sys_now(). Thus, it assumes that sys_now() returns a time value that is + * relative to the boot time, i.e., that it starts at 0 at system boot, and + * only ever increases monotonically. + * + * For efficiency reasons, a single MD5 input buffer is used, and partially + * filled in at initialization time. Specifically, of this 64-byte buffer, the + * first 36 bytes are used for the four-way TCP tuple data, followed by the + * 16-byte secret, followed by 12-byte zero padding. The 64-byte size of the + * buffer should achieve the best performance for the actual MD5 computation. + * + * Basic usage: + * + * 1. in your lwipopts.h, add the following lines: + * + * #include + * struct ip_addr; + * u32_t lwip_hook_tcp_isn(const struct ip_addr *local_ip, u16_t local_port, + * const struct ip_addr *remote_ip, u16_t remote_port); + * "#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn"; + * + * 2. from your own code, call lwip_init_tcp_isn() at initialization time, with + * appropriate parameters. + */ + +/* + * Copyright (c) 2016 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: David van Moolenbroek + */ + +#include "tcp_isn.h" +#include "lwip/ip_addr.h" +#include "lwip/sys.h" +#include + +#ifdef LWIP_HOOK_TCP_ISN + +/* pull in md5 of ppp? */ +#include "netif/ppp/ppp_opts.h" +#if !PPP_SUPPORT || (!LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS) +#undef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#include "netif/ppp/polarssl/md5.h" +#endif + +static u8_t input[64]; +static u32_t base_time; + +/** + * Initialize the TCP ISN module, with the boot time and a secret. + * + * @param boot_time Wall clock boot time of the system, in seconds. + * @param secret_16_bytes A 16-byte secret used to randomize the TCP ISNs. + */ +void +lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes) +{ + /* Initialize the input buffer with the secret and trailing zeroes. */ + memset(input, 0, sizeof(input)); + + MEMCPY(&input[36], secret_16_bytes, 16); + + /* Save the boot time in 4-us units. Overflow is no problem here. */ + base_time = boot_time * 250000; +} + +/** + * Hook to generate an Initial Sequence Number (ISN) for a new TCP connection. + * + * @param local_ip The local IP address. + * @param local_port The local port number, in host-byte order. + * @param remote_ip The remote IP address. + * @param remote_port The remote port number, in host-byte order. + * @return The ISN to use for the new TCP connection. + */ +u32_t +lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port) +{ + md5_context ctx; + u8_t output[16]; + u32_t isn; + +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_V6(local_ip)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV6 + { + const ip6_addr_t *local_ip6, *remote_ip6; + + local_ip6 = ip_2_ip6(local_ip); + remote_ip6 = ip_2_ip6(remote_ip); + + SMEMCPY(&input[0], &local_ip6->addr, 16); + SMEMCPY(&input[16], &remote_ip6->addr, 16); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + const ip4_addr_t *local_ip4, *remote_ip4; + + local_ip4 = ip_2_ip4(local_ip); + remote_ip4 = ip_2_ip4(remote_ip); + + /* Represent IPv4 addresses as IPv4-mapped IPv6 addresses, to ensure that + * the IPv4 and IPv6 address spaces are completely disjoint. */ + memset(&input[0], 0, 10); + input[10] = 0xff; + input[11] = 0xff; + SMEMCPY(&input[12], &local_ip4->addr, 4); + memset(&input[16], 0, 10); + input[26] = 0xff; + input[27] = 0xff; + SMEMCPY(&input[28], &remote_ip4->addr, 4); + } +#endif /* LWIP_IPV4 */ + + input[32] = (u8_t)(local_port >> 8); + input[33] = (u8_t)(local_port & 0xff); + input[34] = (u8_t)(remote_port >> 8); + input[35] = (u8_t)(remote_port & 0xff); + + /* The secret and padding are already filled in. */ + + /* Generate the hash, using MD5. */ + md5_starts(&ctx); + md5_update(&ctx, input, sizeof(input)); + md5_finish(&ctx, output); + + /* Arbitrarily take the first 32 bits from the generated hash. */ + MEMCPY(&isn, output, sizeof(isn)); + + /* Add the current time in 4-microsecond units. */ + return isn + base_time + sys_now() * 250; +} + +#endif /* LWIP_HOOK_TCP_ISN */ diff --git a/contrib/addons/tcp_isn/tcp_isn.h b/contrib/addons/tcp_isn/tcp_isn.h new file mode 100644 index 0000000..ebaeca2 --- /dev/null +++ b/contrib/addons/tcp_isn/tcp_isn.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: David van Moolenbroek + */ + +#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H +#define LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes); +u32_t lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H */ diff --git a/contrib/addons/tcp_md5/README b/contrib/addons/tcp_md5/README new file mode 100644 index 0000000..a6408ca --- /dev/null +++ b/contrib/addons/tcp_md5/README @@ -0,0 +1,27 @@ +This folder provides an example implementation of how to add custom tcp header +options and custom socket options. + +It does this by implementing the (seldom used) tcp md5 signature. + +To enable it, add an LWIP_HOOK_FILENAME hook file, include tcp_md5.h in it and +define these hooks: + + #define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) tcp_md5_check_inpacket(pcb, hdr, optlen, opt1len, opt2, p) + #define LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT(pcb, internal_len) tcp_md5_get_additional_option_length(pcb, internal_len) + #define LWIP_HOOK_TCP_ADD_TX_OPTIONS(p, hdr, pcb, opts) tcp_md5_add_tx_options(p, hdr, pcb, opts) + #define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) tcp_md5_setsockopt_hook(sock, level, optname, optval, optlen, err) + +Then, in your sockets application, enable md5 signature on a socket like this: + + struct tcp_md5sig md5; + struct sockaddr_storage addr_remote; /* Initialize this to remote address and port */ + memcpy(&md5.tcpm_addr, &addr_remote, sizeof(addr_remote)); + strcpy(md5.tcpm_key, key); /* this is the md5 key per connection */ + md5.tcpm_keylen = strlen(key); + if ((ret = setsockopt(sockfd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5))) < 0) { + perror("setsockopt TCP_MD5SIG"); + return; + } + +After that, your connection (client) or all incoming connections (server) require +tcp md5 signatures. diff --git a/contrib/addons/tcp_md5/tcp_md5.c b/contrib/addons/tcp_md5/tcp_md5.c new file mode 100644 index 0000000..e7815d8 --- /dev/null +++ b/contrib/addons/tcp_md5/tcp_md5.c @@ -0,0 +1,534 @@ +/** + * @file: An implementation of TCP MD5 signatures by using various hooks in + * lwIP to implement custom tcp options and custom socket options. + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Simon Goldschmidt + */ + +#include "tcp_md5.h" +#include "lwip/ip_addr.h" +#include "lwip/sys.h" +#include "lwip/prot/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/sockets.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/api.h" +#include + +/* pull in md5 of ppp? */ +#include "netif/ppp/ppp_opts.h" +#if !PPP_SUPPORT || (!LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS) +#undef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#include "netif/ppp/polarssl/md5.h" +#endif + +#if !LWIP_TCP_PCB_NUM_EXT_ARGS +#error tcp_md5 needs LWIP_TCP_PCB_NUM_EXT_ARGS +#endif + +#define LWIP_TCP_OPT_MD5 19 /* number of the md5 option */ +#define LWIP_TCP_OPT_LEN_MD5 18 /* length of the md5 option */ +#define LWIP_TCP_OPT_LEN_MD5_OUT 20 /* 18 + alignment */ + +#define LWIP_TCP_MD5_DIGEST_LEN 16 + +/* This keeps the md5 state internally */ +struct tcp_md5_conn_info { + struct tcp_md5_conn_info *next; + ip_addr_t remote_addr; + u16_t remote_port; + u8_t key[TCP_MD5SIG_MAXKEYLEN]; + u16_t key_len; +}; + +/* Callback function prototypes: */ +static void tcp_md5_extarg_destroy(u8_t id, void *data); +static err_t tcp_md5_extarg_passive_open(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); +/* Define our tcp ext arg callback structure: */ +const struct tcp_ext_arg_callbacks tcp_md5_ext_arg_callbacks = { + tcp_md5_extarg_destroy, + tcp_md5_extarg_passive_open +}; + +static u8_t tcp_md5_extarg_id = LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID; +static u8_t tcp_md5_opts_buf[40]; + +/** Initialize this module (allocates a tcp ext arg id) */ +void +tcp_md5_init(void) +{ + tcp_md5_extarg_id = tcp_ext_arg_alloc_id(); +} + +/* Create a conn-info structure that holds the md5 state per connection */ +static struct tcp_md5_conn_info * +tcp_md5_conn_info_alloc(void) +{ + return (struct tcp_md5_conn_info *)mem_malloc(sizeof(struct tcp_md5_conn_info)); +} + +/* Frees a conn-info structure that holds the md5 state per connection */ +static void +tcp_md5_conn_info_free(struct tcp_md5_conn_info *info) +{ + mem_free(info); +} + +/* A pcb is about to be destroyed. Free its extdata */ +static void +tcp_md5_extarg_destroy(u8_t id, void *data) +{ + struct tcp_md5_conn_info *iter; + + LWIP_ASSERT("tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID", + tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID); + LWIP_ASSERT("id == tcp_md5_extarg_id", id == tcp_md5_extarg_id); + LWIP_UNUSED_ARG(id); + + iter = (struct tcp_md5_conn_info *)data; + while (iter != NULL) { + struct tcp_md5_conn_info *info = iter; + iter = iter->next; + tcp_md5_conn_info_free(info); + } +} + +/* Try to find an md5 connection info for the specified remote connection */ +static struct tcp_md5_conn_info * +tcp_md5_get_info(const struct tcp_pcb *pcb, const ip_addr_t *remote_ip, u16_t remote_port) +{ + if (pcb != NULL) { + struct tcp_md5_conn_info *info = (struct tcp_md5_conn_info *)tcp_ext_arg_get(pcb, tcp_md5_extarg_id); + while (info != NULL) { + if (ip_addr_eq(&info->remote_addr, remote_ip)) { + if (info->remote_port == remote_port) { + return info; + } + } + info = info->next; + } + } + return NULL; +} + +/* Passive open: copy md5 connection info from listen pcb to connection pcb + * or return error (connection will be closed) + */ +static err_t +tcp_md5_extarg_passive_open(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb) +{ + struct tcp_md5_conn_info *iter; + + LWIP_ASSERT("lpcb != NULL", lpcb != NULL); + LWIP_ASSERT("cpcb != NULL", cpcb != NULL); + LWIP_ASSERT("tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID", + tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID); + LWIP_ASSERT("id == tcp_md5_extarg_id", id == tcp_md5_extarg_id); + LWIP_UNUSED_ARG(id); + + iter = (struct tcp_md5_conn_info *)tcp_ext_arg_get((struct tcp_pcb *)lpcb, id); + while (iter != NULL) { + if (iter->remote_port == cpcb->remote_port) { + if (ip_addr_eq(&iter->remote_addr, &cpcb->remote_ip)) { + struct tcp_md5_conn_info *info = tcp_md5_conn_info_alloc(); + if (info != NULL) { + memcpy(info, iter, sizeof(struct tcp_md5_conn_info)); + tcp_ext_arg_set(cpcb, id, info); + tcp_ext_arg_set_callbacks(cpcb, id, &tcp_md5_ext_arg_callbacks); + return ERR_OK; + } else { + return ERR_MEM; + } + } + } + iter = iter->next; + } + /* remote connection not found */ + return ERR_VAL; +} + +/* Parse tcp header options and return 1 if an md5 signature option was found */ +static int +tcp_md5_parseopt(const u8_t *opts, u16_t optlen, u8_t *md5_digest_out) +{ + u8_t data; + u16_t optidx; + + /* Parse the TCP MSS option, if present. */ + if (optlen != 0) { + for (optidx = 0; optidx < optlen; ) { + u8_t opt = opts[optidx++]; + switch (opt) { + case LWIP_TCP_OPT_EOL: + /* End of options. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); + return 0; + case LWIP_TCP_OPT_NOP: + /* NOP option. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); + break; + case LWIP_TCP_OPT_MD5: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MD5\n")); + if (opts[optidx++] != LWIP_TCP_OPT_LEN_MD5 || (optidx - 2 + LWIP_TCP_OPT_LEN_MD5) > optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return 0; + } + /* An MD5 option with the right option length. */ + memcpy(md5_digest_out, &opts[optidx], LWIP_TCP_MD5_DIGEST_LEN); + /* no need to process the options further */ + return 1; + break; + default: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); + data = opts[optidx++]; + if (data < 2) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + /* If the length field is zero, the options are malformed + and we don't process them further. */ + return 0; + } + /* All other options have a length field, so that we easily + can skip past them. */ + optidx += data - 2; + } + } + } + return 0; +} + +/* Get tcp options into contiguous memory. May be required if input pbufs + * are chained. + */ +static const u8_t* +tcp_md5_options_singlebuf(struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2) +{ + const u8_t *opts; + LWIP_ASSERT("hdr != NULL", hdr != NULL); + LWIP_ASSERT("optlen >= opt1len", optlen >= opt1len); + opts = (const u8_t *)hdr + TCP_HLEN; + if (optlen == opt1len) { + /* arleady in one piece */ + return opts; + } + if (optlen > sizeof(tcp_md5_opts_buf)) { + /* options too long */ + return NULL; + } + LWIP_ASSERT("opt2 != NULL", opt2 != NULL); + /* copy first part */ + memcpy(tcp_md5_opts_buf, opts, opt1len); + /* copy second part */ + memcpy(&tcp_md5_opts_buf[opt1len], opt2, optlen - opt1len); + return tcp_md5_opts_buf; +} + +/* Create the md5 digest for a given segment */ +static int +tcp_md5_create_digest(const ip_addr_t *ip_src, const ip_addr_t *ip_dst, const struct tcp_hdr *hdr, + const u8_t *key, size_t key_len, u8_t *digest_out, struct pbuf *p) +{ + md5_context ctx; + u8_t tmp8; + u16_t tmp16; + const size_t addr_len = IP_ADDR_RAW_SIZE(*ip_src); + + if (p != NULL) { + LWIP_ASSERT("pbuf must not point to tcp header here!", (const void *)hdr != p->payload); + } + + /* Generate the hash, using MD5. */ + md5_starts(&ctx); + /* 1. the TCP pseudo-header (in the order: source IP address, + destination IP address, zero-padded protocol number, and + segment length) */ + md5_update(&ctx, (const unsigned char*)ip_src, addr_len); + md5_update(&ctx, (const unsigned char*)ip_dst, addr_len); + tmp8 = 0; /* zero-padded */ + md5_update(&ctx, &tmp8, 1); + tmp8 = IP_PROTO_TCP; + md5_update(&ctx, &tmp8, 1); + tmp16 = lwip_htons(TCPH_HDRLEN_BYTES(hdr) + (p ? p->tot_len : 0)); + md5_update(&ctx, (const unsigned char*)&tmp16, 2); + /* 2. the TCP header, excluding options, and assuming a checksum of + zero */ + md5_update(&ctx, (const unsigned char*)hdr, sizeof(struct tcp_hdr)); + /* 3. the TCP segment data (if any) */ + if ((p != NULL) && (p->tot_len != 0)) { + struct pbuf *q; + for (q = p; q != NULL; q = q->next) { + md5_update(&ctx, (const unsigned char*)q->payload, q->len); + } + } + /* 4. an independently-specified key or password, known to both TCPs + and presumably connection-specific */ + md5_update(&ctx, key, key_len); + + md5_finish(&ctx, digest_out); + return 1; +} + +/* Duplicate a tcp header and make sure the fields are in network byte order */ +static void +tcp_md5_dup_tcphdr(struct tcp_hdr *tcphdr_copy, const struct tcp_hdr *tcphdr_in, int tcphdr_in_is_host_order) +{ + memcpy(tcphdr_copy, tcphdr_in, sizeof(struct tcp_hdr)); + tcphdr_copy->chksum = 0; /* checksum is zero for the pseudo header */ + if (tcphdr_in_is_host_order) { + /* lwIP writes the TCP header values back to the buffer, we need to invert that here: */ + tcphdr_copy->src = lwip_htons(tcphdr_copy->src); + tcphdr_copy->dest = lwip_htons(tcphdr_copy->dest); + tcphdr_copy->seqno = lwip_htonl(tcphdr_copy->seqno); + tcphdr_copy->ackno = lwip_htonl(tcphdr_copy->ackno); + tcphdr_copy->wnd = lwip_htons(tcphdr_copy->wnd); + tcphdr_copy->urgp = lwip_htons(tcphdr_copy->urgp); + } +} + +/* Check if md5 is enabled on a given pcb */ +static int +tcp_md5_is_enabled_on_pcb(const struct tcp_pcb *pcb) +{ + if (tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID) { + struct tcp_md5_conn_info *info = (struct tcp_md5_conn_info *)tcp_ext_arg_get(pcb, tcp_md5_extarg_id); + if (info != NULL) { + return 1; + } + } + return 0; +} + +/* Check if md5 is enabled on a given listen pcb */ +static int +tcp_md5_is_enabled_on_lpcb(const struct tcp_pcb_listen *lpcb) +{ + /* same as for connection pcbs */ + return tcp_md5_is_enabled_on_pcb((const struct tcp_pcb *)lpcb); +} + +/* Hook implementation for LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT */ +u8_t +tcp_md5_get_additional_option_length(const struct tcp_pcb *pcb, u8_t internal_option_length) +{ + if ((pcb != NULL) && tcp_md5_is_enabled_on_pcb(pcb)) { + u8_t new_option_length = internal_option_length + LWIP_TCP_OPT_LEN_MD5_OUT; + LWIP_ASSERT("overflow", new_option_length > internal_option_length); + LWIP_ASSERT("options too long", new_option_length <= TCP_MAX_OPTION_BYTES); + return new_option_length; + } + return internal_option_length; +} + +/* Hook implementation for LWIP_HOOK_TCP_INPACKET_PCB when called for listen pcbs */ +static err_t +tcp_md5_check_listen(struct tcp_pcb_listen* lpcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2) +{ + LWIP_ASSERT("lpcb != NULL", lpcb != NULL); + + if (tcp_md5_is_enabled_on_lpcb(lpcb)) { + const u8_t *opts; + u8_t digest_received[LWIP_TCP_MD5_DIGEST_LEN]; + u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN]; + const struct tcp_md5_conn_info *info = tcp_md5_get_info((struct tcp_pcb *)lpcb, ip_current_src_addr(), hdr->src); + if (info != NULL) { + opts = tcp_md5_options_singlebuf(hdr, optlen, opt1len, opt2); + if (opts != NULL) { + if (tcp_md5_parseopt(opts, optlen, digest_received)) { + struct tcp_hdr tcphdr_copy; + tcp_md5_dup_tcphdr(&tcphdr_copy, hdr, 1); + if (tcp_md5_create_digest(ip_current_src_addr(), ip_current_dest_addr(), &tcphdr_copy, info->key, info->key_len, digest_calculated, NULL)) { + /* everything set up, compare the digests */ + if (!memcmp(digest_received, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN)) { + /* equal */ + return ERR_OK; + } + /* not equal */ + } + } + } + } + /* md5 enabled on this pcb but no match or other error -> fail */ + return ERR_VAL; + } + return ERR_OK; +} + +/* Hook implementation for LWIP_HOOK_TCP_INPACKET_PCB */ +err_t +tcp_md5_check_inpacket(struct tcp_pcb* pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + + if (pcb->state == LISTEN) { + return tcp_md5_check_listen((struct tcp_pcb_listen *)pcb, hdr, optlen, opt1len, opt2); + } + + if (tcp_md5_is_enabled_on_pcb(pcb)) { + const struct tcp_md5_conn_info *info = tcp_md5_get_info(pcb, ip_current_src_addr(), hdr->src); + if (info != NULL) { + const u8_t *opts; + u8_t digest_received[LWIP_TCP_MD5_DIGEST_LEN]; + u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN]; + opts = tcp_md5_options_singlebuf(hdr, optlen, opt1len, opt2); + if (opts != NULL) { + if (tcp_md5_parseopt(opts, optlen, digest_received)) { + struct tcp_hdr hdr_copy; + tcp_md5_dup_tcphdr(&hdr_copy, hdr, 1); + if (tcp_md5_create_digest(&pcb->remote_ip, &pcb->local_ip, &hdr_copy, info->key, info->key_len, digest_calculated, p)) { + /* everything set up, compare the digests */ + if (!memcmp(digest_received, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN)) { + /* equal */ + return ERR_OK; + } + /* not equal */ + } + } + } + } + /* md5 enabled on this pcb but no match or other error -> fail */ + return ERR_VAL; + } + return ERR_OK; +} + +/* Hook implementation for LWIP_HOOK_TCP_ADD_TX_OPTIONS */ +u32_t * +tcp_md5_add_tx_options(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts) +{ + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("hdr != NULL", hdr != NULL); + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("opts != NULL", opts != NULL); + + if (tcp_md5_is_enabled_on_pcb(pcb)) { + u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN]; + u32_t *opts_ret = opts + 5; /* we use 20 bytes: 2 bytes padding + 18 bytes for this option */ + u8_t *ptr = (u8_t*)opts; + + const struct tcp_md5_conn_info *info = tcp_md5_get_info(pcb, &pcb->remote_ip, pcb->remote_port); + if (info != NULL) { + struct tcp_hdr hdr_copy; + size_t hdrsize = TCPH_HDRLEN_BYTES(hdr); + tcp_md5_dup_tcphdr(&hdr_copy, hdr, 0); + /* p->payload points to the tcp header */ + LWIP_ASSERT("p->payload == hdr", p->payload == hdr); + if (!pbuf_remove_header(p, hdrsize)) { + u8_t ret; + if (!tcp_md5_create_digest(&pcb->local_ip, &pcb->remote_ip, &hdr_copy, info->key, info->key_len, digest_calculated, p)) { + info = NULL; + } + ret = pbuf_add_header_force(p, hdrsize); + LWIP_ASSERT("tcp_md5_add_tx_options: pbuf_add_header_force failed", !ret); + LWIP_UNUSED_ARG(ret); + } else { + LWIP_ASSERT("error", 0); + } + } + if (info == NULL) { + /* create an invalid signature by zeroing the digest */ + memset(&digest_calculated, 0, sizeof(digest_calculated)); + } + + *ptr++ = LWIP_TCP_OPT_NOP; + *ptr++ = LWIP_TCP_OPT_NOP; + *ptr++ = LWIP_TCP_OPT_MD5; + *ptr++ = LWIP_TCP_OPT_LEN_MD5; + memcpy(ptr, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN); + ptr += LWIP_TCP_MD5_DIGEST_LEN; + LWIP_ASSERT("ptr == opts_ret", ptr == (u8_t *)opts_ret); + return opts_ret; + } + return opts; +} + +/* Hook implementation for LWIP_HOOK_SOCKETS_SETSOCKOPT */ +int +tcp_md5_setsockopt_hook(struct lwip_sock *sock, int level, int optname, const void *optval, socklen_t optlen, int *err) +{ + LWIP_ASSERT("sock != NULL", sock != NULL); + LWIP_ASSERT("err != NULL", err != NULL); + + if ((level == IPPROTO_TCP) && (optname == TCP_MD5SIG)) { + const struct tcp_md5sig *md5 = (const struct tcp_md5sig*)optval; + if ((optval == NULL) || (optlen < sizeof(struct tcp_md5sig))) { + *err = EINVAL; + } else { + if (sock->conn && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (sock->conn->pcb.tcp != NULL)) { + if (tcp_md5_extarg_id == LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID) { + /* not initialized */ + *err = EINVAL; + } else { + struct tcp_md5_conn_info *info = tcp_md5_conn_info_alloc(); + if (info == NULL) { + *err = ENOMEM; + } else { + int addr_valid = 0; + /* OK, fill and link this request */ + memcpy(info->key, md5->tcpm_key, TCP_MD5SIG_MAXKEYLEN); + info->key_len = md5->tcpm_keylen; + memset(&info->remote_addr, 0, sizeof(info->remote_addr)); + if (md5->tcpm_addr.ss_family == AF_INET) { +#if LWIP_IPV4 + const struct sockaddr_in *sin = (const struct sockaddr_in *)&md5->tcpm_addr; + memcpy(&info->remote_addr, &sin->sin_addr, sizeof(sin->sin_addr)); + IP_SET_TYPE_VAL(info->remote_addr, IPADDR_TYPE_V4); + info->remote_port = lwip_htons(sin->sin_port); + addr_valid = 1; +#endif /* LWIP_IPV4 */ + } else if (md5->tcpm_addr.ss_family == AF_INET6) { +#if LWIP_IPV6 + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)&md5->tcpm_addr; + memcpy(&info->remote_addr, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); + IP_SET_TYPE_VAL(info->remote_addr, IPADDR_TYPE_V6); + info->remote_port = lwip_htons(sin6->sin6_port); + addr_valid = 1; +#endif /* LWIP_IPV6 */ + } + if (addr_valid) { + /* store it */ + tcp_ext_arg_set_callbacks(sock->conn->pcb.tcp, tcp_md5_extarg_id, &tcp_md5_ext_arg_callbacks); + info->next = (struct tcp_md5_conn_info *)tcp_ext_arg_get(sock->conn->pcb.tcp, tcp_md5_extarg_id); + tcp_ext_arg_set(sock->conn->pcb.tcp, tcp_md5_extarg_id, info); + } else { + *err = EINVAL; + tcp_md5_conn_info_free(info); + } + } + } + } else { + /* not a tcp netconn */ + *err = EINVAL; + } + } + return 1; + } + return 0; +} diff --git a/contrib/addons/tcp_md5/tcp_md5.h b/contrib/addons/tcp_md5/tcp_md5.h new file mode 100644 index 0000000..e55740a --- /dev/null +++ b/contrib/addons/tcp_md5/tcp_md5.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Simon Goldschmidt + * + * To use the hooks in this file, make sure this file is included in LWIP_HOOK_FILENAME + * and define these hooks: + * + * #define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) tcp_md5_check_inpacket(pcb, hdr, optlen, opt1len, opt2, p) + * #define LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT(pcb, internal_len) tcp_md5_get_additional_option_length(pcb, internal_len) + * #define LWIP_HOOK_TCP_ADD_TX_OPTIONS(p, hdr, pcb, opts) tcp_md5_add_tx_options(p, hdr, pcb, opts) + * + * #define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) tcp_md5_setsockopt_hook(sock, level, optname, optval, optlen, err) + */ + +#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H +#define LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#include "lwip/priv/sockets_priv.h" +#include "lwip/priv/tcp_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* setsockopt definitions and structs: */ + +/* This is the optname (for level = IPPROTO_TCP) */ +#ifndef TCP_MD5SIG +#define TCP_MD5SIG 14 +#endif + +#define TCP_MD5SIG_MAXKEYLEN 80 + +/* This is the optval type */ +struct tcp_md5sig { + struct sockaddr_storage tcpm_addr; + u16_t __tcpm_pad1; + u16_t tcpm_keylen; + u32_t __tcpm_pad2; + u8_t tcpm_key[TCP_MD5SIG_MAXKEYLEN]; +}; + +/* socket setsockopt hook: */ +int tcp_md5_setsockopt_hook(struct lwip_sock *sock, int level, int optname, const void *optval, u32_t optlen, int *err); + +/* Internal hook functions */ +void tcp_md5_init(void); +err_t tcp_md5_check_inpacket(struct tcp_pcb* pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p); +u8_t tcp_md5_get_additional_option_length(const struct tcp_pcb *pcb, u8_t internal_option_length); +u32_t *tcp_md5_add_tx_options(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H */ diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/CCodeGeneration.csproj b/contrib/apps/LwipMibCompiler/CCodeGeneration/CCodeGeneration.csproj new file mode 100644 index 0000000..06d5075 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/CCodeGeneration.csproj @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B} + Library + Properties + CCodeGeneration + CCodeGeneration + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/CFile.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/CFile.cs new file mode 100644 index 0000000..6f12274 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/CFile.cs @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace CCodeGeneration +{ + public class CFile: CodeContainerBase + { + public CFile() + { + base.IncreaseLevel = false; + } + + public void Save(CGenerator generator) + { + if (generator == null) + { + throw new ArgumentNullException("generator"); + } + + this.GenerateCode(0, generator); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/CGenerator.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/CGenerator.cs new file mode 100644 index 0000000..4e8dfbc --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/CGenerator.cs @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.IO; + +namespace CCodeGeneration +{ + public class CGenerator + { + public TextWriter OutputStream { get; private set; } + public string File { get; private set; } + public uint IndentCount { get; private set; } + public string IndentChar { get; private set; } + public string NewLine { get; private set; } + + public CGenerator(System.IO.TextWriter outputStream, string file, uint indentCount, string indentChar, string newLine) + { + this.OutputStream = outputStream; + this.File = file; + this.IndentCount = indentCount; + this.IndentChar = indentChar; + this.NewLine = newLine; + } + + public string FileName + { + get + { + if (!String.IsNullOrWhiteSpace(this.File)) + { + return Path.GetFileName(this.File); + } + + return null; + } + } + + public void WriteSequence(string value, uint repetitions) + { + while (repetitions > 0) + { + this.OutputStream.Write(value); + repetitions--; + } + } + + public void IndentLine(int level) + { + while (level > 0) + { + WriteSequence(this.IndentChar, this.IndentCount); + level--; + } + } + + public void WriteNewLine() + { + this.OutputStream.Write(this.NewLine); + } + + public void WriteMultilineString(string value, int level = 0) + { + if (String.IsNullOrEmpty(value)) + { + return; + } + + // only \n and \r\n are recognized as linebreaks + string[] lines = value.Split(new char[] { '\n' }, StringSplitOptions.None); + + for (int l = 0; l < (lines.Length - 1); l++) + { + if (lines[l].EndsWith("\r")) + { + this.OutputStream.Write(lines[l].Substring(0, lines[l].Length-1)); + } + else + { + this.OutputStream.Write(lines[l]); + } + + this.WriteNewLine(); + this.IndentLine(level); + } + + this.OutputStream.Write(lines[lines.Length - 1]); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/Code.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/Code.cs new file mode 100644 index 0000000..4834508 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/Code.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class Code: CodeElement + { + public string Code_ { get; set; } + + public Code() + { + } + + public Code(string code) + { + this.Code_ = code; + } + + public override void GenerateCode(int level, CGenerator generator) + { + generator.IndentLine(level); + generator.WriteMultilineString(this.Code_, level); + generator.WriteNewLine(); + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeContainerBase.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeContainerBase.cs new file mode 100644 index 0000000..4327d92 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeContainerBase.cs @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System.Collections.Generic; +using System; + +namespace CCodeGeneration +{ + public class CodeContainerBase: CodeElement + { + private readonly List declarations = new List(); + private readonly List innerElements = new List(); + private bool increaseLevel = true; + + public List Declarations + { + get { return this.declarations; } + } + + public List InnerElements + { + get { return this.innerElements; } + } + + protected bool IncreaseLevel + { + get { return this.increaseLevel; } + set { this.increaseLevel = value; } + } + + public void AddElements(IList elements, params CodeElement[] spacerElements) + { + if (elements != null) + { + if ((spacerElements == null) || (spacerElements.Length == 0)) + { + this.innerElements.AddRange(elements); + } + else + { + bool spacerAdded = false; + + foreach (CodeElement element in elements) + { + this.innerElements.Add(element); + this.innerElements.AddRange(spacerElements); + spacerAdded = true; + } + + if (spacerAdded) + { + // remove last spacer again + this.innerElements.RemoveRange(this.innerElements.Count - spacerElements.Length, spacerElements.Length); + } + } + } + } + + public CodeElement AddElement(CodeElement element) + { + if (element != null) + { + this.innerElements.Add(element); + } + + return element; + } + + public Code AddCode(string code) + { + return this.AddElement(new Code(code)) as Code; + } + + public Code AddCodeFormat(string codeFormat, params object[] args) + { + return this.AddElement(new Code(String.Format(codeFormat, args))) as Code; + } + + public CodeElement AddDeclaration(CodeElement declaration) + { + if (declaration != null) + { + this.declarations.Add(declaration); + } + + return declaration; + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (this.increaseLevel) + level++; + + if (this.declarations.Count > 0) + { + foreach (CodeElement element in this.declarations) + { + element.GenerateCode(level, generator); + } + + EmptyLine.SingleLine.GenerateCode(level, generator); + } + + foreach (CodeElement element in this.innerElements) + { + element.GenerateCode(level, generator); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeElement.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeElement.cs new file mode 100644 index 0000000..51cf2d2 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/CodeElement.cs @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class CodeElement + { + public virtual void GenerateCode(int level, CGenerator generator) + { + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/Comment.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/Comment.cs new file mode 100644 index 0000000..51779be --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/Comment.cs @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class Comment: CodeElement + { + public const string CommentStart = "/*"; + public const string CommentEnd = "*/"; + + public string Comment_ { get; set; } + public bool SingleLine { get; set; } + + public Comment() + { + } + + public Comment(string comment, bool singleLine = false) + { + this.Comment_ = comment; + this.SingleLine = singleLine; + } + + public override void GenerateCode(int level, CGenerator generator) + { + generator.IndentLine(level); + generator.OutputStream.Write(CommentStart); + + if (!this.SingleLine) + { + generator.WriteNewLine(); + generator.IndentLine(level); + generator.WriteMultilineString(this.Comment_, level); + generator.WriteNewLine(); + generator.IndentLine(level); + } + else + { + generator.OutputStream.Write(" " + Comment_ + " "); + } + + generator.OutputStream.Write(CommentEnd); + generator.WriteNewLine(); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/EmptyLine.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/EmptyLine.cs new file mode 100644 index 0000000..604c947 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/EmptyLine.cs @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class EmptyLine : CodeElement + { + public static readonly EmptyLine SingleLine = new EmptyLine(); + public static readonly EmptyLine TwoLines = new EmptyLine(2); + public static readonly EmptyLine ThreeLines = new EmptyLine(3); + + public uint Count { get; set; } + + public EmptyLine() + { + this.Count = 1; + } + + public EmptyLine(uint count) + { + this.Count = count; + } + + public override void GenerateCode(int level, CGenerator generator) + { + uint c = this.Count; + + while (c > 0) + { + generator.WriteNewLine(); + c--; + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/Function.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/Function.cs new file mode 100644 index 0000000..d81f6e5 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/Function.cs @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; + +namespace CCodeGeneration +{ + public class Function: CodeContainerBase + { + public string Name { get; set; } + public bool IsStatic { get; set; } + + private readonly List parameter = new List(); + private VariableType returnType = VariableType.Void; + + public Function() + { + } + + public Function(string name, bool isStatic = false) + { + this.Name = name; + this.IsStatic = isStatic; + } + + public List Parameter + { + get { return this.parameter; } + } + + public VariableType ReturnType + { + get { return this.returnType; } + set + { + if (value == null) + { + throw new ArgumentNullException("ReturnValue"); + } + this.returnType = value; + } + } + + public static Function FromDeclaration(FunctionDeclaration decl) + { + Function result = new Function(decl.Name, decl.IsStatic); + result.ReturnType = decl.ReturnType.Clone() as VariableType; + + foreach (VariableType param in decl.Parameter) + { + result.parameter.Add(param.Clone() as VariableType); + } + + return result; + } + + public override void GenerateCode(int level, CGenerator generator) + { + generator.IndentLine(level); + + if (this.IsStatic) + { + generator.OutputStream.Write("static "); + } + + this.returnType.GenerateCode(generator); + generator.OutputStream.Write(" " + this.Name + "("); + + if (this.Parameter.Count > 0) + { + for (int i = 0; i < this.parameter.Count; i++) + { + this.parameter[i].GenerateCode(generator); + + if (i < (this.parameter.Count - 1)) + { + generator.OutputStream.Write(", "); + } + } + } + else + { + generator.OutputStream.Write("void"); + } + + generator.OutputStream.Write(")"); + generator.WriteNewLine(); + generator.IndentLine(level); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + base.GenerateCode(level, generator); + + generator.IndentLine(level); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/FunctionDeclaration.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/FunctionDeclaration.cs new file mode 100644 index 0000000..3bc4288 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/FunctionDeclaration.cs @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; + +namespace CCodeGeneration +{ + public class FunctionDeclaration: CodeElement + { + public string Name { get; set; } + public bool IsStatic { get; set; } + public bool IsExtern { get; set; } + + private readonly List parameter = new List(); + private VariableType returnType = VariableType.Void; + + public FunctionDeclaration() + { + } + + public FunctionDeclaration(string name, bool isStatic = false, bool isExtern = false) + { + this.Name = name; + this.IsStatic = isStatic; + this.IsExtern = isExtern; + } + + public List Parameter + { + get { return this.parameter; } + } + + public VariableType ReturnType + { + get { return this.returnType; } + set + { + if (value == null) + { + throw new ArgumentNullException("ReturnValue"); + } + this.returnType = value; + } + } + + public override void GenerateCode(int level, CGenerator generator) + { + generator.IndentLine(level); + + if (this.IsExtern) + { + generator.OutputStream.Write("extern "); + } + + if (this.IsStatic) + { + generator.OutputStream.Write("static "); + } + + this.returnType.GenerateCode(generator); + generator.OutputStream.Write(" " + this.Name + "("); + + if (this.Parameter.Count > 0) + { + for (int i = 0; i < this.parameter.Count; i++) + { + this.parameter[i].GenerateCode(generator); + + if (i < (this.parameter.Count - 1)) + { + generator.OutputStream.Write(", "); + } + } + } + else + { + generator.OutputStream.Write("void"); + } + + generator.OutputStream.Write(");"); + generator.WriteNewLine(); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/IfThenElse.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/IfThenElse.cs new file mode 100644 index 0000000..c471022 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/IfThenElse.cs @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; + +namespace CCodeGeneration +{ + public class ElseIf : CodeContainerBase + { + public string Condition { get; set; } + + public ElseIf() + { + } + + public ElseIf(string condition) + { + this.Condition = condition; + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Condition)) + { + generator.IndentLine(level); + generator.OutputStream.Write(String.Format("else if ({0})", this.Condition)); + generator.WriteNewLine(); + generator.IndentLine(level); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + base.GenerateCode(level, generator); + + generator.IndentLine(level); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + } + } + } + + public class IfThenElse: CodeContainerBase + { + public string Condition { get; set; } + + private List elseIf = new List(); + private CodeContainerBase else_ = new CodeContainerBase(); + + public IfThenElse() + { + } + + public IfThenElse(string condition) + { + this.Condition = condition; + } + + public List ElseIf + { + get { return this.elseIf; } + } + + public CodeContainerBase Else + { + get { return this.else_; } + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Condition)) + { + generator.IndentLine(level); + generator.OutputStream.Write(String.Format("if ({0})", this.Condition)); + generator.WriteNewLine(); + generator.IndentLine(level); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + base.GenerateCode(level, generator); + + generator.IndentLine(level); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + + foreach (ElseIf elif in this.elseIf) + { + elif.GenerateCode(level, generator); + } + + if (this.else_.InnerElements.Count > 0) + { + generator.IndentLine(level); + generator.OutputStream.Write("else"); + generator.WriteNewLine(); + generator.IndentLine(level); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + this.else_.GenerateCode(level, generator); + + generator.IndentLine(level); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + } + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_If.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_If.cs new file mode 100644 index 0000000..5568215 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_If.cs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace CCodeGeneration +{ + public class PP_If: CodeContainerBase + { + public string Condition { get; set; } + + public PP_If() + { + base.IncreaseLevel = false; + } + + public PP_If(string condition) + : this() + { + this.Condition = condition; + } + + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Condition)) + { + generator.OutputStream.Write("#if " + this.Condition); + generator.WriteNewLine(); + + base.GenerateCode(level, generator); + + generator.OutputStream.Write("#endif /* " + this.Condition + " */"); + generator.WriteNewLine(); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Ifdef.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Ifdef.cs new file mode 100644 index 0000000..fd4f45a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Ifdef.cs @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace CCodeGeneration +{ + public class PP_Ifdef: CodeContainerBase + { + public string Macro { get; set; } + public bool Inverted { get; set; } + + public PP_Ifdef() + { + base.IncreaseLevel = false; + } + + public PP_Ifdef(string macro, bool inverted = false) + : this() + { + this.Macro = macro; + this.Inverted = inverted; + } + + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Macro)) + { + if (this.Inverted) + { + generator.OutputStream.Write("#ifndef " + this.Macro); + } + else + { + generator.OutputStream.Write("#ifdef " + this.Macro); + } + generator.WriteNewLine(); + + base.GenerateCode(level, generator); + + generator.OutputStream.Write("#endif /* " + this.Macro + " */"); + generator.WriteNewLine(); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Include.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Include.cs new file mode 100644 index 0000000..0393d27 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Include.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace CCodeGeneration +{ + public class PP_Include : CodeElement + { + public string File { get; set; } + public bool IsLocal { get; set; } + + public PP_Include() + { + this.IsLocal = true; + } + + public PP_Include(string file, bool isLocal = true) + { + this.File = file; + this.IsLocal = isLocal; + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.File)) + { + // includes are never indented + if (this.IsLocal) + { + generator.OutputStream.Write("#include \"" + this.File + "\""); + } + else + { + generator.OutputStream.Write("#include <" + this.File + ">"); + } + + generator.WriteNewLine(); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Macro.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Macro.cs new file mode 100644 index 0000000..6f302aa --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/PP_Macro.cs @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class PP_Macro: CodeElement + { + public string Name { get; set; } + public string Value { get; set; } + + public PP_Macro() + { + } + + public PP_Macro(string name, string value) + { + this.Name = name; + this.Value = value; + } + + + public override void GenerateCode(int level, CGenerator generator) + { + // macros are not indented at all + generator.OutputStream.Write("#define " + this.Name + " "); + generator.WriteMultilineString(this.Value); + generator.WriteNewLine(); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/PlainText.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/PlainText.cs new file mode 100644 index 0000000..d5e076f --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/PlainText.cs @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class PlainText : CodeElement + { + public string Value { get; set; } + + public PlainText(string value) + { + this.Value = value; + } + + public override void GenerateCode(int level, CGenerator generator) + { + generator.WriteMultilineString(this.Value); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/Properties/AssemblyInfo.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4c716ad --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("CCodeGeneration")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CCodeGeneration")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("8f07a0fa-86f4-48a0-97c7-f94fc5c3f103")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/Switch.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/Switch.cs new file mode 100644 index 0000000..9166fb8 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/Switch.cs @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; + +namespace CCodeGeneration +{ + public class SwitchCase : CodeContainerBase + { + public string Value { get; set; } + + public SwitchCase() + { + } + + public SwitchCase(string value) + { + this.Value = value; + } + + public bool IsDefault + { + get { return (this.Value.ToLowerInvariant() == "default"); } + } + + public static SwitchCase GenerateDefault() + { + return new SwitchCase("default"); + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Value)) + { + generator.IndentLine(level); + if (this.IsDefault) + { + generator.OutputStream.Write("default:"); + } + else + { + generator.OutputStream.Write(String.Format("case {0}:", this.Value)); + } + generator.WriteNewLine(); + generator.IndentLine(level + 1); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + base.GenerateCode(level + 1, generator); + + generator.IndentLine(level + 1); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + + generator.IndentLine(level + 1); + generator.OutputStream.Write("break;"); + generator.WriteNewLine(); + } + } + } + + public class Switch: CodeElement + { + public string SwitchVar { get; set; } + + private List switches = new List(); + + public Switch() + { + } + + public Switch(string switchVar) + { + this.SwitchVar = switchVar; + } + + public List Switches + { + get { return this.switches; } + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.SwitchVar)) + { + generator.IndentLine(level); + generator.OutputStream.Write(String.Format("switch ({0})", this.SwitchVar)); + generator.WriteNewLine(); + generator.IndentLine(level); + generator.OutputStream.Write("{"); + generator.WriteNewLine(); + + SwitchCase defaultCase = null; // generate 'default' always as last case + foreach (SwitchCase switchCase in this.switches) + { + if (switchCase.IsDefault) + { + defaultCase = switchCase; + } + else + { + switchCase.GenerateCode(level + 1, generator); + } + } + if (defaultCase != null) + { + defaultCase.GenerateCode(level + 1, generator); + } + + generator.IndentLine(level); + generator.OutputStream.Write("}"); + generator.WriteNewLine(); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableDeclaration.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableDeclaration.cs new file mode 100644 index 0000000..bf2c902 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableDeclaration.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace CCodeGeneration +{ + public class VariableDeclaration : CodeElement + { + public VariableType Type { get; set; } + public string InitialValue { get; set; } + public bool IsStatic { get; set; } + + public VariableDeclaration() + : base() + { + } + + public VariableDeclaration(VariableType type, string initialValue = null, bool isStatic = false) : + base() + { + this.Type = type; + this.InitialValue = initialValue; + this.IsStatic = isStatic; + } + + public override void GenerateCode(int level, CGenerator generator) + { + if (this.Type != null) + { + generator.IndentLine(level); + + if (this.IsStatic) + { + generator.OutputStream.Write("static "); + } + + // declare the variable + this.Type.GenerateCode(generator); + + if (!String.IsNullOrWhiteSpace(this.InitialValue)) + { + // add initialization value + generator.OutputStream.Write(" = "); + generator.WriteMultilineString(this.InitialValue, level); + } + + generator.OutputStream.Write(";"); + generator.WriteNewLine(); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/VariablePrototype.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariablePrototype.cs new file mode 100644 index 0000000..38a4166 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariablePrototype.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +namespace CCodeGeneration +{ + public class VariablePrototype : CodeElement + { + public VariableType Type { get; set; } + + public VariablePrototype() + : base() + { + } + + public VariablePrototype(VariableType type) : + base() + { + Type = type; + } + + public static VariablePrototype FromVariableDeclaration(VariableDeclaration declaration) + { + return new VariablePrototype(declaration.Type); + } + + + public override void GenerateCode(int level, CGenerator generator) + { + if (this.Type != null) + { + generator.IndentLine(level); + + generator.OutputStream.Write("extern "); + + // declare the variable + this.Type.GenerateCode(generator); + + generator.OutputStream.Write(";"); + generator.WriteNewLine(); + } + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableType.cs b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableType.cs new file mode 100644 index 0000000..313abbe --- /dev/null +++ b/contrib/apps/LwipMibCompiler/CCodeGeneration/VariableType.cs @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; + +namespace CCodeGeneration +{ + public enum ConstType + { + None, + Value, + Indirection, + Both + } + + public class VariableType : ICloneable + { + public const string VoidString = "void"; + public static readonly VariableType Void = new VariableType(null, "void"); + + public string Name { get; set; } + public string Type { get; set; } + public string Indirection { get; set; } + public ConstType Const { get; set; } + public string ArraySpecifier { get; set; } + + public VariableType() + { + } + + public VariableType(string name, string type, string indirection = null, ConstType const_ = ConstType.None, string arraySpecifier = null) + { + this.Name = name; + this.Type = type; + this.Indirection = indirection; + this.Const = const_; + this.ArraySpecifier = arraySpecifier; + } + + public void GenerateCode(CGenerator generator) + { + if (!String.IsNullOrWhiteSpace(this.Type)) + { + generator.OutputStream.Write(this.ToString().Trim()); + } + } + + public override string ToString() + { + if (!String.IsNullOrWhiteSpace(this.Type)) + { + StringBuilder vt = new StringBuilder(); + + if ((this.Const == ConstType.Value) || (this.Const == ConstType.Both)) + { + vt.Append("const "); + } + + vt.Append(this.Type); + vt.Append(" "); + + if (!String.IsNullOrWhiteSpace(this.Indirection)) + { + vt.Append(this.Indirection); + } + + if ((this.Const == ConstType.Indirection) || (this.Const == ConstType.Both)) + { + vt.Append("const "); + } + + if (!String.IsNullOrWhiteSpace(this.Name)) + { + vt.Append(this.Name); + } + + if (this.ArraySpecifier != null) + { + vt.Append("["); + vt.Append(this.ArraySpecifier); + vt.Append("]"); + } + + return vt.ToString().Trim(); + } + + return base.ToString(); + } + + #region ICloneable Member + + public object Clone() + { + // we only have value types as members -> simply use .net base function + return this.MemberwiseClone(); + } + + #endregion + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipMibCompiler.sln b/contrib/apps/LwipMibCompiler/LwipMibCompiler.sln new file mode 100644 index 0000000..ee04141 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipMibCompiler.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LwipMibCompiler", "LwipMibCompiler\LwipMibCompiler.csproj", "{C25D5640-D999-49BD-82E0-A1975296A91E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LwipSnmpCodeGeneration", "LwipSnmpCodeGeneration\LwipSnmpCodeGeneration.csproj", "{AABCAB90-1540-45D4-A159-14831A54E9A3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCodeGeneration", "CCodeGeneration\CCodeGeneration.csproj", "{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSnmpLib.Mib", "SharpSnmpLib\SharpSnmpLib.Mib.csproj", "{CBE20411-5DB7-487D-825D-7694267BB6F5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MibViewer", "MibViewer\MibViewer.csproj", "{86CC0B65-7985-4017-A252-0A7A18DCAEF3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Release|Any CPU.Build.0 = Release|Any CPU + {86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Release|Any CPU.Build.0 = Release|Any CPU + {AABCAB90-1540-45D4-A159-14831A54E9A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AABCAB90-1540-45D4-A159-14831A54E9A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AABCAB90-1540-45D4-A159-14831A54E9A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AABCAB90-1540-45D4-A159-14831A54E9A3}.Release|Any CPU.Build.0 = Release|Any CPU + {C25D5640-D999-49BD-82E0-A1975296A91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C25D5640-D999-49BD-82E0-A1975296A91E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C25D5640-D999-49BD-82E0-A1975296A91E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C25D5640-D999-49BD-82E0-A1975296A91E}.Release|Any CPU.Build.0 = Release|Any CPU + {CBE20411-5DB7-487D-825D-7694267BB6F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CBE20411-5DB7-487D-825D-7694267BB6F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CBE20411-5DB7-487D-825D-7694267BB6F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CBE20411-5DB7-487D-825D-7694267BB6F5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = LwipMibCompiler\LwipMibCompiler.csproj + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/apps/LwipMibCompiler/LwipMibCompiler/LwipMibCompiler.csproj b/contrib/apps/LwipMibCompiler/LwipMibCompiler/LwipMibCompiler.csproj new file mode 100644 index 0000000..694263a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipMibCompiler/LwipMibCompiler.csproj @@ -0,0 +1,73 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C25D5640-D999-49BD-82E0-A1975296A91E} + Exe + Properties + LwipMibCompiler + LwipMibCompiler + v4.0 + 512 + + + + true + bin\Debug\ + DEBUG;TRACE + full + AnyCPU + prompt + false + false + 4 + false + false + + + bin\Release\ + TRACE + true + pdbonly + AnyCPU + prompt + 4 + false + + + + + + + + + + + + + + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B} + CCodeGeneration + + + {AABCAB90-1540-45D4-A159-14831A54E9A3} + LwipSnmpCodeGeneration + + + {CBE20411-5DB7-487D-825D-7694267BB6F5} + SharpSnmpLib.Mib + + + + + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/LwipMibCompiler/Program.cs b/contrib/apps/LwipMibCompiler/LwipMibCompiler/Program.cs new file mode 100644 index 0000000..5dff840 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipMibCompiler/Program.cs @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using CCodeGeneration; +using Lextm.SharpSnmpLib.Mib; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using Lextm.SharpSnmpLib.Mib.Elements.Types; +using LwipSnmpCodeGeneration; + +namespace LwipMibCompiler +{ + class Program + { + private static readonly Regex _alphaNumericRegex = new Regex("[^a-zA-Z0-9]"); + + static void Main(string[] args) + { + Console.WriteLine("lwIP MIB Compiler"); + Console.WriteLine(""); + + // check args + if ((args.Length < 2) || String.IsNullOrWhiteSpace(args[0]) || String.IsNullOrWhiteSpace(args[1])) + { + PrintUsage(); + return; + } + + string mibFile = args[0]; + if (!File.Exists(mibFile)) + { + Console.WriteLine(String.Format("Unable to find file '{0}'!", mibFile)); + } + + string destFile = args[1]; + string destHeaderFile; + + if (Directory.Exists(destFile)) + { + // only directory passed -> create dest filename from mib filename + string mibFileName = Path.GetFileNameWithoutExtension(mibFile).ToLowerInvariant(); + destFile = Path.Combine(destFile, mibFileName + ".c"); + } + + string destFileExt = Path.GetExtension(destFile); + if (!String.IsNullOrEmpty(destFileExt)) + { + destHeaderFile = destFile.Substring(0, destFile.Length - destFileExt.Length); + } + else + { + destHeaderFile = destFile; + } + destHeaderFile += ".h"; + + for (int i=2; i [ ...]", appName)); + Console.WriteLine(""); + Console.WriteLine(" "); + Console.WriteLine(" Path and filename of MIB file to convert."); + Console.WriteLine(""); + Console.WriteLine(" "); + Console.WriteLine(" Destination path and file. If a path is passed only, filename is auto"); + Console.WriteLine(" generated from MIB file name."); + Console.WriteLine(""); + Console.WriteLine(" "); + Console.WriteLine(" It's important to provide all referred MIB's in order to correctly "); + Console.WriteLine(" resolve all used types."); + Console.WriteLine(""); + } + + + #region Generation of LWIP Object Tree + + private static void ProcessMibTreeNode(MibTreeNode mibTreeNode, SnmpTreeNode assignedSnmpNode) + { + foreach (MibTreeNode mtn in mibTreeNode.ChildNodes) + { + // in theory container nodes may also be scalars or tables at the same time (for now only process real containers) + if (mtn.NodeType == MibTreeNodeType.Container) + { + SnmpTreeNode snmpTreeNode = GenerateSnmpTreeNode(mtn, assignedSnmpNode); + assignedSnmpNode.ChildNodes.Add(snmpTreeNode); + + ProcessMibTreeNode(mtn, snmpTreeNode); + } + else if ((mtn.NodeType & MibTreeNodeType.Scalar) != 0) + { + SnmpScalarNode snmpScalarNode = GenerateSnmpScalarNode(mtn, assignedSnmpNode); + if (snmpScalarNode != null) + { + assignedSnmpNode.ChildNodes.Add(snmpScalarNode); + } + } + else if ((mtn.NodeType & MibTreeNodeType.Table) != 0) + { + SnmpTableNode snmpTableNode = GenerateSnmpTableNode(mtn, assignedSnmpNode); + if (snmpTableNode != null) + { + assignedSnmpNode.ChildNodes.Add(snmpTableNode); + } + } + } + } + + private static SnmpTreeNode GenerateSnmpTreeNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode) + { + SnmpTreeNode result = new SnmpTreeNode(parentNode); + result.Name = _alphaNumericRegex.Replace (mibTreeNode.Entity.Name, ""); + result.Oid = mibTreeNode.Entity.Value; + result.FullOid = MibTypesResolver.ResolveOid(mibTreeNode.Entity).GetOidString(); + + return result; + } + + private static SnmpScalarNode GenerateSnmpScalarNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode, bool ignoreAccessibleFlag = false) + { + ObjectType ote = mibTreeNode.Entity as ObjectType; + if (ote != null) + { + return GenerateSnmpScalarNode(ote, parentNode, ignoreAccessibleFlag); + } + + return null; + } + + private static SnmpScalarNode GenerateSnmpScalarNode(ObjectType ote, SnmpTreeNode parentNode, bool ignoreAccessibleFlag = false) + { + SnmpScalarNode result; + + ITypeAssignment mibType = ote.BaseType; + IntegerType it = (mibType as IntegerType); + if (it != null) + { + if (ote.ReferredType.Name == Symbol.TruthValue.ToString()) + { + result = new SnmpScalarNodeTruthValue(parentNode); + } + else if ((it.Type == IntegerType.Types.Integer) || (it.Type == IntegerType.Types.Integer32)) + { + result = new SnmpScalarNodeInt(parentNode); + } + else + { + Console.WriteLine(String.Format("Unsupported IntegerType '{0}'!", it.Type)); + return null; + } + if (it.IsEnumeration) + { + result.Restrictions.AddRange(CreateRestrictions(it.Enumeration)); + } + else + { + result.Restrictions.AddRange(CreateRestrictions(it.Ranges)); + } + } + else + { + UnsignedType ut = (mibType as UnsignedType); + if (ut != null) + { + if ((ut.Type == UnsignedType.Types.Unsigned32) || + (ut.Type == UnsignedType.Types.Gauge32)) + { + result = new SnmpScalarNodeUint(SnmpDataType.Gauge, parentNode); + } + else if (ut.Type == UnsignedType.Types.Counter32) + { + result = new SnmpScalarNodeUint(SnmpDataType.Counter, parentNode); + } + else if (ut.Type == UnsignedType.Types.TimeTicks) + { + result = new SnmpScalarNodeUint(SnmpDataType.TimeTicks, parentNode); + } + else if (ut.Type == UnsignedType.Types.Counter64) + { + result = new SnmpScalarNodeCounter64(parentNode); + if ((ut.Ranges != null) && (ut.Ranges.Count > 0)) + { + Console.WriteLine(String.Format("Generation of ranges is not supported for Counter64 type!")); + return null; + } + } + else + { + Console.WriteLine(String.Format("Unsupported UnsignedType '{0}'!", ut.Type)); + return null; + } + result.Restrictions.AddRange(CreateRestrictions(ut.Ranges)); + } + else if (mibType is IpAddressType) + { + result = new SnmpScalarNodeOctetString(SnmpDataType.IpAddress, parentNode); + result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size)); + } + else if (mibType is OpaqueType) + { + result = new SnmpScalarNodeOctetString(SnmpDataType.Opaque, parentNode); + result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size)); + } + else if (mibType is OctetStringType) + { + result = new SnmpScalarNodeOctetString(SnmpDataType.OctetString, parentNode); + result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size)); + } + else if (mibType is ObjectIdentifierType) + { + result = new SnmpScalarNodeObjectIdentifier(parentNode); + } + else if (mibType is BitsType) + { + result = new SnmpScalarNodeBits(parentNode, (uint)((mibType as BitsType).Map.GetHighestValue() + 1)); + result.Restrictions.AddRange(CreateRestrictions(mibType as BitsType)); + } + else + { + TypeAssignment ta = mibType as TypeAssignment; + if (ta != null) + { + Console.WriteLine(String.Format("Unsupported BaseType: Module='{0}', Name='{1}', Type='{2}'!", ta.Module.Name, ta.Name, ta.Type)); + } + else + { + Console.WriteLine(String.Format("Unsupported BaseType: Module='{0}', Name='{1}'!", mibType.Module, mibType.Name)); + } + + return null; + } + } + + result.Name = _alphaNumericRegex.Replace(ote.Name, ""); + result.Oid = ote.Value; + + if (ote.Access == MaxAccess.readWrite) + { + result.AccessMode = SnmpAccessMode.ReadWrite; + } + else if (ote.Access == MaxAccess.readOnly) + { + result.AccessMode = SnmpAccessMode.ReadOnly; + } + else if (ote.Access == MaxAccess.readCreate) + { + result.AccessMode = SnmpAccessMode.ReadOnly; + } + else if (ignoreAccessibleFlag && (ote.Access == MaxAccess.notAccessible)) + { + result.AccessMode = SnmpAccessMode.NotAccessible; + } + else + { + // not accessible or unsupported access type + return null; + } + + return result; + } + + private static IEnumerable CreateRestrictions(ValueRanges ranges) + { + List result = new List(); + + if (ranges != null) + { + foreach (ValueRange range in ranges) + { + if (!range.End.HasValue) + { + result.Add(new IsEqualRestriction(range.Start)); + } + else + { + result.Add(new IsInRangeRestriction(range.Start, range.End.Value)); + } + } + } + + return result; + } + + private static IEnumerable CreateRestrictions(ValueMap map) + { + if ((map != null) && (map.Count > 0)) + { + return CreateRestrictions(map.GetContinousRanges()); + } + + return new List(); + } + + private static IEnumerable CreateRestrictions(BitsType bt) + { + List result = new List(); + + if ((bt != null) && (bt.Map != null)) + { + result.Add(new BitMaskRestriction(bt.Map.GetBitMask())); + } + + return result; + } + + private static SnmpTableNode GenerateSnmpTableNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode) + { + SnmpTableNode result = new SnmpTableNode(parentNode); + result.Name = mibTreeNode.Entity.Name; + result.Oid = mibTreeNode.Entity.Value; + + // expect exactly one row entry + if ((mibTreeNode.ChildNodes.Count != 1) || ((mibTreeNode.ChildNodes[0].NodeType & MibTreeNodeType.TableRow) == 0) || (mibTreeNode.ChildNodes[0].Entity.Value != 1)) + { + Console.WriteLine("Found table with unsupported properties! Table needs exactly one (fixed) TableRow with OID=1 ! (" + mibTreeNode.Entity.Name + ")"); + return null; + } + + MibTreeNode rowNode = mibTreeNode.ChildNodes[0]; + + ObjectType rot = rowNode.Entity as ObjectType; + if (rot != null) + { + if (!String.IsNullOrWhiteSpace(rot.Augments)) + { + result.AugmentedTableRow = rot.Augments; + + // the indices from another table shall be used because this table is only an extension of it + rot = MibTypesResolver.ResolveDeclaration(rot.Module, rot.Augments) as ObjectType; + } + + if (rot.Indices != null) + { + foreach (string index in rot.Indices) + { + ObjectType indexEntity = MibTypesResolver.ResolveDeclaration(rot.Module, index) as ObjectType; + if (indexEntity == null) + { + Console.WriteLine(String.Format("Could not resolve index '{0}' for table '{1}'! Table omitted!", index, result.Name)); + return null; + } + + result.IndexNodes.Add(GenerateSnmpScalarNode(indexEntity, parentNode, ignoreAccessibleFlag: true)); + } + } + } + + if (result.IndexNodes.Count == 0) + { + // a table cannot be used without index + Console.WriteLine("Found table without any index column ! (" + mibTreeNode.Entity.Name + ")"); + return null; + } + + // add child nodes + foreach (MibTreeNode cellNode in rowNode.ChildNodes) + { + SnmpScalarNode ssn = GenerateSnmpScalarNode(cellNode, parentNode); + if (ssn != null) + { + result.CellNodes.Add(ssn); + } + } + + return result; + } + + #endregion + + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipMibCompiler/Properties/AssemblyInfo.cs b/contrib/apps/LwipMibCompiler/LwipMibCompiler/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d30b842 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipMibCompiler/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("ConsoleApplication28")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApplication28")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("0abf7541-6a96-43cd-9e24-462e074b2c96")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/contrib/apps/LwipMibCompiler/LwipMibCompiler/app.config b/contrib/apps/LwipMibCompiler/LwipMibCompiler/app.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipMibCompiler/app.config @@ -0,0 +1,3 @@ + + + diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/IRestriction.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/IRestriction.cs new file mode 100644 index 0000000..ee2f453 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/IRestriction.cs @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace LwipSnmpCodeGeneration +{ + public interface IRestriction + { + string GetCheckCodeValid(string varNameToCheck); + string GetCheckCodeInvalid(string varNameToCheck); + } + + public class BitMaskRestriction : IRestriction + { + UInt32 mask; + + public BitMaskRestriction(UInt32 mask) + { + this.mask = mask; + } + + public string GetCheckCodeValid(string varNameToCheck) + { + return String.Format("(({0} & {1}) == {0})", varNameToCheck, this.mask); + } + + public string GetCheckCodeInvalid(string varNameToCheck) + { + return String.Format("(({0} & {1}) != {0})", varNameToCheck, this.mask); + } + } + + public class IsEqualRestriction : IRestriction + { + private Int64 value; + + public IsEqualRestriction(Int64 value) + { + this.value = value; + } + + public long Value + { + get { return value; } + } + + public string GetCheckCodeValid(string varNameToCheck) + { + return String.Format("({0} == {1})", varNameToCheck, this.value); + } + + public string GetCheckCodeInvalid(string varNameToCheck) + { + return String.Format("({0} != {1})", varNameToCheck, this.value); + } + } + + public class IsInRangeRestriction : IRestriction + { + private Int64 rangeStart; + private Int64 rangeEnd; + + public IsInRangeRestriction(Int64 rangeStart, Int64 rangeEnd) + { + this.rangeStart = rangeStart; + this.rangeEnd = rangeEnd; + } + + public long RangeStart + { + get { return this.rangeStart; } + } + + public long RangeEnd + { + get { return this.rangeEnd; } + } + + public string GetCheckCodeValid(string varNameToCheck) + { + return String.Format("(({0} >= {1}) && ({0} <= {2}))", varNameToCheck, this.rangeStart, this.rangeEnd); + } + + public string GetCheckCodeInvalid(string varNameToCheck) + { + return String.Format("(({0} < {1}) || ({0} > {2}))", varNameToCheck, this.rangeStart, this.rangeEnd); + } + } + +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmp.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmp.cs new file mode 100644 index 0000000..edac59e --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmp.cs @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; + +namespace LwipSnmpCodeGeneration +{ + public static class LwipOpts + { + public static bool GenerateEmptyFolders = false; + /// + /// If a tree node only has scalar nodes as child nodes, it is replaced by + /// a single scalar array node in order to save memory and have only one single get/test/set method for all scalars. + /// + public static bool GenerateScalarArrays = true; + /// + /// If a tree node has multiple scalars as subnodes as well as other treenodes it + /// defines a single get/test/set method for all scalar child node. + /// (without other treenodes as child it would have been converted to scalar array node). + /// + public static bool GenerateSingleAccessMethodsForTreeNodeScalars = GenerateScalarArrays; + } + + public static class LwipDefs + { + public const string Null = "NULL"; + public const string Vt_U8 = "u8_t"; + public const string Vt_U16 = "u16_t"; + public const string Vt_U32 = "u32_t"; + public const string Vt_S8 = "s8_t"; + public const string Vt_S16 = "s16_t"; + public const string Vt_S32 = "s32_t"; + public const string Vt_Snmp_err = "snmp_err_t"; + + public const string Incl_SnmpOpts = "lwip/apps/snmp_opts.h"; + public const string Opt_SnmpEnabled = "LWIP_SNMP"; + + public const string Vt_StMib = "struct snmp_mib"; + public const string Vt_StObjectId = "struct snmp_obj_id"; + public const string Vt_StNode = "struct snmp_node"; + public const string Vt_StNodeInstance = "struct snmp_node_instance"; + public const string Vt_StTreeNode = "struct snmp_tree_node"; + public const string Vt_StScalarNode = "struct snmp_scalar_node"; + public const string Vt_StScalarArrayNode = "struct snmp_scalar_array_node"; + public const string Vt_StScalarArrayNodeDef = "struct snmp_scalar_array_node_def"; + public const string Vt_StTableNode = "struct snmp_table_node"; + public const string Vt_StTableColumnDef = "struct snmp_table_col_def"; + public const string Vt_StNextOidState = "struct snmp_next_oid_state"; + + public const string Def_NodeAccessReadOnly = "SNMP_NODE_INSTANCE_READ_ONLY"; + public const string Def_NodeAccessReadWrite = "SNMP_NODE_INSTANCE_READ_WRITE"; + public const string Def_NodeAccessWriteOnly = "SNMP_NODE_INSTANCE_WRITE_ONLY"; + public const string Def_NodeAccessNotAccessible = "SNMP_NODE_INSTANCE_NOT_ACCESSIBLE"; + + public const string Def_ErrorCode_Ok = "SNMP_ERR_NOERROR"; + public const string Def_ErrorCode_WrongValue = "SNMP_ERR_WRONGVALUE"; + public const string Def_ErrorCode_NoSuchInstance = "SNMP_ERR_NOSUCHINSTANCE"; + + public const string FnctSuffix_GetValue = "_get_value"; + public const string FnctSuffix_SetTest = "_set_test"; + public const string FnctSuffix_SetValue = "_set_value"; + public const string FnctSuffix_GetInstance = "_get_instance"; + public const string FnctSuffix_GetNextInstance = "_get_next_instance"; + + public const string FnctName_SetTest_Ok = "snmp_set_test_ok"; + + public static string GetLwipDefForSnmpAccessMode(SnmpAccessMode am) + { + switch (am) + { + case SnmpAccessMode.ReadOnly: return Def_NodeAccessReadOnly; + case SnmpAccessMode.ReadWrite: return Def_NodeAccessReadWrite; + case SnmpAccessMode.NotAccessible: return Def_NodeAccessNotAccessible; + case SnmpAccessMode.WriteOnly: return Def_NodeAccessWriteOnly; + default: throw new NotSupportedException("Unknown SnmpAccessMode!"); + } + } + + public static string GetAsn1DefForSnmpDataType(SnmpDataType dt) + { + switch (dt) + { + // primitive + case SnmpDataType.Null: + return "SNMP_ASN1_TYPE_NULL"; + case SnmpDataType.Bits: + case SnmpDataType.OctetString: + return "SNMP_ASN1_TYPE_OCTET_STRING"; + case SnmpDataType.ObjectIdentifier: + return "SNMP_ASN1_TYPE_OBJECT_ID"; + case SnmpDataType.Integer: + return "SNMP_ASN1_TYPE_INTEGER"; + + // application + case SnmpDataType.IpAddress: + return "SNMP_ASN1_TYPE_IPADDR"; + case SnmpDataType.Counter: + return "SNMP_ASN1_TYPE_COUNTER"; + case SnmpDataType.Gauge: + return "SNMP_ASN1_TYPE_GAUGE"; + case SnmpDataType.TimeTicks: + return "SNMP_ASN1_TYPE_TIMETICKS"; + case SnmpDataType.Opaque: + return "SNMP_ASN1_TYPE_OPAQUE"; + case SnmpDataType.Counter64: + return "SNMP_ASN1_TYPE_COUNTER64"; + default: + throw new NotSupportedException("Unknown SnmpDataType!"); + } + } + + public static string GetLengthForSnmpDataType(SnmpDataType dt) + { + switch (dt) + { + case SnmpDataType.Null: + return "0"; + + case SnmpDataType.Integer: + case SnmpDataType.Counter: + case SnmpDataType.IpAddress: + case SnmpDataType.Gauge: + case SnmpDataType.TimeTicks: + return "4"; + + case SnmpDataType.Counter64: + return "8"; + + case SnmpDataType.OctetString: + case SnmpDataType.ObjectIdentifier: + case SnmpDataType.Bits: + case SnmpDataType.Opaque: + return null; + + default: + throw new NotSupportedException("Unknown SnmpDataType!"); + } + } + } + + public enum SnmpDataType + { + Null, + + Integer, // INTEGER, Integer32 + + Counter, // Counter, Counter32 + Gauge, // Gauge, Gauge32, Unsigned32 + TimeTicks, + + Counter64, + + OctetString, + Opaque, + Bits, + + ObjectIdentifier, + + IpAddress, + } + + public enum SnmpAccessMode + { + ReadOnly, + ReadWrite, + WriteOnly, + NotAccessible + } + +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmpCodeGeneration.csproj b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmpCodeGeneration.csproj new file mode 100644 index 0000000..f4541c0 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/LwipSnmpCodeGeneration.csproj @@ -0,0 +1,72 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {AABCAB90-1540-45D4-A159-14831A54E9A3} + Library + Properties + LwipSnmpCodeGeneration + LwipSnmpCodeGeneration + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + {7DA7C0AB-0982-4BF5-9324-F59A7A08D65B} + CCodeGeneration + + + + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibCFile.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibCFile.cs new file mode 100644 index 0000000..c48ec29 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibCFile.cs @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System.Collections.Generic; +using CCodeGeneration; +using System; +using System.IO; + +namespace LwipSnmpCodeGeneration +{ + public class MibCFile + { + #region Fields + + private const string PreservedSectionMarker = "LWIP MIB generator - preserved section begin"; + private const string PreservedSectionHeader = + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" + + PreservedSectionMarker + "\n" + + "Code below is preserved on regeneration. Remove these comment lines to regenerate code.\n" + + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; + + private readonly List includes = new List(); + private readonly List defines = new List(); + private readonly List declarations = new List(); + private readonly List implementation = new List(); + private readonly List preservedCode = new List(); + + #endregion + + public MibCFile() + { + } + + #region Accessors + + public List Includes + { + get { return this.includes; } + } + + public List Defines + { + get { return this.defines; } + } + + public List Declarations + { + get { return this.declarations; } + } + + public List Implementation + { + get { return this.implementation; } + } + + public List PreservedCode + { + get { return this.preservedCode; } + } + + #endregion + + #region Methods + + public void Save(CGenerator cGenerator) + { + CFile cFile = new CFile(); + + cFile.AddElement(new Comment("Generated by LwipMibCompiler")); + cFile.AddElement(EmptyLine.SingleLine); + + cFile.AddElement(new PP_Include(LwipDefs.Incl_SnmpOpts)); + CodeContainerBase e = cFile.AddElement(new PP_If(LwipDefs.Opt_SnmpEnabled)) as CodeContainerBase; + e.AddElement(EmptyLine.SingleLine); + + // include header file + string file = cGenerator.FileName; + if (!String.IsNullOrWhiteSpace(file)) + { + string ext = System.IO.Path.GetExtension(file); + + string headerFile = !String.IsNullOrEmpty(ext) ? file.Substring(0, file.Length - ext.Length) : file; + headerFile += ".h"; + + e.AddElement(new PP_Include(headerFile)); + } + + // include common snmp files + e.AddElement(new PP_Include("lwip/apps/snmp.h")); + e.AddElement(new PP_Include("lwip/apps/snmp_core.h")); + e.AddElement(new PP_Include("lwip/apps/snmp_scalar.h")); + e.AddElement(new PP_Include("lwip/apps/snmp_table.h")); + + if (this.includes.Count > 0) + { + e.AddElement(EmptyLine.SingleLine); + e.AddElements(this.includes); + } + + if (this.defines.Count > 0) + { + e.AddElement(EmptyLine.SingleLine); + e.AddElements(this.defines); + } + + if (this.declarations.Count > 0) + { + e.AddElement(EmptyLine.TwoLines); + e.AddElements(this.declarations); + } + + if (this.implementation.Count > 0) + { + e.AddElement(EmptyLine.TwoLines); + e.AddElements(this.implementation); + } + + if (this.preservedCode.Count > 0) + { + e.AddElement(EmptyLine.TwoLines); + e.AddElement(new Comment(PreservedSectionHeader)); + e.AddElement(EmptyLine.SingleLine); + e.AddElements(this.preservedCode); + } + + cFile.Save(cGenerator); + } + + public static string GetPreservedCode(string file) + { + if (File.Exists(file)) + { + using (StreamReader fileStream = new StreamReader(file)) + { + while (!fileStream.EndOfStream) + { + string line = fileStream.ReadLine(); + if (line == PreservedSectionMarker) + { + break; + } + } + + if (!fileStream.EndOfStream) + { + // skip the rest of the comment + spacer line + fileStream.ReadLine(); // "Code below is preserved... + fileStream.ReadLine(); // "+++++++++++++++++++++++... + fileStream.ReadLine(); // */ + fileStream.ReadLine(); // + + string preservedCode = fileStream.ReadToEnd(); + + int lastEndif = preservedCode.LastIndexOf("#endif", StringComparison.Ordinal); + preservedCode = preservedCode.Remove(lastEndif); + + return preservedCode; + } + } + } + + return null; + } + + #endregion + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibHeaderFile.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibHeaderFile.cs new file mode 100644 index 0000000..95f2a06 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/MibHeaderFile.cs @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System.Collections.Generic; +using System.Text.RegularExpressions; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class MibHeaderFile + { + + #region Fields + + private readonly List defines = new List(); + private readonly List includes = new List(); + private readonly List functionDeclarations = new List(); + private readonly List variableDeclarations = new List(); + + #endregion + + public MibHeaderFile() + { + } + + #region Accessors + + public List Defines + { + get { return this.defines; } + } + + public List Includes + { + get { return this.includes; } + } + + public List FunctionDeclarations + { + get { return this.functionDeclarations; } + } + + public List VariableDeclarations + { + get { return this.variableDeclarations; } + } + + #endregion + + #region Methods + + public void Save(CGenerator cGenerator) + { + CFile cFile = new CFile(); + + cFile.AddElement(new Comment("Generated by LwipMibCompiler")); + cFile.AddElement(EmptyLine.SingleLine); + + string headerDefine = cGenerator.FileName; + headerDefine = new Regex("[^a-zA-Z0-9]").Replace(headerDefine, "_"); + headerDefine = headerDefine.ToUpperInvariant(); + + CodeContainerBase e = cFile.AddElement(new PP_Ifdef(headerDefine, inverted: true)) as CodeContainerBase; + e.AddElement(new PP_Macro(headerDefine, headerDefine)); + e.AddElement(EmptyLine.SingleLine); + + e.AddElement(new PP_Include(LwipDefs.Incl_SnmpOpts)); + e = e.AddElement(new PP_If(LwipDefs.Opt_SnmpEnabled)) as CodeContainerBase; + e.AddElement(EmptyLine.SingleLine); + + CodeContainerBase cplusplusopen = e.AddElement(new PP_Ifdef("__cplusplus")) as CodeContainerBase; + cplusplusopen.AddElement(new Code("extern \"C\" {")); + e.AddElement(EmptyLine.SingleLine); + + if (this.includes.Count > 0) + { + e.AddElements(this.includes); + e.AddElement(EmptyLine.SingleLine); + } + + if (this.defines.Count > 0) + { + e.AddElements(this.defines); + e.AddElement(EmptyLine.SingleLine); + } + + e.AddElements(this.functionDeclarations, EmptyLine.SingleLine); + e.AddElements(this.variableDeclarations, EmptyLine.SingleLine); + + e.AddElement(EmptyLine.SingleLine); + CodeContainerBase cplusplusclose = e.AddElement(new PP_Ifdef("__cplusplus")) as CodeContainerBase; + cplusplusclose.AddElement(new Code("}")); + + e.AddElement(EmptyLine.SingleLine); + cFile.Save(cGenerator); + } + + #endregion + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/Properties/AssemblyInfo.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e68b43d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("LwipSnmpCodeGeneration")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LwipSnmpCodeGeneration")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("8cfbbb8b-dfbb-4dd5-80c9-e07845dd58c9")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpMib.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpMib.cs new file mode 100644 index 0000000..477a18b --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpMib.cs @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpMib : SnmpTreeNode + { + public uint[] BaseOid { get; set; } + + public SnmpMib() + : base(null) + { + } + + public SnmpMib(uint[] baseOid) + : base(null) + { + this.BaseOid = baseOid; + } + + public override string FullNodeName + { + get { return this.Name.ToLowerInvariant() + "_root"; } + } + + public override void GenerateCode(MibCFile mibFile) + { + base.GenerateCode(mibFile); + + System.Diagnostics.Debug.Assert((this.BaseOid != null) && (this.BaseOid.Length > 0)); + + // create and add BaseOID declarations + StringBuilder boidInitialization = new StringBuilder("{"); + foreach (uint t in this.BaseOid) + { + boidInitialization.Append(t); + boidInitialization.Append(","); + } + boidInitialization.Length -= 1; + boidInitialization.Append("}"); + + VariableDeclaration boidDecl = new VariableDeclaration( + new VariableType(this.Name.ToLowerInvariant() + "_base_oid", LwipDefs.Vt_U32, null, ConstType.Value, String.Empty), + boidInitialization.ToString(), true); + + mibFile.Declarations.Add(boidDecl); + mibFile.Declarations.Add(GetExportDeclaration()); + } + + public override void GenerateHeaderCode(MibHeaderFile mibHeaderFile) + { + mibHeaderFile.Includes.Add(new PP_Include("lwip/apps/snmp_core.h")); + + mibHeaderFile.VariableDeclarations.Add(VariablePrototype.FromVariableDeclaration(GetExportDeclaration())); + } + + VariableDeclaration GetExportDeclaration() + { + return new VariableDeclaration( + new VariableType(this.Name.ToLowerInvariant(), LwipDefs.Vt_StMib, null, ConstType.Value), + String.Format("{{{0}_base_oid, LWIP_ARRAYSIZE({0}_base_oid), &{1}.node}}", this.Name.ToLowerInvariant(), this.FullNodeName)); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpNode.cs new file mode 100644 index 0000000..fceb4d5 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpNode.cs @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text.RegularExpressions; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public abstract class SnmpNode + { + public static readonly Regex NameValidationRegex = new Regex(@"^\w+$"); + + private string name; + private readonly SnmpTreeNode parentNode; + + protected SnmpNode(SnmpTreeNode parentNode) + { + this.parentNode = parentNode; + } + + public SnmpTreeNode ParentNode + { + get { return this.parentNode; } + } + + public virtual uint Oid { get; set; } + + public abstract string FullNodeName + { + get; + } + + public virtual string Name + { + get { return this.name; } + set + { + if (value != this.name) + { + // check for valid name + if (!NameValidationRegex.IsMatch(value)) + { + throw new ArgumentOutOfRangeException("Name"); + } + + this.name = value; + } + } + } + + public virtual void Generate(MibCFile generatedFile, MibHeaderFile generatedHeaderFile) + { + int declCount = generatedFile.Declarations.Count; + int implCount = generatedFile.Implementation.Count; + + this.GenerateHeaderCode(generatedHeaderFile); + this.GenerateCode(generatedFile); + + if (generatedFile.Declarations.Count != declCount) + { + generatedFile.Declarations.Add(EmptyLine.SingleLine); + } + if (generatedFile.Implementation.Count != implCount) + { + generatedFile.Implementation.Add(EmptyLine.SingleLine); + } + } + + public abstract void GenerateCode(MibCFile mibFile); + + public virtual void GenerateHeaderCode(MibHeaderFile mibHeaderFile) + { + } + + /// + /// Called after node structure creation is completed and before code is created. + /// Offers the possibility to perform operations depending on properties/subnodes. + /// If the node shall be transformed to another node(-type) than the own instance + /// may be replaced on parent node by the transformed instance. + /// Calling sequence is always from leafs up to root. So a tree node can assume + /// that the analyze method was already called on all child nodes. + /// E.g. a tree node only has scalar sub nodes -> it transforms itself to a scalar array node + /// + /// The transformed node or null if nothing shall be changed in parent structure. + public virtual void Analyze() + { + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarAggregationNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarAggregationNode.cs new file mode 100644 index 0000000..f5c558c --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarAggregationNode.cs @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System.Collections.Generic; +using System.Globalization; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public abstract class SnmpScalarAggregationNode: SnmpNode + { + private bool getMethodRequired = false; + private bool testMethodRequired = false; + private bool setMethodRequired = false; + + protected SnmpScalarAggregationNode(SnmpTreeNode parentNode) + : base(parentNode) + { + } + + protected virtual string GetMethodName + { + get { return this.FullNodeName + LwipDefs.FnctSuffix_GetValue; } + } + + protected bool GetMethodRequired + { + get { return this.getMethodRequired; } + } + + protected virtual string TestMethodName + { + get { return this.FullNodeName + LwipDefs.FnctSuffix_SetTest; } + } + + protected bool TestMethodRequired + { + get { return this.testMethodRequired; } + } + + protected virtual string SetMethodName + { + get { return this.FullNodeName + LwipDefs.FnctSuffix_SetValue; } + } + + protected bool SetMethodRequired + { + get { return this.setMethodRequired; } + } + + protected abstract IEnumerable AggregatedScalarNodes + { + get; + } + + public override void Analyze() + { + base.Analyze(); + + this.getMethodRequired = false; + this.testMethodRequired = false; + this.setMethodRequired = false; + + foreach (SnmpScalarNode scalarNode in this.AggregatedScalarNodes) + { + if ((scalarNode.AccessMode == SnmpAccessMode.ReadOnly) || (scalarNode.AccessMode == SnmpAccessMode.ReadWrite)) + { + this.getMethodRequired = true; + } + if ((scalarNode.AccessMode == SnmpAccessMode.WriteOnly) || (scalarNode.AccessMode == SnmpAccessMode.ReadWrite)) + { + this.testMethodRequired = true; + this.setMethodRequired = true; + } + + if (this.getMethodRequired && this.setMethodRequired) + { + break; + } + } + } + + protected void GenerateAggregatedCode(MibCFile mibFile, VariableType instanceType, string switchSelector, bool generateDeclarations = true, bool generateImplementations = true) + { + if (this.getMethodRequired) + { + FunctionDeclaration getMethodDecl = new FunctionDeclaration(this.GetMethodName, isStatic: true); + getMethodDecl.Parameter.Add(instanceType); + getMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + getMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_S16); + + if (generateDeclarations) + { + mibFile.Declarations.Add(getMethodDecl); + } + if (generateImplementations) + { + Function getMethod = Function.FromDeclaration(getMethodDecl); + GenerateGetMethodCode(getMethod, switchSelector); + mibFile.Implementation.Add(getMethod); + } + } + + if (this.testMethodRequired) + { + FunctionDeclaration testMethodDecl = new FunctionDeclaration(this.TestMethodName, isStatic: true); + testMethodDecl.Parameter.Add(instanceType); + testMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); + testMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + testMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + + if (generateDeclarations) + { + mibFile.Declarations.Add(testMethodDecl); + } + if (generateImplementations) + { + Function testMethod = Function.FromDeclaration(testMethodDecl); + GenerateTestMethodCode(testMethod, switchSelector); + mibFile.Implementation.Add(testMethod); + } + } + + if (this.setMethodRequired) + { + FunctionDeclaration setMethodDecl = new FunctionDeclaration(this.SetMethodName, isStatic: true); + setMethodDecl.Parameter.Add(instanceType); + setMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); + setMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + setMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + + if (generateDeclarations) + { + mibFile.Declarations.Add(setMethodDecl); + } + if (generateImplementations) + { + Function setMethod = Function.FromDeclaration(setMethodDecl); + GenerateSetMethodCode(setMethod, switchSelector); + mibFile.Implementation.Add(setMethod); + } + } + } + + protected virtual void GenerateGetMethodCode(Function getMethod, string switchSelector) + { + VariableDeclaration returnValue = new VariableDeclaration((VariableType)getMethod.ReturnType.Clone()); + returnValue.Type.Name = "value_len"; + getMethod.Declarations.Add(returnValue); + Switch sw = new Switch(switchSelector); + + bool valueVarUsed = false; + + foreach (SnmpScalarNode scalarNode in this.AggregatedScalarNodes) + { + if ((scalarNode.AccessMode == SnmpAccessMode.ReadOnly) || (scalarNode.AccessMode == SnmpAccessMode.ReadWrite)) + { + SwitchCase sc = new SwitchCase(scalarNode.Oid.ToString(CultureInfo.InvariantCulture)); + sc.Declarations.Add(new Comment(scalarNode.Name, singleLine: true)); + + scalarNode.GenerateGetMethodCode(sc, getMethod.Parameter[1].Name, ref valueVarUsed, returnValue.Type.Name); + + sw.Switches.Add(sc); + } + } + + SwitchCase scd = SwitchCase.GenerateDefault(); + scd.AddCodeFormat("LWIP_DEBUGF(SNMP_MIB_DEBUG,(\"{0}(): unknown id: %\"S32_F\"\\n\", {1}));", getMethod.Name, switchSelector); + scd.AddCodeFormat("{0} = 0;", returnValue.Type.Name); + sw.Switches.Add(scd); + + if (!valueVarUsed) + { + getMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getMethod.Parameter[1].Name); + } + + getMethod.AddElement(sw); + + getMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + } + + protected virtual void GenerateTestMethodCode(Function testMethod, string switchSelector) + { + VariableDeclaration returnValue = new VariableDeclaration((VariableType)testMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_WrongValue); + returnValue.Type.Name = "err"; + testMethod.Declarations.Add(returnValue); + Switch sw = new Switch(switchSelector); + + bool valueVarUsed = false; + bool lenVarUsed = false; + + foreach (SnmpScalarNode scalarNode in this.AggregatedScalarNodes) + { + if ((scalarNode.AccessMode == SnmpAccessMode.WriteOnly) || (scalarNode.AccessMode == SnmpAccessMode.ReadWrite)) + { + SwitchCase sc = new SwitchCase(scalarNode.Oid.ToString(CultureInfo.InvariantCulture)); + sc.Declarations.Add(new Comment(scalarNode.Name, singleLine: true)); + + scalarNode.GenerateTestMethodCode(sc, testMethod.Parameter[2].Name, ref valueVarUsed, testMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); + + sw.Switches.Add(sc); + } + } + + SwitchCase scd = SwitchCase.GenerateDefault(); + scd.AddCodeFormat("LWIP_DEBUGF(SNMP_MIB_DEBUG,(\"{0}(): unknown id: %\"S32_F\"\\n\", {1}));", testMethod.Name, switchSelector); + sw.Switches.Add(scd); + + if (!valueVarUsed) + { + testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[2].Name); + } + if (!lenVarUsed) + { + testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[1].Name); + } + + testMethod.AddElement(sw); + + testMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + } + + protected virtual void GenerateSetMethodCode(Function setMethod, string switchSelector) + { + VariableDeclaration returnValue = new VariableDeclaration((VariableType)setMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_Ok); + returnValue.Type.Name = "err"; + setMethod.Declarations.Add(returnValue); + Switch sw = new Switch(switchSelector); + + bool valueVarUsed = false; + bool lenVarUsed = false; + + foreach (SnmpScalarNode scalarNode in this.AggregatedScalarNodes) + { + if ((scalarNode.AccessMode == SnmpAccessMode.WriteOnly) || (scalarNode.AccessMode == SnmpAccessMode.ReadWrite)) + { + SwitchCase sc = new SwitchCase(scalarNode.Oid.ToString(CultureInfo.InvariantCulture)); + sc.Declarations.Add(new Comment(scalarNode.Name, singleLine: true)); + + scalarNode.GenerateSetMethodCode(sc, setMethod.Parameter[2].Name, ref valueVarUsed, setMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); + + sw.Switches.Add(sc); + } + } + + SwitchCase scd = SwitchCase.GenerateDefault(); + scd.AddCodeFormat("LWIP_DEBUGF(SNMP_MIB_DEBUG,(\"{0}(): unknown id: %\"S32_F\"\\n\", {1}));", setMethod.Name, switchSelector); + sw.Switches.Add(scd); + + if (!valueVarUsed) + { + setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[2].Name); + } + if (!lenVarUsed) + { + setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[1].Name); + } + + setMethod.AddElement(sw); + + setMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarArrayNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarArrayNode.cs new file mode 100644 index 0000000..086fbb9 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarArrayNode.cs @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarArrayNode : SnmpScalarAggregationNode + { + private readonly List scalarNodes; + + public SnmpScalarArrayNode(List scalarNodes, SnmpTreeNode parentNode) + : base(parentNode) + { + this.scalarNodes = scalarNodes; + } + + public override string FullNodeName + { + get { return this.Name.ToLowerInvariant() + "_scalars"; } + } + + protected override IEnumerable AggregatedScalarNodes + { + get { return this.scalarNodes; } + } + + public override void GenerateCode(MibCFile mibFile) + { + VariableType instanceType = new VariableType("node", LwipDefs.Vt_StScalarArrayNodeDef, "*", ConstType.Value); + GenerateAggregatedCode( + mibFile, + instanceType, + instanceType.Name + "->oid"); + + + // create and add node definitions + StringBuilder nodeDefs = new StringBuilder(); + foreach (SnmpScalarNode scalarNode in this.scalarNodes) + { + nodeDefs.AppendFormat(" {{{0}, {1}, {2}}}, /* {3} */ \n", + scalarNode.Oid, + LwipDefs.GetAsn1DefForSnmpDataType(scalarNode.DataType), + LwipDefs.GetLwipDefForSnmpAccessMode(scalarNode.AccessMode), + scalarNode.Name); + } + if (nodeDefs.Length > 0) + nodeDefs.Length--; + + VariableDeclaration nodeDefsDecl = new VariableDeclaration( + new VariableType(this.FullNodeName + "_nodes", LwipDefs.Vt_StScalarArrayNodeDef, null, ConstType.Value, String.Empty), + "{\n" + nodeDefs + "\n}" , + isStatic: true); + + mibFile.Declarations.Add(nodeDefsDecl); + + + // create and add node declaration + string nodeInitialization = String.Format("SNMP_SCALAR_CREATE_ARRAY_NODE({0}, {1}, {2}, {3}, {4})", + this.Oid, + nodeDefsDecl.Type.Name, + (this.GetMethodRequired) ? this.GetMethodName : LwipDefs.Null, + (this.TestMethodRequired) ? this.TestMethodName : LwipDefs.Null, + (this.SetMethodRequired) ? this.SetMethodName : LwipDefs.Null + ); + + mibFile.Declarations.Add(new VariableDeclaration( + new VariableType(this.FullNodeName, LwipDefs.Vt_StScalarArrayNode, null, ConstType.Value), + nodeInitialization, + isStatic: true)); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNode.cs new file mode 100644 index 0000000..6be54c4 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNode.cs @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNode: SnmpNode + { + protected const string LocalValueName = "v"; // name of (casted) local value variable + + private SnmpDataType dataType; + private SnmpAccessMode accessMode; + private readonly List restrictions = new List(); + + private bool useExternalMethods = false; + private string externalGetMethod; + private string externalTestMethod; + private string externalSetMethod; + + + public SnmpScalarNode(SnmpTreeNode parentNode) + : base(parentNode) + { + } + + public override string FullNodeName + { + get { return this.Name.ToLowerInvariant() + "_scalar"; } + } + + public SnmpDataType DataType + { + get { return this.dataType; } + set { this.dataType = value; } + } + + public List Restrictions + { + get { return this.restrictions; } + } + + public SnmpAccessMode AccessMode + { + get { return this.accessMode; } + set { this.accessMode = value; } + } + + public virtual string FixedValueLength + { + get { return null; } + } + + /// + /// If scalar is used as a table index its value becomes part of the OID. This value returns how many OID parts are required to represent this value. + /// + public virtual int OidRepresentationLen + { + get { return -1; } + } + + public bool UseExternalMethods + { + get { return this.useExternalMethods; } + set { this.useExternalMethods = value; } + } + + public string ExternalGetMethod + { + get { return this.externalGetMethod; } + set { this.externalGetMethod = value; } + } + public string ExternalTestMethod + { + get { return this.externalTestMethod; } + set { this.externalTestMethod = value; } + } + public string ExternalSetMethod + { + get { return this.externalSetMethod; } + set { this.externalSetMethod = value; } + } + + public override void GenerateCode(MibCFile mibFile) + { + string getMethodName; + string testMethodName; + string setMethodName; + + if (this.useExternalMethods) + { + getMethodName = this.externalGetMethod; + testMethodName = this.externalTestMethod; + setMethodName = this.externalSetMethod; + } + else + { + getMethodName = LwipDefs.Null; + testMethodName = LwipDefs.Null; + setMethodName = LwipDefs.Null; + + if ((this.accessMode == SnmpAccessMode.ReadWrite) || (this.accessMode == SnmpAccessMode.ReadOnly)) + { + FunctionDeclaration getMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_GetValue, isStatic: true); + getMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); + getMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + getMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_S16); + mibFile.Declarations.Add(getMethodDecl); + + Function getMethod = Function.FromDeclaration(getMethodDecl); + getMethodName = getMethod.Name; + + VariableDeclaration returnValue = new VariableDeclaration((VariableType)getMethod.ReturnType.Clone()); + returnValue.Type.Name = "value_len"; + getMethod.Declarations.Add(returnValue); + getMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getMethod.Parameter[0].Name); + + bool valueVarUsed = false; + GenerateGetMethodCode(getMethod, getMethod.Parameter[1].Name, ref valueVarUsed, returnValue.Type.Name); + if (!valueVarUsed) + { + getMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getMethod.Parameter[1].Name); + } + + getMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + + mibFile.Implementation.Add(getMethod); + } + + if ((this.accessMode == SnmpAccessMode.ReadWrite) || (this.accessMode == SnmpAccessMode.WriteOnly)) + { + bool valueVarUsed; + bool lenVarUsed; + VariableDeclaration returnValue; + + if (this.restrictions.Count > 0) + { + FunctionDeclaration testMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_SetTest, isStatic: true); + testMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); + testMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); + testMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + testMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + mibFile.Declarations.Add(testMethodDecl); + + Function testMethod = Function.FromDeclaration(testMethodDecl); + testMethodName = testMethod.Name; + + returnValue = new VariableDeclaration((VariableType)testMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_WrongValue); + returnValue.Type.Name = "err"; + testMethod.Declarations.Add(returnValue); + testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[0].Name); + + valueVarUsed = false; + lenVarUsed = false; + + GenerateTestMethodCode(testMethod, testMethod.Parameter[2].Name, ref valueVarUsed, testMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); + + if (!valueVarUsed) + { + testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[2].Name); + } + if (!lenVarUsed) + { + testMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", testMethod.Parameter[1].Name); + } + + testMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + + mibFile.Implementation.Add(testMethod); + + } + else + { + testMethodName = LwipDefs.FnctName_SetTest_Ok; + } + + FunctionDeclaration setMethodDecl = null; + setMethodDecl = new FunctionDeclaration(this.Name + LwipDefs.FnctSuffix_SetValue, isStatic: true); + setMethodDecl.Parameter.Add(new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*")); + setMethodDecl.Parameter.Add(new VariableType("len", LwipDefs.Vt_U16)); + setMethodDecl.Parameter.Add(new VariableType("value", VariableType.VoidString, "*")); + setMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + mibFile.Declarations.Add(setMethodDecl); + + Function setMethod = Function.FromDeclaration(setMethodDecl); + setMethodName = setMethod.Name; + + returnValue = new VariableDeclaration((VariableType)setMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_Ok); + returnValue.Type.Name = "err"; + setMethod.Declarations.Add(returnValue); + setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[0].Name); + + valueVarUsed = false; + lenVarUsed = false; + + GenerateSetMethodCode(setMethod, setMethod.Parameter[2].Name, ref valueVarUsed, setMethod.Parameter[1].Name, ref lenVarUsed, returnValue.Type.Name); + + if (!valueVarUsed) + { + setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[2].Name); + } + if (!lenVarUsed) + { + setMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", setMethod.Parameter[1].Name); + } + + setMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + + mibFile.Implementation.Add(setMethod); + } + } + + // create and add node declaration + string nodeInitialization; + if (this.accessMode == SnmpAccessMode.ReadOnly) + { + nodeInitialization = String.Format("SNMP_SCALAR_CREATE_NODE_READONLY({0}, {1}, {2})", + this.Oid, + LwipDefs.GetAsn1DefForSnmpDataType(this.dataType), + getMethodName); + } + else + { + nodeInitialization = String.Format("SNMP_SCALAR_CREATE_NODE({0}, {1}, {2}, {3}, {4}, {5})", + this.Oid, + LwipDefs.GetLwipDefForSnmpAccessMode(this.accessMode), + LwipDefs.GetAsn1DefForSnmpDataType(this.dataType), + getMethodName, + testMethodName, + setMethodName); + } + + mibFile.Declarations.Add(new VariableDeclaration( + new VariableType(this.FullNodeName, LwipDefs.Vt_StScalarNode, null, ConstType.Value), + nodeInitialization, isStatic: true)); + } + + public virtual void GenerateGetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string retLenVarName) + { + bool localValueVarUsed; + if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) + { + valueVarUsed = true; + localValueVarUsed = false; + } + else + { + localValueVarUsed = true; // do not generate UNUSED_ARG code + } + + if (this.FixedValueLength == null) + { + // check that value with variable length fits into buffer + container.AddElement(new Comment(String.Format("TODO: take care that value with variable length fits into buffer: ({0} <= SNMP_MAX_VALUE_SIZE)", retLenVarName), singleLine: true)); + } + + GenerateGetMethodCodeCore(container, LocalValueName, ref localValueVarUsed, retLenVarName); + if (!localValueVarUsed) + { + container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); + } + } + + protected virtual void GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName) + { + container.AddElement(new Comment(String.Format("TODO: put requested value to '*{0}' here", localValueVarName), singleLine: true)); + container.AddCodeFormat("{0} = {1};", + retLenVarName, + (!String.IsNullOrWhiteSpace(this.FixedValueLength)) ? this.FixedValueLength : "0"); + } + + public virtual void GenerateTestMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + if (this.Restrictions.Count > 0) + { + bool localVarUsed; + if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) + { + valueVarUsed = true; + localVarUsed = false; + } + else + { + localVarUsed = true; // do not generate UNUSED_ARG code + } + + if (!String.IsNullOrWhiteSpace(this.FixedValueLength)) + { + // check for fixed value + container.AddCodeFormat("LWIP_ASSERT(\"Invalid length for datatype\", ({0} == {1}));", lenVarName, this.FixedValueLength); + lenVarUsed = true; + } + + GenerateTestMethodCodeCore(container, LocalValueName, ref localVarUsed, lenVarName, ref lenVarUsed, retErrVarName); + + if (!localVarUsed) + { + container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); + } + } + else + { + container.AddCodeFormat("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok); + } + } + + protected virtual void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + container.AddElement(new Comment(String.Format("TODO: test new value here:\nif (*{0} == ) {1} = {2};", localValueVarName, retErrVarName, LwipDefs.Def_ErrorCode_Ok))); + } + + public virtual void GenerateSetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + bool localVarUsed; + if (GenerateValueDeclaration(container, LocalValueName, valueVarName)) + { + valueVarUsed = true; + localVarUsed = false; + } + else + { + localVarUsed = true; // do not generate UNUSED_ARG code + } + + GenerateSetMethodCodeCore(container, LocalValueName, ref localVarUsed, lenVarName, ref lenVarUsed, retErrVarName); + + if (!localVarUsed) + { + container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", LocalValueName)); + } + } + + protected virtual void GenerateSetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + container.AddElement(new Comment(String.Format("TODO: store new value contained in '*{0}' here", localValueVarName), singleLine: true)); + } + + + protected virtual bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) + { + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName, LwipDefs.Vt_U8, "*"), + "(" + new VariableType(null, LwipDefs.Vt_U8, "*") + ")" + sourceName)); + + return true; + } + + public static SnmpScalarNode CreateFromDatatype(SnmpDataType dataType, SnmpTreeNode parentNode) + { + switch (dataType) + { + case SnmpDataType.Integer: + return new SnmpScalarNodeInt(parentNode); + + case SnmpDataType.Gauge: + case SnmpDataType.Counter: + case SnmpDataType.TimeTicks: + return new SnmpScalarNodeUint(dataType, parentNode); + } + + return new SnmpScalarNode(parentNode); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeBits.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeBits.cs new file mode 100644 index 0000000..906a5a6 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeBits.cs @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeBits : SnmpScalarNode + { + private readonly uint bitCount; + + public SnmpScalarNodeBits(SnmpTreeNode parentNode, uint bitCount) + : base(parentNode) + { + this.DataType = SnmpDataType.Bits; + this.bitCount = bitCount; + } + + public override void GenerateGetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string retLenVarName) + { + container.AddCode(String.Format( + "{0} = snmp_encode_bits(({1} *){2}, SNMP_MAX_VALUE_SIZE, 0 /* TODO: pass real value here */, {3});", + retLenVarName, + LwipDefs.Vt_U8, + valueVarName, + this.bitCount)); + + valueVarUsed = true; + } + + public override void GenerateTestMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + if (this.Restrictions.Count > 0) + { + const string bitVarName = "bits"; + + container.Declarations.Add(new VariableDeclaration(new VariableType(bitVarName, LwipDefs.Vt_U32))); + + IfThenElse ite = new IfThenElse(String.Format( + "snmp_decode_bits(({0} *){1}, {2}, &{3}) == ERR_OK", + LwipDefs.Vt_U8, + valueVarName, + lenVarName, + bitVarName)); + + valueVarUsed = true; + lenVarUsed = true; + + StringBuilder innerIfCond = new StringBuilder(); + foreach (IRestriction restriction in this.Restrictions) + { + innerIfCond.Append(restriction.GetCheckCodeValid(bitVarName)); + innerIfCond.Append(" || "); + } + + innerIfCond.Length -= 4; + + IfThenElse innerIte = new IfThenElse(innerIfCond.ToString()); + innerIte.AddCode(String.Format("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok)); + ite.AddElement(innerIte); + container.AddElement(ite); + } + else + { + base.GenerateTestMethodCode(container, valueVarName, ref valueVarUsed, lenVarName, ref lenVarUsed, retErrVarName); + } + } + + public override void GenerateSetMethodCode(CodeContainerBase container, string valueVarName, ref bool valueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + const string bitVarName = "bits"; + + container.Declarations.Add(new VariableDeclaration(new VariableType(bitVarName, LwipDefs.Vt_U32))); + + IfThenElse ite = new IfThenElse(String.Format( + "snmp_decode_bits(({0} *){1}, {2}, &{3}) == ERR_OK", + LwipDefs.Vt_U8, + valueVarName, + lenVarName, + bitVarName)); + + valueVarUsed = true; + lenVarUsed = true; + + ite.AddElement(new Comment(String.Format("TODO: store new value contained in '{0}' here", bitVarName), singleLine: true)); + + container.AddElement(ite); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeCounter64.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeCounter64.cs new file mode 100644 index 0000000..8f450c8 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeCounter64.cs @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeCounter64 : SnmpScalarNode + { + public SnmpScalarNodeCounter64(SnmpTreeNode parentNode) + : base(parentNode) + { + this.DataType = SnmpDataType.Counter64; + } + + protected override bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) + { + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName + "_high", LwipDefs.Vt_U32, "*"), + "(" + new VariableType(null, LwipDefs.Vt_U32, "*").ToString() + ")" + sourceName)); + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName + "_low", LwipDefs.Vt_U32, "*"), + variableName + "_high + 1")); + + container.AddCode(String.Format("LWIP_UNUSED_ARG({0}_high);", variableName)); + container.AddCode(String.Format("LWIP_UNUSED_ARG({0}_low);", variableName)); + + return false; + } + + public override string FixedValueLength + { + get { return String.Format("(2 * sizeof({0}))", LwipDefs.Vt_U32); } + } + + public override int OidRepresentationLen + { + get { return 1; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeInt.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeInt.cs new file mode 100644 index 0000000..a381234 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeInt.cs @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeInt : SnmpScalarNode + { + public SnmpScalarNodeInt(SnmpTreeNode parentNode) + : base(parentNode) + { + this.DataType = SnmpDataType.Integer; + } + + protected override void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + System.Diagnostics.Trace.Assert(this.Restrictions.Count > 0); + + StringBuilder ifCond = new StringBuilder(); + foreach (IRestriction restriction in this.Restrictions) + { + ifCond.Append(restriction.GetCheckCodeValid("*" + localValueVarName)); + ifCond.Append(" || "); + + localValueVarUsed = true; + } + + ifCond.Length -= 4; + + IfThenElse ite = new IfThenElse(ifCond.ToString()); + ite.AddCode(String.Format("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok)); + container.AddElement(ite); + } + + protected override bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) + { + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName, LwipDefs.Vt_S32, "*"), + "(" + new VariableType(null, LwipDefs.Vt_S32, "*") + ")" + sourceName)); + + return true; + } + + public override string FixedValueLength + { + get { return String.Format("sizeof({0})", LwipDefs.Vt_S32); } + } + + public override int OidRepresentationLen + { + get { return 1; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeObjectIdentifier.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeObjectIdentifier.cs new file mode 100644 index 0000000..5ce8d14 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeObjectIdentifier.cs @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeObjectIdentifier: SnmpScalarNode + { + public SnmpScalarNodeObjectIdentifier(SnmpTreeNode parentNode) + : base(parentNode) + { + this.DataType = SnmpDataType.ObjectIdentifier; + } + + protected override bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) + { + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName, LwipDefs.Vt_U32, "*"), + "(" + new VariableType(null, LwipDefs.Vt_U32, "*") + ")" + sourceName)); + + return true; + } + + protected override void GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName) + { + container.AddElement(new Comment(String.Format("TODO: put requested value to '*{0}' here. '{0}' has to be interpreted as {1}[]", localValueVarName, LwipDefs.Vt_U32), singleLine: true)); + container.AddElement(EmptyLine.SingleLine); + container.AddCode(String.Format("{0} = 0; // TODO: return real value length here (should be 'numOfElements * sizeof({1})')", retLenVarName, LwipDefs.Vt_U32)); + } + + protected override void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + VariableDeclaration objIdLenVar = new VariableDeclaration( + new VariableType(localValueVarName + "_len", LwipDefs.Vt_U8), + String.Format("{0} / sizeof({1})", lenVarName, LwipDefs.Vt_U32)); + lenVarUsed = true; + + container.Declarations.Add(objIdLenVar); + + base.GenerateTestMethodCodeCore(container, localValueVarName, ref localValueVarUsed, lenVarName, ref lenVarUsed, retErrVarName); + + container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", objIdLenVar.Type.Name)); + } + + protected override void GenerateSetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + VariableDeclaration objIdLenVar = new VariableDeclaration( + new VariableType(localValueVarName + "_len", LwipDefs.Vt_U8), + String.Format("{0} / sizeof({1})", lenVarName, LwipDefs.Vt_U32)); + lenVarUsed = true; + + container.Declarations.Add(objIdLenVar); + + base.GenerateSetMethodCodeCore(container, localValueVarName, ref localValueVarUsed, lenVarName, ref lenVarUsed, retErrVarName); + + container.AddCode(String.Format("LWIP_UNUSED_ARG({0});", objIdLenVar.Type.Name)); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeOctetString.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeOctetString.cs new file mode 100644 index 0000000..bf10f9a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeOctetString.cs @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeOctetString : SnmpScalarNode + { + public SnmpScalarNodeOctetString(SnmpDataType dataType, SnmpTreeNode parentNode) + : base(parentNode) + { + System.Diagnostics.Debug.Assert( + (dataType == SnmpDataType.OctetString) || + (dataType == SnmpDataType.Opaque) || + (dataType == SnmpDataType.IpAddress)); + + this.DataType = dataType; + } + + protected override void GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName) + { + if (this.Restrictions.Count > 0) + { + StringBuilder ifCond = new StringBuilder(); + foreach (IRestriction restriction in this.Restrictions) + { + ifCond.Append(restriction.GetCheckCodeValid(retLenVarName)); + ifCond.Append(" || "); + } + + ifCond.Length -= 4; + container.AddElement(new Comment("TODO: take care of len restrictions defined in MIB: " + ifCond, singleLine: true)); + } + base.GenerateGetMethodCodeCore(container, localValueVarName, ref localValueVarUsed, retLenVarName); + } + + protected override void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + System.Diagnostics.Trace.Assert(this.Restrictions.Count > 0); + + // checks refer to length of octet string + StringBuilder ifCond = new StringBuilder(); + foreach (IRestriction restriction in this.Restrictions) + { + ifCond.Append(restriction.GetCheckCodeValid(lenVarName)); + ifCond.Append(" || "); + + lenVarUsed = true; + } + + ifCond.Length -= 4; + + IfThenElse ite = new IfThenElse(ifCond.ToString()); + ite.AddCode(String.Format("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok)); + container.AddElement(ite); + } + + public override int OidRepresentationLen + { + get + { + // check restrictions if we are set to one fixed length + if ((this.Restrictions != null) && (this.Restrictions.Count > 0)) + { + foreach (IRestriction restriction in this.Restrictions) + { + if (restriction is IsInRangeRestriction) + { + if ((restriction as IsInRangeRestriction).RangeStart == (restriction as IsInRangeRestriction).RangeEnd) + { + return (int)(restriction as IsInRangeRestriction).RangeStart; + } + } + else if (restriction is IsEqualRestriction) + { + return (int)(restriction as IsEqualRestriction).Value; + } + } + } + + return -1; // variable length + } + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeTruthValue.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeTruthValue.cs new file mode 100644 index 0000000..0f55752 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeTruthValue.cs @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeTruthValue : SnmpScalarNodeInt + { + public SnmpScalarNodeTruthValue(SnmpTreeNode parentNode) + : base(parentNode) + { + } + + protected override void GenerateGetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string retLenVarName) + { + container.AddCodeFormat("snmp_encode_truthvalue({0}, /* TODO: put requested bool value here */ 0);", localValueVarName); + localValueVarUsed = true; + + container.AddCode(String.Format("{0} = {1};", + retLenVarName, + (!String.IsNullOrWhiteSpace(this.FixedValueLength)) ? this.FixedValueLength : "0")); + } + + protected override void GenerateSetMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + VariableType truthVar = new VariableType("bool_value", LwipDefs.Vt_U8); + container.Declarations.Add(new VariableDeclaration(truthVar)); + + container.AddCodeFormat("snmp_decode_truthvalue({0}, &{1});", localValueVarName, truthVar.Name); + localValueVarUsed = true; + + container.AddElement(new Comment(String.Format("TODO: store new value contained in '{0}' here", truthVar.Name), singleLine: true)); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeUint.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeUint.cs new file mode 100644 index 0000000..edc161a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpScalarNodeUint.cs @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpScalarNodeUint : SnmpScalarNode + { + public SnmpScalarNodeUint(SnmpDataType dataType, SnmpTreeNode parentNode) + : base(parentNode) + { + System.Diagnostics.Debug.Assert( + (dataType == SnmpDataType.Counter) || + (dataType == SnmpDataType.Gauge) || + (dataType == SnmpDataType.TimeTicks)); + + this.DataType = dataType; + } + + protected override void GenerateTestMethodCodeCore(CodeContainerBase container, string localValueVarName, ref bool localValueVarUsed, string lenVarName, ref bool lenVarUsed, string retErrVarName) + { + System.Diagnostics.Trace.Assert(this.Restrictions.Count > 0); + + StringBuilder ifCond = new StringBuilder(); + foreach (IRestriction restriction in this.Restrictions) + { + ifCond.Append(restriction.GetCheckCodeValid("*" + localValueVarName)); + ifCond.Append(" || "); + + localValueVarUsed = true; + } + + ifCond.Length -= 4; + + IfThenElse ite = new IfThenElse(ifCond.ToString()); + ite.AddCode(String.Format("{0} = {1};", retErrVarName, LwipDefs.Def_ErrorCode_Ok)); + container.AddElement(ite); + } + + protected override bool GenerateValueDeclaration(CodeContainerBase container, string variableName, string sourceName) + { + container.AddDeclaration(new VariableDeclaration( + new VariableType(variableName, LwipDefs.Vt_U32, "*"), + "(" + new VariableType(null, LwipDefs.Vt_U32, "*") + ")" + sourceName)); + + return true; + } + + public override string FixedValueLength + { + get { return String.Format("sizeof({0})", LwipDefs.Vt_U32); } + } + + public override int OidRepresentationLen + { + get { return 1; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTableNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTableNode.cs new file mode 100644 index 0000000..13a3bf2 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTableNode.cs @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpTableNode: SnmpScalarAggregationNode + { + private readonly List cellNodes = new List(); + private readonly List indexNodes = new List(); + private string augmentedTableRow = null; + + + public SnmpTableNode(SnmpTreeNode parentNode) + : base(parentNode) + { + } + + public List CellNodes + { + get { return cellNodes; } + } + + public List IndexNodes + { + get { return indexNodes; } + } + + public string AugmentedTableRow + { + get { return this.augmentedTableRow; } + set { this.augmentedTableRow = value; } + } + + public override string FullNodeName + { + get + { + string result = this.Name.ToLowerInvariant(); + if (!result.Contains("table")) + { + result += "_table"; + } + + return result; + } + } + + protected override IEnumerable AggregatedScalarNodes + { + get { return this.cellNodes; } + } + + public override void GenerateCode(MibCFile mibFile) + { + FunctionDeclaration getInstanceMethodDecl = new FunctionDeclaration(this.FullNodeName + LwipDefs.FnctSuffix_GetInstance, isStatic: true); + getInstanceMethodDecl.Parameter.Add(new VariableType("column", LwipDefs.Vt_U32, "*", ConstType.Value)); + getInstanceMethodDecl.Parameter.Add(new VariableType("row_oid", LwipDefs.Vt_U32, "*", ConstType.Value)); + getInstanceMethodDecl.Parameter.Add(new VariableType("row_oid_len", LwipDefs.Vt_U8, "")); + getInstanceMethodDecl.Parameter.Add(new VariableType("cell_instance", LwipDefs.Vt_StNodeInstance, "*")); + getInstanceMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + mibFile.Declarations.Add(getInstanceMethodDecl); + + Function getInstanceMethod = Function.FromDeclaration(getInstanceMethodDecl); + GenerateGetInstanceMethodCode(getInstanceMethod); + mibFile.Implementation.Add(getInstanceMethod); + + + FunctionDeclaration getNextInstanceMethodDecl = new FunctionDeclaration(this.FullNodeName + LwipDefs.FnctSuffix_GetNextInstance, isStatic: true); + getNextInstanceMethodDecl.Parameter.Add(new VariableType("column", LwipDefs.Vt_U32, "*", ConstType.Value)); + getNextInstanceMethodDecl.Parameter.Add(new VariableType("row_oid", LwipDefs.Vt_StObjectId, "*")); + getNextInstanceMethodDecl.Parameter.Add(new VariableType("cell_instance", LwipDefs.Vt_StNodeInstance, "*")); + getNextInstanceMethodDecl.ReturnType = new VariableType(null, LwipDefs.Vt_Snmp_err); + mibFile.Declarations.Add(getNextInstanceMethodDecl); + + Function getNextInstanceMethod = Function.FromDeclaration(getNextInstanceMethodDecl); + GenerateGetNextInstanceMethodCode(getNextInstanceMethod); + mibFile.Implementation.Add(getNextInstanceMethod); + + + VariableType instanceType = new VariableType("cell_instance", LwipDefs.Vt_StNodeInstance, "*"); + GenerateAggregatedCode( + mibFile, + instanceType, + String.Format("SNMP_TABLE_GET_COLUMN_FROM_OID({0}->instance_oid.id)", instanceType.Name)); + + + #region create and add column/table definitions + + StringBuilder colDefs = new StringBuilder(); + foreach (SnmpScalarNode colNode in this.cellNodes) + { + colDefs.AppendFormat(" {{{0}, {1}, {2}}}, /* {3} */ \n", + colNode.Oid, + LwipDefs.GetAsn1DefForSnmpDataType(colNode.DataType), + LwipDefs.GetLwipDefForSnmpAccessMode(colNode.AccessMode), + colNode.Name); + } + if (colDefs.Length > 0) + { + colDefs.Length--; + } + + VariableDeclaration colDefsDecl = new VariableDeclaration( + new VariableType(this.FullNodeName + "_columns", LwipDefs.Vt_StTableColumnDef, null, ConstType.Value, String.Empty), + "{\n" + colDefs + "\n}", + isStatic: true); + + mibFile.Declarations.Add(colDefsDecl); + + string nodeInitialization = String.Format("SNMP_TABLE_CREATE({0}, {1}, {2}, {3}, {4}, {5}, {6})", + this.Oid, + colDefsDecl.Type.Name, + getInstanceMethodDecl.Name, getNextInstanceMethodDecl.Name, + (this.GetMethodRequired) ? this.GetMethodName : LwipDefs.Null, + (this.TestMethodRequired) ? this.TestMethodName : LwipDefs.Null, + (this.SetMethodRequired) ? this.SetMethodName : LwipDefs.Null + ); + + mibFile.Declarations.Add(new VariableDeclaration( + new VariableType(this.FullNodeName, LwipDefs.Vt_StTableNode, null, ConstType.Value), + nodeInitialization, + isStatic: true)); + + #endregion + } + + protected virtual void GenerateGetInstanceMethodCode(Function getInstanceMethod) + { + VariableDeclaration returnValue = new VariableDeclaration((VariableType)getInstanceMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_NoSuchInstance); + returnValue.Type.Name = "err"; + getInstanceMethod.Declarations.Add(returnValue); + + int instanceOidLength = 0; + StringBuilder indexColumns = new StringBuilder(); + foreach (SnmpScalarNode indexNode in this.indexNodes) + { + if (instanceOidLength >= 0) + { + if (indexNode.OidRepresentationLen >= 0) + { + instanceOidLength += indexNode.OidRepresentationLen; + } + else + { + // at least one index column has a variable length -> we cannot perform a static check + instanceOidLength = -1; + } + } + + indexColumns.AppendFormat( + " {0} ({1}, OID length = {2})\n", + indexNode.Name, + indexNode.DataType, + (indexNode.OidRepresentationLen >= 0) ? indexNode.OidRepresentationLen.ToString() : "variable"); + } + if (indexColumns.Length > 0) + { + indexColumns.Length--; + + getInstanceMethod.Declarations.Insert(0, new Comment(String.Format( + "The instance OID of this table consists of following (index) column(s):\n{0}", + indexColumns))); + } + + string augmentsHint = ""; + if (!String.IsNullOrWhiteSpace(this.augmentedTableRow)) + { + augmentsHint = String.Format( + "This table augments table '{0}'! Index columns therefore belong to table '{0}'!\n" + + "You may simply call the '*{1}' method of this table.\n\n", + (this.augmentedTableRow.ToLowerInvariant().EndsWith("entry")) ? this.augmentedTableRow.Substring(0, this.augmentedTableRow.Length-5) : this.augmentedTableRow, + LwipDefs.FnctSuffix_GetInstance); + } + + CodeContainerBase ccb = getInstanceMethod; + if (instanceOidLength > 0) + { + IfThenElse ite = new IfThenElse(String.Format("{0} == {1}", getInstanceMethod.Parameter[2].Name, instanceOidLength)); + getInstanceMethod.AddElement(ite); + ccb = ite; + } + + ccb.AddCodeFormat("LWIP_UNUSED_ARG({0});", getInstanceMethod.Parameter[0].Name); + ccb.AddCodeFormat("LWIP_UNUSED_ARG({0});", getInstanceMethod.Parameter[1].Name); + if (instanceOidLength <= 0) + { + ccb.AddCodeFormat("LWIP_UNUSED_ARG({0});", getInstanceMethod.Parameter[2].Name); + } + ccb.AddCodeFormat("LWIP_UNUSED_ARG({0});", getInstanceMethod.Parameter[3].Name); + + ccb.AddElement(new Comment(String.Format( + "TODO: check if '{0}'/'{1}' params contain a valid instance oid for a row\n" + + "If so, set '{2} = {3};'\n\n" + + "snmp_oid_* methods may be used for easier processing of oid\n\n" + + "{4}" + + "In order to avoid decoding OID a second time in subsequent get_value/set_test/set_value methods,\n" + + "you may store an arbitrary value (like a pointer to target value object) in '{5}->reference'/'{5}->reference_len'.\n" + + "But be aware that not always a subsequent method is called -> Do NOT allocate memory here and try to release it in subsequent methods!\n\n" + + "You also may replace function pointers in '{5}' param for get/test/set methods which contain the default values from table definition,\n" + + "in order to provide special methods, for the currently processed cell. Changed pointers are only valid for current request.", + getInstanceMethod.Parameter[1].Name, + getInstanceMethod.Parameter[2].Name, + returnValue.Type.Name, + LwipDefs.Def_ErrorCode_Ok, + augmentsHint, + getInstanceMethod.Parameter[3].Name + ))); + + getInstanceMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + } + + protected virtual void GenerateGetNextInstanceMethodCode(Function getNextInstanceMethod) + { + getNextInstanceMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getNextInstanceMethod.Parameter[0].Name); + getNextInstanceMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getNextInstanceMethod.Parameter[1].Name); + getNextInstanceMethod.AddCodeFormat("LWIP_UNUSED_ARG({0});", getNextInstanceMethod.Parameter[2].Name); + + VariableDeclaration returnValue = new VariableDeclaration((VariableType)getNextInstanceMethod.ReturnType.Clone(), LwipDefs.Def_ErrorCode_NoSuchInstance); + returnValue.Type.Name = "err"; + getNextInstanceMethod.Declarations.Add(returnValue); + + StringBuilder indexColumns = new StringBuilder(); + foreach (SnmpScalarNode indexNode in this.indexNodes) + { + indexColumns.AppendFormat( + " {0} ({1}, OID length = {2})\n", + indexNode.Name, + indexNode.DataType, + (indexNode.OidRepresentationLen >= 0) ? indexNode.OidRepresentationLen.ToString() : "variable"); + } + if (indexColumns.Length > 0) + { + indexColumns.Length--; + + getNextInstanceMethod.Declarations.Insert(0, new Comment(String.Format( + "The instance OID of this table consists of following (index) column(s):\n{0}", + indexColumns))); + } + + string augmentsHint = ""; + if (!String.IsNullOrWhiteSpace(this.augmentedTableRow)) + { + augmentsHint = String.Format( + "This table augments table '{0}'! Index columns therefore belong to table '{0}'!\n" + + "You may simply call the '*{1}' method of this table.\n\n", + (this.augmentedTableRow.ToLowerInvariant().EndsWith("entry")) ? this.augmentedTableRow.Substring(0, this.augmentedTableRow.Length-5) : this.augmentedTableRow, + LwipDefs.FnctSuffix_GetNextInstance); + } + + getNextInstanceMethod.AddElement(new Comment(String.Format( + "TODO: analyze '{0}->id'/'{0}->len' and return the subsequent row instance\n" + + "Be aware that '{0}->id'/'{0}->len' must not point to a valid instance or have correct instance length.\n" + + "If '{0}->len' is 0, return the first instance. If '{0}->len' is longer than expected, cut superfluous OID parts.\n" + + "If a valid next instance is found, store it in '{0}->id'/'{0}->len' and set '{1} = {2};'\n\n" + + "snmp_oid_* methods may be used for easier processing of oid\n\n" + + "{3}" + + "In order to avoid decoding OID a second time in subsequent get_value/set_test/set_value methods,\n" + + "you may store an arbitrary value (like a pointer to target value object) in '{4}->reference'/'{4}->reference_len'.\n" + + "But be aware that not always a subsequent method is called -> Do NOT allocate memory here and try to release it in subsequent methods!\n\n" + + "You also may replace function pointers in '{4}' param for get/test/set methods which contain the default values from table definition,\n" + + "in order to provide special methods, for the currently processed cell. Changed pointers are only valid for current request.", + getNextInstanceMethod.Parameter[1].Name, + returnValue.Type.Name, + LwipDefs.Def_ErrorCode_Ok, + augmentsHint, + getNextInstanceMethod.Parameter[2].Name + ))); + + getNextInstanceMethod.AddElement(new Comment(String.Format( + "For easier processing and getting the next instance, you may use the 'snmp_next_oid_*' enumerator.\n" + + "Simply pass all known instance OID's to it and it returns the next valid one:\n\n" + + "{0} state;\n" + + "{1} result_buf;\n" + + "snmp_next_oid_init(&state, {2}->id, {2}->len, result_buf.id, SNMP_MAX_OBJ_ID_LEN);\n" + + "while ({{not all instances passed}}) {{\n" + + " {1} test_oid;\n" + + " {{fill test_oid to create instance oid for next instance}}\n" + + " snmp_next_oid_check(&state, test_oid.id, test_oid.len, {{target_data_ptr}});\n" + + "}}\n" + + "if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {{\n" + + " snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);\n" + + " {3}->reference.ptr = state.reference; //==target_data_ptr, for usage in subsequent get/test/set\n" + + " {4} = {5};\n" + + "}}" + , + LwipDefs.Vt_StNextOidState, + LwipDefs.Vt_StObjectId, + getNextInstanceMethod.Parameter[1].Name, + getNextInstanceMethod.Parameter[2].Name, + returnValue.Type.Name, + LwipDefs.Def_ErrorCode_Ok + ))); + + getNextInstanceMethod.AddCodeFormat("return {0};", returnValue.Type.Name); + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTreeNode.cs b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTreeNode.cs new file mode 100644 index 0000000..bf0c604 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/LwipSnmpCodeGeneration/SnmpTreeNode.cs @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Collections.Generic; +using System.Text; +using CCodeGeneration; + +namespace LwipSnmpCodeGeneration +{ + public class SnmpTreeNode: SnmpScalarAggregationNode + { + private readonly List childNodes = new List(); + private readonly List childScalarNodes = new List(); + private string fullOid = ""; + + public SnmpTreeNode(SnmpTreeNode parentNode) + : base(parentNode) + { + } + + public override string FullNodeName + { + get { return this.Name.ToLowerInvariant() + "_treenode"; } + } + + public string FullOid + { + get { return this.fullOid; } + set { this.fullOid = value; } + } + + public List ChildNodes + { + get { return this.childNodes; } + } + + protected override IEnumerable AggregatedScalarNodes + { + get { return this.childScalarNodes; } + } + + private void GenerateAggregatedCode(MibCFile mibFile, bool generateDeclarations, bool generateImplementations) + { + VariableType instanceType = new VariableType("instance", LwipDefs.Vt_StNodeInstance, "*"); + base.GenerateAggregatedCode( + mibFile, + instanceType, + String.Format("{0}->node->oid", instanceType.Name), + generateDeclarations, + generateImplementations); + } + + private void GenerateAggregateMethodDeclarations(MibCFile mibFile) + { + if (LwipOpts.GenerateSingleAccessMethodsForTreeNodeScalars && (this.childScalarNodes.Count > 1)) + { + GenerateAggregatedCode(mibFile, true, false); + } + } + + public override void GenerateCode(MibCFile mibFile) + { + string nodeInitialization; + + if (LwipOpts.GenerateSingleAccessMethodsForTreeNodeScalars && (this.childScalarNodes.Count > 1)) + { + GenerateAggregatedCode(mibFile, false, true); + } + + // create and add node declaration + if (this.childNodes.Count > 0) + { + StringBuilder subnodeArrayInitialization = new StringBuilder(); + + for (int i=0; i=0; i--) + { + this.ChildNodes[i].Analyze(); + } + + // collect scalar nodes + foreach (SnmpNode childNode in this.childNodes) + { + SnmpScalarNode scalarNode = childNode as SnmpScalarNode; + if (scalarNode != null) + { + this.childScalarNodes.Add(scalarNode); + } + } + + base.Analyze(); + + // check if we can merge this node to a scalar array node (all childs need to be scalars) + if (this.childNodes.Count > 0) + { + if (LwipOpts.GenerateScalarArrays && (this.childScalarNodes.Count == this.childNodes.Count) && (this.ParentNode != null)) + { + SnmpScalarArrayNode scalarArrayNode = new SnmpScalarArrayNode(this.childScalarNodes, this.ParentNode); + scalarArrayNode.Oid = this.Oid; + scalarArrayNode.Name = this.Name; + scalarArrayNode.Analyze(); + + for (int i=0; i 1)) + { + foreach (SnmpScalarNode scalarNode in this.childScalarNodes) + { + scalarNode.UseExternalMethods = true; + scalarNode.ExternalGetMethod = this.GetMethodName; + scalarNode.ExternalTestMethod = this.TestMethodName; + scalarNode.ExternalSetMethod = this.SetMethodName; + } + } + } + else // if (this.childNodes.Count == 0) + { + if (!LwipOpts.GenerateEmptyFolders && (this.ParentNode != null)) + { + // do not generate this empty folder because it only waste (static) memory + for (int i=0; i + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); + this.treeMib = new System.Windows.Forms.TreeView(); + this.imagelistTreeNodeImages = new System.Windows.Forms.ImageList(this.components); + this.splitContainerMain = new System.Windows.Forms.SplitContainer(); + this.listviewNodeDetails = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStripMain = new System.Windows.Forms.ToolStrip(); + this.toolbuttonOpenMib = new System.Windows.Forms.ToolStripButton(); + this.dialogOpenMib = new System.Windows.Forms.OpenFileDialog(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainerMain)).BeginInit(); + this.splitContainerMain.Panel1.SuspendLayout(); + this.splitContainerMain.Panel2.SuspendLayout(); + this.splitContainerMain.SuspendLayout(); + this.toolStripMain.SuspendLayout(); + this.SuspendLayout(); + // + // treeMib + // + this.treeMib.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeMib.ImageIndex = 0; + this.treeMib.ImageList = this.imagelistTreeNodeImages; + this.treeMib.Location = new System.Drawing.Point(0, 0); + this.treeMib.Name = "treeMib"; + this.treeMib.SelectedImageIndex = 0; + this.treeMib.Size = new System.Drawing.Size(1028, 418); + this.treeMib.TabIndex = 0; + this.treeMib.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeMib_AfterSelect); + // + // imagelistTreeNodeImages + // + this.imagelistTreeNodeImages.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imagelistTreeNodeImages.ImageStream"))); + this.imagelistTreeNodeImages.TransparentColor = System.Drawing.Color.Transparent; + this.imagelistTreeNodeImages.Images.SetKeyName(0, "ntimgContainer"); + this.imagelistTreeNodeImages.Images.SetKeyName(1, "ntimgTable"); + this.imagelistTreeNodeImages.Images.SetKeyName(2, "ntimgRow"); + this.imagelistTreeNodeImages.Images.SetKeyName(3, "ntimgColumn"); + this.imagelistTreeNodeImages.Images.SetKeyName(4, "ntimgScalar"); + this.imagelistTreeNodeImages.Images.SetKeyName(5, "ntimgUnknown"); + // + // splitContainerMain + // + this.splitContainerMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainerMain.Location = new System.Drawing.Point(0, 25); + this.splitContainerMain.Name = "splitContainerMain"; + this.splitContainerMain.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainerMain.Panel1 + // + this.splitContainerMain.Panel1.Controls.Add(this.treeMib); + // + // splitContainerMain.Panel2 + // + this.splitContainerMain.Panel2.Controls.Add(this.listviewNodeDetails); + this.splitContainerMain.Size = new System.Drawing.Size(1028, 625); + this.splitContainerMain.SplitterDistance = 418; + this.splitContainerMain.TabIndex = 1; + // + // listviewNodeDetails + // + this.listviewNodeDetails.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.listviewNodeDetails.Dock = System.Windows.Forms.DockStyle.Fill; + this.listviewNodeDetails.FullRowSelect = true; + this.listviewNodeDetails.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.listviewNodeDetails.Location = new System.Drawing.Point(0, 0); + this.listviewNodeDetails.Name = "listviewNodeDetails"; + this.listviewNodeDetails.Size = new System.Drawing.Size(1028, 203); + this.listviewNodeDetails.TabIndex = 0; + this.listviewNodeDetails.UseCompatibleStateImageBehavior = false; + this.listviewNodeDetails.View = System.Windows.Forms.View.Details; + // + // columnHeader1 + // + this.columnHeader1.Text = ""; + this.columnHeader1.Width = 150; + // + // columnHeader2 + // + this.columnHeader2.Text = ""; + this.columnHeader2.Width = 777; + // + // toolStripMain + // + this.toolStripMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolbuttonOpenMib}); + this.toolStripMain.Location = new System.Drawing.Point(0, 0); + this.toolStripMain.Name = "toolStripMain"; + this.toolStripMain.Size = new System.Drawing.Size(1028, 25); + this.toolStripMain.TabIndex = 2; + // + // toolbuttonOpenMib + // + this.toolbuttonOpenMib.Image = ((System.Drawing.Image)(resources.GetObject("toolbuttonOpenMib.Image"))); + this.toolbuttonOpenMib.Name = "toolbuttonOpenMib"; + this.toolbuttonOpenMib.Size = new System.Drawing.Size(65, 22); + this.toolbuttonOpenMib.Text = "Open..."; + this.toolbuttonOpenMib.Click += new System.EventHandler(this.toolbuttonOpenMib_Click); + // + // FormMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1028, 650); + this.Controls.Add(this.splitContainerMain); + this.Controls.Add(this.toolStripMain); + this.Name = "FormMain"; + this.Text = "MIB Viewer"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.splitContainerMain.Panel1.ResumeLayout(false); + this.splitContainerMain.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainerMain)).EndInit(); + this.splitContainerMain.ResumeLayout(false); + this.toolStripMain.ResumeLayout(false); + this.toolStripMain.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TreeView treeMib; + private System.Windows.Forms.SplitContainer splitContainerMain; + private System.Windows.Forms.ListView listviewNodeDetails; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ImageList imagelistTreeNodeImages; + private System.Windows.Forms.ToolStrip toolStripMain; + private System.Windows.Forms.ToolStripButton toolbuttonOpenMib; + private System.Windows.Forms.OpenFileDialog dialogOpenMib; + } +} + diff --git a/contrib/apps/LwipMibCompiler/MibViewer/FormMain.cs b/contrib/apps/LwipMibCompiler/MibViewer/FormMain.cs new file mode 100644 index 0000000..7d2490d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/FormMain.cs @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System.Windows.Forms; +using Lextm.SharpSnmpLib.Mib; +using Lextm.SharpSnmpLib.Mib.Elements; +using Lextm.SharpSnmpLib.Mib.Elements.Types; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using System.IO; + +namespace LwipMibViewer +{ + public partial class FormMain : Form + { + readonly ListViewGroup listviewgroupAbstract; + readonly ListViewGroup listviewgroupElement; + readonly ListViewGroup listviewgroupBaseType; + readonly ListViewGroup listviewgroupTypeChain; + + public FormMain() + { + this.Font = SystemInformation.MenuFont; + InitializeComponent(); + + this.listviewgroupAbstract = new ListViewGroup("Abstract", System.Windows.Forms.HorizontalAlignment.Left); + this.listviewgroupElement = new ListViewGroup("Element Properties", System.Windows.Forms.HorizontalAlignment.Left); + this.listviewgroupBaseType = new ListViewGroup("Element Base Type", System.Windows.Forms.HorizontalAlignment.Left); + this.listviewgroupTypeChain = new ListViewGroup("Element Type Chain", System.Windows.Forms.HorizontalAlignment.Left); + this.listviewNodeDetails.Groups.AddRange(new System.Windows.Forms.ListViewGroup[] { + listviewgroupAbstract, + listviewgroupElement, + listviewgroupBaseType, + listviewgroupTypeChain}); + + try + { + DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(Application.ExecutablePath)); + if (dirInfo != null) + { + dirInfo = dirInfo.Parent; + if (dirInfo != null) + { + dirInfo = dirInfo.Parent; + if (dirInfo != null) + { + dirInfo = new DirectoryInfo(Path.Combine(dirInfo.FullName, "Mibs")); + if (dirInfo.Exists) + { + MibTypesResolver.RegisterResolver(new FileSystemMibResolver(dirInfo.FullName, true)); + } + } + } + } + } + catch + { } + } + + #region GUI Event Handler + + private void toolbuttonOpenMib_Click(object sender, System.EventArgs e) + { + if (this.dialogOpenMib.ShowDialog() == DialogResult.OK) + { + OpenMib(this.dialogOpenMib.FileName); + } + } + + private void treeMib_AfterSelect(object sender, TreeViewEventArgs e) + { + listviewNodeDetails.Items.Clear(); + + if (e.Node != null) + { + MibTreeNode mtn = e.Node.Tag as MibTreeNode; + if (mtn != null) + { + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Abstract", mtn.NodeType.ToString() }, this.listviewgroupAbstract)); + + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Module", (mtn.Entity.Module != null) ? mtn.Entity.Module.Name : "" }, this.listviewgroupElement)); + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Type", mtn.Entity.GetType().Name }, this.listviewgroupElement)); + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Name", mtn.Entity.Name }, this.listviewgroupElement)); + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Description", mtn.Entity.Description }, this.listviewgroupElement)); + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "OID", mtn.Entity.Value.ToString() }, this.listviewgroupElement)); + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Full OID", MibTypesResolver.ResolveOid(mtn.Entity).GetOidString() }, this.listviewgroupElement)); + if (mtn.Entity is ObjectType) + { + listviewNodeDetails.Items.Add(new ListViewItem(new string[] { "Access", (mtn.Entity as ObjectType).Access.ToString() }, this.listviewgroupElement)); + } + + ITypeReferrer tr = mtn.Entity as ITypeReferrer; + if (tr != null) + { + ShowTypeDetails(listviewNodeDetails, this.listviewgroupBaseType, tr.BaseType); + ShowTypeChain(listviewNodeDetails, tr.ReferredType); + } + } + } + } + + #endregion + + #region Methods + + private void OpenMib(string file) + { + try + { + MibDocument md = new MibDocument(file); + MibTypesResolver.ResolveTypes(md.Modules[0]); + + this.treeMib.Nodes.Clear(); + this.listviewNodeDetails.Items.Clear(); + + MibTree mt = new MibTree(md.Modules[0] as MibModule); + foreach (MibTreeNode mibTreeNode in mt.Root) + { + AddNode(mibTreeNode, this.treeMib.Nodes); + + foreach (TreeNode node in this.treeMib.Nodes) + { + node.Expand(); + } + } + } + catch + { + } + } + + private void AddNode(MibTreeNode mibNode, TreeNodeCollection parentNodes) + { + int imgIndex = 5; //unknown + if ((mibNode.NodeType & MibTreeNodeType.Table) != 0) + { + imgIndex = 1; + } + else if ((mibNode.NodeType & MibTreeNodeType.TableRow) != 0) + { + imgIndex = 2; + } + else if ((mibNode.NodeType & MibTreeNodeType.TableCell) != 0) + { + imgIndex = 3; + } + else if ((mibNode.NodeType & MibTreeNodeType.Scalar) != 0) + { + imgIndex = 4; + } + else if ((mibNode.NodeType & MibTreeNodeType.Container) != 0) + { + imgIndex = 0; + } + + TreeNode newNode = new TreeNode(mibNode.Entity.Name, imgIndex, imgIndex); + newNode.Tag = mibNode; + + parentNodes.Add(newNode); + + foreach (MibTreeNode child in mibNode.ChildNodes) + { + AddNode(child, newNode.Nodes); + } + } + + private void ShowTypeChain(ListView lv, ITypeAssignment type) + { + ShowTypeDetails(lv, this.listviewgroupTypeChain, type); + + ITypeReferrer tr = type as ITypeReferrer; + if ((tr != null) && (tr.ReferredType != null)) + { + lv.Items.Add(new ListViewItem(new string[] { " >>>", "" }, this.listviewgroupTypeChain)); + ShowTypeChain(listviewNodeDetails, tr.ReferredType); + } + } + + private void ShowTypeDetails(ListView lv, ListViewGroup lvg, ITypeAssignment type) + { + lv.Items.Add(new ListViewItem(new string[] { "Module", (type.Module != null) ? type.Module.Name : "" }, lvg)); + lv.Items.Add(new ListViewItem(new string[] { "Type", type.GetType().Name }, lvg)); + lv.Items.Add(new ListViewItem(new string[] { "Name", type.Name }, lvg)); + } + + #endregion + + } +} diff --git a/contrib/apps/LwipMibCompiler/MibViewer/FormMain.resx b/contrib/apps/LwipMibCompiler/MibViewer/FormMain.resx new file mode 100644 index 0000000..973f546 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/FormMain.resx @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABo + IQAAAk1TRnQBSQFMAgEBBgEAARABAAEQAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEgBgABIBIAAwQBBQMWAR4DIgEyAzEBTwJGAUQBhwMvAUsDHgErAxsBJgMYASIDFQEd + AxIBGAMNARIDCgENAwcBCQMEAQUDAQECAwQBBQMWAR4DIgEyAzEBTgJGAUQBhwMvAUsDHgErAxsBJgMb + ASYDIQExAyEBMAMdASoDGwEmAxgBIQMLAQ8DAQECgAADAgEDAwwBEAMrAUMCRgFEAYIC/wHwAf8CRgFE + AYIDKgFAAw8BFAMNAREDCwEPAwkBDAMHAQoDBQEHAwQBBQMCAQMDAAEBAwIBAwMLAQ8DKwFDAkYBRAGC + Av8B8AH/AkYBRAGCAyoBQAMOARMDEgEZAT0COwFpAVwBRQFCAawBZwE+AToBxAFaAUUBQwGqATwBOwE6 + AWYDEAEWAwABAYQAAx4BKwJEAUIBewL/AfAB/wLpAdoD/wHxAf8CRAFCAXsDHgErJAADHgErAkQBQgF7 + Av8B8AH/AukB2gP/AfEB/wJEAUIBewMeASsBLgItAUcBdwFHATwByQG7AVQBPQHxA+4B/wG7AVMBPAHx + AXcBRgE8AckBLgItAUeEAAMdASoCRAFCAXcC/wHwAf8B6wHdAbEB/wH3AcEBNwH/Ae0B3wGzA/8B8gH/ + AkQBQgF3Ax0BKhwAAx0BKgJEAUIBdwL/AfAB/wLpAdoB/wLqAdwB/wLrAd4D/wHyAf8CRAFCAXcBZAFJ + AUIBrwG2AVkBQQHxAc0BVAEyAf8BvQF5AWIB/wHFAVABLgH/AbEBUQE1AfEBXAFIAUQBn4QAAkMBQQF2 + Av8B8AH/AukB2gH/AecBqwEhAf8B5wGrASEB/wHnAasBIQH/AeoB2wGwA/8B9AH/AkMBQQF2Ax0BKhgA + AkMBQQF2Av8B8AH/AukB2gH/AuoB3AH/AusB3gH/AuwB3wH/Au0B4QP/AfQB/wGAAUQBMQHaAc4BcAFN + AfwBugFMASoB/wPSAf8BvgGLAXgB/wG7AVIBMgH8AW8BSQE/AbqEAAMdASkCQwFBAXQC/wHxAf8B5wHX + AasB/wHXAZYBDAH/AdcBlgEMAf8B1wGWAQwB/wHoAdgBrgP/AfUB/wJDAUEBdAMdASkUAAMdASkCQwFB + AXQC/wHxAf8C6wHeAf8C7AHfAf8C7QHhAf8C7gHjAf8C7wHlAf8BzQF5AV4B/wHOAXcBWAH3AbwBVAEy + Af8BtAFMASoB/wPmAf8BtwFlAUsB8AFdAUkBRAGdiAADHQEpAkIBQQFyAv8B8gH/AeUB1AGpAf8BzQGJ + AQAB/wHNAYkBAAH/Ac0BiQEAAf8B6AHXAa8D/wH3Af8CQgFBAXIDHAEoFAADHQEpAkIBQQFyAv8B8gH/ + Au0B4QH/Au4B4wH/Au8B5QH/AvAB5wH/AeABuwGqAf8BzgFpAUgB/wHjAcsBwQH5BP8B3gHHAb0B9QF+ + AU8BQgHEAi0BLAFFjAADHAEoAkEBQAFxAv8B9AH/AecB1gGsAf8B0QGOAQQB/wHRAY4BBAH/AdEBjgEE + Af8B7AHbAbMD/wH4Af8CQQFAAXEDHAEoFAADHAEoAkEBQAFxAv8B9AH/Au8B5QH/AvAB5wH/AvEB6QH/ + AvMB6gH/AeQBvgGsAf8B1AGBAWIB/wGGAUoBNAHXAWYBTQFEAaoCLQEsAUWUAAMcAScCQQFAAW8C/wH1 + Af8B7AHcAbMB/wHfAaEBFwH/Ad8BoQEXAf8B3wGhARcB/wHxAeIBuwP/AfoB/wJBAUABbwMcAScUAAMc + AScCQQFAAW8C/wH1Af8C8QHpAf8C8wHqAf8C9AHsAf8C9QHuAf8C9gHwA/8B+gH/AkEBQAFvAxwBJ5gA + AxwBJwJAAT8BbQL/AfcB/wHyAeMBuwH/AfABuAEuAf8B8AG4AS4B/wHwAbgBLgH/AvgB9AP/AfsB/wJA + AT8BbQMcAScUAAMcAScCQAE/AW0C/wH3Af8C9AHsAf8C9QHuAf8C9gHwAf8C9wHyAf8C+AH0A/8B+wH/ + AkABPwFtAxwBJ5gAAxsBJgJAAT8BbAL/AfgB/wH3AeoBwwH/Af0ByQE/Af8B+QHsAccB/wL7AfcB/wL8 + AfkD/wH8Af8CQAE/AWwDGwEmFAADGwEmAkABPwFsAv8B+AH/AvYB8AH/AvcB8gH/AvgB9AH/AvsB9wH/ + AvwB+QP/AfwB/wJAAT8BbAMbASaYAAMbASYCPwE+AWsC/wH6Af8C+AH0Af8C+wH3Af8C3wHVAf8CyQG5 + Af8C4AHWA/8B/gH/Aj8BPgFrGAADGwEmAj8BPgFrAv8B+gH/AvgB9AH/AvsB9wH/At8B1QH/AskBuQH/ + AuAB1gP/Af4B/wI/AT4Ba5wAAxoBJQI/AT0BaQL/AfsB/wL8AfkB/wK8AawB/wQAArwBrAP/Af4B/wI/ + AT0BaRwAAxoBJQI/AT0BaQL/AfsB/wL8AfkB/wK8AawB/wQAArwBrAP/Af4B/wI/AT0BaaAAAxoBJQI+ + AT0BaAL/AfwB/wLLAcEB/wKgAZAB/wLLAcED/wH+Af8CPgE9AWggAAMaASUCPgE9AWgC/wH8Af8CywHB + Af8CoAGQAf8CywHBA/8B/gH/Aj4BPQFopAADGgElAj4BPQFnAv8B/gP/Af4D/wH+Bf8CPgE9AWckAAMa + ASUCPgE9AWcC/wH+A/8B/gP/Af4F/wI+AT0BZ6gAAxoBJAI+AT0BZgI+AT0BZgI+AT0BZgI+AT0BZgMx + AU0oAAMaASQCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYDMQFNlAADIQEwAUABRgFIAXwBQwFOAVIBkgMF + AQccAAMHAQkDEAEWAxMBGgMTARoDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEa + AxABFgMHAQkDBwEJAxABFgMTARoDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEa + AxMBGgMQARYDBwEJAwcBCQMQARYDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEaAxMBGgMTARoDEwEa + AxMBGgMTARoDEAEWAwcBCQwAAjIBMwFQAUMBUQFXAZkBRQFkAXQBwAFYAYsBogHgATwBWAFqAcEDEwEa + AwUBBxgAAjwBOwFpAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGH + AkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAjwBOwFpAjkBNAFpAkABNwGHAkABNwGH + AkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGHAkABNwGH + AkABNwGHAkABNwGHAjkBNAFpAjwBOwFpAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGH + AkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAkYBRAGHAjwBOwFpAw0BEQMa + ASQBRAFNAVEBmAE8AYkBrAHyAWcBrwHTAfoBggHLAewB/wGFAc4B7gH/ARUBWwGCAe8BOgFXAWYBxAE6 + AVcBZgHEAT4BWgFqAb4BPgFaAWoBvgE+AVoBagG+AUQBTQFRAZgDGgEkAw0BEQJGAUMBgQL5AekB/wLz + AeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLz + AeIB/wLzAeIB/wL5AekB/wJGAUMBgQJDAToBgQL5AekB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLz + AeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wL5AekB/wJDAToBgQJG + AUMBgQL5AekB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLzAeIB/wLz + AeIB/wLzAeIB/wLzAeIB/wLzAeIB/wL5AekB/wJGAUMBgQMHAQkDDQESAUIBWwFmAbIBiAHQAe8B/wF9 + AcoB6QH/AX0BygHpAf8BhwHQAe8B/wEkAXsBqQH/AX0BvAHbAf8BfQG8AdsB/wGNAdEB8wH/AY0B0QHz + Af8BkAHUAfUB/wFCAVsBZgGyATACMQFNAwcBCQJEAUMBegL0AeQC/wHMAUIB/wH+AcsBQQH/AewB0gGG + Af8C2gHJAf8C2AHHAf8C1gHFAf8C1AHDAf8C0wHCAf8C0QHAAf8CzwG+Af8CzgG9Af8CzQG8Af8C9AHk + Af8CRAFDAXoCRgE+AXoC9AHkAv8BzAFDAf8B/gHLAUIB/wHsAdIBhgH/AtoByQH/AtgBxwH/AtYBxQH/ + AtQBwwH/AtMBwgH/AtEBwAH/As8BvgH/As4BvQH/As0BvAH/AvQB5AH/AkYBPgF6AkQBQwF6AvQB5AL/ + AcwBQgH/Af4BywFBAf8B7AHSAYYB/wLaAckB/wLYAccB/wHnAWEBPwH/AecBYQE/Af8B5wFhAT8B/wHn + AWEBPwH/As8BvgH/As4BvQH/As0BvAH/AvQB5AH/AkQBQwF6CAABQwFXAWABpAGKAdMB8AH/AYIBzQHr + Af8BggHNAesB/wGKAdMB8AH/ASQBfAGrAf8BegG5AdgB/wF6AbkB2AH/AYoBzgHwAf8BigHOAfAB/wGP + AdMB9AH/AfQBtgEsAf8BQwFXAWABpAQAAkQBQgF3AvUB5gL/AcwBQgL/Ae4BiAH/AewB0gGGAf8C9QHu + Af8C9QHuAf8C1gHFAf8C9QHuAf8C9QHuAf8C0QHAAf8C9QHuAf8C9QHuAf8CzQG8Af8C9QHmAf8CRAFC + AXcCRwE/AXcC9QHmAv8BzAFDAv8B7gGIAf8B7AHSAYYB/wL1Ae4B/wL1Ae4B/wLWAcUB/wL1Ae4B/wL1 + Ae4B/wLRAcAB/wL1Ae4B/wL1Ae4B/wLNAbwB/wL1AeYB/wJHAT8BdwJEAUIBdwL1AeYC/wHMAUIC/wHu + AYgB/wHsAdIBhgH/AvUB7gH/AvUB7gH/AdkBWAE2Af8B8gHJAbgB/wHyAckBuAH/AdkBWAE2Af8C9QHu + Af8C9QHuAf8CzQG8Af8C9QHmAf8CRAFCAXcIAAFDAVUBXgGeAY4B1gHyAf8BhwHQAe0B/wGHAdAB7QH/ + AY4B1gHyAf8BJgGCAa8B/wF7AboB2AH/AXsBugHYAf8BiwHPAfEB/wGLAc8B8QH/AZEB1QH1Af8B/gHJ + AT8B/wFDAVUBXgGeBAACQwFBAXUC9gHpAv8BzAFCAf8B/gHLAUEB/wHsAdIBhgH/AtoByQH/AtgBxwH/ + AtwBzAH/AtQBwwH/AtMBwgH/AtgByAH/As8BvgH/As4BvQH/As0BvAH/AvYB6QH/AkMBQQF1AkcBPwF1 + AvYB6QL/AcwBQwH/Af4BywFCAf8B7AHSAYYB/wLaAckB/wLYAccB/wLcAcwB/wLUAcMB/wLTAcIB/wLY + AcgB/wLPAb4B/wLOAb0B/wLNAbwB/wL2AekB/wJHAT8BdQJDAUEBdQL2AekC/wHMAUIB/wH+AcsBQQH/ + AewB0gGGAf8C2gHJAf8C2AHHAf8ByAFPAS0B/wHeAbYBngH/Ad4BtQGdAf8ByAFPAS0B/wLPAb4B/wLO + Ab0B/wLNAbwB/wL2AekB/wJDAUEBdQgAAUQBVQFdAZsBkgHaAfQB/wGLAdQB8AH/AYsB1AHwAf8BkgHa + AfQB/wEpAYUBswH/AX0BvAHaAf8BfQG8AdoB/wGNAdEB8wH/AY0B0QHzAf8BkwHXAfYB/wLrAd0B/wFE + AVUBXQGbBAACQgFBAXMC9wHrAv8BzAFCAv8B7gGIAf8B7AHSAYYB/wL3AfEB/wL3AfEB/wLWAcUB/wL3 + AfEB/wL3AfEB/wLRAcAB/wL3AfEB/wL3AfEB/wLNAbwB/wL3AesB/wJCAUEBcwJHAT8BcwL3AesC/wHM + AUMC/wHuAYgB/wHsAdIBhgH/AvcB8QH/AvcB8QH/AtYBxQH/AvcB8QH/AvcB8QH/AtEBwAH/AvcB8QH/ + AvcB8QH/As0BvAH/AvcB6wH/AkcBPwFzAkIBQQFzAvcB6wL/AcwBQgL/Ae4BiAH/AewB0gGGAf8C9wHx + Af8C9wHxAf8BuAFHASUB/wHzAcsBuQH/AfMBywG5Af8BuAFHASUB/wL3AfEB/wL3AfEB/wLNAbwB/wL3 + AesB/wJCAUEBcwgAAUQBUwFbApcB3gH2Af8BkAHYAfIB/wGQAdgB8gH/AZcB3gH2Af8BKwGJAbcB/wGA + Ab0B3AH/AYABvQHcAf8BjwHTAfUB/wGPAdMB9QH/AZUB2QH4Af8C9QHuAf8BRAFTAVsBlwQAAkIBQQFy + AvgB7gL/AcwBQgH/Af4BywFBAf8B7AHSAYYB/wLaAckB/wLYAccB/wLdAc4B/wLUAcMB/wLTAcIB/wLZ + AcoB/wLPAb4B/wLOAb0B/wLNAbwB/wL4Ae4B/wJCAUEBcgJIAUABcgL4Ae4B/wHsAYYBYwH/AeIBewFZ + Af8B1AFuAUwB/wHEAWABPgH/AbYBUgEwAf8BrQFHASUB/wGrAUMBIQH/AbEBRAEiAf8BvQFKASgB/wHM + AVIBMAH/AdsBWgE4Af8B6AFiAUAB/wL4Ae4B/wJIAUABcgJCAUEBcgL4Ae4C/wHMAUIB/wH+AcsBQQH/ + AewB0gGGAf8C2gHJAf8C2AHHAf8BrQFCASAB/wHeAbYBngH/Ad4BtQGdAf8BrQFCASAB/wLPAb4B/wLO + Ab0B/wLNAbwB/wL4Ae4B/wJCAUEBcggAAUQBUwFaAZQBmwHhAfcB/wGUAdsB9AH/AZQB2wH0Af8BmwHh + AfcB/wEuAY0BvAH/AYEBvgHdAf8BgQG+Ad0B/wGQAdQB9gH/AZAB1AH2Af8BlwHbAfkB/wL+Af0B/wFE + AVMBWgGUBAACQQFAAXAC+QHxAv8BzAFCAv8B7gGIAf8B7AHSAYYB/wL5AfUB/wL5AfUB/wLWAcUB/wL5 + AfUB/wL5AfUB/wLRAcAB/wL5AfUB/wL5AfUB/wLNAbwB/wL5AfEB/wJBAUABcAJHAUABcAL5AfEB/wHs + AYYBYwH/AfgBxQF5Af8B7QG1AXgB/wH1AcwBvAH/AfUBzAG8Af8B4AG3AZ8B/wH1AcwBvAH/AfUBzAG8 + Af8B3QG0AZwB/wH1AcwBvAH/AfUBzAG8Af8B6AFiAUAB/wL5AfEB/wJHAUABcAJBAUABcAL5AfEC/wHM + AUIC/wHuAYgB/wHsAdIBhgH/AvkB9QH/AvkB9QH/AasBRAEiAf8B9QHMAbwB/wH1AcwBvAH/AasBRAEi + Af8C+QH1Af8C+QH1Af8CzQG8Af8C+QHxAf8CQQFAAXAIAAFEAVEBVwGQAZ4B5QH5Af8BmAHfAfYB/wGY + Ad8B9gH/AZ4B5QH5Af8BMAGQAcAB/wGDAcAB3wH/AYMBwAHfAf8BkgHWAfgB/wGSAdYB+AH/AZkB3QH6 + Af8BRAFRAVcBkAMjATMEAAJBAUABbgL7AfQC/wHMAUIB/wH+AcsBQQH/AewB0gGGAf8C2gHJAf8C2AHH + Af8C3gHQAf8C1AHDAf8C0wHCAf8C2gHMAf8CzwG+Af8CzgG9Af8CzQG8Af8C+wH0Af8CQQFAAW4CRwFA + AW4C+wH0Af8B7AGGAWMB/wHiAXsBWQH/AdQBbgFMAf8BxAFgAT4B/wG2AVIBMAH/Aa0BRwElAf8BqwFD + ASEB/wGxAUQBIgH/Ab0BSgEoAf8BzAFSATAB/wHbAVoBOAH/AegBYgFAAf8C+wH0Af8CRwFAAW4CQQFA + AW4C+wH0Av8BzAFCAf8B/gHLAUEB/wHsAdIBhgH/AtoByQH/AtgBxwH/AbIBTAEqAf8B3gG2AZ4B/wHe + AbUBnQH/AbIBTAEqAf8CzwG+Af8CzgG9Af8CzQG8Af8C+wH0Af8CQQFAAW4IAAFDAU8BVQGNAaMB6AH7 + Af8BnQHjAfkB/wGdAeMB+QH/AaMB6AH7Af8BMwGUAcUB/wGFAcIB4QH/AYUBwgHhAf8BlAHYAfoB/wGU + AdgB+gH/AZsB3wH8Af8BQwFPAVUBjQgAAkABPwFtAvwB9wL/AcwBQgL/Ae4BiAH/AewB0gGGAf8C/AH6 + Af8C/AH6Af8C1gHFAf8C/AH6Af8C/AH6Af8C0QHAAf8C/AH6Af8C/AH6Af8CzQG8Af8C/AH3Af8CQAE/ + AW0CRwFAAW0C/AH3Av8BzAFDAv8B7gGIAf8B7AHSAYYB/wL8AfoB/wL8AfoB/wLWAcUB/wL8AfoB/wL8 + AfoB/wLRAcAB/wL8AfoB/wL8AfoB/wLNAbwB/wL8AfcB/wJHAUABbQJAAT8BbQL8AfcC/wHMAUIC/wHu + AYgB/wHsAdIBhgH/AvwB+gH/AvwB+gH/AcABWgE4Af8B9gHOAb8B/wH2Ac4BvwH/AcABWgE4Af8C/AH6 + Af8C/AH6Af8CzQG8Af8C/AH3Af8CQAE/AW0IAAFDAU8BVAGKAaYB6wH8Af8BoQHmAfsB/wGhAeYB+wH/ + AaYB6wH8Af8BOgGdAc8B/wGHAcQB4gH/AYcBxAHiAf8BlgHaAfwB/wGWAdoB/AH/AZ4B4gH9Af8BQwFP + AVQBiggAAj8BPgFrAv0B+QL/AcwBQgH/Af4BywFBAf8B9QHOAWIB/wHrAdIBhQH/AekB0AGDAf8B5wHO + AYEB/wHlAcwBgAH/AeQBywF8Af8B4gHJAXoB/wHgAccBeAH/Ad8BxgF3Af8B3gHFAXYB/wL9AfkB/wI/ + AT4BawJHAUABawL9AfkC/wHMAUMB/wH+AcsBQgH/AfUBzgFjAf8B6wHSAYUB/wHpAdABgwH/AecBzgGB + Af8B5QHMAYAB/wHkAcsBfQH/AeIByQF7Af8B4AHHAXkB/wHfAcYBeAH/Ad4BxQF3Af8C/QH5Af8CRwFA + AWsCPwE+AWsC/QH5Av8BzAFCAf8B/gHLAUEB/wH1Ac4BYgH/AesB0gGFAf8B6QHQAYMB/wHRAWoBSAH/ + AekBsQF0Af8B6AGwAXMB/wHRAWoBSAH/AeABxwF4Af8B3wHGAXcB/wHeAcUBdgH/Av0B+QH/Aj8BPgFr + CAABQgFNAVIBhwGpAe4B/QH/AaQB6QH8Af8BpAHpAfwB/wGqAe8B/QH/AUABoQHRAf8BkAHRAfEB/wGW + AdoB+wH/AZcB2wH9Af8BlwHbAf0B/wGfAeMB/gH/AUIBTQFSAYcIAAI/AT4BagL+AfwC/wHMAUIC/wHu + AYgB/wH9AcoBQAH/AfwB6wGFAf8B+wHqAYQB/wH4AcUBOwH/AfYB5QF9Af8B9AHjAXsB/wHzAcABNgH/ + AfEB4AF4Af8B7wHeAXYB/wHvAbwBMgH/Av4B/AH/Aj8BPgFqAkcBQAFqAv4B/AL/AcwBQwL/Ae4BiAH/ + Af0BygFBAf8B/AHrAYUB/wH7AeoBhAH/AfgBxQE8Af8B9gHlAX4B/wH0AeMBfAH/AfMBwAE3Af8B8QHg + AXkB/wHvAd4BdwH/Ae8BvAEzAf8C/gH8Af8CRwFAAWoCPwE+AWoC/gH8Av8BzAFCAv8B7gGIAf8B/QHK + AUAB/wH8AesBhQH/AfsB6gGEAf8B4QF5AVcB/wHzAcABcwH/AfIBvwFyAf8B4QF5AVcB/wHxAeABeAH/ + Ae8B3gF2Af8B7wG8ATIB/wL+AfwB/wI/AT4BaggAAUMBTAFSAYUBrQHxAv8BqwHvAf4B/wGVAeIB+AH/ + AWwByQHtAf8BRgGpAdkB/wGYAdwB/gH/AZgB3AH+Af8BmAHcAf4B/wGYAdwB/gH/AaEB5QL/AUMBTAFS + AYUIAAI+AT0BaAL/Af4C/wHMAUIB/wH+AcsBQQH/Af0BygFAAf8B/AHJAT8B/wH6AccBPQH/AfgBxQE7 + Af8B9gHDAToB/wH1AcIBOAH/AfMBwAE2Af8B8QG+ATQB/wHwAb0BMwH/Ae8BvAEyA/8B/gH/Aj4BPQFo + AkcBQAFoAv8B/gL/AcwBQwH/Af4BywFCAf8B/QHKAUEB/wH8AckBQAH/AfoBxwE+Af8B+AHFATwB/wH2 + AcMBOwH/AfUBwgE5Af8B8wHAATcB/wHxAb4BNQH/AfABvQE0Af8B7wG8ATMD/wH+Af8CRwFAAWgCPgE9 + AWgC/wH+Av8BzAFCAf8B/gHLAUEB/wH9AcoBQAH/AfwByQE/Af8B+gHHAT0B/wHsAYYBYgH/AewBhgFi + Af8B7AGGAWIB/wHsAYYBYgH/AfEBvgE0Af8B8AG9ATMB/wHvAbwBMgP/Af4B/wI+AT0BaAgAAUMBTAFQ + AYMBiAHcAfQB/wFeAcAB6QH/AV0BvwHqAf8BgAHTAfQB/wGcAeMB/QH/AaIB5gL/AaIB5gL/AaIB5gL/ + AaIB5gL/AaYB6gL/AUMBTAFQAYMIAAI+AT0BZzj/Aj4BPQFnAkcBQAFnOP8CRwFAAWcCPgE9AWc4/wI+ + AT0BZwgAATkBOwE9AWEBQgFLAU8BgQFCAUsBTwGBAUIBSwFPAYEBQgFLAU8BgQFCAUsBTwGBAUIBSwFP + AYEBQgFLAU8BgQFCAUsBTwGBAUIBSwFPAYEBQgFLAU8BgQE5ATsBPQFhCAADMQFNAj4BPQFmAj4BPQFm + Aj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFmAj4BPQFm + Aj4BPQFmAj4BPQFmAzEBTQI3ATQBTQJHAUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgJH + AUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgJHAUABZgI3ATQBTQMxAU0CPgE9 + AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9AWYCPgE9 + AWYCPgE9AWYCPgE9AWYCPgE9AWYDMQFNAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYA + A/8RAAGAAf8BgAEBBQABfwEAAQEFAAE/AQABAQUAAR8BAAEBBAABgAEPAYABAQQAAcABBwHAAQMEAAHg + AQMB4AEDBAAB8AEBAfABAQQAAfgBAAH4BQAB/AEAAfwFAAH+AQgB/gEIBAAB/wEAAf8FAAH/AYAB/wGA + BAAB/wHAAf8BwAQAAfgBfwYAAeABPxYAAcABAQYAAcABAQYAAcABAQYAAcABAQYAAcABAQYAAcABAQYA + AcABAwYAAcABAwYAAcABAwYAAcABAwYAAcABAwYAAcABAwYACw== + + + + 211, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAK6SURBVDhPjZNbSNNRHMfPU9DtwR71oZf5IgkF0YMEEYb2 + EGgG5YNgGQmGSUoYimbel5KKmlM0u3jJSpv3ad7WnGkzb2yO4bByF3WuuTnnnLv47Zw/9YclQQc+/L// + P+d8/r/f+Z8/Ib/HjJDcmhaS3P+Bzf2zjr8qiki+QyuE6dNNbIzFw6F8DJ++AVh97c9GK9jcA4LJAlKI + rQ7sW9/DpauGZSoFg6JwfJSU+TE0XIXOgqCaAwJ5ASn2bb6F19TM4bO+w4z4HgwWC9YcDugpK3Y7umQy + FOZEDMRkZQX7SWS5pMRrboVn9RUHy1/aEqDSajGn0WDZbIZ6bQ0t/f1gIzojI8lPMvaIPPWsN2FP/5yD + ZdmLWLwUi/FhZASSqSlOUtXczBMcGZnFVzGUTSr2jI1wfq/lYHms4Tqkc3MYnZ2F0mDAqs3GV8LaiUhN + TeYFA5mkenelHg5tNQfLw3UxaOrpQZdUiu7xca5/Mc0do6PQb28jPDk5hRf0PiQi5zcR7JoKDpYHaqIg + VyohW1jg+lcZjVwlCzod1p1OXEhMvM8LOtNJvWOpEjZVKQfL/ZVX0NrXh165HP2Tk5hQqzGuUmFQocCm + y4XzCQlpvKA9jTTa1WWwzBdzsNxdfhmfFxcxQRct0Q3UmEzY2t2FdWcHdrcb5+LiHvCC1hTSbFOWwDyT + x8GyuDQCbRIJ3tBPp6CfU0pbcdA3M4mDCs7ExqYzwWHKibo7pNs6T4+yIofDSqtof3IJBtqzTq+Hx+uF + y+OBky5kkh2aT0VFZTNBAEWQFEFqhyvO2pclSe6f03nYnC1EW9FFGOnGGSi+/X14KW6fD3tUtkdzYFiY + 0O801iWSaNFtUteWGST92nL1R/q1Q7ojAkHV0ZCQkuOhocV/c0wguHvgn2APyuPJ6dI4kpV/gzyjtycp + gf8g4Begs1B6Kbj3cQAAAABJRU5ErkJggg== + + + + 337, 17 + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/MibViewer/MibViewer.csproj b/contrib/apps/LwipMibCompiler/MibViewer/MibViewer.csproj new file mode 100644 index 0000000..957c058 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/MibViewer.csproj @@ -0,0 +1,94 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {86CC0B65-7985-4017-A252-0A7A18DCAEF3} + WinExe + Properties + LwipMibViewer + MibViewer + v4.0 + 512 + + + + true + bin\Debug\ + DEBUG;TRACE + full + prompt + true + true + 4 + false + false + + + bin\Release\ + TRACE + true + pdbonly + AnyCPU + prompt + true + true + 4 + false + + + + + + + + + Form + + + FormMain.cs + + + + + FormMain.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {CBE20411-5DB7-487D-825D-7694267BB6F5} + SharpSnmpLib.Mib + + + + + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Program.cs b/contrib/apps/LwipMibCompiler/MibViewer/Program.cs new file mode 100644 index 0000000..cd3ef31 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Program.cs @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +using System; +using System.Windows.Forms; + +namespace LwipMibViewer +{ + static class Program + { + /// + /// Der Haupteinstiegspunkt für die Anwendung. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new FormMain()); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Properties/AssemblyInfo.cs b/contrib/apps/LwipMibCompiler/MibViewer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..06e7286 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("LwipMibViewer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LwipMibViewer")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("7ffbd1c1-1c64-45bb-b243-2400446c649d")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.Designer.cs b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.Designer.cs new file mode 100644 index 0000000..bf15717 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.225 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace LwipMibViewer.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LwipMibViewer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.resx b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.Designer.cs b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.Designer.cs new file mode 100644 index 0000000..9831b20 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.225 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace LwipMibViewer.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.settings b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/contrib/apps/LwipMibCompiler/MibViewer/app.config b/contrib/apps/LwipMibCompiler/MibViewer/app.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/MibViewer/app.config @@ -0,0 +1,3 @@ + + + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB new file mode 100644 index 0000000..1010795 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB @@ -0,0 +1,131 @@ + + + IANA-ADDRESS-FAMILY-NUMBERS-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, + mib-2 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + + ianaAddressFamilyNumbers MODULE-IDENTITY + LAST-UPDATED "200203140000Z" -- March 14, 2002 + ORGANIZATION "IANA" + CONTACT-INFO + "Postal: Internet Assigned Numbers Authority + Internet Corporation for Assigned Names + and Numbers + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292-6601 + USA + + Tel: +1 310-823-9358 + E-Mail: iana&iana.org" + DESCRIPTION + "The MIB module defines the AddressFamilyNumbers + textual convention." + + -- revision history + + REVISION "200203140000Z" -- March 14, 2002 + DESCRIPTION "AddressFamilyNumbers assignment 22 to + fibreChannelWWPN. AddressFamilyNumbers + assignment 23 to fibreChannelWWNN. + AddressFamilyNumers assignment 24 to gwid." + + REVISION "200009080000Z" -- September 8, 2000 + DESCRIPTION "AddressFamilyNumbers assignment 19 to xtpOverIpv4. + AddressFamilyNumbers assignment 20 to xtpOverIpv6. + AddressFamilyNumbers assignment 21 to xtpNativeModeXTP." + + REVISION "200003010000Z" -- March 1, 2000 + DESCRIPTION "AddressFamilyNumbers assignment 17 to distinguishedName. + AddressFamilyNumbers assignment 18 to asNumber." + + REVISION "200002040000Z" -- February 4, 2000 + DESCRIPTION "AddressFamilyNumbers assignment 16 to dns." + + REVISION "9908260000Z" -- August 26, 1999 + DESCRIPTION "Initial version, published as RFC 2677." + + ::= { mib-2 72 } + + + AddressFamilyNumbers ::= TEXTUAL-CONVENTION + + STATUS current + DESCRIPTION + "The definition of this textual convention with the + addition of newly assigned values is published + periodically by the IANA, in either the Assigned + Numbers RFC, or some derivative of it specific to + Internet Network Management number assignments. + (The latest arrangements can be obtained by + contacting the IANA.) + + The enumerations are described as: + + other(0), -- none of the following + ipV4(1), -- IP Version 4 + ipV6(2), -- IP Version 6 + nsap(3), -- NSAP + hdlc(4), -- (8-bit multidrop) + bbn1822(5), + all802(6), -- (includes all 802 media + -- plus Ethernet 'canonical format') + e163(7), + e164(8), -- (SMDS, Frame Relay, ATM) + f69(9), -- (Telex) + x121(10), -- (X.25, Frame Relay) + ipx(11), -- IPX (Internet Protocol Exchange) + appleTalk(12), -- Apple Talk + decnetIV(13), -- DEC Net Phase IV + banyanVines(14), -- Banyan Vines + e164withNsap(15), + -- (E.164 with NSAP format subaddress) + dns(16), -- (Domain Name System) + distinguishedName(17), -- (Distinguished Name, per X.500) + asNumber(18), -- (16-bit quantity, per the AS number space) + xtpOverIpv4(19), -- XTP over IP version 4 + xtpOverIpv6(20), -- XTP over IP version 6 + xtpNativeModeXTP(21), -- XTP native mode XTP + fibreChannelWWPN(22), -- Fibre Channel World-Wide Port Name + fibreChannelWWNN(23), -- Fibre Channel World-Wide Node Name + gwid(24), -- Gateway Identifier + afi(25), -- AFI for L2VPN information + reserved(65535) + + + + Requests for new values should be made to IANA via + email (iana&iana.org)." + + SYNTAX INTEGER { + other(0), + ipV4(1), + ipV6(2), + nsap(3), + hdlc(4), + bbn1822(5), + all802(6), + e163(7), + e164(8), + f69(9), + x121(10), + ipx(11), + appleTalk(12), + decnetIV(13), + banyanVines(14), + e164withNsap(15), + dns(16), + distinguishedName(17), -- (Distinguished Name, per X.500) + asNumber(18), -- (16-bit quantity, per the AS number space) + xtpOverIpv4(19), + xtpOverIpv6(20), + xtpNativeModeXTP(21), + fibreChannelWWPN(22), + fibreChannelWWNN(23), + gwid(24), + afi(25), + reserved(65535) + } + END diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA-CHARSET-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA-CHARSET-MIB new file mode 100644 index 0000000..499d54e --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA-CHARSET-MIB @@ -0,0 +1,345 @@ +IANA-CHARSET-MIB DEFINITIONS ::= BEGIN +-- http://www.iana.org/assignments/ianacharset-mib + +IMPORTS + MODULE-IDENTITY, + mib-2 + FROM SNMPv2-SMI -- [RFC2578] + TEXTUAL-CONVENTION + FROM SNMPv2-TC; -- [RFC2579] + +ianaCharsetMIB MODULE-IDENTITY + LAST-UPDATED "200705140000Z" + ORGANIZATION "IANA" + CONTACT-INFO " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + E-Mail: iana&iana.org" + + DESCRIPTION "This MIB module defines the IANACharset + TEXTUAL-CONVENTION. The IANACharset TC is used to + specify the encoding of string objects defined in + a MIB. + + Each version of this MIB will be released based on + the IANA Charset Registry file (see RFC 2978) at + http://www.iana.org/assignments/character-sets. + + Note: The IANACharset TC, originally defined in + RFC 1759, was inaccurately named CodedCharSet. + + Note: Best practice is to define new MIB string + objects with invariant UTF-8 (RFC 3629) syntax + using the SnmpAdminString TC (defined in RFC 3411) + in accordance with IETF Policy on Character Sets and + Languages (RFC 2277). + + Copyright (C) The Internet Society (2004). The + initial version of this MIB module was published + in RFC 3808; for full legal notices see the RFC + itself. Supplementary information may be + available on + http://www.ietf.org/copyrights/ianamib.html." + + -- revision history + + REVISION "200705140000Z" + DESCRIPTION "Registration of new charset 2107." + + REVISION "200612070000Z" + DESCRIPTION "Registration of new charsets numbered 118, 119, + and 2106." + + REVISION "200406080000Z" + DESCRIPTION "Original version transferred from Printer MIB, + generated from the IANA maintained assignments + http://www.iana.org/assignments/character-sets." + + ::= { mib-2 106 } + +IANACharset ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Specifies an IANA registered 'charset' - coded character set + (CCS) plus optional character encoding scheme (CES) - terms + defined in 'IANA Charset Registration Procedures' (RFC 2978). + + Objects of this syntax are used to specify the encoding for + string objects defined in one or more MIBs. For example, the + prtLocalizationCharacterSet, prtInterpreterDefaultCharSetIn, and + prtInterpreterDefaultCharSetOut objects defined in Printer MIB. + + The current list of 'charset' names and enumerated values + is contained in the IANA Character Set Registry at: + + http://www.iana.org/assignments/character-sets + + Enum names are derived from the IANA Charset Registry 'Alias' + fields that begin with 'cs' (for character set). + Enum values are derived from the parallel 'MIBenum' fields." + SYNTAX INTEGER { + other(1), -- used if the designated + -- character set is not currently + -- registered by IANA + unknown(2), -- used as a default value + csASCII(3), + csISOLatin1(4), + csISOLatin2(5), + csISOLatin3(6), + csISOLatin4(7), + csISOLatinCyrillic(8), + csISOLatinArabic(9), + csISOLatinGreek(10), + csISOLatinHebrew(11), + csISOLatin5(12), + csISOLatin6(13), + csISOTextComm(14), + csHalfWidthKatakana(15), + csJISEncoding(16), + csShiftJIS(17), + csEUCPkdFmtJapanese(18), + csEUCFixWidJapanese(19), + csISO4UnitedKingdom(20), + csISO11SwedishForNames(21), + csISO15Italian(22), + csISO17Spanish(23), + csISO21German(24), + csISO60DanishNorwegian(25), + csISO69French(26), + csISO10646UTF1(27), + csISO646basic1983(28), + csINVARIANT(29), + csISO2IntlRefVersion(30), + csNATSSEFI(31), + csNATSSEFIADD(32), + csNATSDANO(33), + csNATSDANOADD(34), + csISO10Swedish(35), + csKSC56011987(36), + csISO2022KR(37), + csEUCKR(38), + csISO2022JP(39), + csISO2022JP2(40), + csISO13JISC6220jp(41), + csISO14JISC6220ro(42), + csISO16Portuguese(43), + csISO18Greek7Old(44), + csISO19LatinGreek(45), + csISO25French(46), + csISO27LatinGreek1(47), + csISO5427Cyrillic(48), + csISO42JISC62261978(49), + csISO47BSViewdata(50), + csISO49INIS(51), + csISO50INIS8(52), + csISO51INISCyrillic(53), + csISO54271981(54), + csISO5428Greek(55), + csISO57GB1988(56), + csISO58GB231280(57), + csISO61Norwegian2(58), + csISO70VideotexSupp1(59), + csISO84Portuguese2(60), + csISO85Spanish2(61), + csISO86Hungarian(62), + csISO87JISX0208(63), + csISO88Greek7(64), + csISO89ASMO449(65), + csISO90(66), + csISO91JISC62291984a(67), + csISO92JISC62991984b(68), + csISO93JIS62291984badd(69), + csISO94JIS62291984hand(70), + csISO95JIS62291984handadd(71), + csISO96JISC62291984kana(72), + csISO2033(73), + csISO99NAPLPS(74), + csISO102T617bit(75), + csISO103T618bit(76), + csISO111ECMACyrillic(77), + csa71(78), + csa72(79), + csISO123CSAZ24341985gr(80), + csISO88596E(81), + csISO88596I(82), + csISO128T101G2(83), + csISO88598E(84), + csISO88598I(85), + csISO139CSN369103(86), + csISO141JUSIB1002(87), + csISO143IECP271(88), + csISO146Serbian(89), + csISO147Macedonian(90), + csISO150(91), + csISO151Cuba(92), + csISO6937Add(93), + csISO153GOST1976874(94), + csISO8859Supp(95), + csISO10367Box(96), + csISO158Lap(97), + csISO159JISX02121990(98), + csISO646Danish(99), + csUSDK(100), + csDKUS(101), + csKSC5636(102), + csUnicode11UTF7(103), + csISO2022CN(104), + csISO2022CNEXT(105), + csUTF8(106), + csISO885913(109), + csISO885914(110), + csISO885915(111), + csISO885916(112), + csGBK(113), + csGB18030(114), + csOSDEBCDICDF0415(115), + csOSDEBCDICDF03IRV(116), + csOSDEBCDICDF041(117), + csISO115481(118), + csKZ1048(119), + csUnicode(1000), + csUCS4(1001), + csUnicodeASCII(1002), + csUnicodeLatin1(1003), + csUnicodeIBM1261(1005), + csUnicodeIBM1268(1006), + csUnicodeIBM1276(1007), + csUnicodeIBM1264(1008), + csUnicodeIBM1265(1009), + csUnicode11(1010), + csSCSU(1011), + csUTF7(1012), + csUTF16BE(1013), + csUTF16LE(1014), + csUTF16(1015), + csCESU8(1016), + csUTF32(1017), + csUTF32BE(1018), + csUTF32LE(1019), + csBOCU1(1020), + csWindows30Latin1(2000), + csWindows31Latin1(2001), + csWindows31Latin2(2002), + csWindows31Latin5(2003), + csHPRoman8(2004), + csAdobeStandardEncoding(2005), + csVenturaUS(2006), + csVenturaInternational(2007), + csDECMCS(2008), + csPC850Multilingual(2009), + csPCp852(2010), + csPC8CodePage437(2011), + csPC8DanishNorwegian(2012), + csPC862LatinHebrew(2013), + csPC8Turkish(2014), + csIBMSymbols(2015), + csIBMThai(2016), + csHPLegal(2017), + csHPPiFont(2018), + csHPMath8(2019), + csHPPSMath(2020), + csHPDesktop(2021), + csVenturaMath(2022), + csMicrosoftPublishing(2023), + csWindows31J(2024), + csGB2312(2025), + csBig5(2026), + csMacintosh(2027), + csIBM037(2028), + csIBM038(2029), + csIBM273(2030), + csIBM274(2031), + csIBM275(2032), + csIBM277(2033), + csIBM278(2034), + csIBM280(2035), + csIBM281(2036), + csIBM284(2037), + csIBM285(2038), + csIBM290(2039), + csIBM297(2040), + csIBM420(2041), + csIBM423(2042), + csIBM424(2043), + csIBM500(2044), + csIBM851(2045), + csIBM855(2046), + csIBM857(2047), + csIBM860(2048), + csIBM861(2049), + csIBM863(2050), + csIBM864(2051), + csIBM865(2052), + csIBM868(2053), + csIBM869(2054), + csIBM870(2055), + csIBM871(2056), + csIBM880(2057), + csIBM891(2058), + csIBM903(2059), + csIBBM904(2060), + csIBM905(2061), + csIBM918(2062), + csIBM1026(2063), + csIBMEBCDICATDE(2064), + csEBCDICATDEA(2065), + csEBCDICCAFR(2066), + csEBCDICDKNO(2067), + csEBCDICDKNOA(2068), + csEBCDICFISE(2069), + csEBCDICFISEA(2070), + csEBCDICFR(2071), + csEBCDICIT(2072), + csEBCDICPT(2073), + csEBCDICES(2074), + csEBCDICESA(2075), + csEBCDICESS(2076), + csEBCDICUK(2077), + csEBCDICUS(2078), + csUnknown8BiT(2079), + csMnemonic(2080), + csMnem(2081), + csVISCII(2082), + csVIQR(2083), + csKOI8R(2084), + csHZGB2312(2085), + csIBM866(2086), + csPC775Baltic(2087), + csKOI8U(2088), + csIBM00858(2089), + csIBM00924(2090), + csIBM01140(2091), + csIBM01141(2092), + csIBM01142(2093), + csIBM01143(2094), + csIBM01144(2095), + csIBM01145(2096), + csIBM01146(2097), + csIBM01147(2098), + csIBM01148(2099), + csIBM01149(2100), + csBig5HKSCS(2101), + csIBM1047(2102), + csPTCP154(2103), + csAmiga1251(2104), + csKOI7switched(2105), + csBRF(2106), + csTSCII(2107), + cswindows1250(2250), + cswindows1251(2251), + cswindows1252(2252), + cswindows1253(2253), + cswindows1254(2254), + cswindows1255(2255), + cswindows1256(2256), + cswindows1257(2257), + cswindows1258(2258), + csTIS620(2259), + reserved(3000) + } +END + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-ITU-ALARM-TC-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-ITU-ALARM-TC-MIB new file mode 100644 index 0000000..8579485 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-ITU-ALARM-TC-MIB @@ -0,0 +1,333 @@ +IANA-ITU-ALARM-TC-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, mib-2 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + + ianaItuAlarmNumbers MODULE-IDENTITY + LAST-UPDATED "200409090000Z" -- September 09, 2004 + ORGANIZATION "IANA" + CONTACT-INFO + "Postal: Internet Assigned Numbers Authority + Internet Corporation for Assigned Names + and Numbers + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292-6601 + USA + + Tel: +1 310-823-9358 + E-Mail: iana&iana.org" + DESCRIPTION + "The MIB module defines the ITU Alarm + textual convention for objects expected to require + regular extension. + + Copyright (C) The Internet Society (2004). The + initial version of this MIB module was published + in RFC 3877. For full legal notices see the RFC + itself. Supplementary information may be available on: + http://www.ietf.org/copyrights/ianamib.html" + REVISION "200409090000Z" + DESCRIPTION + "Initial version, published as RFC 3877." + ::= { mib-2 119 } + + + IANAItuProbableCause ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "ITU-T probable cause values. Duplicate values defined in + X.733 are appended with X733 to ensure syntactic uniqueness. + Probable cause value 0 is reserved for special purposes. + + The Internet Assigned Number Authority (IANA) is responsible + for the assignment of the enumerations in this TC. + IANAItuProbableCause value of 0 is reserved for special + purposes and MUST NOT be assigned. + + Values of IANAItuProbableCause in the range 1 to 1023 are + reserved for causes that correspond to ITU-T probable cause. + + All other requests for new causes will be handled on a + first-come, first served basis and will be assigned + enumeration values starting with 1025. + + Request should come in the form of well-formed + SMI [RFC2578] for enumeration names that are unique and + sufficiently descriptive. + + While some effort will be taken to ensure that new probable + causes do not conceptually duplicate existing probable + causes it is acknowledged that the existence of conceptual + duplicates in the starting probable cause list is an known + industry reality. + + To aid IANA in the administration of probable cause names + and values, the OPS Area Director will appoint one or more + experts to help review requests. + + See http://www.iana.org" + REFERENCE + "ITU Recommendation M.3100, 'Generic Network Information + Model', 1995 + ITU Recommendation X.733, 'Information Technology - Open + Systems Interconnection - System Management: Alarm + Reporting Function', 1992 + ITU Recommendation X.736, 'Information Technology - Open + Systems Interconnection - System Management: Security + Alarm Reporting Function', 1992" + + SYNTAX INTEGER + { + -- The following probable causes were defined in M.3100 + aIS (1), + callSetUpFailure (2), + degradedSignal (3), + farEndReceiverFailure (4), + framingError (5), + lossOfFrame (6), + lossOfPointer (7), + lossOfSignal (8), + payloadTypeMismatch (9), + transmissionError (10), + remoteAlarmInterface (11), + excessiveBER (12), + pathTraceMismatch (13), + unavailable (14), + signalLabelMismatch (15), + lossOfMultiFrame (16), + receiveFailure (17), + transmitFailure (18), + modulationFailure (19), + demodulationFailure (20), + broadcastChannelFailure (21), + connectionEstablishmentError (22), + invalidMessageReceived (23), + localNodeTransmissionError (24), + remoteNodeTransmissionError (25), + routingFailure (26), + --Values 27-50 are reserved for communications alarm related + --probable causes + -- The following are used with equipment alarm. + backplaneFailure (51), + dataSetProblem (52), + equipmentIdentifierDuplication (53), + externalIFDeviceProblem (54), + lineCardProblem (55), + multiplexerProblem (56), + nEIdentifierDuplication (57), + powerProblem (58), + processorProblem (59), + protectionPathFailure (60), + receiverFailure (61), + replaceableUnitMissing (62), + replaceableUnitTypeMismatch (63), + synchronizationSourceMismatch (64), + terminalProblem (65), + timingProblem (66), + transmitterFailure (67), + trunkCardProblem (68), + replaceableUnitProblem (69), + realTimeClockFailure (70), + --An equipment alarm to be issued if the system detects that the + --real time clock has failed + antennaFailure (71), + batteryChargingFailure (72), + diskFailure (73), + frequencyHoppingFailure (74), + iODeviceError (75), + lossOfSynchronisation (76), + lossOfRedundancy (77), + powerSupplyFailure (78), + signalQualityEvaluationFailure (79), + tranceiverFailure (80), + protectionMechanismFailure (81), + protectingResourceFailure (82), + -- Values 83-100 are reserved for equipment alarm related probable + -- causes + -- The following are used with environmental alarm. + airCompressorFailure (101), + airConditioningFailure (102), + airDryerFailure (103), + batteryDischarging (104), + batteryFailure (105), + commercialPowerFailure (106), + coolingFanFailure (107), + engineFailure (108), + fireDetectorFailure (109), + fuseFailure (110), + generatorFailure (111), + lowBatteryThreshold (112), + pumpFailure (113), + rectifierFailure (114), + rectifierHighVoltage (115), + rectifierLowFVoltage (116), + ventilationsSystemFailure (117), + enclosureDoorOpen (118), + explosiveGas (119), + fire (120), + flood (121), + highHumidity (122), + highTemperature (123), + highWind (124), + iceBuildUp (125), + intrusionDetection (126), + lowFuel (127), + lowHumidity (128), + lowCablePressure (129), + lowTemperatue (130), + lowWater (131), + smoke (132), + toxicGas (133), + coolingSystemFailure (134), + externalEquipmentFailure (135), + externalPointFailure (136), + -- Values 137-150 are reserved for environmental alarm related + -- probable causes + -- The following are used with Processing error alarm. + storageCapacityProblem (151), + memoryMismatch (152), + corruptData (153), + outOfCPUCycles (154), + sfwrEnvironmentProblem (155), + sfwrDownloadFailure (156), + lossOfRealTimel (157), + --A processing error alarm to be issued after the system has + --reinitialised. This will indicate + --to the management systems that the view they have of the managed + --system may no longer + --be valid. Usage example: The managed + --system issues this alarm after a reinitialization with severity + --warning to inform the + --management system about the event. No clearing notification will + --be sent. + applicationSubsystemFailure (158), + configurationOrCustomisationError (159), + databaseInconsistency (160), + fileError (161), + outOfMemory (162), + softwareError (163), + timeoutExpired (164), + underlayingResourceUnavailable (165), + versionMismatch (166), + --Values 168-200 are reserved for processing error alarm related + -- probable causes. + bandwidthReduced (201), + congestion (202), + excessiveErrorRate (203), + excessiveResponseTime (204), + excessiveRetransmissionRate (205), + reducedLoggingCapability (206), + systemResourcesOverload (207 ), + -- The following were defined X.733 + adapterError (500), + applicationSubsystemFailture (501), + bandwidthReducedX733 (502), + callEstablishmentError (503), + communicationsProtocolError (504), + communicationsSubsystemFailure (505), + configurationOrCustomizationError (506), + congestionX733 (507), + coruptData (508), + cpuCyclesLimitExceeded (509), + dataSetOrModemError (510), + degradedSignalX733 (511), + dteDceInterfaceError (512), + enclosureDoorOpenX733 (513), + equipmentMalfunction (514), + excessiveVibration (515), + fileErrorX733 (516), + fireDetected (517), + framingErrorX733 (518), + heatingVentCoolingSystemProblem (519), + humidityUnacceptable (520), + inputOutputDeviceError (521), + inputDeviceError (522), + lanError (523), + leakDetected (524), + localNodeTransmissionErrorX733 (525), + lossOfFrameX733 (526), + lossOfSignalX733 (527), + materialSupplyExhausted (528), + multiplexerProblemX733 (529), + outOfMemoryX733 (530), + ouputDeviceError (531), + performanceDegraded (532), + powerProblems (533), + pressureUnacceptable (534), + processorProblems (535), + pumpFailureX733 (536), + queueSizeExceeded (537), + receiveFailureX733 (538), + receiverFailureX733 (539), + remoteNodeTransmissionErrorX733 (540), + resourceAtOrNearingCapacity (541), + responseTimeExecessive (542), + retransmissionRateExcessive (543), + softwareErrorX733 (544), + softwareProgramAbnormallyTerminated (545), + softwareProgramError (546), + storageCapacityProblemX733 (547), + temperatureUnacceptable (548), + thresholdCrossed (549), + timingProblemX733 (550), + toxicLeakDetected (551), + transmitFailureX733 (552), + transmiterFailure (553), + underlyingResourceUnavailable (554), + versionMismatchX733 (555), + -- The following are defined in X.736 + authenticationFailure (600), + breachOfConfidentiality (601), + cableTamper (602), + delayedInformation (603), + denialOfService (604), + duplicateInformation (605), + informationMissing (606), + informationModificationDetected (607), + informationOutOfSequence (608), + keyExpired (609), + nonRepudiationFailure (610), + outOfHoursActivity (611), + outOfService (612), + proceduralError (613), + unauthorizedAccessAttempt (614), + unexpectedInformation (615), + + other (1024) + } + + IANAItuEventType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The ITU event Type values. + + The Internet Assigned Number Authority (IANA) is + responsible for the assignment of the enumerations + in this TC. + + Request should come in the form of well-formed + SMI [RFC2578] for enumeration names that are unique + and sufficiently descriptive. + + See http://www.iana.org " + REFERENCE + "ITU Recommendation X.736, 'Information Technology - Open + Systems Interconnection - System Management: Security + Alarm Reporting Function', 1992" + SYNTAX INTEGER + { + other (1), + communicationsAlarm (2), + qualityOfServiceAlarm (3), + processingErrorAlarm (4), + equipmentAlarm (5), + environmentalAlarm (6), + integrityViolation (7), + operationalViolation (8), + physicalViolation (9), + securityServiceOrMechanismViolation (10), + timeDomainViolation (11) + } + + END diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-LANGUAGE-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-LANGUAGE-MIB new file mode 100644 index 0000000..6210f72 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-LANGUAGE-MIB @@ -0,0 +1,127 @@ + + IANA-LANGUAGE-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-IDENTITY, mib-2 + FROM SNMPv2-SMI; + + ianaLanguages MODULE-IDENTITY + LAST-UPDATED "200005100000Z" -- May 10, 2000 + ORGANIZATION "IANA" + CONTACT-INFO + "Internet Assigned Numbers Authority (IANA) + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 x20 + E-Mail: iana&iana.org" + DESCRIPTION + "The MIB module registers object identifier values for + well-known programming and scripting languages. Every + language registration MUST describe the format used + when transferring scripts written in this language. + + Any additions or changes to the contents of this MIB + module require Designated Expert Review as defined in + the Guidelines for Writing IANA Considerations Section + document. The Designated Expert will be selected by + the IESG Area Director of the OPS Area. + + Note, this module does not have to register all possible + languages since languages are identified by object + identifier values. It is therefore possible to registered + languages in private OID trees. The references given below are not + normative with regard to the language version. Other + references might be better suited to describe some newer + versions of this language. The references are only + provided as `a pointer into the right direction'." + + -- Revision log, in reverse chronological order + + REVISION "200005100000Z" -- May 10, 2000 + DESCRIPTION "Import mib-2 instead of experimental, so that + this module compiles" + + REVISION "199909090900Z" -- September 9, 1999 + DESCRIPTION "Initial version as published at time of + publication of RFC 2591." + + ::= { mib-2 73 } + + + ianaLangJavaByteCode OBJECT-IDENTITY + STATUS current + DESCRIPTION + "Java byte code to be processed by a Java virtual machine. + A script written in Java byte code is transferred by using + the Java archive file format (JAR)." + REFERENCE + "The Java Virtual Machine Specification. + ISBN 0-201-63452-X" + ::= { ianaLanguages 1 } + + ianaLangTcl OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The Tool Command Language (Tcl). A script written in the + Tcl language is transferred in Tcl source code format." + REFERENCE + "Tcl and the Tk Toolkit. + ISBN 0-201-63337-X" + ::= { ianaLanguages 2 } + + ianaLangPerl OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The Perl language. A script written in the Perl language + is transferred in Perl source code format." + REFERENCE + "Programming Perl. + ISBN 1-56592-149-6" + ::= { ianaLanguages 3 } + + ianaLangScheme OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The Scheme language. A script written in the Scheme + language is transferred in Scheme source code format." + REFERENCE + "The Revised^4 Report on the Algorithmic Language Scheme. + MIT Press" + ::= { ianaLanguages 4 } + + ianaLangSRSL OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP Script Language defined by SNMP Research. A + script written in the SNMP Script Language is transferred + in the SNMP Script Language source code format." + ::= { ianaLanguages 5 } + + ianaLangPSL OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The Patrol Script Language defined by BMC Software. A script + written in the Patrol Script Language is transferred in the + Patrol Script Language source code format." + REFERENCE + "PATROL Script Language Reference Manual, Version 3.0, + November 30, 1995. BMC Software, Inc. 2101 City West Blvd., + Houston, Texas 77042." + ::= { ianaLanguages 6 } + + ianaLangSMSL OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The Systems Management Scripting Language. A script written + in the SMSL language is transferred in the SMSL source code + format." + REFERENCE + "ISO/ITU Command Sequencer. + ISO 10164-21 or ITU X.753" + ::= { ianaLanguages 7 } + + END + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MALLOC-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MALLOC-MIB new file mode 100644 index 0000000..5869a36 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MALLOC-MIB @@ -0,0 +1,67 @@ + +IANA-MALLOC-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, mib-2 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + +ianaMallocMIB MODULE-IDENTITY + LAST-UPDATED "200301271200Z" -- January 27, 2003 + ORGANIZATION "IANA" + CONTACT-INFO + " Internet Assigned Numbers Authority + Internet Corporation for Assigned Names and Numbers + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292-6601 + + Phone: +1 310 823 9358 + EMail: iana&iana.org" + DESCRIPTION + "This MIB module defines the IANAscopeSource and + IANAmallocRangeSource textual conventions for use in MIBs + which need to identify ways of learning multicast scope and + range information. + + Any additions or changes to the contents of this MIB module + require either publication of an RFC, or Designated Expert + Review as defined in the Guidelines for Writing IANA + Considerations Section document. The Designated Expert will + be selected by the IESG Area Director(s) of the Transport + Area." + + -- revision log + + REVISION "200301271200Z" -- January 27, 2003 + DESCRIPTION + "Initial version." + ::= { mib-2 102 } + +IANAscopeSource ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The source of multicast scope information." + SYNTAX INTEGER { + other(1), -- none of the following + manual(2), -- statically configured + local(3), -- automatically added by the system, + -- such as a Source-Specific Multicast + -- scope + mzap(4), -- MZAP + madcap(5) -- MADCAP + } + +IANAmallocRangeSource ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The source of multicast address allocation range + information." + SYNTAX INTEGER { + other(1), -- none of the following + manual(2), -- statically configured + local(3) -- automatically added by the system, + -- such as a Source-Specific Multicast + -- range + } + +END + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MAU-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MAU-MIB new file mode 100644 index 0000000..35c3f4a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-MAU-MIB @@ -0,0 +1,770 @@ +IANA-MAU-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-IDENTITY, mib-2 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION + FROM SNMPv2-TC + ; + + ianaMauMIB MODULE-IDENTITY + LAST-UPDATED "200704210000Z" -- April 21, 2007 + ORGANIZATION "IANA" + CONTACT-INFO " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1-310-823-9358 + EMail: iana&iana.org" + + DESCRIPTION + "This MIB module defines dot3MauType OBJECT-IDENTITIES and + IANAifMauListBits, IANAifMauMediaAvailable, + IANAifMauAutoNegCapBits, and IANAifJackType + + TEXTUAL-CONVENTIONs, specifying enumerated values of the + ifMauTypeListBits, ifMauMediaAvailable / rpMauMediaAvailable, + ifMauAutoNegCapabilityBits / ifMauAutoNegCapAdvertisedBits / + ifMauAutoNegCapReceivedBits and ifJackType / rpJackType objects + respectively, defined in the MAU-MIB. + + It is intended that each new MAU type, Media Availability + state, Auto Negotiation capability and/or Jack type defined by + the IEEE 802.3 working group and approved for publication in a + revision of IEEE Std 802.3 will be added to this MIB module, + provided that it is suitable for being managed by the base + objects in the MAU-MIB. An Expert Review, as defined in + RFC 2434 [RFC2434], is REQUIRED for such additions. + + The following reference is used throughout this MIB module: + + [IEEE802.3] refers to: + IEEE Std 802.3, 2005 Edition: 'IEEE Standard for + Information technology - Telecommunications and information + exchange between systems - Local and metropolitan area + networks - Specific requirements - + Part 3: Carrier sense multiple access with collision + detection (CSMA/CD) access method and physical layer + specifications'. + + This reference should be updated as appropriate when new + MAU types, Media Availability states, Auto Negotiation + capabilities, and/or Jack types are added to this MIB module. + + Copyright (C) The IETF Trust (2007). + The initial version of this MIB module was published in + RFC 4836; for full legal notices see the RFC itself. + Supplementary information may be available at: + http://www.ietf.org/copyrights/ianamib.html" + + REVISION "200704210000Z" -- April 21, 2007 + DESCRIPTION "Initial version of this MIB as published in + RFC 4836." + ::= { mib-2 154 } + + -- Textual Conventions + + IANAifMauTypeListBits ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This data type is used as the syntax of the ifMauTypeListBits + object in the (updated) definition of MAU-MIB's ifMauTable. + + The most recent version of this textual convention is available + in the online version of this MIB module on the IANA web site. + + Requests for new values should be made to IANA via email + (iana&iana.org). + + Note that changes in this textual convention SHALL be + synchronized with relevant changes in the dot3MauType + OBJECT-IDENTITIES." + REFERENCE + "[IEEE802.3], Section 30.5.1.1.2" + SYNTAX BITS { + bOther(0), -- other or unknown + bAUI(1), -- AUI + b10base5(2), -- 10BASE-5 + bFoirl(3), -- FOIRL + + b10base2(4), -- 10BASE-2 + b10baseT(5), -- 10BASE-T duplex mode unknown + b10baseFP(6), -- 10BASE-FP + b10baseFB(7), -- 10BASE-FB + b10baseFL(8), -- 10BASE-FL duplex mode unknown + b10broad36(9), -- 10BROAD36 + b10baseTHD(10), -- 10BASE-T half duplex mode + b10baseTFD(11), -- 10BASE-T full duplex mode + b10baseFLHD(12), -- 10BASE-FL half duplex mode + b10baseFLFD(13), -- 10BASE-FL full duplex mode + b100baseT4(14), -- 100BASE-T4 + b100baseTXHD(15), -- 100BASE-TX half duplex mode + b100baseTXFD(16), -- 100BASE-TX full duplex mode + b100baseFXHD(17), -- 100BASE-FX half duplex mode + b100baseFXFD(18), -- 100BASE-FX full duplex mode + b100baseT2HD(19), -- 100BASE-T2 half duplex mode + b100baseT2FD(20), -- 100BASE-T2 full duplex mode + + b1000baseXHD(21), -- 1000BASE-X half duplex mode + b1000baseXFD(22), -- 1000BASE-X full duplex mode + b1000baseLXHD(23), -- 1000BASE-LX half duplex mode + b1000baseLXFD(24), -- 1000BASE-LX full duplex mode + b1000baseSXHD(25), -- 1000BASE-SX half duplex mode + b1000baseSXFD(26), -- 1000BASE-SX full duplex mode + b1000baseCXHD(27), -- 1000BASE-CX half duplex mode + b1000baseCXFD(28), -- 1000BASE-CX full duplex mode + b1000baseTHD(29), -- 1000BASE-T half duplex mode + b1000baseTFD(30), -- 1000BASE-T full duplex mode + + b10GbaseX(31), -- 10GBASE-X + b10GbaseLX4(32), -- 10GBASE-LX4 + + b10GbaseR(33), -- 10GBASE-R + b10GbaseER(34), -- 10GBASE-ER + b10GbaseLR(35), -- 10GBASE-LR + b10GbaseSR(36), -- 10GBASE-SR + b10GbaseW(37), -- 10GBASE-W + b10GbaseEW(38), -- 10GBASE-EW + b10GbaseLW(39), -- 10GBASE-LW + b10GbaseSW(40), -- 10GBASE-SW + -- new since RFC 3636 + b10GbaseCX4(41), -- 10GBASE-CX4 + b2BaseTL(42), -- 2BASE-TL + b10PassTS(43), -- 10PASS-TS + b100BaseBX10D(44), -- 100BASE-BX10D + b100BaseBX10U(45), -- 100BASE-BX10U + b100BaseLX10(46), -- 100BASE-LX10 + b1000BaseBX10D(47), -- 1000BASE-BX10D + b1000BaseBX10U(48), -- 1000BASE-BX10U + b1000BaseLX10(49), -- 1000BASE-LX10 + b1000BasePX10D(50), -- 1000BASE-PX10D + b1000BasePX10U(51), -- 1000BASE-PX10U + b1000BasePX20D(52), -- 1000BASE-PX20D + b1000BasePX20U(53) -- 1000BASE-PX20U + } + + IANAifMauMediaAvailable ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This data type is used as the syntax of the + ifMauMediaAvailable and rpMauMediaAvailable objects in the + (updated) definition of MAU-MIB's ifMauTable and rpMauTable + respectively. + + Possible values are: + other(1) - undefined (not listed below) + unknown(2) - MAU's true state is unknown; e.g., + during initialization + available(3) - link, light, or loopback is normal + notAvailable(4) - link loss, low light, or no loopback + remoteFault(5) - a fault has been detected at the + remote end of the link. This value + applies to 10BASE-FB, 100BASE-T4 Far + End Fault Indication and non-specified + remote faults from a system running + auto-negotiation + invalidSignal(6) - invalid signal has been received from + the other end of the link, 10BASE-FB + only + remoteJabber(7) - remote fault, due to jabber + + remoteLinkLoss(8) - remote fault, due to link loss + remoteTest(9) - remote fault, due to test + offline(10) - offline, Clause 37 Auto-Negotiation + only + autoNegError(11) - Auto-Negotiation Error, Clause 37 + Auto-Negotiation only + pmdLinkFault(12) - PMA/PMD receive link fault. In case + of PAF (2BASE-TL / 10PASS-TS PHYs), + all PMEs in the aggregation group have + detected a link fault + wisFrameLoss(13) - WIS loss of frame, 10GBASE-W only + wisSignalLoss(14) - WIS loss of signal, 10GBASE-W only + pcsLinkFault(15) - PCS receive link fault + excessiveBER(16) - PCS Bit Error Ratio monitor + reporting excessive error ratio + dxsLinkFault(17) - DTE XGXS receive link fault, XAUI only + pxsLinkFault(18) - PHY XGXS receive link fault, XAUI only + availableReduced(19) - link normal, reduced bandwidth, + 2BASE-TL / 10PASS-TS only + ready(20) - at least one PME in the aggregation + group is detecting handshake tones, + 2BASE-TL / 10PASS-TS only + + If the MAU is a 10M b/s link or fiber type (FOIRL, 10BASE-T, + 10BASE-F), then this is equivalent to the link test fail + state/low light function. For an AUI, 10BASE2, 10BASE5, or + 10BROAD36 MAU, this indicates whether loopback is detected on + the DI circuit. The value of this attribute persists between + packets for MAU types AUI, 10BASE5, 10BASE2, 10BROAD36, and + 10BASEFP. + + At power-up or following a reset, the Media Available state + will be unknown(2) for AUI, 10BASE5, 10BASE2, 10BROAD36, and + 10BASE-FP MAUs. For these MAUs loopback will be tested on each + transmission during which no collision is detected. + If DI is receiving input when DO returns to IDL after a + transmission and there has been no collision during the + transmission, then loopback will be detected. The Media + Available state will only change during noncollided + transmissions for AUI, 10BASE2, 10BASE5, 10BROAD36, and + 10BASE-FP MAUs. + + For 100BASE-T2, 100BASE-T4, 100BASE-TX, 100BASE-FX, + 100BASE-LX10, and 100BASE-BX10 PHYs the enumerations match the + states within the link integrity state diagram. + Any MAU that implements management of [IEEE802.3] Clause + 28 Auto-Negotiation, will map remote fault indication to + remoteFault(5). + + Any MAU that implements management of Clause 37 + Auto-Negotiation, will map the received RF1 and RF2 bits as + follows: Offline maps to offline(10), Link_Failure maps to + remoteFault(5), and Auto-Negotiation Error maps to + autoNegError(11). + + The value remoteFault(5) applies to 10BASE-FB remote + fault indication, the 100BASE-X far-end fault indication, and + nonspecified remote faults from a system running Clause 28 + Auto-Negotiation. + + The value remoteJabber(7), remoteLink loss(8), or remoteTest(9) + SHOULD be used instead of remoteFault(5) where the reason for + remote fault is identified in the remote signaling protocol. + Where a Clause 22 MII or Clause 35 GMII is present, a logic + one in the remote fault bit maps to the value remoteFault(5), + a logic zero in the link status bit maps to the enumeration + notAvailable(4). The value notAvailable(4) takes precedence + over remoteFault(5). + + For 2BASE-TL and 10PASS-TS PHYs, the value unknown(2) maps to + the condition where the PHY (PCS with connected PMEs) is + initializing, the value ready(20) maps to the condition where + the interface is down and at least one PME in the aggregation + group is ready for handshake, the value available(3) maps to + the condition where all the PMEs in the aggregation group are + up, the value notAvailable(4) maps to the condition where all + the PMEs in the aggregation group are down and no handshake + tones are detected, the value availableReduced(19) maps to the + condition where the interface is up, a link fault is detected + at the receive direction by one or more PMEs in the + aggregation group, but at least one PME is up and the + enumeration pmdLinkFault(12) maps to the condition where a link + fault is detected at the receive direction by all of the PMEs + in the aggregation group. + + For 10 Gb/s the enumerations map to value of the link_fault + variable within the Link Fault Signaling state diagram + as follows: the value OK maps to the value available(3), + the value Local Fault maps to the value notAvailable(4), + and the value Remote Fault maps to the value remoteFault(5). + The value pmdLinkFault(12), wisFrameLoss(13), + wisSignalLoss(14), pcsLinkFault(15), excessiveBER(16), or + dxsLinkFault(17) SHOULD be used instead of the value + notAvailable(4), where the reason for the Local Fault state can + be identified through the use of the Clause 45 MDIO Interface. + Where multiple reasons for the Local Fault state can be + identified, only the highest precedence error SHOULD be + + reported. This precedence in descending order is as follows: + + pxsLinkFault + pmdLinkFault + wisFrameLoss + wisSignalLoss + pcsLinkFault + excessiveBER + dxsLinkFault. + + Where a Clause 45 MDIO interface is present a logic zero in + the PMA/PMD Receive link status bit ([IEEE802.3] + Section 45.2.1.2.2) maps to the value pmdLinkFault(12), + logic one in the LOF status bit (Section 45.2.2.10.4) maps + to the value wisFrameLoss(13), a logic one in the LOS + status bit (Section 45.2.2.10.5) maps to the value + wisSignalLoss, a logic zero in the PCS Receive + link status bit (Section 45.2.3.2.2) maps to the value + pcsLinkFault(15), a logic one in the 10GBASE-R PCS Latched + high BER status bit (Section 45.2.3.12.2) maps to the value + excessiveBER, a logic zero in the DTE XS receive link status + bit (Section 45.2.5.2.2) maps to the value dxsLinkFault(17) + and a logic zero in the PHY XS transmit link status bit + (Section 45.2.4.2.2) maps to the value pxsLinkFault(18). + + The most recent version of this textual convention is available + in the online version of this MIB module on the IANA web site. + + Requests for new values should be made to IANA via email + (iana&iana.org)." + REFERENCE + "[IEEE802.3], Section 30.5.1.1.4" + SYNTAX INTEGER { + other(1), + unknown(2), + available(3), + notAvailable(4), + remoteFault(5), + invalidSignal(6), + remoteJabber(7), + remoteLinkLoss(8), + remoteTest(9), + offline(10), + autoNegError(11), + pmdLinkFault(12), + wisFrameLoss(13), + wisSignalLoss(14), + pcsLinkFault(15), + + excessiveBER(16), + dxsLinkFault(17), + pxsLinkFault(18), + availableReduced(19), + ready(20) + } + + IANAifMauAutoNegCapBits ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This data type is used as the syntax of the + ifMauAutoNegCapabilityBits, ifMauAutoNegCapAdvertisedBits, and + ifMauAutoNegCapReceivedBits objects in the (updated) definition + of MAU-MIB's ifMauAutoNegTable. + + The most recent version of this textual convention is available + in the online version of this MIB module on the IANA web site. + + Requests for new values should be made to IANA via email + (iana&iana.org)." + REFERENCE + "[IEEE802.3], Section 30.6.1.1.5" + SYNTAX BITS { + bOther(0), -- other or unknown + b10baseT(1), -- 10BASE-T half duplex mode + b10baseTFD(2), -- 10BASE-T full duplex mode + b100baseT4(3), -- 100BASE-T4 + b100baseTX(4), -- 100BASE-TX half duplex mode + b100baseTXFD(5), -- 100BASE-TX full duplex mode + b100baseT2(6), -- 100BASE-T2 half duplex mode + b100baseT2FD(7), -- 100BASE-T2 full duplex mode + bFdxPause(8), -- PAUSE for full-duplex links + bFdxAPause(9), -- Asymmetric PAUSE for full-duplex + -- links + bFdxSPause(10), -- Symmetric PAUSE for full-duplex + -- links + bFdxBPause(11), -- Asymmetric and Symmetric PAUSE for + -- full-duplex links + b1000baseX(12), -- 1000BASE-X, -LX, -SX, -CX half + -- duplex mode + b1000baseXFD(13), -- 1000BASE-X, -LX, -SX, -CX full + -- duplex mode + b1000baseT(14), -- 1000BASE-T half duplex mode + b1000baseTFD(15) -- 1000BASE-T full duplex mode + } + + IANAifJackType ::= TEXTUAL-CONVENTION + STATUS current + + DESCRIPTION + "Common enumeration values for repeater and interface MAU + jack types. This data type is used as the syntax of the + ifJackType and rpJackType objects in the (updated) definition + of MAU-MIB's ifJackTable and rpJackTable respectively. + + Possible values are: + other(1) - undefined or unknown + rj45(2) - RJ45 + rj45S(3) - RJ45 shielded + db9(4) - DB9 + bnc(5) - BNC + fAUI(6) - AUI female + mAUI(7) - AUI male + fiberSC(8) - SC fiber + fiberMIC(9) - MIC fiber + fiberST(10) - ST fiber + telco(11) - Telco + mtrj(12) - MT-RJ fiber + hssdc(13) - fiber channel style-2 + fiberLC(14) - LC fiber + cx4(15) - IB4X for 10GBASE-CX4 + + The most recent version of this textual convention is available + in the online version of this MIB module on the IANA web site. + + Requests for new values should be made to IANA via email + (iana&iana.org)." + SYNTAX INTEGER { + other(1), + rj45(2), + rj45S(3), + db9(4), + bnc(5), + fAUI(6), + mAUI(7), + fiberSC(8), + fiberMIC(9), + fiberST(10), + telco(11), + mtrj(12), + hssdc(13), + fiberLC(14), + -- new since RFC 3636 + cx4(15) + } + + -- OBJECT IDENTITIES for MAU types + + -- (see rpMauType and ifMauType of MAU-MIB for usage) + -- The following definitions has been moved from RFC 3636 and + -- no longer appear in its revision. + + dot3MauType OBJECT IDENTIFIER ::= { mib-2 snmpDot3MauMgt(26) 4 } + + dot3MauTypeAUI OBJECT-IDENTITY + STATUS current + DESCRIPTION "no internal MAU, view from AUI" + REFERENCE "[IEEE802.3], Section 7" + ::= { dot3MauType 1 } + + dot3MauType10Base5 OBJECT-IDENTITY + STATUS current + DESCRIPTION "thick coax MAU" + REFERENCE "[IEEE802.3], Section 7" + ::= { dot3MauType 2 } + + dot3MauTypeFoirl OBJECT-IDENTITY + STATUS current + DESCRIPTION "FOIRL MAU" + REFERENCE "[IEEE802.3], Section 9.9" + ::= { dot3MauType 3 } + + dot3MauType10Base2 OBJECT-IDENTITY + STATUS current + DESCRIPTION "thin coax MAU" + REFERENCE "[IEEE802.3], Section 10" + ::= { dot3MauType 4 } + + dot3MauType10BaseT OBJECT-IDENTITY + STATUS current + DESCRIPTION "UTP MAU. + Note that it is strongly recommended that + agents return either dot3MauType10BaseTHD or + dot3MauType10BaseTFD if the duplex mode is + known. However, management applications should + be prepared to receive this MAU type value from + older agent implementations." + REFERENCE "[IEEE802.3], Section 14" + ::= { dot3MauType 5 } + + dot3MauType10BaseFP OBJECT-IDENTITY + STATUS current + DESCRIPTION "passive fiber MAU" + REFERENCE "[IEEE802.3], Section 16" + ::= { dot3MauType 6 } + + dot3MauType10BaseFB OBJECT-IDENTITY + STATUS current + DESCRIPTION "sync fiber MAU" + REFERENCE "[IEEE802.3], Section 17" + ::= { dot3MauType 7 } + + dot3MauType10BaseFL OBJECT-IDENTITY + STATUS current + DESCRIPTION "async fiber MAU. + Note that it is strongly recommended that + agents return either dot3MauType10BaseFLHD or + dot3MauType10BaseFLFD if the duplex mode is + known. However, management applications should + be prepared to receive this MAU type value from + older agent implementations." + REFERENCE "[IEEE802.3], Section 18" + ::= { dot3MauType 8 } + + dot3MauType10Broad36 OBJECT-IDENTITY + STATUS current + DESCRIPTION "broadband DTE MAU. + Note that 10BROAD36 MAUs can be attached to + interfaces but not to repeaters." + REFERENCE "[IEEE802.3], Section 11" + ::= { dot3MauType 9 } + + ------ new since RFC 1515: + dot3MauType10BaseTHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "UTP MAU, half duplex mode" + REFERENCE "[IEEE802.3], Section 14" + ::= { dot3MauType 10 } + + dot3MauType10BaseTFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "UTP MAU, full duplex mode" + REFERENCE "[IEEE802.3], Section 14" + ::= { dot3MauType 11 } + + dot3MauType10BaseFLHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "async fiber MAU, half duplex mode" + REFERENCE "[IEEE802.3], Section 18" + ::= { dot3MauType 12 } + + dot3MauType10BaseFLFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "async fiber MAU, full duplex mode" + + REFERENCE "[IEEE802.3], Section 18" + ::= { dot3MauType 13 } + + dot3MauType100BaseT4 OBJECT-IDENTITY + STATUS current + DESCRIPTION "4 pair category 3 UTP" + REFERENCE "[IEEE802.3], Section 23" + ::= { dot3MauType 14 } + + dot3MauType100BaseTXHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "2 pair category 5 UTP, half duplex mode" + REFERENCE "[IEEE802.3], Section 25" + ::= { dot3MauType 15 } + + dot3MauType100BaseTXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "2 pair category 5 UTP, full duplex mode" + REFERENCE "[IEEE802.3], Section 25" + ::= { dot3MauType 16 } + + dot3MauType100BaseFXHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "X fiber over PMT, half duplex mode" + REFERENCE "[IEEE802.3], Section 26" + ::= { dot3MauType 17 } + + dot3MauType100BaseFXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "X fiber over PMT, full duplex mode" + REFERENCE "[IEEE802.3], Section 26" + ::= { dot3MauType 18 } + + dot3MauType100BaseT2HD OBJECT-IDENTITY + STATUS current + DESCRIPTION "2 pair category 3 UTP, half duplex mode" + REFERENCE "[IEEE802.3], Section 32" + ::= { dot3MauType 19 } + + dot3MauType100BaseT2FD OBJECT-IDENTITY + STATUS current + DESCRIPTION "2 pair category 3 UTP, full duplex mode" + REFERENCE "[IEEE802.3], Section 32" + ::= { dot3MauType 20 } + + ------ new since RFC 2239: + dot3MauType1000BaseXHD OBJECT-IDENTITY + STATUS current + + DESCRIPTION "PCS/PMA, unknown PMD, half duplex mode" + REFERENCE "[IEEE802.3], Section 36" + ::= { dot3MauType 21 } + + dot3MauType1000BaseXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "PCS/PMA, unknown PMD, full duplex mode" + REFERENCE "[IEEE802.3], Section 36" + ::= { dot3MauType 22 } + + dot3MauType1000BaseLXHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Fiber over long-wavelength laser, half duplex + mode" + REFERENCE "[IEEE802.3], Section 38" + ::= { dot3MauType 23 } + + dot3MauType1000BaseLXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Fiber over long-wavelength laser, full duplex + mode" + REFERENCE "[IEEE802.3], Section 38" + ::= { dot3MauType 24 } + + dot3MauType1000BaseSXHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Fiber over short-wavelength laser, half + duplex mode" + REFERENCE "[IEEE802.3], Section 38" + ::= { dot3MauType 25 } + + dot3MauType1000BaseSXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Fiber over short-wavelength laser, full + duplex mode" + REFERENCE "[IEEE802.3], Section 38" + ::= { dot3MauType 26 } + + dot3MauType1000BaseCXHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Copper over 150-Ohm balanced cable, half + duplex mode" + REFERENCE "[IEEE802.3], Section 39" + ::= { dot3MauType 27 } + + dot3MauType1000BaseCXFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Copper over 150-Ohm balanced cable, full + + duplex mode" + REFERENCE "[IEEE802.3], Section 39" + ::= { dot3MauType 28 } + + dot3MauType1000BaseTHD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Four-pair Category 5 UTP, half duplex mode" + REFERENCE "[IEEE802.3], Section 40" + ::= { dot3MauType 29 } + + dot3MauType1000BaseTFD OBJECT-IDENTITY + STATUS current + DESCRIPTION "Four-pair Category 5 UTP, full duplex mode" + REFERENCE "[IEEE802.3], Section 40" + ::= { dot3MauType 30 } + + ------ new since RFC 2668: + dot3MauType10GigBaseX OBJECT-IDENTITY + STATUS current + DESCRIPTION "X PCS/PMA, unknown PMD." + REFERENCE "[IEEE802.3], Section 48" + ::= { dot3MauType 31 } + + dot3MauType10GigBaseLX4 OBJECT-IDENTITY + STATUS current + DESCRIPTION "X fiber over WWDM optics" + REFERENCE "[IEEE802.3], Section 53" + ::= { dot3MauType 32 } + + dot3MauType10GigBaseR OBJECT-IDENTITY + STATUS current + DESCRIPTION "R PCS/PMA, unknown PMD." + REFERENCE "[IEEE802.3], Section 49" + ::= { dot3MauType 33 } + + dot3MauType10GigBaseER OBJECT-IDENTITY + STATUS current + DESCRIPTION "R fiber over 1550 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 34 } + + dot3MauType10GigBaseLR OBJECT-IDENTITY + STATUS current + DESCRIPTION "R fiber over 1310 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 35 } + + dot3MauType10GigBaseSR OBJECT-IDENTITY + + STATUS current + DESCRIPTION "R fiber over 850 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 36 } + + dot3MauType10GigBaseW OBJECT-IDENTITY + STATUS current + DESCRIPTION "W PCS/PMA, unknown PMD." + REFERENCE "[IEEE802.3], Section 49 and 50" + ::= { dot3MauType 37 } + + dot3MauType10GigBaseEW OBJECT-IDENTITY + STATUS current + DESCRIPTION "W fiber over 1550 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 38 } + + dot3MauType10GigBaseLW OBJECT-IDENTITY + STATUS current + DESCRIPTION "W fiber over 1310 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 39 } + + dot3MauType10GigBaseSW OBJECT-IDENTITY + STATUS current + DESCRIPTION "W fiber over 850 nm optics" + REFERENCE "[IEEE802.3], Section 52" + ::= { dot3MauType 40 } + + ------ new since RFC 3636: + dot3MauType10GigBaseCX4 OBJECT-IDENTITY + STATUS current + DESCRIPTION "X copper over 8 pair 100-Ohm balanced cable" + REFERENCE "[IEEE802.3], Section 54" + ::= { dot3MauType 41 } + + dot3MauType2BaseTL OBJECT-IDENTITY + STATUS current + DESCRIPTION "Voice grade UTP copper, up to 2700m, optional PAF" + REFERENCE "[IEEE802.3], Sections 61 and 63" + ::= { dot3MauType 42 } + + dot3MauType10PassTS OBJECT-IDENTITY + STATUS current + DESCRIPTION "Voice grade UTP copper, up to 750m, optional PAF" + REFERENCE "[IEEE802.3], Sections 61 and 62" + ::= { dot3MauType 43 } + + dot3MauType100BaseBX10D OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber OLT, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 58" + ::= { dot3MauType 44 } + + dot3MauType100BaseBX10U OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber ONU, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 58" + ::= { dot3MauType 45 } + + dot3MauType100BaseLX10 OBJECT-IDENTITY + STATUS current + DESCRIPTION "Two single-mode fibers, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 58" + ::= { dot3MauType 46 } + + dot3MauType1000BaseBX10D OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber OLT, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 59" + ::= { dot3MauType 47 } + + dot3MauType1000BaseBX10U OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber ONU, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 59" + ::= { dot3MauType 48 } + + dot3MauType1000BaseLX10 OBJECT-IDENTITY + STATUS current + DESCRIPTION "Two sigle-mode fiber, long wavelength, 10km" + REFERENCE "[IEEE802.3], Section 59" + ::= { dot3MauType 49 } + + dot3MauType1000BasePX10D OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber EPON OLT, 10km" + REFERENCE "[IEEE802.3], Section 60" + ::= { dot3MauType 50 } + + dot3MauType1000BasePX10U OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber EPON ONU, 10km" + REFERENCE "[IEEE802.3], Section 60" + ::= { dot3MauType 51 } + + dot3MauType1000BasePX20D OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber EPON OLT, 20km" + REFERENCE "[IEEE802.3], Section 60" + ::= { dot3MauType 52 } + + dot3MauType1000BasePX20U OBJECT-IDENTITY + STATUS current + DESCRIPTION "One single-mode fiber EPON ONU, 20km" + REFERENCE "[IEEE802.3], Section 60" + ::= { dot3MauType 53 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-PRINTER-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-PRINTER-MIB new file mode 100644 index 0000000..856ed5f --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-PRINTER-MIB @@ -0,0 +1,1319 @@ +IANA-PRINTER-MIB DEFINITIONS ::= BEGIN + -- http://www.iana.org/assignments/ianaprinter-mib + +IMPORTS + MODULE-IDENTITY, + mib-2 + FROM SNMPv2-SMI -- [RFC2578] + TEXTUAL-CONVENTION + FROM SNMPv2-TC; -- [RFC2579] + +ianaPrinterMIB MODULE-IDENTITY + LAST-UPDATED "200509140000Z" -- September 14, 2005 + + ORGANIZATION "IANA" + CONTACT-INFO "Internet Assigned Numbers Authority + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + E-Mail: iana&iana.org" + + DESCRIPTION "This MIB module defines a set of printing-related + TEXTUAL-CONVENTIONs for use in Printer MIB (RFC 3805), + Finisher MIB (RFC 3806), and other MIBs which need to + specify printing mechanism details. + + Any additions or changes to the contents of this MIB + module require either publication of an RFC, or + Designated Expert Review as defined in RFC 2434, + Guidelines for Writing an IANA Considerations Section + in RFCs. The Designated Expert will be selected by + the IESG Area Director(s) of the Applications Area. + + Copyright (C) The Internet Society (2004). The + initial version of this MIB module was published + in RFC 3805. For full legal notices see the RFC + itself or see: + http://www.ietf.org/copyrights/ianamib.html" + + REVISION "200509140000Z" -- September 14, 2005 + DESCRIPTION "Updates to include missing 'unknown' values + for PrtCoverStatusTC, PrtChannelTypeTC, + PrtAlertGroupTC and removal of comment for + for PrtAlertGroupTC." + + REVISION "200406020000Z" -- June 2, 2004 + DESCRIPTION "Original version, published in coordination + with Printer MIB (RFC 3805)." + ::= { mib-2 109 } + +-- +-- Generic TEXTUAL-CONVENTIONs +-- + +PrtCoverStatusTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtCoverStatus in RFC 1759. + STATUS current + DESCRIPTION + "Values for encoding the state of a particular cover or + access panel on the printer case or enclosure." + SYNTAX INTEGER { + other(1), + unknown(2), + coverOpen(3), + coverClosed(4), + interlockOpen(5), + interlockClosed(6) + + } + +-- +-- General Group TEXTUAL-CONVENTIONs +-- + +PrtGeneralResetTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtGeneralReset in RFC 1759. + STATUS current + DESCRIPTION + "Values for reading and writing the prtGeneralReset object. + + If a device does not have NVRAM, the device shall none the + less respond to a SET with the value resetToNVRAM(5) with a + sort of warm reset that resets the device to implementation- + defined state that is preferably under control of the system + administrator by some means outside the scope of the Printer + MIB specification." + + SYNTAX INTEGER { + notResetting(3), + powerCycleReset(4), -- Cold Start + resetToNVRAM(5), -- Warm Start + resetToFactoryDefaults(6) -- Reset contents of + -- NVRAM to factory + -- defaults + } +-- +-- Channel Group TEXTUAL-CONVENTIONs +-- + +PrtChannelTypeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtChannelType in RFC 1759. + STATUS current + DESCRIPTION + "This enumeration indicates the type of channel that is + receiving jobs." + SYNTAX INTEGER { + other(1), + unknown(2), + chSerialPort(3), + chParallelPort(4), + chIEEE1284Port(5), + chSCSIPort(6), + chAppleTalkPAP(7), + -- AppleTalk Printer + -- Access Protocol (PAP) + -- + -- prtChannelInformation entry: + + -- + -- Printer Name + -- Keyword: Name + -- Syntax: Name + -- Status: Optional + -- Multiplicity: Single + -- Description: The name of the printer + -- within the AppleTalk naming scope + chLPDServer(8), + -- prtChannelInformation entry: + -- + -- Printer queue name + -- Keyword: Queue + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: queue name as + -- defined in [RFC1179]. + chNetwareRPrinter(9), + -- Novell, Inc. + -- For each entry of this type, the + -- prtChannelInformation must have a pair of + -- keywords. For Netware 3.x channels this must + -- be a (PServer, Printer) pair. For Netware + -- 4.x channels and for IntranetWare channels + -- this must be a (NDSTree, NDSPrinter) pair. + -- + -- prtChannelInformation entries: + + -- Print Server Name + -- Keyword: PServer + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The Pserver's SAP name + -- + -- Printer Number + -- Keyword: Printer + -- Syntax: Integer + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The printer number + -- + -- NDSTree + -- Keyword: NDSTree + -- Syntax: Name + -- Multiplicity: Single + -- Description: The tree's SAP name + + -- + -- NDS Printer object + -- Keyword: NDSPrinter + -- Syntax: Text (Unicode) + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The fully qualified + -- name of the Printer + -- + -- In the Netware 3.x environment, the + -- client checks the Bindery object + -- representing the named PServer. The + -- client then checks for queues which + -- are associated with the numbered + -- printer. In the 4.x and IntraNetware + -- environment, the client looks up the + -- queues which are associated with the + -- NDS Printer Object in the named Tree. + -- Depending on client access rights to + -- those queues, the client submits jobs + -- to the appropriate queue. + chNetwarePServer(10), + -- Novell,Inc. + -- For each entry of this type, the + -- prtChannelInformation must have a pair + -- of keywords. For Netware 3.x channels + -- this must be a (Server, PServer) pair. + -- For Netware 4.x and IntranetWare + -- channels, this must be a + -- (NDSTree, NDSPServer) pair. + -- + -- prtChannelInformation entries: + -- + -- Server Name + -- Keyword: Server + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The SAP name of the + -- server for which the PServer is defined. + -- + -- PServer + -- Keyword: PServer + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The bindery name of + -- the PServer + + -- + -- NDS Tree + -- Keyword: NDSTree + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The NDS Tree name + -- + -- PServer + -- Keyword: NDSPServer + -- Syntax: Text (Unicode) + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The fully qualified + -- name of the PServer object in the tree. + -- + -- In the 3.x environment, the client + -- checks the bindery object + -- representing the named PServer on the + -- named Server. In the 4.x and + -- IntranetWare environment, + -- the client checks the NDS object + -- representing the named PServer in the + -- named Tree. In either case, the + -- client then checks for all queues + -- associated with the Pserver object. + -- Depending on client access rights + -- to those queues, the client submits + -- jobs to the appropriate queue. + chPort9100(11), + -- DEPRECATED + -- (see chPortTCP - 37; chBidirPortTCP - 38) + chAppSocket(12), + -- A bi-directional, LPD-like, protocol using + -- 9101 for control and 9100 for data. + -- Adobe Systems, Inc. + chFTP(13), -- [RFC959] + chTFTP(14), -- [RFC1350] + chDLCLLCPort(15), + chIBM3270(16), -- IBM Coax + chIBM5250(17), -- IBM Twinax + chFax(18), + chIEEE1394(19), + chTransport1(20), + -- TCP port 35, for reserved TCP port list see + -- [RFC3232]. This RFC should also be + -- referenced for other channel + -- enumerations utilizing TCP port + + -- numbers 0 through 1024. + chCPAP(21), -- TCP port 170 + -- Digital Equipment Corp. + chDCERemoteProcCall(22), -- OSF + -- DEPRECATED + chONCRemoteProcCall(23), -- SUN Microsystems + -- DEPRECATED + chOLE(24), -- Microsoft + -- DEPRECATED + chNamedPipe(25), + chPCPrint(26), -- Banyan + chServerMessageBlock(27), + -- File/Print sharing protocol used by + -- various network operating systems + -- from IBM 3Com, Microsoft and others + -- + -- prtChannelInformation entry: + -- + -- Service Name + -- Keyword: Name + -- Syntax: Name + -- Status: Optional + -- Multiplicity: Single + -- Description: The service name of + -- the printer + chDPMF(28), -- IBM Infoprint + chDLLAPI(29), -- Microsoft + -- DEPRECATED + chVxDAPI(30), -- Microsoft + -- DEPRECATED + chSystemObjectManager(31), -- IBM + chDECLAT(32), + -- Digital Equipment Corp. + -- + -- prtChannelInformation entries: + -- + -- Port Name + -- Keyword: Port + -- Syntax: Name + -- Status: Conditionally + -- Mandatory + -- (see note below) + -- Multiplicity: Single + -- Description: LAT port name + -- + -- Service Name + -- Keyword: Service + -- Syntax: Name + + -- Status: Conditionally + -- Mandatory + -- Multiplicity: Single + -- Description: LAT service name + -- + -- The LAT channel may be + -- identified by either a port or + -- service, so either a + -- Port or Service entry must be + -- specified, but not both. + chNPAP(33), + chUSB(34), -- Not in RFC 1759 + -- Universal Serial Bus + chIRDA(35), -- Not in RFC 1759 + -- Infrared Data Assoc. Prot. + chPrintXChange(36), -- Not in RFC 1759 + -- PrintXChange Protocol + chPortTCP(37), -- Not in RFC 1759 + -- A unidirectional "raw" TCP + -- channel that uses an administratively + -- assigned TCP port address. + -- + -- prtChannelInformation entry: + -- + -- Port Number + -- Keyword: Port + -- Syntax: decimal number + -- Status: Mandatory + -- Multiplicity: Single + -- Description: TCP port number + chBidirPortTCP(38), -- Not in RFC 1759 + -- A bi-directional version of chPortTCP + -- + -- prtChannelInformation entries: + -- (See chPortTCP) + chUNPP(39), -- Not in RFC 1759 + -- Universal Network Printing + -- Protocol(UNPP). A bi-directional, + -- multiport network printing + -- application protocol available on + -- multiple transport protocols. + -- Underscore, Inc. + -- Contact: info&underscore.com + chAppleTalkADSP(40), -- Not in RFC 1759 + -- AppleTalk Data Stream Protocol. + -- ADSP is part of the AppleTalk + -- suite of protocols. + -- It is a symmetric, connection- + + -- oriented protocol that makes + -- possible the establishment + -- and maintenance of full-duplex + -- streams of data bytes between + -- two sockets in an AppleTalk + -- internet. + -- See [APPLEMAC]. + chPortSPX(41), -- Not in RFC 1759 + -- Sequenced Packet Exchange (SPX) + -- socket. + -- Novell, Inc. Similar to TCP, a + -- bi-directional data pipe using + -- Novell SPX as a transport. + -- + -- prtChannelInformation entries: + -- + -- Network Number + -- Keyword: Net + -- Syntax: HexString + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The network number + -- + -- Node Number + -- Keyword: Node + -- Syntax: HexString + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The node number + -- + -- Socket Number + -- Keyword: Socket + -- Syntax: HexString + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The SPX socket number + -- + -- There must be exactly one "Net" and + -- one "Node" and one "Socket" entry. A + -- HexString is a binary value + -- represented as a string of + -- ASCII characters using hexadecimal + -- notation. + chPortHTTP(42), -- Not in RFC 1759 + -- Hypertext Transfer Protocol. See [RFC1945] + -- and [RFC2616]. + chNDPS(43), -- Not in RFC 1759 + -- Novell, Inc. + + -- + -- prtChannelInformation entry: + -- + -- Printer Agent Name + -- Keyword: PA + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Description: The NDPS Printer + -- Agent Name + chIPP(44), -- Not in RFC 1759 + -- Internet Printing Protocol (IPP), + -- (IPP/1.1 - see [RFC2910] and [RFC2911]) + -- also applies to all future versions of IPP. + -- + -- IPP Printer URI + -- Keyword: URI + -- Syntax: URI (Unicode UTF-8 per + -- [RFC2396]) + -- Status: Mandatory + -- Multiplicity: Single + -- Default: not applicable + -- Description: URI of this IPP Printer + -- within Internet naming scope. Unicode + -- UTF-8 [RFC3629] string with + -- hexadecimal escapes for any non-ASCII + -- characters (per [RFC2396]). + -- Conformance: An IPP Printer shall list all + -- IPP URI it supports (one per IPP Channel + -- entry). If a URI contains the 'http:' + -- scheme it must have an explicit port. + -- See: [RFC3629], [RFC2396], [RFC2910], + -- [RFC2911]. + -- + -- IPP Printer Client Authentication + -- Keyword: Auth + -- Syntax: Keyword + -- Status: Optional + -- Multiplicity: Single + -- Default: 'none' + -- Description: A client authentication + -- mechanism supported for this IPP Printer + -- URI: + -- 'none' + -- no client authentication mechanism + -- 'requesting-user-name' + -- authenticated user in 'requesting- + -- user-name' + + -- 'basic' + -- authenticated user via HTTP Basic + -- mechanism + -- 'digest' + -- authenticated user via HTTP Digest + -- mechanism + -- 'certificate' + -- authenticated user via certificate + -- mechanism + -- Conformance: An IPP Printer should list + -- all IPP client authentication mechanisms + -- it supports (one per IPP Channel entry). + -- See: [RFC2911] and [RFC2910]. + -- + -- IPP Printer Security + -- Keyword: Security + -- Syntax: Keyword + -- Status: Optional + -- Multiplicity: Single + -- Default: 'none' + -- Description: A security mechanism + -- supported for this IPP Printer URI: + -- 'none' + -- no security mechanism + -- 'ssl3' + -- SSL3 secure communications channel + -- protocol + -- 'tls' + -- TLS secure communications channel + -- protocol + -- Conformance: An IPP Printer should list + -- all IPP security mechanisms it supports + -- (one per IPP Channel entry). + -- See: [RFC2246], [RFC2911]. + -- + -- IPP Printer Protocol Version + -- Keyword: Version + -- Syntax: Keyword + -- Status: Optional + -- Multiplicity: Multiple + -- Default: '1.1' + -- Description: All of the IPP protocol + -- versions (major.minor) supported for + -- this IPP Printer URI: + -- '1.0' + -- IPP/1.0 conforming Printer + -- '1.1' + -- IPP/1.1 conforming Printer + + -- Conformance: An IPP Printer should list + -- all IPP versions it supports (all listed + -- in each IPP Channel entry). An IPP + -- Client should select the highest + -- numbered version the IPP Client supports + -- for use in all IPP Requests (for optimum + -- interworking). + -- See: [RFC2911]. + chSMTP(45) + -- Print Job submission via Simple Mail + -- Transfer Protocol (SMTP) - see [RFC2821] + -- + -- prtChannelInformation entry: + -- + -- Keyword: Mailto + -- Syntax: Name + -- Status: Mandatory + -- Multiplicity: Single + -- Default: not applicable + -- Description: The SMTP URL of the printer. +} + +-- +-- Interpreter Group TEXTUAL-CONVENTIONs +-- + +PrtInterpreterLangFamilyTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtInterpreterLangFamily in RFC 1759. + STATUS current + DESCRIPTION + "This enumeration indicates the type of interpreter that is + receiving jobs." + SYNTAX INTEGER { + other(1), + unknown(2), -- Not in RFC 1759 + langPCL(3), -- PCL. Starting with PCL version 5, + -- HP-GL/2 is included as part of the + -- PCL language. + -- PCL and HP-GL/2 are registered + -- trademarks of Hewlett-Packard + -- Company. + langHPGL(4), -- Hewlett-Packard Graphics Language. + -- HP-GL is a registered trademark of + -- Hewlett-Packard Company. + langPJL(5), -- Peripheral Job Language. Appears in + -- the data stream between data intended + -- for a page description language. + -- Hewlett-Packard Co. + + langPS(6), -- PostScript (tm) Language + -- Postscript - a trademark of Adobe + -- Systems Incorporated which may be + -- registered in certain jurisdictions + langIPDS(7), -- Intelligent Printer Data Stream + -- Bi-directional print data stream for + -- documents consisting of data objects + -- (text, image, graphics, bar codes), + -- resources (fonts, overlays) and page, + -- form and finishing instructions. + -- Facilitates system level device + -- control, document tracking and error + -- recovery throughout the print + -- process. + -- IBM Corporation. + langPPDS(8), -- IBM Personal Printer Data Stream. + -- Originally called IBM ASCII, the name + -- was changed to PPDS when the Laser + -- Printer was introduced in 1989. + -- Lexmark International, Inc. + langEscapeP(9), -- Epson Corp. + langEpson(10), + langDDIF(11), -- Digital Document Interchange Format + -- Digital Equipment Corp., Maynard MA + langInterpress(12), + -- Xerox Corp. + langISO6429(13), -- ISO 6429. Control functions for + -- Coded Character Sets (has ASCII + -- control characters, plus additional + -- controls for + -- character imaging devices.) + langLineData(14), -- line-data: Lines of data as + -- separate ASCII or EBCDIC records + -- and containing no control functions + -- (no CR, LF, HT, FF, etc.) + -- For use with traditional line + -- printers. May use CR and/or LF to + -- delimit lines, instead of records. + -- See ISO 10175 Document Printing + -- Application (DPA) [ISO10175]. + langMODCA(15), -- Mixed Object Document Content + -- Architecture + -- Definitions that allow the + -- composition, interchange, and + -- presentation of final form + -- documents as a collection of data + -- objects (text, image, graphics, bar + -- codes), resources (fonts, overlays) + + -- and page, form and finishing + -- instructions. + -- IBM Corporation. + langREGIS(16), -- Remote Graphics Instruction Set, + -- Digital Equipment Corp., Maynard MA + langSCS(17), -- SNA Character String + -- Bi-directional print data stream for + -- SNA LU-1 mode of communication. + -- IBM + langSPDL(18), -- ISO 10180 Standard Page Description + -- Language + -- ISO Standard + langTEK4014(19), -- Tektronix Corp. + langPDS(20), + langIGP(21), -- Printronix Corp. + langCodeV(22), -- Magnum Code-V, Image and printer + -- control language used to control + -- impact/dot-matrix printers. + -- QMS, Inc., Mobile AL + langDSCDSE(23), -- DSC-DSE: Data Stream Compatible and + -- Emulation Bi-directional print data + -- stream for non-SNA (DSC) and SNA LU-3 + -- 3270 controller (DSE) communications + -- IBM + langWPS(24), -- Windows Printing System, Resource + -- based command/data stream used by + -- Microsoft At Work Peripherals. + -- Developed by the Microsoft + -- Corporation. + langLN03(25), -- Early DEC-PPL3, Digital Equipment + -- Corp. + langCCITT(26), + langQUIC(27), -- QUIC (Quality Information Code), Page + -- Description Language for laser + -- printers. Included graphics, printer + -- control capability and emulation of + -- other well-known printer. + -- QMS, Inc. + langCPAP(28), -- Common Printer Access Protocol + -- Digital Equipment Corp. + langDecPPL(29), -- Digital ANSI-Compliant Printing + -- Protocol + -- (DEC-PPL) + -- Digital Equipment Corp. + langSimpleText(30), + -- simple-text: character coded data, + -- including NUL, CR , LF, HT, and FF + -- control characters. See ISO 10175 + + -- Document Printing Application (DPA) + -- [ISO10175]. + langNPAP(31), -- Network Printer Alliance Protocol + -- (NPAP). This protocol has been + -- superseded by the IEEE 1284.1 TIPSI + -- Std (ref. LangTIPSI(49)). + langDOC(32), -- Document Option Commands, Appears in + -- the data stream between data + -- intended for a page description. + -- QMS, Inc. + langimPress(33), -- imPRESS, Page description language + -- originally developed for the + -- ImageServer product line. A binary + -- language providing representations + -- of text, simple graphics, and some + -- large forms (simple + -- bit-map and CCITT group 3/4 + -- encoded).The + -- language was intended to be sent over + -- an 8-bit channel and supported early + -- document preparation languages (e.g., + -- TeX and TROFF). + -- QMS, Inc. + langPinwriter(34), + -- 24 wire dot matrix printer for + -- USA, Europe, and Asia except + -- Japan. + -- More widely used in Germany, and + -- some Asian countries than in US. + -- NEC + langNPDL(35), -- Page printer for Japanese market. + -- NEC + langNEC201PL(36), -- Serial printer language used in + -- the Japanese market. + -- NEC + langAutomatic(37), + -- Automatic PDL sensing. Automatic + -- sensing of the interpreter + -- language family by the printer + -- examining the document content. + -- Which actual interpreter language + -- families are sensed depends on + -- the printer implementation. + langPages(38), -- Page printer Advanced Graphic + -- Escape Set + -- IBM Japan + langLIPS(39), -- LBP Image Processing System + langTIFF(40), -- Tagged Image File Format (Aldus) + + langDiagnostic(41), + -- A hex dump of the input to the + -- interpreter + langPSPrinter(42), + -- The PostScript Language used for + -- control (with any PDLs) + -- Adobe Systems Incorporated + langCaPSL(43), -- Canon Print Systems Language + langEXCL(44), -- Extended Command Language + -- Talaris Systems Inc. + langLCDS(45), -- Line Conditioned Data Stream + -- Xerox Corporation + langXES(46), -- Xerox Escape Sequences + -- Xerox Corporation + langPCLXL(47), -- Not in RFC 1759 + -- Printer Control Language. Extended + -- language features for printing, and + -- printer control. + -- Hewlett-Packard Co. + langART(48), -- Not in RFC 1759 + -- Advanced Rendering Tools (ART). + -- Page Description language + -- originally developed for the Laser + -- Press printers. + -- Technical reference manual: "ART IV + -- Reference Manual", No F33M. + -- Fuji Xerox Co., Ltd. + langTIPSI(49), -- Not in RFC 1759 + -- Transport Independent Printer + -- System Interface (ref. IEEE Std. + -- 1284.1) + langPrescribe(50), -- Not in RFC 1759 + -- Page description and printer + -- control language. It can be + -- described with ordinary ASCII + -- Technical reference manual: + -- "PRESCRIBE II Programming Manual" + langLinePrinter(51), -- Not in RFC 1759 + -- A simple-text character stream which + -- supports the control codes LF, VT, + -- FF, and plus Centronics or + -- Dataproducts Vertical Format Unit + -- (VFU) language is commonly used on + -- many older model line and matrix + -- printers. + langIDP(52), -- Not in RFC 1759 + -- Imaging Device Protocol + -- Apple Computer. + + langXJCL(53), -- Not in RFC 1759 + -- Xerox Job Control Language (JCL). + -- A Job Control language originally + -- developed for the LaserPress printers + -- and is capable of switching PDLs. + -- Technical reference manual: + -- "ART IV Reference Manual", No F33M. + -- Fuji Xerox Co., Ltd. + langPDF(54), -- Not in RFC 1759 + -- Adobe Portable Document Format + -- Adobe Systems, Inc. + langRPDL(55), -- Not in RFC 1759 + -- Ricoh Page Description Language for + -- printers. + -- Technical manual "RPDL command + -- reference" No.307029 + -- RICOH, Co. LTD + langIntermecIPL(56), -- Not in RFC 1759 + -- Intermec Printer Language for label + -- printers. + -- Technical Manual: "IPL Programmers + -- Reference Manual" + -- Intermec Corporation + langUBIFingerprint(57), -- Not in RFC 1759 + -- An intelligent basic-like programming + -- language for label printers. + -- Reference Manual: "UBI Fingerprint + -- 7.1", No. 1-960434-00 + -- United Barcode Industries + langUBIDirectProtocol(58), -- Not in RFC 1759 + -- An intelligent control language for + -- label printers. + -- Programmers guide: " UBI Direct + -- Protocol", No. 1-960419-00 + -- United Barcode Industries + langFujitsu(59), -- Not in RFC 1759 + -- Fujitsu Printer Language + -- Reference Manual: + -- "FM Printer Sequence" No. 80HP-0770 + -- FUJITSU LIMITED + langCGM(60), -- Not in RFC 1759 + -- Computer Graphics Metafile + -- MIME type 'image/cgm' + langJPEG(61), -- Not in RFC 1759 + -- Joint Photographic Experts Group + -- MIME type 'image/jpeg' + langCALS1(62), -- Not in RFC 1759 + -- US DOD CALS1 (see MIL-STD-1840) + + -- MIME type 'application/cals-1840' + langCALS2(63), -- Not in RFC 1759 + -- US DOD CALS2 (see MIL-STD-1840) + -- MIME type 'application/cals-1840' + langNIRS(64), -- Not in RFC 1759 + -- US DOD NIRS (see MIL-STD-1840) + -- MIME type 'application/cals-1840' + langC4(65) -- Not in RFC 1759 + -- US DOD C4 (see MIL-STD-1840) + -- MIME type 'application/cals-1840' +} + +-- +-- Input/Output Group TEXTUAL-CONVENTIONs +-- + +PrtInputTypeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtInputType in RFC 1759. + STATUS current + DESCRIPTION + "The type of technology (discriminated primarily according to + feeder mechanism type) employed by a specific component or + components." + SYNTAX INTEGER { + other(1), + unknown(2), + sheetFeedAutoRemovableTray(3), + sheetFeedAutoNonRemovableTray(4), + sheetFeedManual(5), + continuousRoll(6), + continuousFanFold(7) + } + +PrtOutputTypeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtOutputType in RFC 1759. + STATUS current + DESCRIPTION + "The Type of technology supported by this output subunit." + SYNTAX INTEGER { + other(1), + unknown(2), + removableBin(3), + unRemovableBin(4), + continuousRollDevice(5), + mailBox(6), + continuousFanFold(7) + } + +-- +-- Marker Group TEXTUAL-CONVENTIONs +-- + +PrtMarkerMarkTechTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtMarkerMarkTech in RFC 1759. + STATUS current + DESCRIPTION + "The type of marking technology used for this marking + subunit." + SYNTAX INTEGER { + other(1), + unknown(2), + electrophotographicLED(3), + electrophotographicLaser(4), + electrophotographicOther(5), + impactMovingHeadDotMatrix9pin(6), + impactMovingHeadDotMatrix24pin(7), + impactMovingHeadDotMatrixOther(8), + impactMovingHeadFullyFormed(9), + impactBand(10), + impactOther(11), + inkjetAqueous(12), + inkjetSolid(13), + inkjetOther(14), + pen(15), + thermalTransfer(16), + thermalSensitive(17), + thermalDiffusion(18), + thermalOther(19), + electroerosion(20), + electrostatic(21), + photographicMicrofiche(22), + photographicImagesetter(23), + photographicOther(24), + ionDeposition(25), + eBeam(26), + typesetter(27) + } + +PrtMarkerSuppliesTypeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtMarkerSuppliesType in RFC 1759. + STATUS current + DESCRIPTION + "The type of this supply." + SYNTAX INTEGER { + other(1), + unknown(2), + + -- Values for Printer MIB + toner(3), + wasteToner(4), + ink(5), + inkCartridge(6), + inkRibbon(7), + wasteInk(8), + opc(9), -- photo conductor + developer(10), + fuserOil(11), + solidWax(12), + ribbonWax(13), + wasteWax(14), + fuser(15), -- Not in RFC 1759 + coronaWire(16), -- Not in RFC 1759 + fuserOilWick(17), -- Not in RFC 1759 + cleanerUnit(18), -- Not in RFC 1759 + fuserCleaningPad(19), -- Not in RFC 1759 + transferUnit(20), -- Not in RFC 1759 + tonerCartridge(21), -- Not in RFC 1759 + fuserOiler(22), -- Not in RFC 1759 + -- End of values for Printer MIB + -- Values for Finisher MIB + water(23), -- Not in RFC 1759 + wasteWater(24), -- Not in RFC 1759 + glueWaterAdditive(25),-- Not in RFC 1759 + wastePaper(26), -- Not in RFC 1759 + bindingSupply(27), -- Not in RFC 1759 + bandingSupply(28), -- Not in RFC 1759 + stitchingWire(29), -- Not in RFC 1759 + shrinkWrap(30), -- Not in RFC 1759 + paperWrap(31), -- Not in RFC 1759 + staples(32), -- Not in RFC 1759 + inserts(33), -- Not in RFC 1759 + covers(34) -- Not in RFC 1759 + -- End of values for Finisher MIB + } + +-- +-- Media Path TEXTUAL-CONVENTIONs +-- + +PrtMediaPathTypeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtMediaPathType in RFC 1759. + STATUS current + DESCRIPTION + "The type of the media path for this media path." + SYNTAX INTEGER { + + other(1), + unknown(2), + longEdgeBindingDuplex(3), + shortEdgeBindingDuplex(4), + simplex(5) + } + +-- +-- Console Group TEXTUAL-CONVENTIONs +-- + +PrtConsoleColorTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtConsoleColor in RFC 1759. + STATUS current + DESCRIPTION + "The color of this light." + SYNTAX INTEGER { + other(1), + unknown(2), + white(3), + red(4), + green(5), + blue(6), + cyan(7), + magenta(8), + yellow(9), + orange(10) -- Not in RFC 1759 + } + +PrtConsoleDisableTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtConsoleDisable in RFC 1759. + STATUS current + DESCRIPTION + "This value indicates whether or not input is accepted from + the operator console. A value of 'enabled' indicates that + input is accepted from the console, and a value of 'disabled' + indicates that input is not accepted from the console. " + SYNTAX INTEGER { + enabled(3), + disabled(4) + } + +-- +-- Alert Group TEXTUAL-CONVENTIONs +-- + +PrtAlertTrainingLevelTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtAlertTrainingLevel in RFC 1759. + + STATUS current + DESCRIPTION + "The level of training required to handle this alert, if + human intervention is required. The noInterventionRequired + value should be used if the event does not require any human + intervention. The training level is an enumeration that is + determined and assigned by the printer manufacturer based on + the information or training required to handle this alert. + The printer will break alerts into these different training + levels. It is the responsibility of a management application + in the system to determine how a particular alert is handled + and how and to whom that alert is routed. The following are + the four training levels of alerts: + + Field Service - Alerts that typically require advanced + training and technical knowledge of the printer and its + subunits. An example of a technical person would be a + manufacturer's Field Service representative, or other + person formally trained by the manufacturer or similar + representative. + Trained - Alerts that require an intermediate or moderate + knowledge of the printer and its subunits. A typical + example of such an alert is replacing a toner cartridge. + Untrained - Alerts that can be fixed without prior + training either because the action to correct the alert + is obvious or the printer can help the untrained person + fix the problem. A typical example of such an alert is + reloading paper trays or emptying output bins on a low + end printer. + Management - Alerts that have to do with overall operation + of and configuration of the printer. Examples of such + management events are configuration change of subunits." + SYNTAX INTEGER { + other(1), + unknown(2), + untrained(3), + trained(4), + fieldService(5), + management(6), + noInterventionRequired(7) -- Not in RFC 1759 + } + +PrtAlertGroupTC ::= TEXTUAL-CONVENTION + -- Values in the range 1 to 29 must not be IANA-assigned without + -- re-publishing Printer MIB. + -- Values of 30 and greater are for use in MIBs that augment + -- the Printer MIB, such as the Finisher MIB. + -- This TC extracted from prtAlertGroup in RFC 1759. + + STATUS current + DESCRIPTION + "The type of subunit within the printer model that this alert + is related. Input, output, and markers are examples of + printer model groups, i.e., examples of types of subunits. + Wherever possible, the enumerations match the sub-identifier + that identifies the relevant table in the Printer MIB. + + NOTE: Alert type codes have been added for the Host Resources + MIB storage table and device table. These additional types + are for situations in which the printer's storage and device + objects must generate alerts (and possibly traps for critical + alerts)." + SYNTAX INTEGER { + other(1), + unknown(2), + -- Values for Host Resources MIB + hostResourcesMIBStorageTable(3), + hostResourcesMIBDeviceTable(4), + -- Values for Printer MIB + generalPrinter(5), + cover(6), + localization(7), + input(8), + output(9), + marker(10), + markerSupplies(11), + markerColorant(12), + mediaPath(13), + channel(14), + interpreter(15), + consoleDisplayBuffer(16), + consoleLights(17), + alert(18), -- Not in RFC 1759 + -- Values (5) to (29) reserved for Printer MIB + -- Values for Finisher MIB + finDevice(30), -- Not in RFC 1759 + finSupply(31), -- Not in RFC 1759 + finSupplyMediaInput(32), -- Not in RFC 1759 + finAttribute(33) -- Not in RFC 1759 + -- Values (30) to (39) reserved for Finisher MIB + } + +PrtAlertCodeTC ::= TEXTUAL-CONVENTION + -- This TC was extracted from prtAlertCode in RFC 1759. + STATUS current + DESCRIPTION + "The code that describes the type of alert for this entry in + + the table. Binary change event alerts describe states of the + subunit while unary change event alerts describe a single + event. The same alert code can be used for a binary change + event or a unary change event, depending on implementation. + Also, the same alert code can be used to indicate a critical + or non-critical (warning) alert, depending on implementation. + The value of prtAlertSeverityLevel specifies binary vs. unary + and critical vs. non-critical for each event for the + implementation. + + While there are some specific codes for many subunits, the + generic codes should be used for most subunit alerts. The + network management station can then query the subunit + specified by prtAlertGroup to determine further subunit + status and other subunit information. + + An agent shall not add two entries to the alert table for the + same event, one containing a generic event code and the other + containing a specific event code; the agent shall add only + one entry in the alert table for each event; either generic + (preferred) or specific, not both. + + Implementation of the unary change event + alertRemovalOfBinaryChangeEntry(1801) is optional. When + implemented, this alert code shall indicate to network + management stations that the trailing edge of a binary change + event has occurred and the corresponding alert entry has been + removed from the alert table. As with all events, the + alertRemovalOfBinaryChangeEntry(1801) alert shall be placed + at the end of the alert table. Such an alert table entry + shall specify the following information: + + prtAlertSeverityLevel warningUnaryChangeEvent(4) + prtAlertTrainingLevel noInterventionRequired(7) + prtAlertGroup alert(18) + prtAlertGroupIndex the index of the row in the + alert table of the binary + change event that this event + has removed. + prtAlertLocation unknown (-2) + prtAlertCode alertRemovalOfBinaryChangeEntry(1801) + prtAlertDescription + prtAlertTime the value of sysUpTime at + the time of the removal of the + binary change event from the + alert table. + + Optionally, the agent may generate a trap coincident with + + removing the binary change event and placing the unary change + event alertRemovalOfBinaryChangeEntry(1801) in the alert + table. For such a trap, the prtAlertIndex sent with the above + trap parameters shall be the index of the + alertRemovalOfBinaryChangeEvent row that was added to the + prtAlertTable; not the index of the row that was removed from + the prtAlertTable." + SYNTAX INTEGER { + other(1), + -- an event that is not represented + -- by one of the alert codes + -- specified below. + unknown(2), + -- The following generic codes are common to + -- multiple groups. The NMS may examine the + -- prtAlertGroup object to determine what group + -- to query for further information. + coverOpen(3), + coverClosed(4), + interlockOpen(5), + interlockClosed(6), + configurationChange(7), + jam(8), + subunitMissing(9), -- Not in RFC 1759 + -- The subunit tray, bin, etc. + -- has been removed. + subunitLifeAlmostOver(10), -- Not in RFC 1759 + subunitLifeOver(11), -- Not in RFC 1759 + subunitAlmostEmpty(12), -- Not in RFC 1759 + subunitEmpty(13), -- Not in RFC 1759 + subunitAlmostFull(14), -- Not in RFC 1759 + subunitFull(15), -- Not in RFC 1759 + subunitNearLimit(16), -- Not in RFC 1759 + subunitAtLimit(17), -- Not in RFC 1759 + subunitOpened(18), -- Not in RFC 1759 + subunitClosed(19), -- Not in RFC 1759 + subunitTurnedOn(20), -- Not in RFC 1759 + subunitTurnedOff(21), -- Not in RFC 1759 + subunitOffline(22), -- Not in RFC 1759 + subunitPowerSaver(23), -- Not in RFC 1759 + subunitWarmingUp(24), -- Not in RFC 1759 + subunitAdded(25), -- Not in RFC 1759 + subunitRemoved(26), -- Not in RFC 1759 + subunitResourceAdded(27), -- Not in RFC 1759 + subunitResourceRemoved(28), -- Not in RFC 1759 + subunitRecoverableFailure(29), + -- Not in RFC 1759 + subunitUnrecoverableFailure(30), + + -- Not in RFC 1759 + subunitRecoverableStorageError(31), + -- Not in RFC 1759 + subunitUnrecoverableStorageError(32), + -- Not in RFC 1759 + subunitMotorFailure(33), -- Not in RFC 1759 + subunitMemoryExhausted(34), -- Not in RFC 1759 + subunitUnderTemperature(35), -- Not in RFC 1759 + subunitOverTemperature(36), -- Not in RFC 1759 + subunitTimingFailure(37), -- Not in RFC 1759 + subunitThermistorFailure(38), -- Not in RFC 1759 + + -- General Printer group + doorOpen(501), -- DEPRECATED + -- Use coverOpened(3) + doorClosed(502), -- DEPRECATED + -- Use coverClosed(4) + powerUp(503), + powerDown(504), + printerNMSReset(505), -- Not in RFC 1759 + -- The printer has been reset by some + -- network management station(NMS) + -- writing into 'prtGeneralReset'. + printerManualReset(506), -- Not in RFC 1759 + -- The printer has been reset manually. + printerReadyToPrint(507), -- Not in RFC 1759 + -- The printer is ready to print. (i.e., + -- not warming up, not in power save + -- state, not adjusting print quality, + -- etc.). + + -- Input Group + inputMediaTrayMissing(801), + inputMediaSizeChange(802), + inputMediaWeightChange(803), + inputMediaTypeChange(804), + inputMediaColorChange(805), + inputMediaFormPartsChange(806), + inputMediaSupplyLow(807), + inputMediaSupplyEmpty(808), + inputMediaChangeRequest(809), -- Not in RFC 1759 + -- An interpreter has detected that a + -- different medium is need in this input + -- tray subunit. The prtAlertDescription may + -- be used to convey a human readable + -- description of the medium required to + -- satisfy the request. + inputManualInputRequest(810), -- Not in RFC 1759 + + -- An interpreter has detected that manual + -- input is required in this subunit. The + -- prtAlertDescription may be used to convey + -- a human readable description of the medium + -- required to satisfy the request. + inputTrayPositionFailure(811), -- Not in RFC 1759 + -- The input tray failed to position correctly. + inputTrayElevationFailure(812), + -- Not in RFC 1759 + inputCannotFeedSizeSelected(813), + -- Not in RFC 1759 + -- Output Group + outputMediaTrayMissing(901), + outputMediaTrayAlmostFull(902), + outputMediaTrayFull(903), + outputMailboxSelectFailure(904), + -- Not in RFC 1759 + -- Marker group + markerFuserUnderTemperature(1001), + markerFuserOverTemperature(1002), + markerFuserTimingFailure(1003), + -- Not in RFC 1759 + markerFuserThermistorFailure(1004), + -- Not in RFC 1759 + markerAdjustingPrintQuality(1005), + -- Not in RFC 1759 + -- Marker Supplies group + markerTonerEmpty(1101), + markerInkEmpty(1102), + markerPrintRibbonEmpty(1103), + markerTonerAlmostEmpty(1104), + markerInkAlmostEmpty(1105), + markerPrintRibbonAlmostEmpty(1106), + markerWasteTonerReceptacleAlmostFull(1107), + markerWasteInkReceptacleAlmostFull(1108), + markerWasteTonerReceptacleFull(1109), + markerWasteInkReceptacleFull(1110), + markerOpcLifeAlmostOver(1111), + markerOpcLifeOver(1112), + markerDeveloperAlmostEmpty(1113), + markerDeveloperEmpty(1114), + markerTonerCartridgeMissing(1115), + -- Not in RFC 1759 + -- Media Path Device Group + mediaPathMediaTrayMissing(1301), + mediaPathMediaTrayAlmostFull(1302), + mediaPathMediaTrayFull(1303), + mediaPathCannotDuplexMediaSelected(1304), + + -- Not in RFC 1759 + -- Interpreter Group + interpreterMemoryIncrease(1501), + interpreterMemoryDecrease(1502), + interpreterCartridgeAdded(1503), + interpreterCartridgeDeleted(1504), + interpreterResourceAdded(1505), + interpreterResourceDeleted(1506), + interpreterResourceUnavailable(1507), + interpreterComplexPageEncountered(1509), + -- Not in RFC 1759 + -- The interpreter has encountered a page + -- that is too complex for the resources that + -- are available. + -- Alert Group + alertRemovalOfBinaryChangeEntry(1801) + -- Not in RFC 1759 + -- A binary change event entry has been + -- removed from the alert table. This unary + -- change alert table entry is added to the + -- end of the alert table. + } +END + + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-RTPROTO-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-RTPROTO-MIB new file mode 100644 index 0000000..952c84e --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANA-RTPROTO-MIB @@ -0,0 +1,92 @@ + +IANA-RTPROTO-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, mib-2 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + +ianaRtProtoMIB MODULE-IDENTITY + LAST-UPDATED "200009260000Z" -- September 26, 2000 + ORGANIZATION "IANA" + CONTACT-INFO + " Internet Assigned Numbers Authority + Internet Corporation for Assigned Names and Numbers + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292-6601 + + Phone: +1 310 823 9358 + EMail: iana&iana.org" + DESCRIPTION + "This MIB module defines the IANAipRouteProtocol and + IANAipMRouteProtocol textual conventions for use in MIBs + which need to identify unicast or multicast routing + mechanisms. + + Any additions or changes to the contents of this MIB module + require either publication of an RFC, or Designated Expert + Review as defined in RFC 2434, Guidelines for Writing an + IANA Considerations Section in RFCs. The Designated Expert + will be selected by the IESG Area Director(s) of the Routing + Area." + + REVISION "200009260000Z" -- September 26, 2000 + DESCRIPTION "Original version, published in coordination + with RFC 2932." + + ::= { mib-2 84 } + +IANAipRouteProtocol ::= TEXTUAL-CONVENTION + STATUS current + + DESCRIPTION + "A mechanism for learning routes. Inclusion of values for + routing protocols is not intended to imply that those + protocols need be supported." + SYNTAX INTEGER { + other (1), -- not specified + local (2), -- local interface + netmgmt (3), -- static route + icmp (4), -- result of ICMP Redirect + + -- the following are all dynamic + -- routing protocols + + egp (5), -- Exterior Gateway Protocol + ggp (6), -- Gateway-Gateway Protocol + hello (7), -- FuzzBall HelloSpeak + rip (8), -- Berkeley RIP or RIP-II + isIs (9), -- Dual IS-IS + esIs (10), -- ISO 9542 + ciscoIgrp (11), -- Cisco IGRP + bbnSpfIgp (12), -- BBN SPF IGP + ospf (13), -- Open Shortest Path First + bgp (14), -- Border Gateway Protocol + idpr (15), -- InterDomain Policy Routing + ciscoEigrp (16), -- Cisco EIGRP + dvmrp (17) -- DVMRP + } + +IANAipMRouteProtocol ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The multicast routing protocol. Inclusion of values for + multicast routing protocols is not intended to imply that + those protocols need be supported." + SYNTAX INTEGER { + other(1), -- none of the following + local(2), -- e.g., manually configured + netmgmt(3), -- set via net.mgmt protocol + dvmrp(4), + mospf(5), + pimSparseDense(6), -- PIMv1, both DM and SM + cbt(7), + pimSparseMode(8), -- PIM-SM + pimDenseMode(9), -- PIM-DM + igmpOnly(10), + bgmp(11), + msdp(12) + } + +END + + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANATn3270eTC-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANATn3270eTC-MIB new file mode 100644 index 0000000..e774ac0 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANATn3270eTC-MIB @@ -0,0 +1,306 @@ + + IANATn3270eTC-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, mib-2 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION + FROM SNMPv2-TC; + + ianaTn3270eTcMib MODULE-IDENTITY + LAST-UPDATED "200005100000Z" -- May 10, 2000 + ORGANIZATION "IANA" + CONTACT-INFO + "Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 x20 + E-Mail: iana&iana.org" + DESCRIPTION + "This module defines a set of textual conventions + for use by the TN3270E-MIB and the TN3270E-RT-MIB. + + Any additions or changes to the contents of this + MIB module must first be discussed on the tn3270e + working group list at: tn3270e&list.nih.gov + and approved by one of the following TN3270E + working group contacts: + + Ed Bailey (co-chair) - elbailey&us.ibm.com + Michael Boe (co-chair) - mboe&cisco.com + Ken White - kennethw&vnet.ibm.com + Robert Moore - remoore&us.ibm.com + + The above list of contacts can be altered with + the approval of the two co-chairs. + + The Textual Conventions defined within this MIB have + no security issues associated with them unless + explicitly stated in their corresponding + DESCRIPTION clause." + + -- revision log, in reverse chronological order + + REVISION "200005100000Z" -- May 10, 2000 + DESCRIPTION "Fix to import mib-2 instead of experimental." + + REVISION "199909011000Z" -- September 1, 1999 + DESCRIPTION + "Initial version transferred from the TN3270E + working group to IANA." + + ::= { mib-2 61 } + + + -- Textual Conventions + + IANATn3270eAddrType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The textual convention for defining the type of a + client address. The enumeration value unknown(0) is + also used to indicate that no actual address is present." + SYNTAX INTEGER { + unknown(0), + ipv4(1), + ipv6(2) + } + + IANATn3270eAddress ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Denotes a client address. The type of client address is + determined by use of the IANATn3270eAddrType textual +convention. + The length in octets of a IANATn3270eAddress object is: + + IANATn3270eAddrType Address Length + +++++++++++++++++++ ++++++++++++++ + unknown(0) not specified or unknown; the + actual length of the + IANATn3270eAddress octet string + indicates if an address + is present + ipv4(1) 4 OCTETS + ipv6(2) 16 OCTETS + + This textual convention is similar to the TAddress + TC defined by RFC1903 except that it allows a + zero-length octet string and is not a full transport + layer address." + SYNTAX OCTET STRING (SIZE (0..255)) + + IANATn3270eClientType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The textual convention for defining the set of + enumerations used by tn3270eTcpConnClientIdFormat + in the TN3270E-MIB: + + ENUMERATION OCTETs DESCRIPTION + + none(1) 0 Not specified + other(2) 1..512 Implementation specific + ipv4(3) 6 4-octet IP Address plus + 2-octet TCP Port + ipv6(4) 18 16-octet IPv6 Address + plus 2-octet TCP Port + domainName(5) 1..512 The DNS name of a + client. + truncDomainName(6) 1..512 The (truncated) DNS name + of a client. + string(7) 1..512 Unknown Utf8String + certificate(8) 1..512 certificate + userId(9) 1..8 Client's userid + x509dn(10) 1..512 X.509 Distinguished Name + + Representation of a certificate(8) may be lead to + a security exposure and is NOT RECOMMENDED without + adequate security." + SYNTAX INTEGER { + none(1), + other(2), + ipv4(3), + ipv6(4), + domainName(5), + truncDomainName(6), + string(7), + certificate(8), + userId(9), + x509dn(10) + } + + IANATn3270Functions ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This textual convention reflects the current set of + TN3270 and TN3270E functions that can be negotiated + between a server and its client: + + RFC856 + transmitBinary The sender of this command REQUESTS + permission to begin transmitting, or + confirms that it will now begin + transmitting characters which are to + be interpreted as 8 bits of binary + data by the receiver of the data. + RFC860 + timingMark The sender of this command REQUESTS + that the receiver of this command + return a WILL TIMING-MARK in the data + stream at the 'appropriate place'. + RFC885 + endOfRecord The sender of this command requests + permission to begin transmission of + the Telnet END-OF-RECORD (EOR) code + when transmitting data characters, or + the sender of this command confirms it + will now begin transmission of EORs + with transmitted data characters. + RFC1091 + terminalType Sender is willing to send terminal + type information in a subsequent + sub-negotiation. + + RFC1041 + tn3270Regime Sender is willing to send list of + supported 3270 Regimes in a + subsequent sub-negotiation. + RFC2355 + scsCtlCodes (Printer sessions only). Allows the + use of the SNA Character Stream (SCS) + and SCS control codes on the session. + SCS is used with LU type 1 SNA sessions. + dataStreamCtl (Printer sessions only). Allows the use + of the standard 3270 data stream. This + corresponds to LU type 3 SNA sessions. + responses Provides support for positive and + negative response handling. Allows the + server to reflect to the client any and + all definite, exception, and no response + requests sent by the host application. + bindImage Allows the server to send the SNA Bind + image and Unbind notification to the + client. + sysreq Allows the client and server to emulate + some (or all, depending on the server) of + the functions of the SYSREQ key in an SNA + environment." + SYNTAX BITS { + transmitBinary(0),-- rfc856 + timemark(1), -- rfc860 + endOfRecord(2), -- rfc885 + terminalType(3), -- rfc1091 + tn3270Regime(4), -- rfc1041 + scsCtlCodes(5), -- rfc2355 + dataStreamCtl(6), -- rfc2355 + responses(7), -- rfc2355 + bindImage(8), -- rfc2355 + sysreq(9) -- rfc2355 + } + + IANATn3270ResourceType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The type of resource defined by a resource pool. Refer + to tn3270eResPoolTable." + SYNTAX INTEGER { + other(1), + terminal(2), + printer(3), + terminalOrPrinter(4) + } + + IANATn3270DeviceType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This textual convention defines the list of device + types that can be set, as defined by RFC 2355." + SYNTAX INTEGER { + -- terminals + ibm3278d2(1), -- (24 row x 80 col display) + ibm3278d2E(2), -- (24 row x 80 col display) + ibm3278d3(3), -- (32 row x 80 col display) + ibm3278d3E(4), -- (32 row x 80 col display) + ibm3278d4(5), -- (43 row x 80 col display) + ibm3278d4E(6), -- (43 row x 80 col display) + ibm3278d5(7), -- (27 row x 132 col display) + ibm3278d5E(8), -- (27 row x 132 col display) + ibmDynamic(9), -- (no pre-defined display size) + + -- printers + ibm3287d1(10), + + unknown(100) + } + + IANATn3270eLogData ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An octet string representing log data as pertaining to + either a TN3270 or TN3270E Session as reported from a + TN3270E Server. Log data is stored in an octet string + in time order (from earliest to latest). + + Each log element has the following form: + + +------+----+---------+------------+ + !length!type!TimeStamp! data ! + +------+----+---------+------------+ + + where + + length = one-octet length of the data portion of the + trace element, not including the length, + type, and TimeStamp fields + type = one-octet code point characterizing the data. + TimeStamp = A 4-octet field representing the number of + TimeTicks since the TN3270E server was last + activated. The server's last activation time + is available in the tn3270eSrvrConfLastActTime + object in the TN3270E MIB, which has the + syntax DateAndTime. + data = initial part of a PDU. + + length type + + 0-255 x'00' - unknown + 0 x'01' - inactivity timer expired + 0 x'02' - dynamic timer expired + 0 x'03' - actlu req + 0 x'04' - bind req + 0 x'05' - clear req + 0 x'06' - dactlu req + 0 x'07' - warm actpu req + 0 x'08' - sdt req + 0 x'09' - unbind req + 0 x'0A' - notify resp + 0 x'0B' - reply PSID neg rsp + 0 x'0C' - reply PSID pos rsp + 0 x'0D' - unbind rsp + 0 x'0E' - hierarchical reset + 0 x'0F' - client connect req + 0 x'10' - client disconnect req + 0 x'11' - timingmark received + 0 x'12' - flowControl timer expired + 0 x'13' - neg rsp to host + 0 x'14' - neg rsp from host + 0 x'15' - data contention + 0 x'16' - no buffer to send SNA data + 0 x'17' - receive response while inbound + 0 x'18' - client protocol error + 0 x'19' - badClientSequenceReceived + 1-255 x'1A' - utf8String + 2 x'1B' - hexCode, implementation dependent + + Log element entries have a minimum length of 6 octets. + The zero-length string indicates that no log data is + available." + SYNTAX OCTET STRING (SIZE (0 | 6..2048)) + + END + + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IANA/IANAifType-MIB b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANAifType-MIB new file mode 100644 index 0000000..39dddf9 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IANA/IANAifType-MIB @@ -0,0 +1,572 @@ + IANAifType-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, mib-2 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + + ianaifType MODULE-IDENTITY + LAST-UPDATED "200709130000Z" -- September 13, 2007 + ORGANIZATION "IANA" + CONTACT-INFO " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + E-Mail: iana&iana.org" + + DESCRIPTION "This MIB module defines the IANAifType Textual + Convention, and thus the enumerated values of + the ifType object defined in MIB-II's ifTable." + + REVISION "200709130000Z" -- September 13, 2007 + DESCRIPTION "Registration of new IANAifTypes 243 and 244." + + REVISION "200705290000Z" -- May 29, 2007 + DESCRIPTION "Changed the description for IANAifType 228." + + REVISION "200703080000Z" -- March 08, 2007 + DESCRIPTION "Registration of new IANAifType 242." + + REVISION "200701230000Z" -- January 23, 2007 + DESCRIPTION "Registration of new IANAifTypes 239, 240, and 241." + + REVISION "200610170000Z" -- October 17, 2006 + DESCRIPTION "Deprecated/Obsoleted IANAifType 230. Registration of + IANAifType 238." + + REVISION "200609250000Z" -- September 25, 2006 + DESCRIPTION "Changed the description for IANA ifType + 184 and added new IANA ifType 237." + + REVISION "200608170000Z" -- August 17, 2006 + DESCRIPTION "Changed the descriptions for IANAifTypes + 20 and 21." + + REVISION "200608110000Z" -- August 11, 2006 + DESCRIPTION "Changed the descriptions for IANAifTypes + 7, 11, 62, 69, and 117." + + REVISION "200607250000Z" -- July 25, 2006 + DESCRIPTION "Registration of new IANA ifType 236." + + REVISION "200606140000Z" -- June 14, 2006 + DESCRIPTION "Registration of new IANA ifType 235." + + REVISION "200603310000Z" -- March 31, 2006 + DESCRIPTION "Registration of new IANA ifType 234." + + REVISION "200603300000Z" -- March 30, 2006 + DESCRIPTION "Registration of new IANA ifType 233." + + REVISION "200512220000Z" -- December 22, 2005 + DESCRIPTION "Registration of new IANA ifTypes 231 and 232." + + REVISION "200510100000Z" -- October 10, 2005 + DESCRIPTION "Registration of new IANA ifType 230." + + REVISION "200509090000Z" -- September 09, 2005 + DESCRIPTION "Registration of new IANA ifType 229." + + REVISION "200505270000Z" -- May 27, 2005 + DESCRIPTION "Registration of new IANA ifType 228." + + REVISION "200503030000Z" -- March 3, 2005 + DESCRIPTION "Added the IANAtunnelType TC and deprecated + IANAifType sixToFour (215) per RFC4087." + + REVISION "200411220000Z" -- November 22, 2004 + DESCRIPTION "Registration of new IANA ifType 227 per RFC4631." + + REVISION "200406170000Z" -- June 17, 2004 + DESCRIPTION "Registration of new IANA ifType 226." + + REVISION "200405120000Z" -- May 12, 2004 + DESCRIPTION "Added description for IANAifType 6, and + changed the descriptions for IANAifTypes + 180, 181, and 182." + + REVISION "200405070000Z" -- May 7, 2004 + DESCRIPTION "Registration of new IANAifType 225." + + REVISION "200308250000Z" -- Aug 25, 2003 + DESCRIPTION "Deprecated IANAifTypes 7 and 11. Obsoleted + IANAifTypes 62, 69, and 117. ethernetCsmacd (6) + should be used instead of these values" + + REVISION "200308180000Z" -- Aug 18, 2003 + DESCRIPTION "Registration of new IANAifType + 224." + + REVISION "200308070000Z" -- Aug 7, 2003 + DESCRIPTION "Registration of new IANAifTypes + 222 and 223." + + REVISION "200303180000Z" -- Mar 18, 2003 + DESCRIPTION "Registration of new IANAifType + 221." + + REVISION "200301130000Z" -- Jan 13, 2003 + DESCRIPTION "Registration of new IANAifType + 220." + + REVISION "200210170000Z" -- Oct 17, 2002 + DESCRIPTION "Registration of new IANAifType + 219." + + REVISION "200207160000Z" -- Jul 16, 2002 + DESCRIPTION "Registration of new IANAifTypes + 217 and 218." + + REVISION "200207100000Z" -- Jul 10, 2002 + DESCRIPTION "Registration of new IANAifTypes + 215 and 216." + + REVISION "200206190000Z" -- Jun 19, 2002 + DESCRIPTION "Registration of new IANAifType + 214." + + REVISION "200201040000Z" -- Jan 4, 2002 + DESCRIPTION "Registration of new IANAifTypes + 211, 212 and 213." + + REVISION "200112200000Z" -- Dec 20, 2001 + DESCRIPTION "Registration of new IANAifTypes + 209 and 210." + + REVISION "200111150000Z" -- Nov 15, 2001 + DESCRIPTION "Registration of new IANAifTypes + 207 and 208." + + + REVISION "200111060000Z" -- Nov 6, 2001 + DESCRIPTION "Registration of new IANAifType + 206." + + + REVISION "200111020000Z" -- Nov 2, 2001 + DESCRIPTION "Registration of new IANAifType + 205." + + + REVISION "200110160000Z" -- Oct 16, 2001 + DESCRIPTION "Registration of new IANAifTypes + 199, 200, 201, 202, 203, and 204." + + + REVISION "200109190000Z" -- Sept 19, 2001 + DESCRIPTION "Registration of new IANAifType + 198." + + REVISION "200105110000Z" -- May 11, 2001 + DESCRIPTION "Registration of new IANAifType + 197." + + + REVISION "200101120000Z" -- Jan 12, 2001 + DESCRIPTION "Registration of new IANAifTypes + 195 and 196." + + REVISION "200012190000Z" -- Dec 19, 2000 + DESCRIPTION "Registration of new IANAifTypes + 193 and 194." + + REVISION "200012070000Z" -- Dec 07, 2000 + DESCRIPTION "Registration of new IANAifTypes + 191 and 192." + + REVISION "200012040000Z" -- Dec 04, 2000 + DESCRIPTION "Registration of new IANAifType + 190." + + REVISION "200010170000Z" -- Oct 17, 2000 + DESCRIPTION "Registration of new IANAifTypes + 188 and 189." + + REVISION "200010020000Z" -- Oct 02, 2000 + DESCRIPTION "Registration of new IANAifType 187." + + REVISION "200009010000Z" -- Sept 01, 2000 + DESCRIPTION "Registration of new IANAifTypes + 184, 185, and 186." + + REVISION "200008240000Z" -- Aug 24, 2000 + DESCRIPTION "Registration of new IANAifType 183." + + REVISION "200008230000Z" -- Aug 23, 2000 + DESCRIPTION "Registration of new IANAifTypes + 174-182." + + REVISION "200008220000Z" -- Aug 22, 2000 + DESCRIPTION "Registration of new IANAifTypes 170, + 171, 172 and 173." + + REVISION "200004250000Z" -- Apr 25, 2000 + DESCRIPTION "Registration of new IANAifTypes 168 and 169." + + REVISION "200003060000Z" -- Mar 6, 2000 + DESCRIPTION "Fixed a missing semi-colon in the IMPORT. + Also cleaned up the REVISION log a bit. + It is not complete, but from now on it will + be maintained and kept up to date with each + change to this MIB module." + + REVISION "199910081430Z" -- Oct 08, 1999 + DESCRIPTION "Include new name assignments up to cnr(85). + This is the first version available via the WWW + at: ftp://ftp.isi.edu/mib/ianaiftype.mib" + + REVISION "199401310000Z" -- Jan 31, 1994 + DESCRIPTION "Initial version of this MIB as published in + RFC 1573." + + ::= { mib-2 30 } + + + IANAifType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This data type is used as the syntax of the ifType + object in the (updated) definition of MIB-II's + ifTable. + + The definition of this textual convention with the + addition of newly assigned values is published + periodically by the IANA, in either the Assigned + Numbers RFC, or some derivative of it specific to + Internet Network Management number assignments. (The + latest arrangements can be obtained by contacting the + IANA.) + + Requests for new values should be made to IANA via + email (iana&iana.org). + + The relationship between the assignment of ifType + values and of OIDs to particular media-specific MIBs + is solely the purview of IANA and is subject to change + without notice. Quite often, a media-specific MIB's + OID-subtree assignment within MIB-II's 'transmission' + subtree will be the same as its ifType value. + However, in some circumstances this will not be the + case, and implementors must not pre-assume any + specific relationship between ifType values and + transmission subtree OIDs." + SYNTAX INTEGER { + other(1), -- none of the following + regular1822(2), + hdh1822(3), + ddnX25(4), + rfc877x25(5), + ethernetCsmacd(6), -- for all ethernet-like interfaces, + -- regardless of speed, as per RFC3635 + iso88023Csmacd(7), -- Deprecated via RFC3635 + -- ethernetCsmacd (6) should be used instead + iso88024TokenBus(8), + iso88025TokenRing(9), + iso88026Man(10), + starLan(11), -- Deprecated via RFC3635 + -- ethernetCsmacd (6) should be used instead + proteon10Mbit(12), + proteon80Mbit(13), + hyperchannel(14), + fddi(15), + lapb(16), + sdlc(17), + ds1(18), -- DS1-MIB + e1(19), -- Obsolete see DS1-MIB + basicISDN(20), -- no longer used + -- see also RFC2127 + primaryISDN(21), -- no longer used + -- see also RFC2127 + propPointToPointSerial(22), -- proprietary serial + ppp(23), + softwareLoopback(24), + eon(25), -- CLNP over IP + ethernet3Mbit(26), + nsip(27), -- XNS over IP + slip(28), -- generic SLIP + ultra(29), -- ULTRA technologies + ds3(30), -- DS3-MIB + sip(31), -- SMDS, coffee + frameRelay(32), -- DTE only. + rs232(33), + para(34), -- parallel-port + arcnet(35), -- arcnet + arcnetPlus(36), -- arcnet plus + atm(37), -- ATM cells + miox25(38), + sonet(39), -- SONET or SDH + x25ple(40), + iso88022llc(41), + localTalk(42), + smdsDxi(43), + frameRelayService(44), -- FRNETSERV-MIB + v35(45), + hssi(46), + hippi(47), + modem(48), -- Generic modem + aal5(49), -- AAL5 over ATM + sonetPath(50), + sonetVT(51), + smdsIcip(52), -- SMDS InterCarrier Interface + propVirtual(53), -- proprietary virtual/internal + propMultiplexor(54),-- proprietary multiplexing + ieee80212(55), -- 100BaseVG + fibreChannel(56), -- Fibre Channel + hippiInterface(57), -- HIPPI interfaces + frameRelayInterconnect(58), -- Obsolete use either + -- frameRelay(32) or + -- frameRelayService(44). + aflane8023(59), -- ATM Emulated LAN for 802.3 + aflane8025(60), -- ATM Emulated LAN for 802.5 + cctEmul(61), -- ATM Emulated circuit + fastEther(62), -- Obsoleted via RFC3635 + -- ethernetCsmacd (6) should be used instead + isdn(63), -- ISDN and X.25 + v11(64), -- CCITT V.11/X.21 + v36(65), -- CCITT V.36 + g703at64k(66), -- CCITT G703 at 64Kbps + g703at2mb(67), -- Obsolete see DS1-MIB + qllc(68), -- SNA QLLC + fastEtherFX(69), -- Obsoleted via RFC3635 + -- ethernetCsmacd (6) should be used instead + channel(70), -- channel + ieee80211(71), -- radio spread spectrum + ibm370parChan(72), -- IBM System 360/370 OEMI Channel + escon(73), -- IBM Enterprise Systems Connection + dlsw(74), -- Data Link Switching + isdns(75), -- ISDN S/T interface + isdnu(76), -- ISDN U interface + lapd(77), -- Link Access Protocol D + ipSwitch(78), -- IP Switching Objects + rsrb(79), -- Remote Source Route Bridging + atmLogical(80), -- ATM Logical Port + ds0(81), -- Digital Signal Level 0 + ds0Bundle(82), -- group of ds0s on the same ds1 + bsc(83), -- Bisynchronous Protocol + async(84), -- Asynchronous Protocol + cnr(85), -- Combat Net Radio + iso88025Dtr(86), -- ISO 802.5r DTR + eplrs(87), -- Ext Pos Loc Report Sys + arap(88), -- Appletalk Remote Access Protocol + propCnls(89), -- Proprietary Connectionless Protocol + hostPad(90), -- CCITT-ITU X.29 PAD Protocol + termPad(91), -- CCITT-ITU X.3 PAD Facility + frameRelayMPI(92), -- Multiproto Interconnect over FR + x213(93), -- CCITT-ITU X213 + adsl(94), -- Asymmetric Digital Subscriber Loop + radsl(95), -- Rate-Adapt. Digital Subscriber Loop + sdsl(96), -- Symmetric Digital Subscriber Loop + vdsl(97), -- Very H-Speed Digital Subscrib. Loop + iso88025CRFPInt(98), -- ISO 802.5 CRFP + myrinet(99), -- Myricom Myrinet + voiceEM(100), -- voice recEive and transMit + voiceFXO(101), -- voice Foreign Exchange Office + voiceFXS(102), -- voice Foreign Exchange Station + voiceEncap(103), -- voice encapsulation + voiceOverIp(104), -- voice over IP encapsulation + atmDxi(105), -- ATM DXI + atmFuni(106), -- ATM FUNI + atmIma (107), -- ATM IMA + pppMultilinkBundle(108), -- PPP Multilink Bundle + ipOverCdlc (109), -- IBM ipOverCdlc + ipOverClaw (110), -- IBM Common Link Access to Workstn + stackToStack (111), -- IBM stackToStack + virtualIpAddress (112), -- IBM VIPA + mpc (113), -- IBM multi-protocol channel support + ipOverAtm (114), -- IBM ipOverAtm + iso88025Fiber (115), -- ISO 802.5j Fiber Token Ring + tdlc (116), -- IBM twinaxial data link control + gigabitEthernet (117), -- Obsoleted via RFC3635 + -- ethernetCsmacd (6) should be used instead + hdlc (118), -- HDLC + lapf (119), -- LAP F + v37 (120), -- V.37 + x25mlp (121), -- Multi-Link Protocol + x25huntGroup (122), -- X25 Hunt Group + trasnpHdlc (123), -- Transp HDLC + interleave (124), -- Interleave channel + fast (125), -- Fast channel + ip (126), -- IP (for APPN HPR in IP networks) + docsCableMaclayer (127), -- CATV Mac Layer + docsCableDownstream (128), -- CATV Downstream interface + docsCableUpstream (129), -- CATV Upstream interface + a12MppSwitch (130), -- Avalon Parallel Processor + tunnel (131), -- Encapsulation interface + coffee (132), -- coffee pot + ces (133), -- Circuit Emulation Service + atmSubInterface (134), -- ATM Sub Interface + l2vlan (135), -- Layer 2 Virtual LAN using 802.1Q + l3ipvlan (136), -- Layer 3 Virtual LAN using IP + l3ipxvlan (137), -- Layer 3 Virtual LAN using IPX + digitalPowerline (138), -- IP over Power Lines + mediaMailOverIp (139), -- Multimedia Mail over IP + dtm (140), -- Dynamic syncronous Transfer Mode + dcn (141), -- Data Communications Network + ipForward (142), -- IP Forwarding Interface + msdsl (143), -- Multi-rate Symmetric DSL + ieee1394 (144), -- IEEE1394 High Performance Serial Bus + if-gsn (145), -- HIPPI-6400 + dvbRccMacLayer (146), -- DVB-RCC MAC Layer + dvbRccDownstream (147), -- DVB-RCC Downstream Channel + dvbRccUpstream (148), -- DVB-RCC Upstream Channel + atmVirtual (149), -- ATM Virtual Interface + mplsTunnel (150), -- MPLS Tunnel Virtual Interface + srp (151), -- Spatial Reuse Protocol + voiceOverAtm (152), -- Voice Over ATM + voiceOverFrameRelay (153), -- Voice Over Frame Relay + idsl (154), -- Digital Subscriber Loop over ISDN + compositeLink (155), -- Avici Composite Link Interface + ss7SigLink (156), -- SS7 Signaling Link + propWirelessP2P (157), -- Prop. P2P wireless interface + frForward (158), -- Frame Forward Interface + rfc1483 (159), -- Multiprotocol over ATM AAL5 + usb (160), -- USB Interface + ieee8023adLag (161), -- IEEE 802.3ad Link Aggregate + bgppolicyaccounting (162), -- BGP Policy Accounting + frf16MfrBundle (163), -- FRF .16 Multilink Frame Relay + h323Gatekeeper (164), -- H323 Gatekeeper + h323Proxy (165), -- H323 Voice and Video Proxy + mpls (166), -- MPLS + mfSigLink (167), -- Multi-frequency signaling link + hdsl2 (168), -- High Bit-Rate DSL - 2nd generation + shdsl (169), -- Multirate HDSL2 + ds1FDL (170), -- Facility Data Link 4Kbps on a DS1 + pos (171), -- Packet over SONET/SDH Interface + dvbAsiIn (172), -- DVB-ASI Input + dvbAsiOut (173), -- DVB-ASI Output + plc (174), -- Power Line Communtications + nfas (175), -- Non Facility Associated Signaling + tr008 (176), -- TR008 + gr303RDT (177), -- Remote Digital Terminal + gr303IDT (178), -- Integrated Digital Terminal + isup (179), -- ISUP + propDocsWirelessMaclayer (180), -- Cisco proprietary Maclayer + propDocsWirelessDownstream (181), -- Cisco proprietary Downstream + propDocsWirelessUpstream (182), -- Cisco proprietary Upstream + hiperlan2 (183), -- HIPERLAN Type 2 Radio Interface + propBWAp2Mp (184), -- PropBroadbandWirelessAccesspt2multipt + -- use of this iftype for IEEE 802.16 WMAN + -- interfaces as per IEEE Std 802.16f is + -- deprecated and ifType 237 should be used instead. + sonetOverheadChannel (185), -- SONET Overhead Channel + digitalWrapperOverheadChannel (186), -- Digital Wrapper + aal2 (187), -- ATM adaptation layer 2 + radioMAC (188), -- MAC layer over radio links + atmRadio (189), -- ATM over radio links + imt (190), -- Inter Machine Trunks + mvl (191), -- Multiple Virtual Lines DSL + reachDSL (192), -- Long Reach DSL + frDlciEndPt (193), -- Frame Relay DLCI End Point + atmVciEndPt (194), -- ATM VCI End Point + opticalChannel (195), -- Optical Channel + opticalTransport (196), -- Optical Transport + propAtm (197), -- Proprietary ATM + voiceOverCable (198), -- Voice Over Cable Interface + infiniband (199), -- Infiniband + teLink (200), -- TE Link + q2931 (201), -- Q.2931 + virtualTg (202), -- Virtual Trunk Group + sipTg (203), -- SIP Trunk Group + sipSig (204), -- SIP Signaling + docsCableUpstreamChannel (205), -- CATV Upstream Channel + econet (206), -- Acorn Econet + pon155 (207), -- FSAN 155Mb Symetrical PON interface + pon622 (208), -- FSAN622Mb Symetrical PON interface + bridge (209), -- Transparent bridge interface + linegroup (210), -- Interface common to multiple lines + voiceEMFGD (211), -- voice E&M Feature Group D + voiceFGDEANA (212), -- voice FGD Exchange Access North American + voiceDID (213), -- voice Direct Inward Dialing + mpegTransport (214), -- MPEG transport interface + sixToFour (215), -- 6to4 interface (DEPRECATED) + gtp (216), -- GTP (GPRS Tunneling Protocol) + pdnEtherLoop1 (217), -- Paradyne EtherLoop 1 + pdnEtherLoop2 (218), -- Paradyne EtherLoop 2 + opticalChannelGroup (219), -- Optical Channel Group + homepna (220), -- HomePNA ITU-T G.989 + gfp (221), -- Generic Framing Procedure (GFP) + ciscoISLvlan (222), -- Layer 2 Virtual LAN using Cisco ISL + actelisMetaLOOP (223), -- Acteleis proprietary MetaLOOP High Speed Link + fcipLink (224), -- FCIP Link + rpr (225), -- Resilient Packet Ring Interface Type + qam (226), -- RF Qam Interface + lmp (227), -- Link Management Protocol + cblVectaStar (228), -- Cambridge Broadband Networks Limited VectaStar + docsCableMCmtsDownstream (229), -- CATV Modular CMTS Downstream Interface + adsl2 (230), -- Asymmetric Digital Subscriber Loop Version 2 + -- (DEPRECATED/OBSOLETED - please use adsl2plus 238 instead) + macSecControlledIF (231), -- MACSecControlled + macSecUncontrolledIF (232), -- MACSecUncontrolled + aviciOpticalEther (233), -- Avici Optical Ethernet Aggregate + atmbond (234), -- atmbond + voiceFGDOS (235), -- voice FGD Operator Services + mocaVersion1 (236), -- MultiMedia over Coax Alliance (MoCA) Interface + -- as documented in information provided privately to IANA + ieee80216WMAN (237), -- IEEE 802.16 WMAN interface + adsl2plus (238), -- Asymmetric Digital Subscriber Loop Version 2, + -- Version 2 Plus and all variants + dvbRcsMacLayer (239), -- DVB-RCS MAC Layer + dvbTdm (240), -- DVB Satellite TDM + dvbRcsTdma (241), -- DVB-RCS TDMA + x86Laps (242), -- LAPS based on ITU-T X.86/Y.1323 + wwanPP (243), -- 3GPP WWAN + wwanPP2 (244) -- 3GPP2 WWAN + } + +IANAtunnelType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The encapsulation method used by a tunnel. The value + direct indicates that a packet is encapsulated + directly within a normal IP header, with no + intermediate header, and unicast to the remote tunnel + endpoint (e.g., an RFC 2003 IP-in-IP tunnel, or an RFC + 1933 IPv6-in-IPv4 tunnel). The value minimal indicates + that a Minimal Forwarding Header (RFC 2004) is + inserted between the outer header and the payload + packet. The value UDP indicates that the payload + packet is encapsulated within a normal UDP packet + (e.g., RFC 1234). + + The values sixToFour, sixOverFour, and isatap + indicates that an IPv6 packet is encapsulated directly + within an IPv4 header, with no intermediate header, + and unicast to the destination determined by the 6to4, + 6over4, or ISATAP protocol. + + The remaining protocol-specific values indicate that a + header of the protocol of that name is inserted + between the outer header and the payload header. + + The assignment policy for IANAtunnelType values is + identical to the policy for assigning IANAifType + values." + SYNTAX INTEGER { + other(1), -- none of the following + direct(2), -- no intermediate header + gre(3), -- GRE encapsulation + minimal(4), -- Minimal encapsulation + l2tp(5), -- L2TP encapsulation + pptp(6), -- PPTP encapsulation + l2f(7), -- L2F encapsulation + udp(8), -- UDP encapsulation + atmp(9), -- ATMP encapsulation + msdp(10), -- MSDP encapsulation + sixToFour(11), -- 6to4 encapsulation + sixOverFour(12), -- 6over4 encapsulation + isatap(13), -- ISATAP encapsulation + teredo(14) -- Teredo encapsulation + } + + END + + + + + + + + + diff --git a/contrib/apps/LwipMibCompiler/Mibs/IF-MIB b/contrib/apps/LwipMibCompiler/Mibs/IF-MIB new file mode 100644 index 0000000..8713894 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IF-MIB @@ -0,0 +1,1899 @@ +IF-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, Counter64, + Integer32, TimeTicks, mib-2, + NOTIFICATION-TYPE FROM SNMPv2-SMI + TEXTUAL-CONVENTION, DisplayString, + PhysAddress, TruthValue, RowStatus, + TimeStamp, AutonomousType, TestAndIncr FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, + NOTIFICATION-GROUP FROM SNMPv2-CONF + snmpTraps FROM SNMPv2-MIB + IANAifType FROM IANAifType-MIB; + + +ifMIB MODULE-IDENTITY + LAST-UPDATED "200006140000Z" + ORGANIZATION "IETF Interfaces MIB Working Group" + CONTACT-INFO + " Keith McCloghrie + Cisco Systems, Inc. + 170 West Tasman Drive + San Jose, CA 95134-1706 + US + + 408-526-5260 + kzm@cisco.com" + DESCRIPTION + "The MIB module to describe generic objects for network + interface sub-layers. This MIB is an updated version of + MIB-II's ifTable, and incorporates the extensions defined in + RFC 1229." + + + REVISION "200006140000Z" + DESCRIPTION + "Clarifications agreed upon by the Interfaces MIB WG, and + published as RFC 2863." + REVISION "199602282155Z" + DESCRIPTION + "Revisions made by the Interfaces MIB WG, and published in + RFC 2233." + REVISION "199311082155Z" + DESCRIPTION + "Initial revision, published as part of RFC 1573." + ::= { mib-2 31 } + + +ifMIBObjects OBJECT IDENTIFIER ::= { ifMIB 1 } + +interfaces OBJECT IDENTIFIER ::= { mib-2 2 } + +-- +-- Textual Conventions +-- + + +-- OwnerString has the same semantics as used in RFC 1271 + +OwnerString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS deprecated + DESCRIPTION + "This data type is used to model an administratively + assigned name of the owner of a resource. This information + is taken from the NVT ASCII character set. It is suggested + that this name contain one or more of the following: ASCII + form of the manager station's transport address, management + station name (e.g., domain name), network management + personnel's name, location, or phone number. In some cases + the agent itself will be the owner of an entry. In these + cases, this string shall be set to a string starting with + 'agent'." + SYNTAX OCTET STRING (SIZE(0..255)) + +-- InterfaceIndex contains the semantics of ifIndex and should be used +-- for any objects defined in other MIB modules that need these semantics. + +InterfaceIndex ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + + + "A unique value, greater than zero, for each interface or + interface sub-layer in the managed system. It is + recommended that values are assigned contiguously starting + from 1. The value for each interface sub-layer must remain + constant at least from one re-initialization of the entity's + network management system to the next re-initialization." + SYNTAX Integer32 (1..2147483647) + +InterfaceIndexOrZero ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "This textual convention is an extension of the + InterfaceIndex convention. The latter defines a greater + than zero value used to identify an interface or interface + sub-layer in the managed system. This extension permits the + additional value of zero. the value zero is object-specific + and must therefore be defined as part of the description of + any object which uses this syntax. Examples of the usage of + zero might include situations where interface was unknown, + or when none or all interfaces need to be referenced." + SYNTAX Integer32 (0..2147483647) + +ifNumber OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of network interfaces (regardless of their + current state) present on this system." + ::= { interfaces 1 } + +ifTableLastChange OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time of the last creation or + deletion of an entry in the ifTable. If the number of + entries has been unchanged since the last re-initialization + of the local network management subsystem, then this object + contains a zero value." + ::= { ifMIBObjects 5 } + + +-- the Interfaces table + +-- The Interfaces table contains information on the entity's + + +-- interfaces. Each sub-layer below the internetwork-layer +-- of a network interface is considered to be an interface. + +ifTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of interface entries. The number of entries is + given by the value of ifNumber." + ::= { interfaces 2 } + +ifEntry OBJECT-TYPE + SYNTAX IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing management information applicable to a + particular interface." + INDEX { ifIndex } + ::= { ifTable 1 } + +IfEntry ::= + SEQUENCE { + ifIndex InterfaceIndex, + ifDescr DisplayString, + ifType IANAifType, + ifMtu Integer32, + ifSpeed Gauge32, + ifPhysAddress PhysAddress, + ifAdminStatus INTEGER, + ifOperStatus INTEGER, + ifLastChange TimeTicks, + ifInOctets Counter32, + ifInUcastPkts Counter32, + ifInNUcastPkts Counter32, -- deprecated + ifInDiscards Counter32, + ifInErrors Counter32, + ifInUnknownProtos Counter32, + ifOutOctets Counter32, + ifOutUcastPkts Counter32, + ifOutNUcastPkts Counter32, -- deprecated + ifOutDiscards Counter32, + ifOutErrors Counter32, + ifOutQLen Gauge32, -- deprecated + ifSpecific OBJECT IDENTIFIER -- deprecated + } + + + +ifIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A unique value, greater than zero, for each interface. It + is recommended that values are assigned contiguously + starting from 1. The value for each interface sub-layer + must remain constant at least from one re-initialization of + the entity's network management system to the next re- + initialization." + ::= { ifEntry 1 } + +ifDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A textual string containing information about the + interface. This string should include the name of the + manufacturer, the product name and the version of the + interface hardware/software." + ::= { ifEntry 2 } + +ifType OBJECT-TYPE + SYNTAX IANAifType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of interface. Additional values for ifType are + assigned by the Internet Assigned Numbers Authority (IANA), + through updating the syntax of the IANAifType textual + convention." + ::= { ifEntry 3 } + +ifMtu OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The size of the largest packet which can be sent/received + on the interface, specified in octets. For interfaces that + are used for transmitting network datagrams, this is the + size of the largest network datagram that can be sent on the + interface." + ::= { ifEntry 4 } + +ifSpeed OBJECT-TYPE + + + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An estimate of the interface's current bandwidth in bits + per second. For interfaces which do not vary in bandwidth + or for those where no accurate estimation can be made, this + object should contain the nominal bandwidth. If the + bandwidth of the interface is greater than the maximum value + reportable by this object then this object should report its + maximum value (4,294,967,295) and ifHighSpeed must be used + to report the interace's speed. For a sub-layer which has + no concept of bandwidth, this object should be zero." + ::= { ifEntry 5 } + +ifPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a MAC address. The interface's media-specific MIB + must define the bit and byte ordering and the format of the + value of this object. For interfaces which do not have such + an address (e.g., a serial line), this object should contain + an octet string of zero length." + ::= { ifEntry 6 } + +ifAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The desired state of the interface. The testing(3) state + indicates that no operational packets can be passed. When a + managed system initializes, all interfaces start with + ifAdminStatus in the down(2) state. As a result of either + explicit management action or per configuration information + retained by the managed system, ifAdminStatus is then + changed to either the up(1) or testing(3) states (or remains + in the down(2) state)." + ::= { ifEntry 7 } + + + +ifOperStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3), -- in some test mode + unknown(4), -- status can not be determined + -- for some reason. + dormant(5), + notPresent(6), -- some component is missing + lowerLayerDown(7) -- down due to state of + -- lower-layer interface(s) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current operational state of the interface. The + testing(3) state indicates that no operational packets can + be passed. If ifAdminStatus is down(2) then ifOperStatus + should be down(2). If ifAdminStatus is changed to up(1) + then ifOperStatus should change to up(1) if the interface is + ready to transmit and receive network traffic; it should + change to dormant(5) if the interface is waiting for + external actions (such as a serial line waiting for an + incoming connection); it should remain in the down(2) state + if and only if there is a fault that prevents it from going + to the up(1) state; it should remain in the notPresent(6) + state if the interface has missing (typically, hardware) + components." + ::= { ifEntry 8 } + +ifLastChange OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time the interface entered + its current operational state. If the current state was + entered prior to the last re-initialization of the local + network management subsystem, then this object contains a + zero value." + ::= { ifEntry 9 } + +ifInOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received on the interface, + + + including framing characters. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 10 } + +ifInUcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were not addressed to a multicast + or broadcast address at this sub-layer. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 11 } + +ifInNUcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a multicast or + broadcast address at this sub-layer. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime. + + This object is deprecated in favour of ifInMulticastPkts and + ifInBroadcastPkts." + ::= { ifEntry 12 } + +ifInDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of inbound packets which were chosen to be + discarded even though no errors had been detected to prevent + + + their being deliverable to a higher-layer protocol. One + possible reason for discarding such a packet could be to + free up buffer space. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 13 } + +ifInErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of inbound + transmission units that contained errors preventing them + from being deliverable to a higher-layer protocol. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 14 } + +ifInUnknownProtos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For packet-oriented interfaces, the number of packets + received via the interface which were discarded because of + an unknown or unsupported protocol. For character-oriented + or fixed-length interfaces that support protocol + multiplexing the number of transmission units received via + the interface which were discarded because of an unknown or + unsupported protocol. For any interface that does not + support protocol multiplexing, this counter will always be + 0. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 15 } + + +ifOutOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted out of the + interface, including framing characters. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 16 } + +ifOutUcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were not addressed to a + multicast or broadcast address at this sub-layer, including + those that were discarded or not sent. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 17 } + +ifOutNUcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + multicast or broadcast address at this sub-layer, including + those that were discarded or not sent. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime. + + This object is deprecated in favour of ifOutMulticastPkts + and ifOutBroadcastPkts." + ::= { ifEntry 18 } + + +ifOutDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of outbound packets which were chosen to be + discarded even though no errors had been detected to prevent + their being transmitted. One possible reason for discarding + such a packet could be to free up buffer space. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 19 } + +ifOutErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifEntry 20 } + +ifOutQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The length of the output packet queue (in packets)." + ::= { ifEntry 21 } + +ifSpecific OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "A reference to MIB definitions specific to the particular + media being used to realize the interface. It is + + + recommended that this value point to an instance of a MIB + object in the media-specific MIB, i.e., that this object + have the semantics associated with the InstancePointer + textual convention defined in RFC 2579. In fact, it is + recommended that the media-specific MIB specify what value + ifSpecific should/can take for values of ifType. If no MIB + definitions specific to the particular media are available, + the value should be set to the OBJECT IDENTIFIER { 0 0 }." + ::= { ifEntry 22 } + + + +-- +-- Extension to the interface table +-- +-- This table replaces the ifExtnsTable table. +-- + +ifXTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfXEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of interface entries. The number of entries is + given by the value of ifNumber. This table contains + additional objects for the interface table." + ::= { ifMIBObjects 1 } + +ifXEntry OBJECT-TYPE + SYNTAX IfXEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing additional management information + applicable to a particular interface." + AUGMENTS { ifEntry } + ::= { ifXTable 1 } + +IfXEntry ::= + SEQUENCE { + ifName DisplayString, + ifInMulticastPkts Counter32, + ifInBroadcastPkts Counter32, + ifOutMulticastPkts Counter32, + ifOutBroadcastPkts Counter32, + ifHCInOctets Counter64, + ifHCInUcastPkts Counter64, + ifHCInMulticastPkts Counter64, + + + ifHCInBroadcastPkts Counter64, + ifHCOutOctets Counter64, + ifHCOutUcastPkts Counter64, + ifHCOutMulticastPkts Counter64, + ifHCOutBroadcastPkts Counter64, + ifLinkUpDownTrapEnable INTEGER, + ifHighSpeed Gauge32, + ifPromiscuousMode TruthValue, + ifConnectorPresent TruthValue, + ifAlias DisplayString, + ifCounterDiscontinuityTime TimeStamp + } + + +ifName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The textual name of the interface. The value of this + object should be the name of the interface as assigned by + the local device and should be suitable for use in commands + entered at the device's `console'. This might be a text + name, such as `le0' or a simple port number, such as `1', + depending on the interface naming syntax of the device. If + several entries in the ifTable together represent a single + interface as named by the device, then each will have the + same value of ifName. Note that for an agent which responds + to SNMP queries concerning an interface on some other + (proxied) device, then the value of ifName for such an + interface is the proxied device's local name for it. + + If there is no local name, or this object is otherwise not + applicable, then this object contains a zero-length string." + ::= { ifXEntry 1 } + +ifInMulticastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a multicast + address at this sub-layer. For a MAC layer protocol, this + includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + + + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 2 } + +ifInBroadcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a broadcast + address at this sub-layer. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 3 } + +ifOutMulticastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + multicast address at this sub-layer, including those that + were discarded or not sent. For a MAC layer protocol, this + includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 4 } + +ifOutBroadcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + broadcast address at this sub-layer, including those that + were discarded or not sent. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + + + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 5 } + +-- +-- High Capacity Counter objects. These objects are all +-- 64 bit versions of the "basic" ifTable counters. These +-- objects all have the same basic semantics as their 32-bit +-- counterparts, however, their syntax has been extended +-- to 64 bits. +-- + +ifHCInOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received on the interface, + including framing characters. This object is a 64-bit + version of ifInOctets. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 6 } + +ifHCInUcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were not addressed to a multicast + or broadcast address at this sub-layer. This object is a + 64-bit version of ifInUcastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 7 } + +ifHCInMulticastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a multicast + address at this sub-layer. For a MAC layer protocol, this + includes both Group and Functional addresses. This object + is a 64-bit version of ifInMulticastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 8 } + +ifHCInBroadcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a broadcast + address at this sub-layer. This object is a 64-bit version + of ifInBroadcastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 9 } + +ifHCOutOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted out of the + interface, including framing characters. This object is a + 64-bit version of ifOutOctets. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 10 } + +ifHCOutUcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + "The total number of packets that higher-level protocols + requested be transmitted, and which were not addressed to a + multicast or broadcast address at this sub-layer, including + those that were discarded or not sent. This object is a + 64-bit version of ifOutUcastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 11 } + +ifHCOutMulticastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + multicast address at this sub-layer, including those that + were discarded or not sent. For a MAC layer protocol, this + includes both Group and Functional addresses. This object + is a 64-bit version of ifOutMulticastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 12 } + +ifHCOutBroadcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + broadcast address at this sub-layer, including those that + were discarded or not sent. This object is a 64-bit version + of ifOutBroadcastPkts. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ifCounterDiscontinuityTime." + ::= { ifXEntry 13 } + +ifLinkUpDownTrapEnable OBJECT-TYPE + + + SYNTAX INTEGER { enabled(1), disabled(2) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Indicates whether linkUp/linkDown traps should be generated + for this interface. + + By default, this object should have the value enabled(1) for + interfaces which do not operate on 'top' of any other + interface (as defined in the ifStackTable), and disabled(2) + otherwise." + ::= { ifXEntry 14 } + +ifHighSpeed OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An estimate of the interface's current bandwidth in units + of 1,000,000 bits per second. If this object reports a + value of `n' then the speed of the interface is somewhere in + the range of `n-500,000' to `n+499,999'. For interfaces + which do not vary in bandwidth or for those where no + accurate estimation can be made, this object should contain + the nominal bandwidth. For a sub-layer which has no concept + of bandwidth, this object should be zero." + ::= { ifXEntry 15 } + +ifPromiscuousMode OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This object has a value of false(2) if this interface only + accepts packets/frames that are addressed to this station. + This object has a value of true(1) when the station accepts + all packets/frames transmitted on the media. The value + true(1) is only legal on certain types of media. If legal, + setting this object to a value of true(1) may require the + interface to be reset before becoming effective. + + The value of ifPromiscuousMode does not affect the reception + of broadcast and multicast packets/frames by the interface." + ::= { ifXEntry 16 } + +ifConnectorPresent OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + + + STATUS current + DESCRIPTION + "This object has the value 'true(1)' if the interface + sublayer has a physical connector and the value 'false(2)' + otherwise." + ::= { ifXEntry 17 } + +ifAlias OBJECT-TYPE + SYNTAX DisplayString (SIZE(0..64)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This object is an 'alias' name for the interface as + specified by a network manager, and provides a non-volatile + 'handle' for the interface. + + On the first instantiation of an interface, the value of + ifAlias associated with that interface is the zero-length + string. As and when a value is written into an instance of + ifAlias through a network management set operation, then the + agent must retain the supplied value in the ifAlias instance + associated with the same interface for as long as that + interface remains instantiated, including across all re- + initializations/reboots of the network management system, + including those which result in a change of the interface's + ifIndex value. + + An example of the value which a network manager might store + in this object for a WAN interface is the (Telco's) circuit + number/identifier of the interface. + + Some agents may support write-access only for interfaces + having particular values of ifType. An agent which supports + write access to this object is required to keep the value in + non-volatile storage, but it may limit the length of new + values depending on how much storage is already occupied by + the current values for other interfaces." + ::= { ifXEntry 18 } + +ifCounterDiscontinuityTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + any one or more of this interface's counters suffered a + discontinuity. The relevant counters are the specific + instances associated with this interface of any Counter32 or + + + Counter64 object contained in the ifTable or ifXTable. If + no such discontinuities have occurred since the last re- + initialization of the local management subsystem, then this + object contains a zero value." + ::= { ifXEntry 19 } + +-- The Interface Stack Group +-- +-- Implementation of this group is optional, but strongly recommended +-- for all systems +-- + +ifStackTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfStackEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing information on the relationships + between the multiple sub-layers of network interfaces. In + particular, it contains information on which sub-layers run + 'on top of' which other sub-layers, where each sub-layer + corresponds to a conceptual row in the ifTable. For + example, when the sub-layer with ifIndex value x runs over + the sub-layer with ifIndex value y, then this table + contains: + + ifStackStatus.x.y=active + + For each ifIndex value, I, which identifies an active + interface, there are always at least two instantiated rows + in this table associated with I. For one of these rows, I + is the value of ifStackHigherLayer; for the other, I is the + value of ifStackLowerLayer. (If I is not involved in + multiplexing, then these are the only two rows associated + with I.) + + For example, two rows exist even for an interface which has + no others stacked on top or below it: + + ifStackStatus.0.x=active + ifStackStatus.x.0=active " + ::= { ifMIBObjects 2 } + + +ifStackEntry OBJECT-TYPE + SYNTAX IfStackEntry + MAX-ACCESS not-accessible + STATUS current + + + DESCRIPTION + "Information on a particular relationship between two sub- + layers, specifying that one sub-layer runs on 'top' of the + other sub-layer. Each sub-layer corresponds to a conceptual + row in the ifTable." + INDEX { ifStackHigherLayer, ifStackLowerLayer } + ::= { ifStackTable 1 } + + +IfStackEntry ::= + SEQUENCE { + ifStackHigherLayer InterfaceIndexOrZero, + ifStackLowerLayer InterfaceIndexOrZero, + ifStackStatus RowStatus + } + + +ifStackHigherLayer OBJECT-TYPE + SYNTAX InterfaceIndexOrZero + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The value of ifIndex corresponding to the higher sub-layer + of the relationship, i.e., the sub-layer which runs on 'top' + of the sub-layer identified by the corresponding instance of + ifStackLowerLayer. If there is no higher sub-layer (below + the internetwork layer), then this object has the value 0." + ::= { ifStackEntry 1 } + + +ifStackLowerLayer OBJECT-TYPE + SYNTAX InterfaceIndexOrZero + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The value of ifIndex corresponding to the lower sub-layer + of the relationship, i.e., the sub-layer which runs 'below' + the sub-layer identified by the corresponding instance of + ifStackHigherLayer. If there is no lower sub-layer, then + this object has the value 0." + ::= { ifStackEntry 2 } + + +ifStackStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + + + "The status of the relationship between two sub-layers. + + Changing the value of this object from 'active' to + 'notInService' or 'destroy' will likely have consequences up + and down the interface stack. Thus, write access to this + object is likely to be inappropriate for some types of + interfaces, and many implementations will choose not to + support write-access for any type of interface." + ::= { ifStackEntry 3 } + +ifStackLastChange OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time of the last change of + the (whole) interface stack. A change of the interface + stack is defined to be any creation, deletion, or change in + value of any instance of ifStackStatus. If the interface + stack has been unchanged since the last re-initialization of + the local network management subsystem, then this object + contains a zero value." + ::= { ifMIBObjects 6 } + + +-- Generic Receive Address Table +-- +-- This group of objects is mandatory for all types of +-- interfaces which can receive packets/frames addressed to +-- more than one address. +-- +-- This table replaces the ifExtnsRcvAddr table. The main +-- difference is that this table makes use of the RowStatus +-- textual convention, while ifExtnsRcvAddr did not. + +ifRcvAddressTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfRcvAddressEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table contains an entry for each address (broadcast, + multicast, or uni-cast) for which the system will receive + packets/frames on a particular interface, except as follows: + + - for an interface operating in promiscuous mode, entries + are only required for those addresses for which the system + would receive frames were it not operating in promiscuous + mode. + + + - for 802.5 functional addresses, only one entry is + required, for the address which has the functional address + bit ANDed with the bit mask of all functional addresses for + which the interface will accept frames. + + A system is normally able to use any unicast address which + corresponds to an entry in this table as a source address." + ::= { ifMIBObjects 4 } + +ifRcvAddressEntry OBJECT-TYPE + SYNTAX IfRcvAddressEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of objects identifying an address for which the + system will accept packets/frames on the particular + interface identified by the index value ifIndex." + INDEX { ifIndex, ifRcvAddressAddress } + ::= { ifRcvAddressTable 1 } + +IfRcvAddressEntry ::= + SEQUENCE { + ifRcvAddressAddress PhysAddress, + ifRcvAddressStatus RowStatus, + ifRcvAddressType INTEGER + } + +ifRcvAddressAddress OBJECT-TYPE + SYNTAX PhysAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An address for which the system will accept packets/frames + on this entry's interface." + ::= { ifRcvAddressEntry 1 } + +ifRcvAddressStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object is used to create and delete rows in the + ifRcvAddressTable." + + ::= { ifRcvAddressEntry 2 } + +ifRcvAddressType OBJECT-TYPE + SYNTAX INTEGER { + + + other(1), + volatile(2), + nonVolatile(3) + } + + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object has the value nonVolatile(3) for those entries + in the table which are valid and will not be deleted by the + next restart of the managed system. Entries having the + value volatile(2) are valid and exist, but have not been + saved, so that will not exist after the next restart of the + managed system. Entries having the value other(1) are valid + and exist but are not classified as to whether they will + continue to exist after the next restart." + + DEFVAL { volatile } + ::= { ifRcvAddressEntry 3 } + +-- definition of interface-related traps. + +linkDown NOTIFICATION-TYPE + OBJECTS { ifIndex, ifAdminStatus, ifOperStatus } + STATUS current + DESCRIPTION + "A linkDown trap signifies that the SNMP entity, acting in + an agent role, has detected that the ifOperStatus object for + one of its communication links is about to enter the down + state from some other state (but not from the notPresent + state). This other state is indicated by the included value + of ifOperStatus." + ::= { snmpTraps 3 } + +linkUp NOTIFICATION-TYPE + OBJECTS { ifIndex, ifAdminStatus, ifOperStatus } + STATUS current + DESCRIPTION + "A linkUp trap signifies that the SNMP entity, acting in an + agent role, has detected that the ifOperStatus object for + one of its communication links left the down state and + transitioned into some other state (but not into the + notPresent state). This other state is indicated by the + included value of ifOperStatus." + ::= { snmpTraps 4 } + +-- conformance information + + + +ifConformance OBJECT IDENTIFIER ::= { ifMIB 2 } + +ifGroups OBJECT IDENTIFIER ::= { ifConformance 1 } +ifCompliances OBJECT IDENTIFIER ::= { ifConformance 2 } + + +-- compliance statements + +ifCompliance3 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for SNMP entities which have + network interfaces." + + MODULE -- this module + MANDATORY-GROUPS { ifGeneralInformationGroup, + linkUpDownNotificationsGroup } + +-- The groups: +-- ifFixedLengthGroup +-- ifHCFixedLengthGroup +-- ifPacketGroup +-- ifHCPacketGroup +-- ifVHCPacketGroup +-- are mutually exclusive; at most one of these groups is implemented +-- for a particular interface. When any of these groups is implemented +-- for a particular interface, then ifCounterDiscontinuityGroup must +-- also be implemented for that interface. + + + GROUP ifFixedLengthGroup + DESCRIPTION + "This group is mandatory for those network interfaces which + are character-oriented or transmit data in fixed-length + transmission units, and for which the value of the + corresponding instance of ifSpeed is less than or equal to + 20,000,000 bits/second." + + GROUP ifHCFixedLengthGroup + DESCRIPTION + "This group is mandatory for those network interfaces which + are character-oriented or transmit data in fixed-length + transmission units, and for which the value of the + corresponding instance of ifSpeed is greater than 20,000,000 + bits/second." + + GROUP ifPacketGroup + DESCRIPTION + + + "This group is mandatory for those network interfaces which + are packet-oriented, and for which the value of the + corresponding instance of ifSpeed is less than or equal to + 20,000,000 bits/second." + + GROUP ifHCPacketGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are packet-oriented and for which the value of the + corresponding instance of ifSpeed is greater than 20,000,000 + bits/second but less than or equal to 650,000,000 + bits/second." + + GROUP ifVHCPacketGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are packet-oriented and for which the value of the + corresponding instance of ifSpeed is greater than + 650,000,000 bits/second." + + + GROUP ifCounterDiscontinuityGroup + DESCRIPTION + "This group is mandatory for those network interfaces that + are required to maintain counters (i.e., those for which one + of the ifFixedLengthGroup, ifHCFixedLengthGroup, + ifPacketGroup, ifHCPacketGroup, or ifVHCPacketGroup is + mandatory)." + + + GROUP ifRcvAddressGroup + DESCRIPTION + "The applicability of this group MUST be defined by the + media-specific MIBs. Media-specific MIBs must define the + exact meaning, use, and semantics of the addresses in this + group." + + OBJECT ifLinkUpDownTrapEnable + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifPromiscuousMode + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifAdminStatus + + + SYNTAX INTEGER { up(1), down(2) } + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, nor is support for the value + testing(3)." + + OBJECT ifAlias + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + ::= { ifCompliances 3 } + +-- units of conformance + +ifGeneralInformationGroup OBJECT-GROUP + OBJECTS { ifIndex, ifDescr, ifType, ifSpeed, ifPhysAddress, + ifAdminStatus, ifOperStatus, ifLastChange, + ifLinkUpDownTrapEnable, ifConnectorPresent, + ifHighSpeed, ifName, ifNumber, ifAlias, + ifTableLastChange } + STATUS current + DESCRIPTION + "A collection of objects providing information applicable to + all network interfaces." + ::= { ifGroups 10 } + +-- the following five groups are mutually exclusive; at most +-- one of these groups is implemented for any interface + +ifFixedLengthGroup OBJECT-GROUP + OBJECTS { ifInOctets, ifOutOctets, ifInUnknownProtos, + ifInErrors, ifOutErrors } + STATUS current + DESCRIPTION + "A collection of objects providing information specific to + non-high speed (non-high speed interfaces transmit and + receive at speeds less than or equal to 20,000,000 + bits/second) character-oriented or fixed-length-transmission + network interfaces." + ::= { ifGroups 2 } + +ifHCFixedLengthGroup OBJECT-GROUP + OBJECTS { ifHCInOctets, ifHCOutOctets, + ifInOctets, ifOutOctets, ifInUnknownProtos, + ifInErrors, ifOutErrors } + STATUS current + DESCRIPTION + + + "A collection of objects providing information specific to + high speed (greater than 20,000,000 bits/second) character- + oriented or fixed-length-transmission network interfaces." + ::= { ifGroups 3 } + +ifPacketGroup OBJECT-GROUP + OBJECTS { ifInOctets, ifOutOctets, ifInUnknownProtos, + ifInErrors, ifOutErrors, + ifMtu, ifInUcastPkts, ifInMulticastPkts, + ifInBroadcastPkts, ifInDiscards, + ifOutUcastPkts, ifOutMulticastPkts, + ifOutBroadcastPkts, ifOutDiscards, + ifPromiscuousMode } + STATUS current + DESCRIPTION + "A collection of objects providing information specific to + non-high speed (non-high speed interfaces transmit and + receive at speeds less than or equal to 20,000,000 + bits/second) packet-oriented network interfaces." + ::= { ifGroups 4 } + +ifHCPacketGroup OBJECT-GROUP + OBJECTS { ifHCInOctets, ifHCOutOctets, + ifInOctets, ifOutOctets, ifInUnknownProtos, + ifInErrors, ifOutErrors, + ifMtu, ifInUcastPkts, ifInMulticastPkts, + ifInBroadcastPkts, ifInDiscards, + ifOutUcastPkts, ifOutMulticastPkts, + ifOutBroadcastPkts, ifOutDiscards, + ifPromiscuousMode } + STATUS current + DESCRIPTION + "A collection of objects providing information specific to + high speed (greater than 20,000,000 bits/second but less + than or equal to 650,000,000 bits/second) packet-oriented + network interfaces." + ::= { ifGroups 5 } + +ifVHCPacketGroup OBJECT-GROUP + OBJECTS { ifHCInUcastPkts, ifHCInMulticastPkts, + ifHCInBroadcastPkts, ifHCOutUcastPkts, + ifHCOutMulticastPkts, ifHCOutBroadcastPkts, + ifHCInOctets, ifHCOutOctets, + ifInOctets, ifOutOctets, ifInUnknownProtos, + ifInErrors, ifOutErrors, + ifMtu, ifInUcastPkts, ifInMulticastPkts, + ifInBroadcastPkts, ifInDiscards, + ifOutUcastPkts, ifOutMulticastPkts, + + + ifOutBroadcastPkts, ifOutDiscards, + ifPromiscuousMode } + STATUS current + DESCRIPTION + "A collection of objects providing information specific to + higher speed (greater than 650,000,000 bits/second) packet- + oriented network interfaces." + ::= { ifGroups 6 } + +ifRcvAddressGroup OBJECT-GROUP + OBJECTS { ifRcvAddressStatus, ifRcvAddressType } + STATUS current + DESCRIPTION + "A collection of objects providing information on the + multiple addresses which an interface receives." + ::= { ifGroups 7 } + +ifStackGroup2 OBJECT-GROUP + OBJECTS { ifStackStatus, ifStackLastChange } + STATUS current + DESCRIPTION + "A collection of objects providing information on the + layering of MIB-II interfaces." + ::= { ifGroups 11 } + +ifCounterDiscontinuityGroup OBJECT-GROUP + OBJECTS { ifCounterDiscontinuityTime } + STATUS current + DESCRIPTION + "A collection of objects providing information specific to + interface counter discontinuities." + ::= { ifGroups 13 } + +linkUpDownNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { linkUp, linkDown } + STATUS current + DESCRIPTION + "The notifications which indicate specific changes in the + value of ifOperStatus." + ::= { ifGroups 14 } + +-- Deprecated Definitions - Objects + + +-- +-- The Interface Test Table +-- +-- This group of objects is optional. However, a media-specific + + +-- MIB may make implementation of this group mandatory. +-- +-- This table replaces the ifExtnsTestTable +-- + +ifTestTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfTestEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "This table contains one entry per interface. It defines + objects which allow a network manager to instruct an agent + to test an interface for various faults. Tests for an + interface are defined in the media-specific MIB for that + interface. After invoking a test, the object ifTestResult + can be read to determine the outcome. If an agent can not + perform the test, ifTestResult is set to so indicate. The + object ifTestCode can be used to provide further test- + specific or interface-specific (or even enterprise-specific) + information concerning the outcome of the test. Only one + test can be in progress on each interface at any one time. + If one test is in progress when another test is invoked, the + second test is rejected. Some agents may reject a test when + a prior test is active on another interface. + + Before starting a test, a manager-station must first obtain + 'ownership' of the entry in the ifTestTable for the + interface to be tested. This is accomplished with the + ifTestId and ifTestStatus objects as follows: + + try_again: + get (ifTestId, ifTestStatus) + while (ifTestStatus != notInUse) + /* + * Loop while a test is running or some other + * manager is configuring a test. + */ + short delay + get (ifTestId, ifTestStatus) + } + + /* + * Is not being used right now -- let's compete + * to see who gets it. + */ + lock_value = ifTestId + + if ( set(ifTestId = lock_value, ifTestStatus = inUse, + + + ifTestOwner = 'my-IP-address') == FAILURE) + /* + * Another manager got the ifTestEntry -- go + * try again + */ + goto try_again; + + /* + * I have the lock + */ + set up any test parameters. + + /* + * This starts the test + */ + set(ifTestType = test_to_run); + + wait for test completion by polling ifTestResult + + when test completes, agent sets ifTestResult + agent also sets ifTestStatus = 'notInUse' + + retrieve any additional test results, and ifTestId + + if (ifTestId == lock_value+1) results are valid + + A manager station first retrieves the value of the + appropriate ifTestId and ifTestStatus objects, periodically + repeating the retrieval if necessary, until the value of + ifTestStatus is 'notInUse'. The manager station then tries + to set the same ifTestId object to the value it just + retrieved, the same ifTestStatus object to 'inUse', and the + corresponding ifTestOwner object to a value indicating + itself. If the set operation succeeds then the manager has + obtained ownership of the ifTestEntry, and the value of the + ifTestId object is incremented by the agent (per the + semantics of TestAndIncr). Failure of the set operation + indicates that some other manager has obtained ownership of + the ifTestEntry. + + Once ownership is obtained, any test parameters can be + setup, and then the test is initiated by setting ifTestType. + On completion of the test, the agent sets ifTestStatus to + 'notInUse'. Once this occurs, the manager can retrieve the + results. In the (rare) event that the invocation of tests + by two network managers were to overlap, then there would be + a possibility that the first test's results might be + overwritten by the second test's results prior to the first + + + results being read. This unlikely circumstance can be + detected by a network manager retrieving ifTestId at the + same time as retrieving the test results, and ensuring that + the results are for the desired request. + + If ifTestType is not set within an abnormally long period of + time after ownership is obtained, the agent should time-out + the manager, and reset the value of the ifTestStatus object + back to 'notInUse'. It is suggested that this time-out + period be 5 minutes. + + In general, a management station must not retransmit a + request to invoke a test for which it does not receive a + response; instead, it properly inspects an agent's MIB to + determine if the invocation was successful. Only if the + invocation was unsuccessful, is the invocation request + retransmitted. + + Some tests may require the interface to be taken off-line in + order to execute them, or may even require the agent to + reboot after completion of the test. In these + circumstances, communication with the management station + invoking the test may be lost until after completion of the + test. An agent is not required to support such tests. + However, if such tests are supported, then the agent should + make every effort to transmit a response to the request + which invoked the test prior to losing communication. When + the agent is restored to normal service, the results of the + test are properly made available in the appropriate objects. + Note that this requires that the ifIndex value assigned to + an interface must be unchanged even if the test causes a + reboot. An agent must reject any test for which it cannot, + perhaps due to resource constraints, make available at least + the minimum amount of information after that test + completes." + ::= { ifMIBObjects 3 } + +ifTestEntry OBJECT-TYPE + SYNTAX IfTestEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "An entry containing objects for invoking tests on an + interface." + AUGMENTS { ifEntry } + ::= { ifTestTable 1 } + +IfTestEntry ::= + + + SEQUENCE { + ifTestId TestAndIncr, + ifTestStatus INTEGER, + ifTestType AutonomousType, + ifTestResult INTEGER, + ifTestCode OBJECT IDENTIFIER, + ifTestOwner OwnerString + } + +ifTestId OBJECT-TYPE + SYNTAX TestAndIncr + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "This object identifies the current invocation of the + interface's test." + ::= { ifTestEntry 1 } + +ifTestStatus OBJECT-TYPE + SYNTAX INTEGER { notInUse(1), inUse(2) } + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "This object indicates whether or not some manager currently + has the necessary 'ownership' required to invoke a test on + this interface. A write to this object is only successful + when it changes its value from 'notInUse(1)' to 'inUse(2)'. + After completion of a test, the agent resets the value back + to 'notInUse(1)'." + ::= { ifTestEntry 2 } + +ifTestType OBJECT-TYPE + SYNTAX AutonomousType + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "A control variable used to start and stop operator- + initiated interface tests. Most OBJECT IDENTIFIER values + assigned to tests are defined elsewhere, in association with + specific types of interface. However, this document assigns + a value for a full-duplex loopback test, and defines the + special meanings of the subject identifier: + + noTest OBJECT IDENTIFIER ::= { 0 0 } + + When the value noTest is written to this object, no action + is taken unless a test is in progress, in which case the + test is aborted. Writing any other value to this object is + + + only valid when no test is currently in progress, in which + case the indicated test is initiated. + + When read, this object always returns the most recent value + that ifTestType was set to. If it has not been set since + the last initialization of the network management subsystem + on the agent, a value of noTest is returned." + ::= { ifTestEntry 3 } + +ifTestResult OBJECT-TYPE + SYNTAX INTEGER { + none(1), -- no test yet requested + success(2), + inProgress(3), + notSupported(4), + unAbleToRun(5), -- due to state of system + aborted(6), + failed(7) + } + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "This object contains the result of the most recently + requested test, or the value none(1) if no tests have been + requested since the last reset. Note that this facility + provides no provision for saving the results of one test + when starting another, as could be required if used by + multiple managers concurrently." + ::= { ifTestEntry 4 } + +ifTestCode OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "This object contains a code which contains more specific + information on the test result, for example an error-code + after a failed test. Error codes and other values this + object may take are specific to the type of interface and/or + test. The value may have the semantics of either the + AutonomousType or InstancePointer textual conventions as + defined in RFC 2579. The identifier: + + testCodeUnknown OBJECT IDENTIFIER ::= { 0 0 } + + is defined for use if no additional result code is + available." + ::= { ifTestEntry 5 } + + +ifTestOwner OBJECT-TYPE + SYNTAX OwnerString + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "The entity which currently has the 'ownership' required to + invoke a test on this interface." + ::= { ifTestEntry 6 } + +-- Deprecated Definitions - Groups + + +ifGeneralGroup OBJECT-GROUP + OBJECTS { ifDescr, ifType, ifSpeed, ifPhysAddress, + ifAdminStatus, ifOperStatus, ifLastChange, + ifLinkUpDownTrapEnable, ifConnectorPresent, + ifHighSpeed, ifName } + STATUS deprecated + DESCRIPTION + "A collection of objects deprecated in favour of + ifGeneralInformationGroup." + ::= { ifGroups 1 } + + +ifTestGroup OBJECT-GROUP + OBJECTS { ifTestId, ifTestStatus, ifTestType, + ifTestResult, ifTestCode, ifTestOwner } + STATUS deprecated + DESCRIPTION + "A collection of objects providing the ability to invoke + tests on an interface." + ::= { ifGroups 8 } + + +ifStackGroup OBJECT-GROUP + OBJECTS { ifStackStatus } + STATUS deprecated + DESCRIPTION + "The previous collection of objects providing information on + the layering of MIB-II interfaces." + ::= { ifGroups 9 } + + +ifOldObjectsGroup OBJECT-GROUP + OBJECTS { ifInNUcastPkts, ifOutNUcastPkts, + ifOutQLen, ifSpecific } + STATUS deprecated + DESCRIPTION + + + "The collection of objects deprecated from the original MIB- + II interfaces group." + ::= { ifGroups 12 } + +-- Deprecated Definitions - Compliance + +ifCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "A compliance statement defined in a previous version of + this MIB module, for SNMP entities which have network + interfaces." + + MODULE -- this module + MANDATORY-GROUPS { ifGeneralGroup, ifStackGroup } + + GROUP ifFixedLengthGroup + DESCRIPTION + "This group is mandatory for all network interfaces which + are character-oriented or transmit data in fixed-length + transmission units." + + GROUP ifHCFixedLengthGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are character-oriented or transmit data in fixed- + length transmission units, and for which the value of the + corresponding instance of ifSpeed is greater than 20,000,000 + bits/second." + + GROUP ifPacketGroup + DESCRIPTION + "This group is mandatory for all network interfaces which + are packet-oriented." + + GROUP ifHCPacketGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are packet-oriented and for which the value of the + corresponding instance of ifSpeed is greater than + 650,000,000 bits/second." + + GROUP ifTestGroup + DESCRIPTION + "This group is optional. Media-specific MIBs which require + interface tests are strongly encouraged to use this group + for invoking tests and reporting results. A medium specific + MIB which has mandatory tests may make implementation of + + + this group mandatory." + + GROUP ifRcvAddressGroup + DESCRIPTION + "The applicability of this group MUST be defined by the + media-specific MIBs. Media-specific MIBs must define the + exact meaning, use, and semantics of the addresses in this + group." + + OBJECT ifLinkUpDownTrapEnable + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifPromiscuousMode + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifStackStatus + SYNTAX INTEGER { active(1) } -- subset of RowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, and only one of the six + enumerated values for the RowStatus textual convention need + be supported, specifically: active(1)." + + OBJECT ifAdminStatus + SYNTAX INTEGER { up(1), down(2) } + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, nor is support for the value + testing(3)." + ::= { ifCompliances 1 } + +ifCompliance2 MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "A compliance statement defined in a previous version of + this MIB module, for SNMP entities which have network + interfaces." + + MODULE -- this module + MANDATORY-GROUPS { ifGeneralInformationGroup, ifStackGroup2, + ifCounterDiscontinuityGroup } + + GROUP ifFixedLengthGroup + DESCRIPTION + + + "This group is mandatory for all network interfaces which + are character-oriented or transmit data in fixed-length + transmission units." + + GROUP ifHCFixedLengthGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are character-oriented or transmit data in fixed- + length transmission units, and for which the value of the + corresponding instance of ifSpeed is greater than 20,000,000 + bits/second." + + GROUP ifPacketGroup + DESCRIPTION + "This group is mandatory for all network interfaces which + are packet-oriented." + + GROUP ifHCPacketGroup + DESCRIPTION + "This group is mandatory only for those network interfaces + which are packet-oriented and for which the value of the + corresponding instance of ifSpeed is greater than + 650,000,000 bits/second." + + GROUP ifRcvAddressGroup + DESCRIPTION + "The applicability of this group MUST be defined by the + media-specific MIBs. Media-specific MIBs must define the + exact meaning, use, and semantics of the addresses in this + group." + + OBJECT ifLinkUpDownTrapEnable + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifPromiscuousMode + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ifStackStatus + SYNTAX INTEGER { active(1) } -- subset of RowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, and only one of the six + enumerated values for the RowStatus textual convention need + be supported, specifically: active(1)." + + + OBJECT ifAdminStatus + SYNTAX INTEGER { up(1), down(2) } + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, nor is support for the value + testing(3)." + + OBJECT ifAlias + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + ::= { ifCompliances 2 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/INET-ADDRESS-MIB b/contrib/apps/LwipMibCompiler/Mibs/INET-ADDRESS-MIB new file mode 100644 index 0000000..a19b8d2 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/INET-ADDRESS-MIB @@ -0,0 +1,421 @@ +INET-ADDRESS-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, mib-2, Unsigned32 FROM SNMPv2-SMI + TEXTUAL-CONVENTION FROM SNMPv2-TC; + +inetAddressMIB MODULE-IDENTITY + LAST-UPDATED "200502040000Z" + ORGANIZATION + "IETF Operations and Management Area" + CONTACT-INFO + "Juergen Schoenwaelder (Editor) + International University Bremen + P.O. Box 750 561 + 28725 Bremen, Germany + + Phone: +49 421 200-3587 + EMail: j.schoenwaelder@iu-bremen.de + + Send comments to ." + DESCRIPTION + "This MIB module defines textual conventions for + representing Internet addresses. An Internet + address can be an IPv4 address, an IPv6 address, + or a DNS domain name. This module also defines + textual conventions for Internet port numbers, + autonomous system numbers, and the length of an + Internet address prefix. + + Copyright (C) The Internet Society (2005). This version + of this MIB module is part of RFC 4001, see the RFC + itself for full legal notices." + REVISION "200502040000Z" + DESCRIPTION + "Third version, published as RFC 4001. This revision + introduces the InetZoneIndex, InetScopeType, and + InetVersion textual conventions." + REVISION "200205090000Z" + DESCRIPTION + "Second version, published as RFC 3291. This + revision contains several clarifications and + introduces several new textual conventions: + InetAddressPrefixLength, InetPortNumber, + InetAutonomousSystemNumber, InetAddressIPv4z, + and InetAddressIPv6z." + REVISION "200006080000Z" + + + + DESCRIPTION + "Initial version, published as RFC 2851." + ::= { mib-2 76 } + +InetAddressType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A value that represents a type of Internet address. + + unknown(0) An unknown address type. This value MUST + be used if the value of the corresponding + InetAddress object is a zero-length string. + It may also be used to indicate an IP address + that is not in one of the formats defined + below. + + ipv4(1) An IPv4 address as defined by the + InetAddressIPv4 textual convention. + + ipv6(2) An IPv6 address as defined by the + InetAddressIPv6 textual convention. + + ipv4z(3) A non-global IPv4 address including a zone + index as defined by the InetAddressIPv4z + textual convention. + + ipv6z(4) A non-global IPv6 address including a zone + index as defined by the InetAddressIPv6z + textual convention. + + dns(16) A DNS domain name as defined by the + InetAddressDNS textual convention. + + Each definition of a concrete InetAddressType value must be + accompanied by a definition of a textual convention for use + with that InetAddressType. + + To support future extensions, the InetAddressType textual + convention SHOULD NOT be sub-typed in object type definitions. + It MAY be sub-typed in compliance statements in order to + require only a subset of these address types for a compliant + implementation. + + Implementations must ensure that InetAddressType objects + and any dependent objects (e.g., InetAddress objects) are + consistent. An inconsistentValue error must be generated + if an attempt to change an InetAddressType object would, + for example, lead to an undefined InetAddress value. In + + + + particular, InetAddressType/InetAddress pairs must be + changed together if the address type changes (e.g., from + ipv6(2) to ipv4(1))." + SYNTAX INTEGER { + unknown(0), + ipv4(1), + ipv6(2), + ipv4z(3), + ipv6z(4), + dns(16) + } + +InetAddress ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Denotes a generic Internet address. + + An InetAddress value is always interpreted within the context + of an InetAddressType value. Every usage of the InetAddress + textual convention is required to specify the InetAddressType + object that provides the context. It is suggested that the + InetAddressType object be logically registered before the + object(s) that use the InetAddress textual convention, if + they appear in the same logical row. + + The value of an InetAddress object must always be + consistent with the value of the associated InetAddressType + object. Attempts to set an InetAddress object to a value + inconsistent with the associated InetAddressType + must fail with an inconsistentValue error. + + When this textual convention is used as the syntax of an + index object, there may be issues with the limit of 128 + sub-identifiers specified in SMIv2, STD 58. In this case, + the object definition MUST include a 'SIZE' clause to + limit the number of potential instance sub-identifiers; + otherwise the applicable constraints MUST be stated in + the appropriate conceptual row DESCRIPTION clauses, or + in the surrounding documentation if there is no single + DESCRIPTION clause that is appropriate." + SYNTAX OCTET STRING (SIZE (0..255)) + +InetAddressIPv4 ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1d.1d.1d.1d" + STATUS current + DESCRIPTION + "Represents an IPv4 network address: + + + + + Octets Contents Encoding + 1-4 IPv4 address network-byte order + + The corresponding InetAddressType value is ipv4(1). + + This textual convention SHOULD NOT be used directly in object + definitions, as it restricts addresses to a specific format. + However, if it is used, it MAY be used either on its own or in + conjunction with InetAddressType, as a pair." + SYNTAX OCTET STRING (SIZE (4)) + +InetAddressIPv6 ::= TEXTUAL-CONVENTION + DISPLAY-HINT "2x:2x:2x:2x:2x:2x:2x:2x" + STATUS current + DESCRIPTION + "Represents an IPv6 network address: + + Octets Contents Encoding + 1-16 IPv6 address network-byte order + + The corresponding InetAddressType value is ipv6(2). + + This textual convention SHOULD NOT be used directly in object + definitions, as it restricts addresses to a specific format. + However, if it is used, it MAY be used either on its own or in + conjunction with InetAddressType, as a pair." + SYNTAX OCTET STRING (SIZE (16)) + +InetAddressIPv4z ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1d.1d.1d.1d%4d" + STATUS current + DESCRIPTION + "Represents a non-global IPv4 network address, together + with its zone index: + + Octets Contents Encoding + 1-4 IPv4 address network-byte order + 5-8 zone index network-byte order + + The corresponding InetAddressType value is ipv4z(3). + + The zone index (bytes 5-8) is used to disambiguate identical + address values on nodes that have interfaces attached to + different zones of the same scope. The zone index may contain + the special value 0, which refers to the default zone for each + scope. + + This textual convention SHOULD NOT be used directly in object + + + + definitions, as it restricts addresses to a specific format. + However, if it is used, it MAY be used either on its own or in + conjunction with InetAddressType, as a pair." + SYNTAX OCTET STRING (SIZE (8)) + +InetAddressIPv6z ::= TEXTUAL-CONVENTION + DISPLAY-HINT "2x:2x:2x:2x:2x:2x:2x:2x%4d" + STATUS current + DESCRIPTION + "Represents a non-global IPv6 network address, together + with its zone index: + + Octets Contents Encoding + 1-16 IPv6 address network-byte order + 17-20 zone index network-byte order + + The corresponding InetAddressType value is ipv6z(4). + + The zone index (bytes 17-20) is used to disambiguate + identical address values on nodes that have interfaces + attached to different zones of the same scope. The zone index + may contain the special value 0, which refers to the default + zone for each scope. + + This textual convention SHOULD NOT be used directly in object + definitions, as it restricts addresses to a specific format. + However, if it is used, it MAY be used either on its own or in + conjunction with InetAddressType, as a pair." + SYNTAX OCTET STRING (SIZE (20)) + +InetAddressDNS ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS current + DESCRIPTION + "Represents a DNS domain name. The name SHOULD be fully + qualified whenever possible. + + The corresponding InetAddressType is dns(16). + + The DESCRIPTION clause of InetAddress objects that may have + InetAddressDNS values MUST fully describe how (and when) + these names are to be resolved to IP addresses. + + The resolution of an InetAddressDNS value may require to + query multiple DNS records (e.g., A for IPv4 and AAAA for + IPv6). The order of the resolution process and which DNS + record takes precedence depends on the configuration of the + resolver. + + + + This textual convention SHOULD NOT be used directly in object + definitions, as it restricts addresses to a specific format. + However, if it is used, it MAY be used either on its own or in + conjunction with InetAddressType, as a pair." + SYNTAX OCTET STRING (SIZE (1..255)) + +InetAddressPrefixLength ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "Denotes the length of a generic Internet network address + prefix. A value of n corresponds to an IP address mask + that has n contiguous 1-bits from the most significant + bit (MSB), with all other bits set to 0. + + An InetAddressPrefixLength value is always interpreted within + the context of an InetAddressType value. Every usage of the + InetAddressPrefixLength textual convention is required to + specify the InetAddressType object that provides the + context. It is suggested that the InetAddressType object be + logically registered before the object(s) that use the + InetAddressPrefixLength textual convention, if they appear + in the same logical row. + + InetAddressPrefixLength values larger than + the maximum length of an IP address for a specific + InetAddressType are treated as the maximum significant + value applicable for the InetAddressType. The maximum + significant value is 32 for the InetAddressType + 'ipv4(1)' and 'ipv4z(3)' and 128 for the InetAddressType + 'ipv6(2)' and 'ipv6z(4)'. The maximum significant value + for the InetAddressType 'dns(16)' is 0. + + The value zero is object-specific and must be defined as + part of the description of any object that uses this + syntax. Examples of the usage of zero might include + situations where the Internet network address prefix + is unknown or does not apply. + + The upper bound of the prefix length has been chosen to + be consistent with the maximum size of an InetAddress." + SYNTAX Unsigned32 (0..2040) + +InetPortNumber ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "Represents a 16 bit port number of an Internet transport + + + + layer protocol. Port numbers are assigned by IANA. A + current list of all assignments is available from + . + + The value zero is object-specific and must be defined as + part of the description of any object that uses this + syntax. Examples of the usage of zero might include + situations where a port number is unknown, or when the + value zero is used as a wildcard in a filter." + REFERENCE "STD 6 (RFC 768), STD 7 (RFC 793) and RFC 2960" + SYNTAX Unsigned32 (0..65535) + +InetAutonomousSystemNumber ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "Represents an autonomous system number that identifies an + Autonomous System (AS). An AS is a set of routers under a + single technical administration, using an interior gateway + protocol and common metrics to route packets within the AS, + and using an exterior gateway protocol to route packets to + other ASes'. IANA maintains the AS number space and has + delegated large parts to the regional registries. + + Autonomous system numbers are currently limited to 16 bits + (0..65535). There is, however, work in progress to enlarge the + autonomous system number space to 32 bits. Therefore, this + textual convention uses an Unsigned32 value without a + range restriction in order to support a larger autonomous + system number space." + REFERENCE "RFC 1771, RFC 1930" + SYNTAX Unsigned32 + +InetScopeType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents a scope type. This textual convention can be used + in cases where a MIB has to represent different scope types + and there is no context information, such as an InetAddress + object, that implicitly defines the scope type. + + Note that not all possible values have been assigned yet, but + they may be assigned in future revisions of this specification. + Applications should therefore be able to deal with values + not yet assigned." + REFERENCE "RFC 3513" + SYNTAX INTEGER { + -- reserved(0), + + + + interfaceLocal(1), + linkLocal(2), + subnetLocal(3), + adminLocal(4), + siteLocal(5), -- site-local unicast addresses + -- have been deprecated by RFC 3879 + -- unassigned(6), + -- unassigned(7), + organizationLocal(8), + -- unassigned(9), + -- unassigned(10), + -- unassigned(11), + -- unassigned(12), + -- unassigned(13), + global(14) + -- reserved(15) + } + +InetZoneIndex ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "A zone index identifies an instance of a zone of a + specific scope. + + The zone index MUST disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index (ifIndex as defined in the + IF-MIB) of the interface on which the address is configured. + + The zone index may contain the special value 0, which refers + to the default zone. The default zone may be used in cases + where the valid zone index is not known (e.g., when a + management application has to write a link-local IPv6 + address without knowing the interface index value). The + default zone SHOULD NOT be used as an easy way out in + cases where the zone index for a non-global IPv6 address + is known." + REFERENCE "RFC4007" + SYNTAX Unsigned32 + +InetVersion ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A value representing a version of the IP protocol. + + unknown(0) An unknown or unspecified version of the IP + protocol. + + + + ipv4(1) The IPv4 protocol as defined in RFC 791 (STD 5). + + ipv6(2) The IPv6 protocol as defined in RFC 2460. + + Note that this textual convention SHOULD NOT be used to + distinguish different address types associated with IP + protocols. The InetAddressType has been designed for this + purpose." + REFERENCE "RFC 791, RFC 2460" + SYNTAX INTEGER { + unknown(0), + ipv4(1), + ipv6(2) + } +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/IP-MIB b/contrib/apps/LwipMibCompiler/Mibs/IP-MIB new file mode 100644 index 0000000..0a93501 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/IP-MIB @@ -0,0 +1,5254 @@ +IP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, + Integer32, Counter32, IpAddress, + mib-2, Unsigned32, Counter64, + zeroDotZero FROM SNMPv2-SMI + PhysAddress, TruthValue, + TimeStamp, RowPointer, + TEXTUAL-CONVENTION, TestAndIncr, + RowStatus, StorageType FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + InetAddress, InetAddressType, + InetAddressPrefixLength, + InetVersion, InetZoneIndex FROM INET-ADDRESS-MIB + InterfaceIndex FROM IF-MIB; + +ipMIB MODULE-IDENTITY + LAST-UPDATED "200602020000Z" + ORGANIZATION "IETF IPv6 MIB Revision Team" + CONTACT-INFO + "Editor: + + + + Shawn A. Routhier + Interworking Labs + 108 Whispering Pines Dr. Suite 235 + Scotts Valley, CA 95066 + USA + EMail: " + DESCRIPTION + "The MIB module for managing IP and ICMP implementations, but + excluding their management of IP routes. + + Copyright (C) The Internet Society (2006). This version of + this MIB module is part of RFC 4293; see the RFC itself for + full legal notices." + + REVISION "200602020000Z" + DESCRIPTION + "The IP version neutral revision with added IPv6 objects for + ND, default routers, and router advertisements. As well as + being the successor to RFC 2011, this MIB is also the + successor to RFCs 2465 and 2466. Published as RFC 4293." + + REVISION "199411010000Z" + DESCRIPTION + "A separate MIB module (IP-MIB) for IP and ICMP management + objects. Published as RFC 2011." + + REVISION "199103310000Z" + DESCRIPTION + "The initial revision of this MIB module was part of MIB-II, + which was published as RFC 1213." + ::= { mib-2 48} + +-- +-- The textual conventions we define and use in this MIB. +-- + +IpAddressOriginTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The origin of the address. + + manual(2) indicates that the address was manually configured + to a specified address, e.g., by user configuration. + + dhcp(4) indicates an address that was assigned to this + system by a DHCP server. + + linklayer(5) indicates an address created by IPv6 stateless + + + + auto-configuration. + + random(6) indicates an address chosen by the system at + random, e.g., an IPv4 address within 169.254/16, or an RFC + 3041 privacy address." + SYNTAX INTEGER { + other(1), + manual(2), + dhcp(4), + linklayer(5), + random(6) + } + +IpAddressStatusTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The status of an address. Most of the states correspond to + states from the IPv6 Stateless Address Autoconfiguration + protocol. + + The preferred(1) state indicates that this is a valid + address that can appear as the destination or source address + of a packet. + + The deprecated(2) state indicates that this is a valid but + deprecated address that should no longer be used as a source + address in new communications, but packets addressed to such + an address are processed as expected. + + The invalid(3) state indicates that this isn't a valid + address and it shouldn't appear as the destination or source + address of a packet. + + The inaccessible(4) state indicates that the address is not + accessible because the interface to which this address is + assigned is not operational. + + The unknown(5) state indicates that the status cannot be + determined for some reason. + + The tentative(6) state indicates that the uniqueness of the + address on the link is being verified. Addresses in this + state should not be used for general communication and + should only be used to determine the uniqueness of the + address. + + The duplicate(7) state indicates the address has been + determined to be non-unique on the link and so must not be + + + + used. + + The optimistic(8) state indicates the address is available + for use, subject to restrictions, while its uniqueness on + a link is being verified. + + In the absence of other information, an IPv4 address is + always preferred(1)." + REFERENCE "RFC 2462" + SYNTAX INTEGER { + preferred(1), + deprecated(2), + invalid(3), + inaccessible(4), + unknown(5), + tentative(6), + duplicate(7), + optimistic(8) + } + +IpAddressPrefixOriginTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The origin of this prefix. + + manual(2) indicates a prefix that was manually configured. + + wellknown(3) indicates a well-known prefix, e.g., 169.254/16 + for IPv4 auto-configuration or fe80::/10 for IPv6 link-local + addresses. Well known prefixes may be assigned by IANA, + the address registries, or by specification in a standards + track RFC. + + dhcp(4) indicates a prefix that was assigned by a DHCP + server. + + routeradv(5) indicates a prefix learned from a router + advertisement. + + Note: while IpAddressOriginTC and IpAddressPrefixOriginTC + are similar, they are not identical. The first defines how + an address was created, while the second defines how a + prefix was found." + SYNTAX INTEGER { + other(1), + manual(2), + wellknown(3), + dhcp(4), + + + + routeradv(5) + } + +Ipv6AddressIfIdentifierTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "2x:" + STATUS current + DESCRIPTION + "This data type is used to model IPv6 address + interface identifiers. This is a binary string + of up to 8 octets in network byte-order." + SYNTAX OCTET STRING (SIZE (0..8)) + +-- +-- the IP general group +-- some objects that affect all of IPv4 +-- + +ip OBJECT IDENTIFIER ::= { mib-2 4 } + +ipForwarding OBJECT-TYPE + SYNTAX INTEGER { + forwarding(1), -- acting as a router + notForwarding(2) -- NOT acting as a router + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The indication of whether this entity is acting as an IPv4 + router in respect to the forwarding of datagrams received + by, but not addressed to, this entity. IPv4 routers forward + datagrams. IPv4 hosts do not (except those source-routed + via the host). + + When this object is written, the entity should save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system. + Note: a stronger requirement is not used because this object + was previously defined." + ::= { ip 1 } + +ipDefaultTTL OBJECT-TYPE + SYNTAX Integer32 (1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The default value inserted into the Time-To-Live field of + the IPv4 header of datagrams originated at this entity, + whenever a TTL value is not supplied by the transport layer + + + + protocol. + + When this object is written, the entity should save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system. + Note: a stronger requirement is not used because this object + was previously defined." + ::= { ip 2 } + +ipReasmTimeout OBJECT-TYPE + SYNTAX Integer32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The maximum number of seconds that received fragments are + held while they are awaiting reassembly at this entity." + ::= { ip 13 } + +-- +-- the IPv6 general group +-- Some objects that affect all of IPv6 +-- + +ipv6IpForwarding OBJECT-TYPE + SYNTAX INTEGER { + forwarding(1), -- acting as a router + notForwarding(2) -- NOT acting as a router + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The indication of whether this entity is acting as an IPv6 + router on any interface in respect to the forwarding of + datagrams received by, but not addressed to, this entity. + IPv6 routers forward datagrams. IPv6 hosts do not (except + those source-routed via the host). + + When this object is written, the entity SHOULD save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system." + ::= { ip 25 } + +ipv6IpDefaultHopLimit OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + + + + "The default value inserted into the Hop Limit field of the + IPv6 header of datagrams originated at this entity whenever + a Hop Limit value is not supplied by the transport layer + protocol. + + When this object is written, the entity SHOULD save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system." + REFERENCE "RFC 2461 Section 6.3.2" + ::= { ip 26 } + +-- +-- IPv4 Interface Table +-- + +ipv4InterfaceTableLastChange OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + a row in the ipv4InterfaceTable was added or deleted, or + when an ipv4InterfaceReasmMaxSize or an + ipv4InterfaceEnableStatus object was modified. + + If new objects are added to the ipv4InterfaceTable that + require the ipv4InterfaceTableLastChange to be updated when + they are modified, they must specify that requirement in + their description clause." + ::= { ip 27 } + +ipv4InterfaceTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ipv4InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing per-interface IPv4-specific + information." + ::= { ip 28 } + +ipv4InterfaceEntry OBJECT-TYPE + SYNTAX Ipv4InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing IPv4-specific information for a specific + interface." + INDEX { ipv4InterfaceIfIndex } + + + + ::= { ipv4InterfaceTable 1 } + +Ipv4InterfaceEntry ::= SEQUENCE { + ipv4InterfaceIfIndex InterfaceIndex, + ipv4InterfaceReasmMaxSize Integer32, + ipv4InterfaceEnableStatus INTEGER, + ipv4InterfaceRetransmitTime Unsigned32 + } + +ipv4InterfaceIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipv4InterfaceEntry 1 } + +ipv4InterfaceReasmMaxSize OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The size of the largest IPv4 datagram that this entity can + re-assemble from incoming IPv4 fragmented datagrams received + on this interface." + ::= { ipv4InterfaceEntry 2 } + +ipv4InterfaceEnableStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), + down(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The indication of whether IPv4 is enabled (up) or disabled + (down) on this interface. This object does not affect the + state of the interface itself, only its connection to an + IPv4 stack. The IF-MIB should be used to control the state + of the interface." + ::= { ipv4InterfaceEntry 3 } + +ipv4InterfaceRetransmitTime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The time between retransmissions of ARP requests to a + neighbor when resolving the address or when probing the + reachability of a neighbor." + REFERENCE "RFC 1122" + DEFVAL { 1000 } + ::= { ipv4InterfaceEntry 4 } + +-- +-- v6 interface table +-- + +ipv6InterfaceTableLastChange OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + a row in the ipv6InterfaceTable was added or deleted or when + an ipv6InterfaceReasmMaxSize, ipv6InterfaceIdentifier, + ipv6InterfaceEnableStatus, ipv6InterfaceReachableTime, + ipv6InterfaceRetransmitTime, or ipv6InterfaceForwarding + object was modified. + + If new objects are added to the ipv6InterfaceTable that + require the ipv6InterfaceTableLastChange to be updated when + they are modified, they must specify that requirement in + their description clause." + ::= { ip 29 } + +ipv6InterfaceTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ipv6InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing per-interface IPv6-specific + information." + ::= { ip 30 } + +ipv6InterfaceEntry OBJECT-TYPE + SYNTAX Ipv6InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing IPv6-specific information for a given + interface." + + + + INDEX { ipv6InterfaceIfIndex } + ::= { ipv6InterfaceTable 1 } + +Ipv6InterfaceEntry ::= SEQUENCE { + ipv6InterfaceIfIndex InterfaceIndex, + ipv6InterfaceReasmMaxSize Unsigned32, + ipv6InterfaceIdentifier Ipv6AddressIfIdentifierTC, + ipv6InterfaceEnableStatus INTEGER, + ipv6InterfaceReachableTime Unsigned32, + ipv6InterfaceRetransmitTime Unsigned32, + ipv6InterfaceForwarding INTEGER + } + +ipv6InterfaceIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipv6InterfaceEntry 1 } + +ipv6InterfaceReasmMaxSize OBJECT-TYPE + SYNTAX Unsigned32 (1500..65535) + UNITS "octets" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The size of the largest IPv6 datagram that this entity can + re-assemble from incoming IPv6 fragmented datagrams received + on this interface." + ::= { ipv6InterfaceEntry 2 } + +ipv6InterfaceIdentifier OBJECT-TYPE + SYNTAX Ipv6AddressIfIdentifierTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Interface Identifier for this interface. The Interface + Identifier is combined with an address prefix to form an + interface address. + + By default, the Interface Identifier is auto-configured + according to the rules of the link type to which this + interface is attached. + + + + + A zero length identifier may be used where appropriate. One + possible example is a loopback interface." + ::= { ipv6InterfaceEntry 3 } + +-- This object ID is reserved as it was used in earlier versions of +-- the MIB module. In theory, OIDs are not assigned until the +-- specification is released as an RFC; however, as some companies +-- may have shipped code based on earlier versions of the MIB, it +-- seems best to reserve this OID. This OID had been +-- ipv6InterfacePhysicalAddress. +-- ::= { ipv6InterfaceEntry 4} + +ipv6InterfaceEnableStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), + down(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The indication of whether IPv6 is enabled (up) or disabled + (down) on this interface. This object does not affect the + state of the interface itself, only its connection to an + IPv6 stack. The IF-MIB should be used to control the state + of the interface. + + When this object is written, the entity SHOULD save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system." + ::= { ipv6InterfaceEntry 5 } + +ipv6InterfaceReachableTime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The time a neighbor is considered reachable after receiving + a reachability confirmation." + REFERENCE "RFC 2461, Section 6.3.2" + ::= { ipv6InterfaceEntry 6 } + +ipv6InterfaceRetransmitTime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + + "The time between retransmissions of Neighbor Solicitation + messages to a neighbor when resolving the address or when + probing the reachability of a neighbor." + REFERENCE "RFC 2461, Section 6.3.2" + ::= { ipv6InterfaceEntry 7 } + +ipv6InterfaceForwarding OBJECT-TYPE + SYNTAX INTEGER { + forwarding(1), -- acting as a router + notForwarding(2) -- NOT acting as a router + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The indication of whether this entity is acting as an IPv6 + router on this interface with respect to the forwarding of + datagrams received by, but not addressed to, this entity. + IPv6 routers forward datagrams. IPv6 hosts do not (except + those source-routed via the host). + + This object is constrained by ipv6IpForwarding and is + ignored if ipv6IpForwarding is set to notForwarding. Those + systems that do not provide per-interface control of the + forwarding function should set this object to forwarding for + all interfaces and allow the ipv6IpForwarding object to + control the forwarding capability. + + When this object is written, the entity SHOULD save the + change to non-volatile storage and restore the object from + non-volatile storage upon re-initialization of the system." + ::= { ipv6InterfaceEntry 8 } + +-- +-- Per-Interface or System-Wide IP statistics. +-- +-- The following two tables, ipSystemStatsTable and ipIfStatsTable, +-- are intended to provide the same counters at different granularities. +-- The ipSystemStatsTable provides system wide counters aggregating +-- the traffic counters for all interfaces for a given address type. +-- The ipIfStatsTable provides the same counters but for specific +-- interfaces rather than as an aggregate. +-- +-- Note well: If a system provides both system-wide and interface- +-- specific values, the system-wide value may not be equal to the sum +-- of the interface-specific values across all interfaces due to e.g., +-- dynamic interface creation/deletion. +-- +-- Note well: Both of these tables contain some items that are + + + +-- represented by two objects, representing the value in either 32 +-- or 64 bits. For those objects, the 32-bit value MUST be the low +-- order 32 bits of the 64-bit value. Also note that the 32-bit +-- counters must be included when the 64-bit counters are included. + +ipTrafficStats OBJECT IDENTIFIER ::= { ip 31 } + +ipSystemStatsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpSystemStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing system wide, IP version specific + traffic statistics. This table and the ipIfStatsTable + contain similar objects whose difference is in their + granularity. Where this table contains system wide traffic + statistics, the ipIfStatsTable contains the same statistics + but counted on a per-interface basis." + ::= { ipTrafficStats 1 } + +ipSystemStatsEntry OBJECT-TYPE + SYNTAX IpSystemStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A statistics entry containing system-wide objects for a + particular IP version." + INDEX { ipSystemStatsIPVersion } + ::= { ipSystemStatsTable 1 } + +IpSystemStatsEntry ::= SEQUENCE { + ipSystemStatsIPVersion InetVersion, + ipSystemStatsInReceives Counter32, + ipSystemStatsHCInReceives Counter64, + ipSystemStatsInOctets Counter32, + ipSystemStatsHCInOctets Counter64, + ipSystemStatsInHdrErrors Counter32, + ipSystemStatsInNoRoutes Counter32, + ipSystemStatsInAddrErrors Counter32, + ipSystemStatsInUnknownProtos Counter32, + ipSystemStatsInTruncatedPkts Counter32, + ipSystemStatsInForwDatagrams Counter32, + ipSystemStatsHCInForwDatagrams Counter64, + ipSystemStatsReasmReqds Counter32, + ipSystemStatsReasmOKs Counter32, + ipSystemStatsReasmFails Counter32, + ipSystemStatsInDiscards Counter32, + ipSystemStatsInDelivers Counter32, + + + + ipSystemStatsHCInDelivers Counter64, + ipSystemStatsOutRequests Counter32, + ipSystemStatsHCOutRequests Counter64, + ipSystemStatsOutNoRoutes Counter32, + ipSystemStatsOutForwDatagrams Counter32, + ipSystemStatsHCOutForwDatagrams Counter64, + ipSystemStatsOutDiscards Counter32, + ipSystemStatsOutFragReqds Counter32, + ipSystemStatsOutFragOKs Counter32, + ipSystemStatsOutFragFails Counter32, + ipSystemStatsOutFragCreates Counter32, + ipSystemStatsOutTransmits Counter32, + ipSystemStatsHCOutTransmits Counter64, + ipSystemStatsOutOctets Counter32, + ipSystemStatsHCOutOctets Counter64, + ipSystemStatsInMcastPkts Counter32, + ipSystemStatsHCInMcastPkts Counter64, + ipSystemStatsInMcastOctets Counter32, + ipSystemStatsHCInMcastOctets Counter64, + ipSystemStatsOutMcastPkts Counter32, + ipSystemStatsHCOutMcastPkts Counter64, + ipSystemStatsOutMcastOctets Counter32, + ipSystemStatsHCOutMcastOctets Counter64, + ipSystemStatsInBcastPkts Counter32, + ipSystemStatsHCInBcastPkts Counter64, + ipSystemStatsOutBcastPkts Counter32, + ipSystemStatsHCOutBcastPkts Counter64, + ipSystemStatsDiscontinuityTime TimeStamp, + ipSystemStatsRefreshRate Unsigned32 + } + +ipSystemStatsIPVersion OBJECT-TYPE + SYNTAX InetVersion + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP version of this row." + ::= { ipSystemStatsEntry 1 } + +-- This object ID is reserved to allow the IDs for this table's objects +-- to align with the objects in the ipIfStatsTable. +-- ::= { ipSystemStatsEntry 2 } + +ipSystemStatsInReceives OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + + "The total number of input IP datagrams received, including + those received in error. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 3 } + +ipSystemStatsHCInReceives OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of input IP datagrams received, including + those received in error. This object counts the same + datagrams as ipSystemStatsInReceives, but allows for larger + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 4 } + +ipSystemStatsInOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in input IP datagrams, + including those received in error. Octets from datagrams + counted in ipSystemStatsInReceives MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 5 } + +ipSystemStatsHCInOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in input IP datagrams, + including those received in error. This object counts the + same octets as ipSystemStatsInOctets, but allows for larger + + + + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 6 } + +ipSystemStatsInHdrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded due to errors in + their IP headers, including version number mismatch, other + format errors, hop count exceeded, errors discovered in + processing their IP options, etc. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 7 } + +ipSystemStatsInNoRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because no route + could be found to transmit them to their destination. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 8 } + +ipSystemStatsInAddrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because the IP + address in their IP header's destination field was not a + valid address to be received at this entity. This count + includes invalid addresses (e.g., ::0). For entities + that are not IP routers and therefore do not forward + + + + datagrams, this counter includes datagrams discarded + because the destination address was not a local address. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 9 } + +ipSystemStatsInUnknownProtos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of locally-addressed IP datagrams received + successfully but discarded because of an unknown or + unsupported protocol. + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 10 } + +ipSystemStatsInTruncatedPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because the + datagram frame didn't carry enough data. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 11 } + +ipSystemStatsInForwDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + + "The number of input datagrams for which this entity was not + their final IP destination and for which this entity + attempted to find a route to forward them to that final + destination. In entities that do not act as IP routers, + this counter will include only those datagrams that were + Source-Routed via this entity, and the Source-Route + processing was successful. + + When tracking interface statistics, the counter of the + incoming interface is incremented for each datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 12 } + +ipSystemStatsHCInForwDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input datagrams for which this entity was not + their final IP destination and for which this entity + attempted to find a route to forward them to that final + destination. This object counts the same packets as + ipSystemStatsInForwDatagrams, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 13 } + +ipSystemStatsReasmReqds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP fragments received that needed to be + reassembled at this interface. + + When tracking interface statistics, the counter of the + interface to which these fragments were addressed is + incremented. This interface might not be the same as the + input interface for some of the fragments. + + Discontinuities in the value of this counter can occur at + + + + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 14 } + +ipSystemStatsReasmOKs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams successfully reassembled. + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 15 } + +ipSystemStatsReasmFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of failures detected by the IP re-assembly + algorithm (for whatever reason: timed out, errors, etc.). + Note that this is not necessarily a count of discarded IP + fragments since some algorithms (notably the algorithm in + RFC 815) can lose track of the number of fragments by + combining them as they are received. + + When tracking interface statistics, the counter of the + interface to which these fragments were addressed is + incremented. This interface might not be the same as the + input interface for some of the fragments. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 16 } + +ipSystemStatsInDiscards OBJECT-TYPE + SYNTAX Counter32 + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams for which no problems were + encountered to prevent their continued processing, but + were discarded (e.g., for lack of buffer space). Note that + this counter does not include any datagrams discarded while + awaiting re-assembly. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 17 } + +ipSystemStatsInDelivers OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of datagrams successfully delivered to IP + user-protocols (including ICMP). + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 18 } + +ipSystemStatsHCInDelivers OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of datagrams successfully delivered to IP + user-protocols (including ICMP). This object counts the + same packets as ipSystemStatsInDelivers, but allows for + larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + + + + ::= { ipSystemStatsEntry 19 } + +ipSystemStatsOutRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that local IP user- + protocols (including ICMP) supplied to IP in requests for + transmission. Note that this counter does not include any + datagrams counted in ipSystemStatsOutForwDatagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 20 } + +ipSystemStatsHCOutRequests OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that local IP user- + protocols (including ICMP) supplied to IP in requests for + transmission. This object counts the same packets as + ipSystemStatsOutRequests, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 21 } + +ipSystemStatsOutNoRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of locally generated IP datagrams discarded + because no route could be found to transmit them to their + destination. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 22 } + + + +ipSystemStatsOutForwDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of datagrams for which this entity was not their + final IP destination and for which it was successful in + finding a path to their final destination. In entities + that do not act as IP routers, this counter will include + only those datagrams that were Source-Routed via this + entity, and the Source-Route processing was successful. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + forwarded datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 23 } + +ipSystemStatsHCOutForwDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of datagrams for which this entity was not their + final IP destination and for which it was successful in + finding a path to their final destination. This object + counts the same packets as ipSystemStatsOutForwDatagrams, + but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 24 } + +ipSystemStatsOutDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of output IP datagrams for which no problem was + encountered to prevent their transmission to their + destination, but were discarded (e.g., for lack of + buffer space). Note that this counter would include + + + + datagrams counted in ipSystemStatsOutForwDatagrams if any + such datagrams met this (discretionary) discard criterion. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 25 } + +ipSystemStatsOutFragReqds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams that would require fragmentation + in order to be transmitted. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 26 } + +ipSystemStatsOutFragOKs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams that have been successfully + fragmented. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 27 } + +ipSystemStatsOutFragFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + + + + STATUS current + DESCRIPTION + "The number of IP datagrams that have been discarded because + they needed to be fragmented but could not be. This + includes IPv4 packets that have the DF bit set and IPv6 + packets that are being forwarded and exceed the outgoing + link MTU. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for an unsuccessfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 28 } + +ipSystemStatsOutFragCreates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of output datagram fragments that have been + generated as a result of IP fragmentation. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 29 } + +ipSystemStatsOutTransmits OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that this entity supplied + to the lower layers for transmission. This includes + datagrams generated locally and those forwarded by this + entity. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + + + + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 30 } + +ipSystemStatsHCOutTransmits OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that this entity supplied + to the lower layers for transmission. This object counts + the same datagrams as ipSystemStatsOutTransmits, but allows + for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 31 } + +ipSystemStatsOutOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets in IP datagrams delivered to the + lower layers for transmission. Octets from datagrams + counted in ipSystemStatsOutTransmits MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 32 } + +ipSystemStatsHCOutOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets in IP datagrams delivered to the + lower layers for transmission. This objects counts the same + octets as ipSystemStatsOutOctets, but allows for larger + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + + + + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 33 } + +ipSystemStatsInMcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams received. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 34 } + +ipSystemStatsHCInMcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams received. This object + counts the same datagrams as ipSystemStatsInMcastPkts but + allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 35 } + +ipSystemStatsInMcastOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in IP multicast + datagrams. Octets from datagrams counted in + ipSystemStatsInMcastPkts MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 36 } + +ipSystemStatsHCInMcastOctets OBJECT-TYPE + SYNTAX Counter64 + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in IP multicast + datagrams. This object counts the same octets as + ipSystemStatsInMcastOctets, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 37 } + +ipSystemStatsOutMcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams transmitted. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 38 } + +ipSystemStatsHCOutMcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams transmitted. This + object counts the same datagrams as + ipSystemStatsOutMcastPkts, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 39 } + +ipSystemStatsOutMcastOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted in IP multicast + datagrams. Octets from datagrams counted in + + + + ipSystemStatsOutMcastPkts MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 40 } + +ipSystemStatsHCOutMcastOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted in IP multicast + datagrams. This object counts the same octets as + ipSystemStatsOutMcastOctets, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 41 } + +ipSystemStatsInBcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams received. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 42 } + +ipSystemStatsHCInBcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams received. This object + counts the same datagrams as ipSystemStatsInBcastPkts but + allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + + + + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 43 } + +ipSystemStatsOutBcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams transmitted. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 44 } + +ipSystemStatsHCOutBcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams transmitted. This + object counts the same datagrams as + ipSystemStatsOutBcastPkts, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipSystemStatsDiscontinuityTime." + ::= { ipSystemStatsEntry 45 } + +ipSystemStatsDiscontinuityTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + any one or more of this entry's counters suffered a + discontinuity. + + If no such discontinuities have occurred since the last re- + initialization of the local management subsystem, then this + object contains a zero value." + ::= { ipSystemStatsEntry 46 } + +ipSystemStatsRefreshRate OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milli-seconds" + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The minimum reasonable polling interval for this entry. + This object provides an indication of the minimum amount of + time required to update the counters in this entry." + ::= { ipSystemStatsEntry 47 } + +ipIfStatsTableLastChange OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + a row in the ipIfStatsTable was added or deleted. + + If new objects are added to the ipIfStatsTable that require + the ipIfStatsTableLastChange to be updated when they are + modified, they must specify that requirement in their + description clause." + ::= { ipTrafficStats 2 } + +ipIfStatsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpIfStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing per-interface traffic statistics. This + table and the ipSystemStatsTable contain similar objects + whose difference is in their granularity. Where this table + contains per-interface statistics, the ipSystemStatsTable + contains the same statistics, but counted on a system wide + basis." + ::= { ipTrafficStats 3 } + +ipIfStatsEntry OBJECT-TYPE + SYNTAX IpIfStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An interface statistics entry containing objects for a + particular interface and version of IP." + INDEX { ipIfStatsIPVersion, ipIfStatsIfIndex } + ::= { ipIfStatsTable 1 } + +IpIfStatsEntry ::= SEQUENCE { + ipIfStatsIPVersion InetVersion, + ipIfStatsIfIndex InterfaceIndex, + + + + ipIfStatsInReceives Counter32, + ipIfStatsHCInReceives Counter64, + ipIfStatsInOctets Counter32, + ipIfStatsHCInOctets Counter64, + ipIfStatsInHdrErrors Counter32, + ipIfStatsInNoRoutes Counter32, + ipIfStatsInAddrErrors Counter32, + ipIfStatsInUnknownProtos Counter32, + ipIfStatsInTruncatedPkts Counter32, + ipIfStatsInForwDatagrams Counter32, + ipIfStatsHCInForwDatagrams Counter64, + ipIfStatsReasmReqds Counter32, + ipIfStatsReasmOKs Counter32, + ipIfStatsReasmFails Counter32, + ipIfStatsInDiscards Counter32, + ipIfStatsInDelivers Counter32, + ipIfStatsHCInDelivers Counter64, + ipIfStatsOutRequests Counter32, + ipIfStatsHCOutRequests Counter64, + ipIfStatsOutForwDatagrams Counter32, + ipIfStatsHCOutForwDatagrams Counter64, + ipIfStatsOutDiscards Counter32, + ipIfStatsOutFragReqds Counter32, + ipIfStatsOutFragOKs Counter32, + ipIfStatsOutFragFails Counter32, + ipIfStatsOutFragCreates Counter32, + ipIfStatsOutTransmits Counter32, + ipIfStatsHCOutTransmits Counter64, + ipIfStatsOutOctets Counter32, + ipIfStatsHCOutOctets Counter64, + ipIfStatsInMcastPkts Counter32, + ipIfStatsHCInMcastPkts Counter64, + ipIfStatsInMcastOctets Counter32, + ipIfStatsHCInMcastOctets Counter64, + ipIfStatsOutMcastPkts Counter32, + ipIfStatsHCOutMcastPkts Counter64, + ipIfStatsOutMcastOctets Counter32, + ipIfStatsHCOutMcastOctets Counter64, + ipIfStatsInBcastPkts Counter32, + ipIfStatsHCInBcastPkts Counter64, + ipIfStatsOutBcastPkts Counter32, + ipIfStatsHCOutBcastPkts Counter64, + ipIfStatsDiscontinuityTime TimeStamp, + ipIfStatsRefreshRate Unsigned32 + } + +ipIfStatsIPVersion OBJECT-TYPE + SYNTAX InetVersion + + + + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP version of this row." + ::= { ipIfStatsEntry 1 } + +ipIfStatsIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipIfStatsEntry 2 } + +ipIfStatsInReceives OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of input IP datagrams received, including + those received in error. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 3 } + +ipIfStatsHCInReceives OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of input IP datagrams received, including + those received in error. This object counts the same + datagrams as ipIfStatsInReceives, but allows for larger + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 4 } + +ipIfStatsInOctets OBJECT-TYPE + + + + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in input IP datagrams, + including those received in error. Octets from datagrams + counted in ipIfStatsInReceives MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 5 } + +ipIfStatsHCInOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in input IP datagrams, + including those received in error. This object counts the + same octets as ipIfStatsInOctets, but allows for larger + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 6 } + +ipIfStatsInHdrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded due to errors in + their IP headers, including version number mismatch, other + format errors, hop count exceeded, errors discovered in + processing their IP options, etc. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 7 } + +ipIfStatsInNoRoutes OBJECT-TYPE + SYNTAX Counter32 + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because no route + could be found to transmit them to their destination. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 8 } + +ipIfStatsInAddrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because the IP + address in their IP header's destination field was not a + valid address to be received at this entity. This count + includes invalid addresses (e.g., ::0). For entities that + are not IP routers and therefore do not forward datagrams, + this counter includes datagrams discarded because the + destination address was not a local address. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 9 } + +ipIfStatsInUnknownProtos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of locally-addressed IP datagrams received + successfully but discarded because of an unknown or + unsupported protocol. + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + + + + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 10 } + +ipIfStatsInTruncatedPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams discarded because the + datagram frame didn't carry enough data. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 11 } + +ipIfStatsInForwDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input datagrams for which this entity was not + their final IP destination and for which this entity + attempted to find a route to forward them to that final + destination. In entities that do not act as IP routers, + this counter will include only those datagrams that were + Source-Routed via this entity, and the Source-Route + processing was successful. + + When tracking interface statistics, the counter of the + incoming interface is incremented for each datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 12 } + +ipIfStatsHCInForwDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input datagrams for which this entity was not + their final IP destination and for which this entity + attempted to find a route to forward them to that final + destination. This object counts the same packets as + + + + ipIfStatsInForwDatagrams, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 13 } + +ipIfStatsReasmReqds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP fragments received that needed to be + reassembled at this interface. + + When tracking interface statistics, the counter of the + interface to which these fragments were addressed is + incremented. This interface might not be the same as the + input interface for some of the fragments. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 14 } + +ipIfStatsReasmOKs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams successfully reassembled. + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 15 } + +ipIfStatsReasmFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + + + + STATUS current + DESCRIPTION + "The number of failures detected by the IP re-assembly + algorithm (for whatever reason: timed out, errors, etc.). + Note that this is not necessarily a count of discarded IP + fragments since some algorithms (notably the algorithm in + RFC 815) can lose track of the number of fragments by + combining them as they are received. + + When tracking interface statistics, the counter of the + interface to which these fragments were addressed is + incremented. This interface might not be the same as the + input interface for some of the fragments. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 16 } + +ipIfStatsInDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input IP datagrams for which no problems were + encountered to prevent their continued processing, but + were discarded (e.g., for lack of buffer space). Note that + this counter does not include any datagrams discarded while + awaiting re-assembly. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 17 } + +ipIfStatsInDelivers OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of datagrams successfully delivered to IP + user-protocols (including ICMP). + + When tracking interface statistics, the counter of the + interface to which these datagrams were addressed is + incremented. This interface might not be the same as the + + + + input interface for some of the datagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 18 } + +ipIfStatsHCInDelivers OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of datagrams successfully delivered to IP + user-protocols (including ICMP). This object counts the + same packets as ipIfStatsInDelivers, but allows for larger + values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 19 } + +ipIfStatsOutRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that local IP user- + protocols (including ICMP) supplied to IP in requests for + transmission. Note that this counter does not include any + datagrams counted in ipIfStatsOutForwDatagrams. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 20 } + +ipIfStatsHCOutRequests OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that local IP user- + protocols (including ICMP) supplied to IP in requests for + transmission. This object counts the same packets as + + + + ipIfStatsOutRequests, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 21 } + +-- This object ID is reserved to allow the IDs for this table's objects +-- to align with the objects in the ipSystemStatsTable. +-- ::= {ipIfStatsEntry 22} + +ipIfStatsOutForwDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of datagrams for which this entity was not their + final IP destination and for which it was successful in + finding a path to their final destination. In entities + that do not act as IP routers, this counter will include + only those datagrams that were Source-Routed via this + entity, and the Source-Route processing was successful. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + forwarded datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 23 } + +ipIfStatsHCOutForwDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of datagrams for which this entity was not their + final IP destination and for which it was successful in + finding a path to their final destination. This object + counts the same packets as ipIfStatsOutForwDatagrams, but + allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + + + + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 24 } + +ipIfStatsOutDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of output IP datagrams for which no problem was + encountered to prevent their transmission to their + destination, but were discarded (e.g., for lack of + buffer space). Note that this counter would include + datagrams counted in ipIfStatsOutForwDatagrams if any such + datagrams met this (discretionary) discard criterion. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 25 } + +ipIfStatsOutFragReqds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams that would require fragmentation + in order to be transmitted. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 26 } + +ipIfStatsOutFragOKs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams that have been successfully + fragmented. + + When tracking interface statistics, the counter of the + + + + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 27 } + +ipIfStatsOutFragFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP datagrams that have been discarded because + they needed to be fragmented but could not be. This + includes IPv4 packets that have the DF bit set and IPv6 + packets that are being forwarded and exceed the outgoing + link MTU. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for an unsuccessfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 28 } + +ipIfStatsOutFragCreates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of output datagram fragments that have been + generated as a result of IP fragmentation. + + When tracking interface statistics, the counter of the + outgoing interface is incremented for a successfully + fragmented datagram. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 29 } + + + + +ipIfStatsOutTransmits OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that this entity supplied + to the lower layers for transmission. This includes + datagrams generated locally and those forwarded by this + entity. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 30 } + +ipIfStatsHCOutTransmits OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of IP datagrams that this entity supplied + to the lower layers for transmission. This object counts + the same datagrams as ipIfStatsOutTransmits, but allows for + larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 31 } + +ipIfStatsOutOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets in IP datagrams delivered to the + lower layers for transmission. Octets from datagrams + counted in ipIfStatsOutTransmits MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 32 } + +ipIfStatsHCOutOctets OBJECT-TYPE + + + + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets in IP datagrams delivered to the + lower layers for transmission. This objects counts the same + octets as ipIfStatsOutOctets, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 33 } + +ipIfStatsInMcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams received. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 34 } + +ipIfStatsHCInMcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams received. This object + counts the same datagrams as ipIfStatsInMcastPkts, but + allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 35 } + +ipIfStatsInMcastOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in IP multicast + + + + datagrams. Octets from datagrams counted in + ipIfStatsInMcastPkts MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 36 } + +ipIfStatsHCInMcastOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets received in IP multicast + datagrams. This object counts the same octets as + ipIfStatsInMcastOctets, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 37 } + +ipIfStatsOutMcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams transmitted. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 38 } + +ipIfStatsHCOutMcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP multicast datagrams transmitted. This + object counts the same datagrams as ipIfStatsOutMcastPkts, + but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + + + + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 39 } + +ipIfStatsOutMcastOctets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted in IP multicast + datagrams. Octets from datagrams counted in + ipIfStatsOutMcastPkts MUST be counted here. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 40 } + +ipIfStatsHCOutMcastOctets OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of octets transmitted in IP multicast + datagrams. This object counts the same octets as + ipIfStatsOutMcastOctets, but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 41 } + +ipIfStatsInBcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams received. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 42 } + +ipIfStatsHCInBcastPkts OBJECT-TYPE + + + + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams received. This object + counts the same datagrams as ipIfStatsInBcastPkts, but + allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 43 } + +ipIfStatsOutBcastPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams transmitted. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 44 } + +ipIfStatsHCOutBcastPkts OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of IP broadcast datagrams transmitted. This + object counts the same datagrams as ipIfStatsOutBcastPkts, + but allows for larger values. + + Discontinuities in the value of this counter can occur at + re-initialization of the management system, and at other + times as indicated by the value of + ipIfStatsDiscontinuityTime." + ::= { ipIfStatsEntry 45 } + +ipIfStatsDiscontinuityTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion at which + + + + any one or more of this entry's counters suffered a + discontinuity. + + If no such discontinuities have occurred since the last re- + initialization of the local management subsystem, then this + object contains a zero value." + ::= { ipIfStatsEntry 46 } + +ipIfStatsRefreshRate OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milli-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The minimum reasonable polling interval for this entry. + This object provides an indication of the minimum amount of + time required to update the counters in this entry." + ::= { ipIfStatsEntry 47 } + +-- +-- Internet Address Prefix table +-- + +ipAddressPrefixTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddressPrefixEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table allows the user to determine the source of an IP + address or set of IP addresses, and allows other tables to + share the information via pointer rather than by copying. + + For example, when the node configures both a unicast and + anycast address for a prefix, the ipAddressPrefix objects + for those addresses will point to a single row in this + table. + + This table primarily provides support for IPv6 prefixes, and + several of the objects are less meaningful for IPv4. The + table continues to allow IPv4 addresses to allow future + flexibility. In order to promote a common configuration, + this document includes suggestions for default values for + IPv4 prefixes. Each of these values may be overridden if an + object is meaningful to the node. + + All prefixes used by this entity should be included in this + table independent of how the entity learned the prefix. + (This table isn't limited to prefixes learned from router + + + + advertisements.)" + ::= { ip 32 } + +ipAddressPrefixEntry OBJECT-TYPE + SYNTAX IpAddressPrefixEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry in the ipAddressPrefixTable." + INDEX { ipAddressPrefixIfIndex, ipAddressPrefixType, + ipAddressPrefixPrefix, ipAddressPrefixLength } + ::= { ipAddressPrefixTable 1 } + +IpAddressPrefixEntry ::= SEQUENCE { + ipAddressPrefixIfIndex InterfaceIndex, + ipAddressPrefixType InetAddressType, + ipAddressPrefixPrefix InetAddress, + ipAddressPrefixLength InetAddressPrefixLength, + ipAddressPrefixOrigin IpAddressPrefixOriginTC, + ipAddressPrefixOnLinkFlag TruthValue, + ipAddressPrefixAutonomousFlag TruthValue, + ipAddressPrefixAdvPreferredLifetime Unsigned32, + ipAddressPrefixAdvValidLifetime Unsigned32 + } + +ipAddressPrefixIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface on + which this prefix is configured. The interface identified + by a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipAddressPrefixEntry 1 } + +ipAddressPrefixType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of ipAddressPrefix." + ::= { ipAddressPrefixEntry 2 } + +ipAddressPrefixPrefix OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + + + + DESCRIPTION + "The address prefix. The address type of this object is + specified in ipAddressPrefixType. The length of this object + is the standard length for objects of that type (4 or 16 + bytes). Any bits after ipAddressPrefixLength must be zero. + + Implementors need to be aware that, if the size of + ipAddressPrefixPrefix exceeds 114 octets, then OIDS of + instances of columns in this row will have more than 128 + sub-identifiers and cannot be accessed using SNMPv1, + SNMPv2c, or SNMPv3." + ::= { ipAddressPrefixEntry 3 } + +ipAddressPrefixLength OBJECT-TYPE + SYNTAX InetAddressPrefixLength + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The prefix length associated with this prefix. + + The value 0 has no special meaning for this object. It + simply refers to address '::/0'." + ::= { ipAddressPrefixEntry 4 } + +ipAddressPrefixOrigin OBJECT-TYPE + SYNTAX IpAddressPrefixOriginTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The origin of this prefix." + ::= { ipAddressPrefixEntry 5 } + +ipAddressPrefixOnLinkFlag OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This object has the value 'true(1)', if this prefix can be + used for on-link determination; otherwise, the value is + 'false(2)'. + + The default for IPv4 prefixes is 'true(1)'." + REFERENCE "For IPv6 RFC 2461, especially sections 2 and 4.6.2 and + RFC 2462" + ::= { ipAddressPrefixEntry 6 } + +ipAddressPrefixAutonomousFlag OBJECT-TYPE + SYNTAX TruthValue + + + + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Autonomous address configuration flag. When true(1), + indicates that this prefix can be used for autonomous + address configuration (i.e., can be used to form a local + interface address). If false(2), it is not used to auto- + configure a local interface address. + + The default for IPv4 prefixes is 'false(2)'." + REFERENCE "For IPv6 RFC 2461, especially sections 2 and 4.6.2 and + RFC 2462" + ::= { ipAddressPrefixEntry 7 } + +ipAddressPrefixAdvPreferredLifetime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remaining length of time, in seconds, that this prefix + will continue to be preferred, i.e., time until deprecation. + + A value of 4,294,967,295 represents infinity. + + The address generated from a deprecated prefix should no + longer be used as a source address in new communications, + but packets received on such an interface are processed as + expected. + + The default for IPv4 prefixes is 4,294,967,295 (infinity)." + REFERENCE "For IPv6 RFC 2461, especially sections 2 and 4.6.2 and + RFC 2462" + ::= { ipAddressPrefixEntry 8 } + +ipAddressPrefixAdvValidLifetime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remaining length of time, in seconds, that this prefix + will continue to be valid, i.e., time until invalidation. A + value of 4,294,967,295 represents infinity. + + The address generated from an invalidated prefix should not + appear as the destination or source address of a packet. + + + + + The default for IPv4 prefixes is 4,294,967,295 (infinity)." + REFERENCE "For IPv6 RFC 2461, especially sections 2 and 4.6.2 and + RFC 2462" + ::= { ipAddressPrefixEntry 9 } + +-- +-- Internet Address Table +-- + +ipAddressSpinLock OBJECT-TYPE + SYNTAX TestAndIncr + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "An advisory lock used to allow cooperating SNMP managers to + coordinate their use of the set operation in creating or + modifying rows within this table. + + In order to use this lock to coordinate the use of set + operations, managers should first retrieve + ipAddressTableSpinLock. They should then determine the + appropriate row to create or modify. Finally, they should + issue the appropriate set command, including the retrieved + value of ipAddressSpinLock. If another manager has altered + the table in the meantime, then the value of + ipAddressSpinLock will have changed, and the creation will + fail as it will be specifying an incorrect value for + ipAddressSpinLock. It is suggested, but not required, that + the ipAddressSpinLock be the first var bind for each set of + objects representing a 'row' in a PDU." + ::= { ip 33 } + +ipAddressTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddressEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table contains addressing information relevant to the + entity's interfaces. + + This table does not contain multicast address information. + Tables for such information should be contained in multicast + specific MIBs, such as RFC 3019. + + While this table is writable, the user will note that + several objects, such as ipAddressOrigin, are not. The + intention in allowing a user to write to this table is to + allow them to add or remove any entry that isn't + + + + permanent. The user should be allowed to modify objects + and entries when that would not cause inconsistencies + within the table. Allowing write access to objects, such + as ipAddressOrigin, could allow a user to insert an entry + and then label it incorrectly. + + Note well: When including IPv6 link-local addresses in this + table, the entry must use an InetAddressType of 'ipv6z' in + order to differentiate between the possible interfaces." + ::= { ip 34 } + +ipAddressEntry OBJECT-TYPE + SYNTAX IpAddressEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An address mapping for a particular interface." + INDEX { ipAddressAddrType, ipAddressAddr } + ::= { ipAddressTable 1 } + +IpAddressEntry ::= SEQUENCE { + ipAddressAddrType InetAddressType, + ipAddressAddr InetAddress, + ipAddressIfIndex InterfaceIndex, + ipAddressType INTEGER, + ipAddressPrefix RowPointer, + ipAddressOrigin IpAddressOriginTC, + ipAddressStatus IpAddressStatusTC, + ipAddressCreated TimeStamp, + ipAddressLastChanged TimeStamp, + ipAddressRowStatus RowStatus, + ipAddressStorageType StorageType + } + +ipAddressAddrType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of ipAddressAddr." + ::= { ipAddressEntry 1 } + +ipAddressAddr OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP address to which this entry's addressing information + + + + pertains. The address type of this object is specified in + ipAddressAddrType. + + Implementors need to be aware that if the size of + ipAddressAddr exceeds 116 octets, then OIDS of instances of + columns in this row will have more than 128 sub-identifiers + and cannot be accessed using SNMPv1, SNMPv2c, or SNMPv3." + ::= { ipAddressEntry 2 } + +ipAddressIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipAddressEntry 3 } + +ipAddressType OBJECT-TYPE + SYNTAX INTEGER { + unicast(1), + anycast(2), + broadcast(3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The type of address. broadcast(3) is not a valid value for + IPv6 addresses (RFC 3513)." + DEFVAL { unicast } + ::= { ipAddressEntry 4 } + +ipAddressPrefix OBJECT-TYPE + SYNTAX RowPointer + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A pointer to the row in the prefix table to which this + address belongs. May be { 0 0 } if there is no such row." + DEFVAL { zeroDotZero } + ::= { ipAddressEntry 5 } + +ipAddressOrigin OBJECT-TYPE + SYNTAX IpAddressOriginTC + MAX-ACCESS read-only + STATUS current + + + + DESCRIPTION + "The origin of the address." + ::= { ipAddressEntry 6 } + +ipAddressStatus OBJECT-TYPE + SYNTAX IpAddressStatusTC + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The status of the address, describing if the address can be + used for communication. + + In the absence of other information, an IPv4 address is + always preferred(1)." + DEFVAL { preferred } + ::= { ipAddressEntry 7 } + +ipAddressCreated OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time this entry was created. + If this entry was created prior to the last re- + initialization of the local network management subsystem, + then this object contains a zero value." + ::= { ipAddressEntry 8 } + +ipAddressLastChanged OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time this entry was last + updated. If this entry was updated prior to the last re- + initialization of the local network management subsystem, + then this object contains a zero value." + ::= { ipAddressEntry 9 } + +ipAddressRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The status of this conceptual row. + + The RowStatus TC requires that this DESCRIPTION clause + states under which circumstances other objects in this row + + + + can be modified. The value of this object has no effect on + whether other objects in this conceptual row can be + modified. + + A conceptual row can not be made active until the + ipAddressIfIndex has been set to a valid index." + ::= { ipAddressEntry 10 } + +ipAddressStorageType OBJECT-TYPE + SYNTAX StorageType + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The storage type for this conceptual row. If this object + has a value of 'permanent', then no other objects are + required to be able to be modified." + DEFVAL { volatile } + ::= { ipAddressEntry 11 } + +-- +-- the Internet Address Translation table +-- + +ipNetToPhysicalTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpNetToPhysicalEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP Address Translation table used for mapping from IP + addresses to physical addresses. + + The Address Translation tables contain the IP address to + 'physical' address equivalences. Some interfaces do not use + translation tables for determining address equivalences + (e.g., DDN-X.25 has an algorithmic method); if all + interfaces are of this type, then the Address Translation + table is empty, i.e., has zero entries. + + While many protocols may be used to populate this table, ARP + and Neighbor Discovery are the most likely + options." + REFERENCE "RFC 826 and RFC 2461" + ::= { ip 35 } + +ipNetToPhysicalEntry OBJECT-TYPE + SYNTAX IpNetToPhysicalEntry + MAX-ACCESS not-accessible + STATUS current + + + + DESCRIPTION + "Each entry contains one IP address to `physical' address + equivalence." + INDEX { ipNetToPhysicalIfIndex, + ipNetToPhysicalNetAddressType, + ipNetToPhysicalNetAddress } + ::= { ipNetToPhysicalTable 1 } + +IpNetToPhysicalEntry ::= SEQUENCE { + ipNetToPhysicalIfIndex InterfaceIndex, + ipNetToPhysicalNetAddressType InetAddressType, + ipNetToPhysicalNetAddress InetAddress, + ipNetToPhysicalPhysAddress PhysAddress, + ipNetToPhysicalLastUpdated TimeStamp, + ipNetToPhysicalType INTEGER, + ipNetToPhysicalState INTEGER, + ipNetToPhysicalRowStatus RowStatus + } + +ipNetToPhysicalIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipNetToPhysicalEntry 1 } + +ipNetToPhysicalNetAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of ipNetToPhysicalNetAddress." + ::= { ipNetToPhysicalEntry 2 } + +ipNetToPhysicalNetAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP Address corresponding to the media-dependent + `physical' address. The address type of this object is + specified in ipNetToPhysicalAddressType. + + Implementors need to be aware that if the size of + + + + ipNetToPhysicalNetAddress exceeds 115 octets, then OIDS of + instances of columns in this row will have more than 128 + sub-identifiers and cannot be accessed using SNMPv1, + SNMPv2c, or SNMPv3." + ::= { ipNetToPhysicalEntry 3 } + +ipNetToPhysicalPhysAddress OBJECT-TYPE + SYNTAX PhysAddress (SIZE(0..65535)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The media-dependent `physical' address. + + As the entries in this table are typically not persistent + when this object is written the entity SHOULD NOT save the + change to non-volatile storage." + ::= { ipNetToPhysicalEntry 4 } + +ipNetToPhysicalLastUpdated OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time this entry was last + updated. If this entry was updated prior to the last re- + initialization of the local network management subsystem, + then this object contains a zero value." + ::= { ipNetToPhysicalEntry 5 } + +ipNetToPhysicalType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + invalid(2), -- an invalidated mapping + dynamic(3), + static(4), + local(5) -- local interface + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The type of mapping. + + Setting this object to the value invalid(2) has the effect + of invalidating the corresponding entry in the + ipNetToPhysicalTable. That is, it effectively dis- + associates the interface identified with said entry from the + mapping identified with said entry. It is an + implementation-specific matter as to whether the agent + + + + removes an invalidated entry from the table. Accordingly, + management stations must be prepared to receive tabular + information from agents that corresponds to entries not + currently in use. Proper interpretation of such entries + requires examination of the relevant ipNetToPhysicalType + object. + + The 'dynamic(3)' type indicates that the IP address to + physical addresses mapping has been dynamically resolved + using e.g., IPv4 ARP or the IPv6 Neighbor Discovery + protocol. + + The 'static(4)' type indicates that the mapping has been + statically configured. Both of these refer to entries that + provide mappings for other entities addresses. + + The 'local(5)' type indicates that the mapping is provided + for an entity's own interface address. + + As the entries in this table are typically not persistent + when this object is written the entity SHOULD NOT save the + change to non-volatile storage." + DEFVAL { static } + ::= { ipNetToPhysicalEntry 6 } + +ipNetToPhysicalState OBJECT-TYPE + SYNTAX INTEGER { + reachable(1), -- confirmed reachability + + stale(2), -- unconfirmed reachability + + delay(3), -- waiting for reachability + -- confirmation before entering + -- the probe state + + probe(4), -- actively probing + + invalid(5), -- an invalidated mapping + + unknown(6), -- state can not be determined + -- for some reason. + + incomplete(7) -- address resolution is being + -- performed. + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + + "The Neighbor Unreachability Detection state for the + interface when the address mapping in this entry is used. + If Neighbor Unreachability Detection is not in use (e.g. for + IPv4), this object is always unknown(6)." + REFERENCE "RFC 2461" + ::= { ipNetToPhysicalEntry 7 } + +ipNetToPhysicalRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The status of this conceptual row. + + The RowStatus TC requires that this DESCRIPTION clause + states under which circumstances other objects in this row + can be modified. The value of this object has no effect on + whether other objects in this conceptual row can be + modified. + + A conceptual row can not be made active until the + ipNetToPhysicalPhysAddress object has been set. + + Note that if the ipNetToPhysicalType is set to 'invalid', + the managed node may delete the entry independent of the + state of this object." + ::= { ipNetToPhysicalEntry 8 } + +-- +-- The IPv6 Scope Zone Index Table. +-- + +ipv6ScopeZoneIndexTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ipv6ScopeZoneIndexEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table used to describe IPv6 unicast and multicast scope + zones. + + For those objects that have names rather than numbers, the + names were chosen to coincide with the names used in the + IPv6 address architecture document. " + REFERENCE "Section 2.7 of RFC 4291" + ::= { ip 36 } + +ipv6ScopeZoneIndexEntry OBJECT-TYPE + SYNTAX Ipv6ScopeZoneIndexEntry + + + + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Each entry contains the list of scope identifiers on a given + interface." + INDEX { ipv6ScopeZoneIndexIfIndex } + ::= { ipv6ScopeZoneIndexTable 1 } + +Ipv6ScopeZoneIndexEntry ::= SEQUENCE { + ipv6ScopeZoneIndexIfIndex InterfaceIndex, + ipv6ScopeZoneIndexLinkLocal InetZoneIndex, + ipv6ScopeZoneIndex3 InetZoneIndex, + ipv6ScopeZoneIndexAdminLocal InetZoneIndex, + ipv6ScopeZoneIndexSiteLocal InetZoneIndex, + ipv6ScopeZoneIndex6 InetZoneIndex, + ipv6ScopeZoneIndex7 InetZoneIndex, + ipv6ScopeZoneIndexOrganizationLocal InetZoneIndex, + ipv6ScopeZoneIndex9 InetZoneIndex, + ipv6ScopeZoneIndexA InetZoneIndex, + ipv6ScopeZoneIndexB InetZoneIndex, + ipv6ScopeZoneIndexC InetZoneIndex, + ipv6ScopeZoneIndexD InetZoneIndex + } + +ipv6ScopeZoneIndexIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface to + which these scopes belong. The interface identified by a + particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipv6ScopeZoneIndexEntry 1 } + +ipv6ScopeZoneIndexLinkLocal OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for the link-local scope on this interface." + ::= { ipv6ScopeZoneIndexEntry 2 } + +ipv6ScopeZoneIndex3 OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + + + + "The zone index for scope 3 on this interface." + ::= { ipv6ScopeZoneIndexEntry 3 } + +ipv6ScopeZoneIndexAdminLocal OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for the admin-local scope on this interface." + ::= { ipv6ScopeZoneIndexEntry 4 } + +ipv6ScopeZoneIndexSiteLocal OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for the site-local scope on this interface." + ::= { ipv6ScopeZoneIndexEntry 5 } + +ipv6ScopeZoneIndex6 OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope 6 on this interface." + ::= { ipv6ScopeZoneIndexEntry 6 } + +ipv6ScopeZoneIndex7 OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope 7 on this interface." + ::= { ipv6ScopeZoneIndexEntry 7 } + +ipv6ScopeZoneIndexOrganizationLocal OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for the organization-local scope on this + interface." + ::= { ipv6ScopeZoneIndexEntry 8 } + +ipv6ScopeZoneIndex9 OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + + + + DESCRIPTION + "The zone index for scope 9 on this interface." + ::= { ipv6ScopeZoneIndexEntry 9 } + +ipv6ScopeZoneIndexA OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope A on this interface." + ::= { ipv6ScopeZoneIndexEntry 10 } + +ipv6ScopeZoneIndexB OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope B on this interface." + ::= { ipv6ScopeZoneIndexEntry 11 } + +ipv6ScopeZoneIndexC OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope C on this interface." + ::= { ipv6ScopeZoneIndexEntry 12 } + +ipv6ScopeZoneIndexD OBJECT-TYPE + SYNTAX InetZoneIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The zone index for scope D on this interface." + ::= { ipv6ScopeZoneIndexEntry 13 } + +-- +-- The Default Router Table +-- This table simply lists the default routers; for more information +-- about routing tables, see the routing MIBs +-- + +ipDefaultRouterTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpDefaultRouterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table used to describe the default routers known to this + + + + entity." + ::= { ip 37 } + +ipDefaultRouterEntry OBJECT-TYPE + SYNTAX IpDefaultRouterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Each entry contains information about a default router known + to this entity." + INDEX {ipDefaultRouterAddressType, ipDefaultRouterAddress, + ipDefaultRouterIfIndex} + ::= { ipDefaultRouterTable 1 } + +IpDefaultRouterEntry ::= SEQUENCE { + ipDefaultRouterAddressType InetAddressType, + ipDefaultRouterAddress InetAddress, + ipDefaultRouterIfIndex InterfaceIndex, + ipDefaultRouterLifetime Unsigned32, + ipDefaultRouterPreference INTEGER + } + +ipDefaultRouterAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type for this row." + ::= { ipDefaultRouterEntry 1 } + +ipDefaultRouterAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP address of the default router represented by this + row. The address type of this object is specified in + ipDefaultRouterAddressType. + + Implementers need to be aware that if the size of + ipDefaultRouterAddress exceeds 115 octets, then OIDS of + instances of columns in this row will have more than 128 + sub-identifiers and cannot be accessed using SNMPv1, + SNMPv2c, or SNMPv3." + ::= { ipDefaultRouterEntry 2 } + +ipDefaultRouterIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + + + + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface by + which the router can be reached. The interface identified + by a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipDefaultRouterEntry 3 } + +ipDefaultRouterLifetime OBJECT-TYPE + SYNTAX Unsigned32 (0..65535) + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remaining length of time, in seconds, that this router + will continue to be useful as a default router. A value of + zero indicates that it is no longer useful as a default + router. It is left to the implementer of the MIB as to + whether a router with a lifetime of zero is removed from the + list. + + For IPv6, this value should be extracted from the router + advertisement messages." + REFERENCE "For IPv6 RFC 2462 sections 4.2 and 6.3.4" + ::= { ipDefaultRouterEntry 4 } + +ipDefaultRouterPreference OBJECT-TYPE + SYNTAX INTEGER { + reserved (-2), + low (-1), + medium (0), + high (1) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An indication of preference given to this router as a + default router as described in he Default Router + Preferences document. Treating the value as a + 2 bit signed integer allows for simple arithmetic + comparisons. + + For IPv4 routers or IPv6 routers that are not using the + updated router advertisement format, this object is set to + medium (0)." + REFERENCE "RFC 4291, section 2.1" + ::= { ipDefaultRouterEntry 5 } + + + +-- +-- Configuration information for constructing router advertisements +-- + +ipv6RouterAdvertSpinLock OBJECT-TYPE + SYNTAX TestAndIncr + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "An advisory lock used to allow cooperating SNMP managers to + coordinate their use of the set operation in creating or + modifying rows within this table. + + In order to use this lock to coordinate the use of set + operations, managers should first retrieve + ipv6RouterAdvertSpinLock. They should then determine the + appropriate row to create or modify. Finally, they should + issue the appropriate set command including the retrieved + value of ipv6RouterAdvertSpinLock. If another manager has + altered the table in the meantime, then the value of + ipv6RouterAdvertSpinLock will have changed and the creation + will fail as it will be specifying an incorrect value for + ipv6RouterAdvertSpinLock. It is suggested, but not + required, that the ipv6RouterAdvertSpinLock be the first var + bind for each set of objects representing a 'row' in a PDU." + ::= { ip 38 } + +ipv6RouterAdvertTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ipv6RouterAdvertEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table containing information used to construct router + advertisements." + ::= { ip 39 } + +ipv6RouterAdvertEntry OBJECT-TYPE + SYNTAX Ipv6RouterAdvertEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing information used to construct router + advertisements. + + Information in this table is persistent, and when this + object is written, the entity SHOULD save the change to + non-volatile storage." + INDEX { ipv6RouterAdvertIfIndex } + + + + ::= { ipv6RouterAdvertTable 1 } + +Ipv6RouterAdvertEntry ::= SEQUENCE { + ipv6RouterAdvertIfIndex InterfaceIndex, + ipv6RouterAdvertSendAdverts TruthValue, + ipv6RouterAdvertMaxInterval Unsigned32, + ipv6RouterAdvertMinInterval Unsigned32, + ipv6RouterAdvertManagedFlag TruthValue, + ipv6RouterAdvertOtherConfigFlag TruthValue, + ipv6RouterAdvertLinkMTU Unsigned32, + ipv6RouterAdvertReachableTime Unsigned32, + ipv6RouterAdvertRetransmitTime Unsigned32, + ipv6RouterAdvertCurHopLimit Unsigned32, + ipv6RouterAdvertDefaultLifetime Unsigned32, + ipv6RouterAdvertRowStatus RowStatus + } + +ipv6RouterAdvertIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index value that uniquely identifies the interface on + which router advertisements constructed with this + information will be transmitted. The interface identified + by a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipv6RouterAdvertEntry 1 } + +ipv6RouterAdvertSendAdverts OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "A flag indicating whether the router sends periodic + router advertisements and responds to router solicitations + on this interface." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { false } + ::= { ipv6RouterAdvertEntry 2 } + +ipv6RouterAdvertMaxInterval OBJECT-TYPE + SYNTAX Unsigned32 (4..1800) + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The maximum time allowed between sending unsolicited router + + + + advertisements from this interface." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { 600 } + ::= { ipv6RouterAdvertEntry 3 } + +ipv6RouterAdvertMinInterval OBJECT-TYPE + SYNTAX Unsigned32 (3..1350) + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The minimum time allowed between sending unsolicited router + advertisements from this interface. + + The default is 0.33 * ipv6RouterAdvertMaxInterval, however, + in the case of a low value for ipv6RouterAdvertMaxInterval, + the minimum value for this object is restricted to 3." + REFERENCE "RFC 2461 Section 6.2.1" + ::= { ipv6RouterAdvertEntry 4 } + +ipv6RouterAdvertManagedFlag OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The true/false value to be placed into the 'managed address + configuration' flag field in router advertisements sent from + this interface." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { false } + ::= { ipv6RouterAdvertEntry 5 } + +ipv6RouterAdvertOtherConfigFlag OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The true/false value to be placed into the 'other stateful + configuration' flag field in router advertisements sent from + this interface." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { false } + ::= { ipv6RouterAdvertEntry 6 } + +ipv6RouterAdvertLinkMTU OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-create + STATUS current + + + + DESCRIPTION + "The value to be placed in MTU options sent by the router on + this interface. + + A value of zero indicates that no MTU options are sent." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { 0 } + ::= { ipv6RouterAdvertEntry 7 } + +ipv6RouterAdvertReachableTime OBJECT-TYPE + SYNTAX Unsigned32 (0..3600000) + UNITS "milliseconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be placed in the reachable time field in router + advertisement messages sent from this interface. + + A value of zero in the router advertisement indicates that + the advertisement isn't specifying a value for reachable + time." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { 0 } + ::= { ipv6RouterAdvertEntry 8 } + +ipv6RouterAdvertRetransmitTime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be placed in the retransmit timer field in + router advertisements sent from this interface. + + A value of zero in the router advertisement indicates that + the advertisement isn't specifying a value for retrans + time." + REFERENCE "RFC 2461 Section 6.2.1" + DEFVAL { 0 } + ::= { ipv6RouterAdvertEntry 9 } + +ipv6RouterAdvertCurHopLimit OBJECT-TYPE + SYNTAX Unsigned32 (0..255) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The default value to be placed in the current hop limit + field in router advertisements sent from this interface. + + + + The value should be set to the current diameter of the + Internet. + + A value of zero in the router advertisement indicates that + the advertisement isn't specifying a value for curHopLimit. + + The default should be set to the value specified in the IANA + web pages (www.iana.org) at the time of implementation." + REFERENCE "RFC 2461 Section 6.2.1" + ::= { ipv6RouterAdvertEntry 10 } + +ipv6RouterAdvertDefaultLifetime OBJECT-TYPE + SYNTAX Unsigned32 (0|4..9000) + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be placed in the router lifetime field of + router advertisements sent from this interface. This value + MUST be either 0 or between ipv6RouterAdvertMaxInterval and + 9000 seconds. + + A value of zero indicates that the router is not to be used + as a default router. + + The default is 3 * ipv6RouterAdvertMaxInterval." + REFERENCE "RFC 2461 Section 6.2.1" + ::= { ipv6RouterAdvertEntry 11 } + +ipv6RouterAdvertRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The status of this conceptual row. + + As all objects in this conceptual row have default values, a + row can be created and made active by setting this object + appropriately. + + The RowStatus TC requires that this DESCRIPTION clause + states under which circumstances other objects in this row + can be modified. The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ipv6RouterAdvertEntry 12 } + +-- + + + +-- ICMP section +-- + +icmp OBJECT IDENTIFIER ::= { mib-2 5 } + +-- +-- ICMP non-message-specific counters +-- + +-- These object IDs are reserved, as they were used in earlier +-- versions of the MIB module. In theory, OIDs are not assigned +-- until the specification is released as an RFC; however, as some +-- companies may have shipped code based on earlier versions of +-- the MIB, it seems best to reserve these OIDs. +-- ::= { icmp 27 } +-- ::= { icmp 28 } + +icmpStatsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IcmpStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table of generic system-wide ICMP counters." + ::= { icmp 29 } + +icmpStatsEntry OBJECT-TYPE + SYNTAX IcmpStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row in the icmpStatsTable." + INDEX { icmpStatsIPVersion } + ::= { icmpStatsTable 1 } + +IcmpStatsEntry ::= SEQUENCE { + icmpStatsIPVersion InetVersion, + icmpStatsInMsgs Counter32, + icmpStatsInErrors Counter32, + icmpStatsOutMsgs Counter32, + icmpStatsOutErrors Counter32 + } + +icmpStatsIPVersion OBJECT-TYPE + SYNTAX InetVersion + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP version of the statistics." + + + + ::= { icmpStatsEntry 1 } + +icmpStatsInMsgs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of ICMP messages that the entity received. + Note that this counter includes all those counted by + icmpStatsInErrors." + ::= { icmpStatsEntry 2 } + +icmpStatsInErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of ICMP messages that the entity received but + determined as having ICMP-specific errors (bad ICMP + checksums, bad length, etc.)." + ::= { icmpStatsEntry 3 } + +icmpStatsOutMsgs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of ICMP messages that the entity attempted + to send. Note that this counter includes all those counted + by icmpStatsOutErrors." + ::= { icmpStatsEntry 4 } + +icmpStatsOutErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of ICMP messages that this entity did not send + due to problems discovered within ICMP, such as a lack of + buffers. This value should not include errors discovered + outside the ICMP layer, such as the inability of IP to route + the resultant datagram. In some implementations, there may + be no types of error that contribute to this counter's + value." + ::= { icmpStatsEntry 5 } + +-- +-- per-version, per-message type ICMP counters + + + +-- + +icmpMsgStatsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IcmpMsgStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table of system-wide per-version, per-message type ICMP + counters." + ::= { icmp 30 } + +icmpMsgStatsEntry OBJECT-TYPE + SYNTAX IcmpMsgStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row in the icmpMsgStatsTable. + + The system should track each ICMP type value, even if that + ICMP type is not supported by the system. However, a + given row need not be instantiated unless a message of that + type has been processed, i.e., the row for + icmpMsgStatsType=X MAY be instantiated before but MUST be + instantiated after the first message with Type=X is + received or transmitted. After receiving or transmitting + any succeeding messages with Type=X, the relevant counter + must be incremented." + INDEX { icmpMsgStatsIPVersion, icmpMsgStatsType } + ::= { icmpMsgStatsTable 1 } + +IcmpMsgStatsEntry ::= SEQUENCE { + icmpMsgStatsIPVersion InetVersion, + icmpMsgStatsType Integer32, + icmpMsgStatsInPkts Counter32, + icmpMsgStatsOutPkts Counter32 + } + +icmpMsgStatsIPVersion OBJECT-TYPE + SYNTAX InetVersion + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP version of the statistics." + ::= { icmpMsgStatsEntry 1 } + +icmpMsgStatsType OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS not-accessible + + + + STATUS current + DESCRIPTION + "The ICMP type field of the message type being counted by + this row. + + Note that ICMP message types are scoped by the address type + in use." + REFERENCE "http://www.iana.org/assignments/icmp-parameters and + http://www.iana.org/assignments/icmpv6-parameters" + ::= { icmpMsgStatsEntry 2 } + +icmpMsgStatsInPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input packets for this AF and type." + ::= { icmpMsgStatsEntry 3 } + +icmpMsgStatsOutPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of output packets for this AF and type." + ::= { icmpMsgStatsEntry 4 } +-- +-- conformance information +-- + +ipMIBConformance OBJECT IDENTIFIER ::= { ipMIB 2 } + +ipMIBCompliances OBJECT IDENTIFIER ::= { ipMIBConformance 1 } +ipMIBGroups OBJECT IDENTIFIER ::= { ipMIBConformance 2 } + +-- compliance statements +ipMIBCompliance2 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for systems that implement IP - + either IPv4 or IPv6. + + There are a number of INDEX objects that cannot be + represented in the form of OBJECT clauses in SMIv2, but + for which we have the following compliance requirements, + expressed in OBJECT clause form in this description + clause: + + + + + -- OBJECT ipSystemStatsIPVersion + -- SYNTAX InetVersion {ipv4(1), ipv6(2)} + -- DESCRIPTION + -- This MIB requires support for only IPv4 and IPv6 + -- versions. + -- + -- OBJECT ipIfStatsIPVersion + -- SYNTAX InetVersion {ipv4(1), ipv6(2)} + -- DESCRIPTION + -- This MIB requires support for only IPv4 and IPv6 + -- versions. + -- + -- OBJECT icmpStatsIPVersion + -- SYNTAX InetVersion {ipv4(1), ipv6(2)} + -- DESCRIPTION + -- This MIB requires support for only IPv4 and IPv6 + -- versions. + -- + -- OBJECT icmpMsgStatsIPVersion + -- SYNTAX InetVersion {ipv4(1), ipv6(2)} + -- DESCRIPTION + -- This MIB requires support for only IPv4 and IPv6 + -- versions. + -- + -- OBJECT ipAddressPrefixType + -- SYNTAX InetAddressType {ipv4(1), ipv6(2)} + -- DESCRIPTION + -- This MIB requires support for only global IPv4 and + -- IPv6 address types. + -- + -- OBJECT ipAddressPrefixPrefix + -- SYNTAX InetAddress (Size(4 | 16)) + -- DESCRIPTION + -- This MIB requires support for only global IPv4 and + -- IPv6 addresses and so the size can be either 4 or + -- 16 bytes. + -- + -- OBJECT ipAddressAddrType + -- SYNTAX InetAddressType {ipv4(1), ipv6(2), + -- ipv4z(3), ipv6z(4)} + -- DESCRIPTION + -- This MIB requires support for only global and + -- non-global IPv4 and IPv6 address types. + -- + -- OBJECT ipAddressAddr + -- SYNTAX InetAddress (Size(4 | 8 | 16 | 20)) + -- DESCRIPTION + -- This MIB requires support for only global and + + + + -- non-global IPv4 and IPv6 addresses and so the size + -- can be 4, 8, 16, or 20 bytes. + -- + -- OBJECT ipNetToPhysicalNetAddressType + -- SYNTAX InetAddressType {ipv4(1), ipv6(2), + -- ipv4z(3), ipv6z(4)} + -- DESCRIPTION + -- This MIB requires support for only global and + -- non-global IPv4 and IPv6 address types. + -- + -- OBJECT ipNetToPhysicalNetAddress + -- SYNTAX InetAddress (Size(4 | 8 | 16 | 20)) + -- DESCRIPTION + -- This MIB requires support for only global and + -- non-global IPv4 and IPv6 addresses and so the size + -- can be 4, 8, 16, or 20 bytes. + -- + -- OBJECT ipDefaultRouterAddressType + -- SYNTAX InetAddressType {ipv4(1), ipv6(2), + -- ipv4z(3), ipv6z(4)} + -- DESCRIPTION + -- This MIB requires support for only global and + -- non-global IPv4 and IPv6 address types. + -- + -- OBJECT ipDefaultRouterAddress + -- SYNTAX InetAddress (Size(4 | 8 | 16 | 20)) + -- DESCRIPTION + -- This MIB requires support for only global and + -- non-global IPv4 and IPv6 addresses and so the size + -- can be 4, 8, 16, or 20 bytes." + + MODULE -- this module + + MANDATORY-GROUPS { ipSystemStatsGroup, ipAddressGroup, + ipNetToPhysicalGroup, ipDefaultRouterGroup, + icmpStatsGroup } + + GROUP ipSystemStatsHCOctetGroup + DESCRIPTION + "This group is mandatory for systems that have an aggregate + bandwidth of greater than 20MB. Including this group does + not allow an entity to neglect the 32 bit versions of these + objects." + + GROUP ipSystemStatsHCPacketGroup + DESCRIPTION + "This group is mandatory for systems that have an aggregate + bandwidth of greater than 650MB. Including this group + + + + does not allow an entity to neglect the 32 bit versions of + these objects." + + GROUP ipIfStatsGroup + DESCRIPTION + "This group is optional for all systems." + + GROUP ipIfStatsHCOctetGroup + DESCRIPTION + "This group is mandatory for systems that include the + ipIfStatsGroup and include links with bandwidths of greater + than 20MB. Including this group does not allow an entity to + neglect the 32 bit versions of these objects." + + GROUP ipIfStatsHCPacketGroup + DESCRIPTION + "This group is mandatory for systems that include the + ipIfStatsGroup and include links with bandwidths of greater + than 650MB. Including this group does not allow an entity + to neglect the 32 bit versions of these objects." + + GROUP ipv4GeneralGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4." + + GROUP ipv4IfGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4." + + GROUP ipv4SystemStatsGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4." + + GROUP ipv4SystemStatsHCPacketGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4 and + that have an aggregate bandwidth of greater than 650MB. + Including this group does not allow an entity to neglect the + 32 bit versions of these objects." + + GROUP ipv4IfStatsGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4 and + including the ipIfStatsGroup." + + GROUP ipv4IfStatsHCPacketGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv4 and + + + + including the ipIfStatsHCPacketGroup. Including this group + does not allow an entity to neglect the 32 bit versions of + these objects." + + GROUP ipv6GeneralGroup2 + DESCRIPTION + "This group is mandatory for all systems supporting IPv6." + + GROUP ipv6IfGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv6." + + GROUP ipAddressPrefixGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv6." + + GROUP ipv6ScopeGroup + DESCRIPTION + "This group is mandatory for all systems supporting IPv6." + + GROUP ipv6RouterAdvertGroup + DESCRIPTION + "This group is mandatory for all IPv6 routers." + + GROUP ipLastChangeGroup + DESCRIPTION + "This group is optional for all agents." + + OBJECT ipv6IpForwarding + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6IpDefaultHopLimit + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv4InterfaceEnableStatus + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6InterfaceEnableStatus + MIN-ACCESS read-only + + + + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6InterfaceForwarding + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipAddressSpinLock + MIN-ACCESS not-accessible + DESCRIPTION + "An agent is not required to provide write access to this + object. However, if an agent provides write access to any + of the other objects in the ipAddressGroup, it SHOULD + provide write access to this object as well." + + OBJECT ipAddressIfIndex + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipAddressType + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipAddressStatus + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipAddressRowStatus + SYNTAX RowStatus { active(1) } + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipAddressStorageType + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object. + + + + If an agent allows this object to be written or created, it + is not required to allow this object to be set to readOnly, + permanent, or nonVolatile." + + OBJECT ipNetToPhysicalPhysAddress + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipNetToPhysicalType + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + OBJECT ipv6RouterAdvertSpinLock + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object. However, if an agent provides write access to + any of the other objects in the ipv6RouterAdvertGroup, it + SHOULD provide write access to this object as well." + + OBJECT ipv6RouterAdvertSendAdverts + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertMaxInterval + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertMinInterval + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertManagedFlag + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + + + + OBJECT ipv6RouterAdvertOtherConfigFlag + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertLinkMTU + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertReachableTime + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertRetransmitTime + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertCurHopLimit + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertDefaultLifetime + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write access to this + object." + + OBJECT ipv6RouterAdvertRowStatus + MIN-ACCESS read-only + DESCRIPTION + "An agent is not required to provide write or create access + to this object." + + ::= { ipMIBCompliances 2 } + +-- units of conformance + +ipv4GeneralGroup OBJECT-GROUP + OBJECTS { ipForwarding, ipDefaultTTL, ipReasmTimeout } + + + + STATUS current + DESCRIPTION + "The group of IPv4-specific objects for basic management of + IPv4 entities." + ::= { ipMIBGroups 3 } + +ipv4IfGroup OBJECT-GROUP + OBJECTS { ipv4InterfaceReasmMaxSize, ipv4InterfaceEnableStatus, + ipv4InterfaceRetransmitTime } + STATUS current + DESCRIPTION + "The group of IPv4-specific objects for basic management of + IPv4 interfaces." + ::= { ipMIBGroups 4 } + +ipv6GeneralGroup2 OBJECT-GROUP + OBJECTS { ipv6IpForwarding, ipv6IpDefaultHopLimit } + STATUS current + DESCRIPTION + "The IPv6 group of objects providing for basic management of + IPv6 entities." + ::= { ipMIBGroups 5 } + +ipv6IfGroup OBJECT-GROUP + OBJECTS { ipv6InterfaceReasmMaxSize, ipv6InterfaceIdentifier, + ipv6InterfaceEnableStatus, ipv6InterfaceReachableTime, + ipv6InterfaceRetransmitTime, ipv6InterfaceForwarding } + STATUS current + DESCRIPTION + "The group of IPv6-specific objects for basic management of + IPv6 interfaces." + ::= { ipMIBGroups 6 } + +ipLastChangeGroup OBJECT-GROUP + OBJECTS { ipv4InterfaceTableLastChange, + ipv6InterfaceTableLastChange, + ipIfStatsTableLastChange } + STATUS current + DESCRIPTION + "The last change objects associated with this MIB. These + objects are optional for all agents. They SHOULD be + implemented on agents where it is possible to determine the + proper values. Where it is not possible to determine the + proper values, for example when the tables are split amongst + several sub-agents using AgentX, the agent MUST NOT + implement these objects to return an incorrect or static + value." + ::= { ipMIBGroups 7 } + + + +ipSystemStatsGroup OBJECT-GROUP + OBJECTS { ipSystemStatsInReceives, + ipSystemStatsInOctets, + ipSystemStatsInHdrErrors, + ipSystemStatsInNoRoutes, + ipSystemStatsInAddrErrors, + ipSystemStatsInUnknownProtos, + ipSystemStatsInTruncatedPkts, + ipSystemStatsInForwDatagrams, + ipSystemStatsReasmReqds, + ipSystemStatsReasmOKs, + ipSystemStatsReasmFails, + ipSystemStatsInDiscards, + ipSystemStatsInDelivers, + ipSystemStatsOutRequests, + ipSystemStatsOutNoRoutes, + ipSystemStatsOutForwDatagrams, + ipSystemStatsOutDiscards, + ipSystemStatsOutFragReqds, + ipSystemStatsOutFragOKs, + ipSystemStatsOutFragFails, + ipSystemStatsOutFragCreates, + ipSystemStatsOutTransmits, + ipSystemStatsOutOctets, + ipSystemStatsInMcastPkts, + ipSystemStatsInMcastOctets, + ipSystemStatsOutMcastPkts, + ipSystemStatsOutMcastOctets, + ipSystemStatsDiscontinuityTime, + ipSystemStatsRefreshRate } + STATUS current + DESCRIPTION + "IP system wide statistics." + ::= { ipMIBGroups 8 } + +ipv4SystemStatsGroup OBJECT-GROUP + OBJECTS { ipSystemStatsInBcastPkts, ipSystemStatsOutBcastPkts } + STATUS current + DESCRIPTION + "IPv4 only system wide statistics." + ::= { ipMIBGroups 9 } + +ipSystemStatsHCOctetGroup OBJECT-GROUP + OBJECTS { ipSystemStatsHCInOctets, + ipSystemStatsHCOutOctets, + ipSystemStatsHCInMcastOctets, + ipSystemStatsHCOutMcastOctets +} + + + + STATUS current + DESCRIPTION + "IP system wide statistics for systems that may overflow the + standard octet counters within 1 hour." + ::= { ipMIBGroups 10 } + +ipSystemStatsHCPacketGroup OBJECT-GROUP + OBJECTS { ipSystemStatsHCInReceives, + ipSystemStatsHCInForwDatagrams, + ipSystemStatsHCInDelivers, + ipSystemStatsHCOutRequests, + ipSystemStatsHCOutForwDatagrams, + ipSystemStatsHCOutTransmits, + ipSystemStatsHCInMcastPkts, + ipSystemStatsHCOutMcastPkts +} + STATUS current + DESCRIPTION + "IP system wide statistics for systems that may overflow the + standard packet counters within 1 hour." + ::= { ipMIBGroups 11 } + +ipv4SystemStatsHCPacketGroup OBJECT-GROUP + OBJECTS { ipSystemStatsHCInBcastPkts, + ipSystemStatsHCOutBcastPkts } + STATUS current + DESCRIPTION + "IPv4 only system wide statistics for systems that may + overflow the standard packet counters within 1 hour." + ::= { ipMIBGroups 12 } + +ipIfStatsGroup OBJECT-GROUP + OBJECTS { ipIfStatsInReceives, ipIfStatsInOctets, + ipIfStatsInHdrErrors, ipIfStatsInNoRoutes, + ipIfStatsInAddrErrors, ipIfStatsInUnknownProtos, + ipIfStatsInTruncatedPkts, ipIfStatsInForwDatagrams, + ipIfStatsReasmReqds, ipIfStatsReasmOKs, + ipIfStatsReasmFails, ipIfStatsInDiscards, + ipIfStatsInDelivers, ipIfStatsOutRequests, + ipIfStatsOutForwDatagrams, ipIfStatsOutDiscards, + ipIfStatsOutFragReqds, ipIfStatsOutFragOKs, + ipIfStatsOutFragFails, ipIfStatsOutFragCreates, + ipIfStatsOutTransmits, ipIfStatsOutOctets, + ipIfStatsInMcastPkts, ipIfStatsInMcastOctets, + ipIfStatsOutMcastPkts, ipIfStatsOutMcastOctets, + ipIfStatsDiscontinuityTime, ipIfStatsRefreshRate } + STATUS current + DESCRIPTION + + + + "IP per-interface statistics." + ::= { ipMIBGroups 13 } + +ipv4IfStatsGroup OBJECT-GROUP + OBJECTS { ipIfStatsInBcastPkts, ipIfStatsOutBcastPkts } + STATUS current + DESCRIPTION + "IPv4 only per-interface statistics." + ::= { ipMIBGroups 14 } + +ipIfStatsHCOctetGroup OBJECT-GROUP + OBJECTS { ipIfStatsHCInOctets, ipIfStatsHCOutOctets, + ipIfStatsHCInMcastOctets, ipIfStatsHCOutMcastOctets } + STATUS current + DESCRIPTION + "IP per-interfaces statistics for systems that include + interfaces that may overflow the standard octet + counters within 1 hour." + ::= { ipMIBGroups 15 } + +ipIfStatsHCPacketGroup OBJECT-GROUP + OBJECTS { ipIfStatsHCInReceives, ipIfStatsHCInForwDatagrams, + ipIfStatsHCInDelivers, ipIfStatsHCOutRequests, + ipIfStatsHCOutForwDatagrams, ipIfStatsHCOutTransmits, + ipIfStatsHCInMcastPkts, ipIfStatsHCOutMcastPkts } + STATUS current + DESCRIPTION + "IP per-interfaces statistics for systems that include + interfaces that may overflow the standard packet counters + within 1 hour." + ::= { ipMIBGroups 16 } + +ipv4IfStatsHCPacketGroup OBJECT-GROUP + OBJECTS { ipIfStatsHCInBcastPkts, ipIfStatsHCOutBcastPkts } + STATUS current + DESCRIPTION + "IPv4 only per-interface statistics for systems that include + interfaces that may overflow the standard packet counters + within 1 hour." + ::= { ipMIBGroups 17 } + +ipAddressPrefixGroup OBJECT-GROUP + OBJECTS { ipAddressPrefixOrigin, + ipAddressPrefixOnLinkFlag, + ipAddressPrefixAutonomousFlag, + ipAddressPrefixAdvPreferredLifetime, + ipAddressPrefixAdvValidLifetime } + STATUS current + + + + DESCRIPTION + "The group of objects for providing information about address + prefixes used by this node." + ::= { ipMIBGroups 18 } + +ipAddressGroup OBJECT-GROUP + OBJECTS { ipAddressSpinLock, ipAddressIfIndex, + ipAddressType, ipAddressPrefix, + ipAddressOrigin, ipAddressStatus, + ipAddressCreated, ipAddressLastChanged, + ipAddressRowStatus, ipAddressStorageType } + STATUS current + DESCRIPTION + "The group of objects for providing information about the + addresses relevant to this entity's interfaces." + ::= { ipMIBGroups 19 } + +ipNetToPhysicalGroup OBJECT-GROUP + OBJECTS { ipNetToPhysicalPhysAddress, ipNetToPhysicalLastUpdated, + ipNetToPhysicalType, ipNetToPhysicalState, + ipNetToPhysicalRowStatus } + STATUS current + DESCRIPTION + "The group of objects for providing information about the + mappings of network address to physical address known to + this node." + ::= { ipMIBGroups 20 } + +ipv6ScopeGroup OBJECT-GROUP + OBJECTS { ipv6ScopeZoneIndexLinkLocal, + ipv6ScopeZoneIndex3, + ipv6ScopeZoneIndexAdminLocal, + ipv6ScopeZoneIndexSiteLocal, + ipv6ScopeZoneIndex6, + ipv6ScopeZoneIndex7, + ipv6ScopeZoneIndexOrganizationLocal, + ipv6ScopeZoneIndex9, + ipv6ScopeZoneIndexA, + ipv6ScopeZoneIndexB, + ipv6ScopeZoneIndexC, + ipv6ScopeZoneIndexD } + STATUS current + DESCRIPTION + "The group of objects for managing IPv6 scope zones." + ::= { ipMIBGroups 21 } + +ipDefaultRouterGroup OBJECT-GROUP + OBJECTS { ipDefaultRouterLifetime, ipDefaultRouterPreference } + + + + STATUS current + DESCRIPTION + "The group of objects for providing information about default + routers known to this node." + ::= { ipMIBGroups 22 } + +ipv6RouterAdvertGroup OBJECT-GROUP + OBJECTS { ipv6RouterAdvertSpinLock, + ipv6RouterAdvertSendAdverts, + ipv6RouterAdvertMaxInterval, + ipv6RouterAdvertMinInterval, + ipv6RouterAdvertManagedFlag, + ipv6RouterAdvertOtherConfigFlag, + ipv6RouterAdvertLinkMTU, + ipv6RouterAdvertReachableTime, + ipv6RouterAdvertRetransmitTime, + ipv6RouterAdvertCurHopLimit, + ipv6RouterAdvertDefaultLifetime, + ipv6RouterAdvertRowStatus +} + STATUS current + DESCRIPTION + "The group of objects for controlling information advertised + by IPv6 routers." + ::= { ipMIBGroups 23 } + +icmpStatsGroup OBJECT-GROUP + OBJECTS {icmpStatsInMsgs, icmpStatsInErrors, + icmpStatsOutMsgs, icmpStatsOutErrors, + icmpMsgStatsInPkts, icmpMsgStatsOutPkts } + STATUS current + DESCRIPTION + "The group of objects providing ICMP statistics." + ::= { ipMIBGroups 24 } + +-- +-- Deprecated objects +-- + +ipInReceives OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of input datagrams received from + interfaces, including those received in error. + + This object has been deprecated, as a new IP version-neutral + + + + table has been added. It is loosely replaced by + ipSystemStatsInRecieves." + ::= { ip 3 } + +ipInHdrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of input datagrams discarded due to errors in + their IPv4 headers, including bad checksums, version number + mismatch, other format errors, time-to-live exceeded, errors + discovered in processing their IPv4 options, etc. + + This object has been deprecated as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsInHdrErrors." + ::= { ip 4 } + +ipInAddrErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of input datagrams discarded because the IPv4 + address in their IPv4 header's destination field was not a + valid address to be received at this entity. This count + includes invalid addresses (e.g., 0.0.0.0) and addresses of + unsupported Classes (e.g., Class E). For entities which are + not IPv4 routers, and therefore do not forward datagrams, + this counter includes datagrams discarded because the + destination address was not a local address. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsInAddrErrors." + ::= { ip 5 } + +ipForwDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of input datagrams for which this entity was not + their final IPv4 destination, as a result of which an + attempt was made to find a route to forward them to that + final destination. In entities which do not act as IPv4 + routers, this counter will include only those packets which + + + + were Source-Routed via this entity, and the Source-Route + option processing was successful. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsInForwDatagrams." + ::= { ip 6 } + +ipInUnknownProtos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of locally-addressed datagrams received + successfully but discarded because of an unknown or + unsupported protocol. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsInUnknownProtos." + ::= { ip 7 } + +ipInDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of input IPv4 datagrams for which no problems + were encountered to prevent their continued processing, but + which were discarded (e.g., for lack of buffer space). Note + that this counter does not include any datagrams discarded + while awaiting re-assembly. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsInDiscards." + ::= { ip 8 } + +ipInDelivers OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of input datagrams successfully delivered + to IPv4 user-protocols (including ICMP). + + This object has been deprecated as a new IP version neutral + table has been added. It is loosely replaced by + + + + ipSystemStatsIndelivers." + ::= { ip 9 } + +ipOutRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of IPv4 datagrams which local IPv4 user + protocols (including ICMP) supplied to IPv4 in requests for + transmission. Note that this counter does not include any + datagrams counted in ipForwDatagrams. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsOutRequests." + ::= { ip 10 } + +ipOutDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of output IPv4 datagrams for which no problem was + encountered to prevent their transmission to their + destination, but which were discarded (e.g., for lack of + buffer space). Note that this counter would include + datagrams counted in ipForwDatagrams if any such packets met + this (discretionary) discard criterion. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsOutDiscards." + ::= { ip 11 } + +ipOutNoRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 datagrams discarded because no route + could be found to transmit them to their destination. Note + that this counter includes any packets counted in + ipForwDatagrams which meet this `no-route' criterion. Note + that this includes any datagrams which a host cannot route + because all of its default routers are down. + + This object has been deprecated, as a new IP version-neutral + + + + table has been added. It is loosely replaced by + ipSystemStatsOutNoRoutes." + ::= { ip 12 } + +ipReasmReqds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 fragments received which needed to be + reassembled at this entity. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsReasmReqds." + ::= { ip 14 } + +ipReasmOKs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 datagrams successfully re-assembled. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsReasmOKs." + ::= { ip 15 } + +ipReasmFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of failures detected by the IPv4 re-assembly + algorithm (for whatever reason: timed out, errors, etc). + Note that this is not necessarily a count of discarded IPv4 + fragments since some algorithms (notably the algorithm in + RFC 815) can lose track of the number of fragments by + combining them as they are received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsReasmFails." + ::= { ip 16 } + +ipFragOKs OBJECT-TYPE + SYNTAX Counter32 + + + + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 datagrams that have been successfully + fragmented at this entity. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsOutFragOKs." + ::= { ip 17 } + +ipFragFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 datagrams that have been discarded + because they needed to be fragmented at this entity but + could not be, e.g., because their Don't Fragment flag was + set. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + ipSystemStatsOutFragFails." + ::= { ip 18 } + +ipFragCreates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of IPv4 datagram fragments that have been + generated as a result of fragmentation at this entity. + + This object has been deprecated as a new IP version neutral + table has been added. It is loosely replaced by + ipSystemStatsOutFragCreates." + ::= { ip 19 } + +ipRoutingDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of routing entries which were chosen to be + discarded even though they are valid. One possible reason + for discarding such an entry could be to free-up buffer + space for other routing entries. + + + + This object was defined in pre-IPv6 versions of the IP MIB. + It was implicitly IPv4 only, but the original specifications + did not indicate this protocol restriction. In order to + clarify the specifications, this object has been deprecated + and a similar, but more thoroughly clarified, object has + been added to the IP-FORWARD-MIB." + ::= { ip 23 } + +-- the deprecated IPv4 address table + +ipAddrTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddrEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The table of addressing information relevant to this + entity's IPv4 addresses. + + This table has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by the + ipAddressTable although several objects that weren't deemed + useful weren't carried forward while another + (ipAdEntReasmMaxSize) was moved to the ipv4InterfaceTable." + ::= { ip 20 } + +ipAddrEntry OBJECT-TYPE + SYNTAX IpAddrEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The addressing information for one of this entity's IPv4 + addresses." + INDEX { ipAdEntAddr } + ::= { ipAddrTable 1 } + +IpAddrEntry ::= SEQUENCE { + ipAdEntAddr IpAddress, + ipAdEntIfIndex INTEGER, + ipAdEntNetMask IpAddress, + ipAdEntBcastAddr INTEGER, + ipAdEntReasmMaxSize INTEGER + } + +ipAdEntAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + + + + "The IPv4 address to which this entry's addressing + information pertains." + ::= { ipAddrEntry 1 } + +ipAdEntIfIndex OBJECT-TYPE + SYNTAX INTEGER (1..2147483647) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The index value which uniquely identifies the interface to + which this entry is applicable. The interface identified by + a particular value of this index is the same interface as + identified by the same value of the IF-MIB's ifIndex." + ::= { ipAddrEntry 2 } + +ipAdEntNetMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The subnet mask associated with the IPv4 address of this + entry. The value of the mask is an IPv4 address with all + the network bits set to 1 and all the hosts bits set to 0." + ::= { ipAddrEntry 3 } + +ipAdEntBcastAddr OBJECT-TYPE + SYNTAX INTEGER (0..1) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The value of the least-significant bit in the IPv4 broadcast + address used for sending datagrams on the (logical) + interface associated with the IPv4 address of this entry. + For example, when the Internet standard all-ones broadcast + address is used, the value will be 1. This value applies to + both the subnet and network broadcast addresses used by the + entity on this (logical) interface." + ::= { ipAddrEntry 4 } + +ipAdEntReasmMaxSize OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The size of the largest IPv4 datagram which this entity can + re-assemble from incoming IPv4 fragmented datagrams received + on this interface." + ::= { ipAddrEntry 5 } + + + +-- the deprecated IPv4 Address Translation table + +-- The Address Translation tables contain the IpAddress to +-- "physical" address equivalences. Some interfaces do not +-- use translation tables for determining address +-- equivalences (e.g., DDN-X.25 has an algorithmic method); +-- if all interfaces are of this type, then the Address +-- Translation table is empty, i.e., has zero entries. + +ipNetToMediaTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpNetToMediaEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The IPv4 Address Translation table used for mapping from + IPv4 addresses to physical addresses. + + This table has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by the + ipNetToPhysicalTable." + ::= { ip 22 } + +ipNetToMediaEntry OBJECT-TYPE + SYNTAX IpNetToMediaEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "Each entry contains one IpAddress to `physical' address + equivalence." + INDEX { ipNetToMediaIfIndex, + ipNetToMediaNetAddress } + ::= { ipNetToMediaTable 1 } + +IpNetToMediaEntry ::= SEQUENCE { + ipNetToMediaIfIndex INTEGER, + ipNetToMediaPhysAddress PhysAddress, + ipNetToMediaNetAddress IpAddress, + ipNetToMediaType INTEGER + } + +ipNetToMediaIfIndex OBJECT-TYPE + SYNTAX INTEGER (1..2147483647) + MAX-ACCESS read-create + STATUS deprecated + DESCRIPTION + "The interface on which this entry's equivalence is + effective. The interface identified by a particular value + of this index is the same interface as identified by the + + + + same value of the IF-MIB's ifIndex. + + This object predates the rule limiting index objects to a + max access value of 'not-accessible' and so continues to use + a value of 'read-create'." + ::= { ipNetToMediaEntry 1 } + +ipNetToMediaPhysAddress OBJECT-TYPE + SYNTAX PhysAddress (SIZE(0..65535)) + MAX-ACCESS read-create + STATUS deprecated + DESCRIPTION + "The media-dependent `physical' address. This object should + return 0 when this entry is in the 'incomplete' state. + + As the entries in this table are typically not persistent + when this object is written the entity should not save the + change to non-volatile storage. Note: a stronger + requirement is not used because this object was previously + defined." + ::= { ipNetToMediaEntry 2 } + +ipNetToMediaNetAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS deprecated + DESCRIPTION + "The IpAddress corresponding to the media-dependent + `physical' address. + + This object predates the rule limiting index objects to a + max access value of 'not-accessible' and so continues to use + a value of 'read-create'." + ::= { ipNetToMediaEntry 3 } + +ipNetToMediaType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + invalid(2), -- an invalidated mapping + dynamic(3), + static(4) + } + MAX-ACCESS read-create + STATUS deprecated + DESCRIPTION + "The type of mapping. + + Setting this object to the value invalid(2) has the effect + + + + of invalidating the corresponding entry in the + ipNetToMediaTable. That is, it effectively dis-associates + the interface identified with said entry from the mapping + identified with said entry. It is an implementation- + specific matter as to whether the agent removes an + invalidated entry from the table. Accordingly, management + stations must be prepared to receive tabular information + from agents that corresponds to entries not currently in + use. Proper interpretation of such entries requires + examination of the relevant ipNetToMediaType object. + + As the entries in this table are typically not persistent + when this object is written the entity should not save the + change to non-volatile storage. Note: a stronger + requirement is not used because this object was previously + defined." + ::= { ipNetToMediaEntry 4 } + +-- the deprecated ICMP group + +icmpInMsgs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of ICMP messages which the entity received. + Note that this counter includes all those counted by + icmpInErrors. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + icmpStatsInMsgs." + ::= { icmp 1 } + +icmpInErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP messages which the entity received but + determined as having ICMP-specific errors (bad ICMP + checksums, bad length, etc.). + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + icmpStatsInErrors." + ::= { icmp 2 } + + + + +icmpInDestUnreachs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Destination Unreachable messages + received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 3 } + +icmpInTimeExcds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Time Exceeded messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 4 } + +icmpInParmProbs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Parameter Problem messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 5 } + +icmpInSrcQuenchs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Source Quench messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 6 } + + + +icmpInRedirects OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Redirect messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 7 } + +icmpInEchos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Echo (request) messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 8 } + +icmpInEchoReps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Echo Reply messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 9 } + +icmpInTimestamps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Timestamp (request) messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 10 } + + + + +icmpInTimestampReps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Timestamp Reply messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 11 } + +icmpInAddrMasks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Address Mask Request messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 12 } + +icmpInAddrMaskReps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Address Mask Reply messages received. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 13 } + +icmpOutMsgs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The total number of ICMP messages which this entity + attempted to send. Note that this counter includes all + those counted by icmpOutErrors. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + icmpStatsOutMsgs." + + + + ::= { icmp 14 } + +icmpOutErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP messages which this entity did not send + due to problems discovered within ICMP, such as a lack of + buffers. This value should not include errors discovered + outside the ICMP layer, such as the inability of IP to route + the resultant datagram. In some implementations, there may + be no types of error which contribute to this counter's + value. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by + icmpStatsOutErrors." + ::= { icmp 15 } + +icmpOutDestUnreachs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Destination Unreachable messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 16 } + +icmpOutTimeExcds OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Time Exceeded messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 17 } + +icmpOutParmProbs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + + + + DESCRIPTION + "The number of ICMP Parameter Problem messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 18 } + +icmpOutSrcQuenchs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Source Quench messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 19 } + +icmpOutRedirects OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Redirect messages sent. For a host, this + object will always be zero, since hosts do not send + redirects. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 20 } + +icmpOutEchos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Echo (request) messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 21 } + +icmpOutEchoReps OBJECT-TYPE + SYNTAX Counter32 + + + + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Echo Reply messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 22 } + +icmpOutTimestamps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Timestamp (request) messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 23 } + +icmpOutTimestampReps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Timestamp Reply messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 24 } + +icmpOutAddrMasks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Address Mask Request messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 25 } + +icmpOutAddrMaskReps OBJECT-TYPE + SYNTAX Counter32 + + + + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of ICMP Address Mask Reply messages sent. + + This object has been deprecated, as a new IP version-neutral + table has been added. It is loosely replaced by a column in + the icmpMsgStatsTable." + ::= { icmp 26 } + +-- deprecated conformance information +-- deprecated compliance statements + +ipMIBCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for systems that implement only + IPv4. For version-independence, this compliance statement + is deprecated in favor of ipMIBCompliance2." + MODULE -- this module + MANDATORY-GROUPS { ipGroup, + icmpGroup } + ::= { ipMIBCompliances 1 } + +-- deprecated units of conformance + +ipGroup OBJECT-GROUP + OBJECTS { ipForwarding, ipDefaultTTL, + ipInReceives, ipInHdrErrors, + ipInAddrErrors, ipForwDatagrams, + ipInUnknownProtos, ipInDiscards, + ipInDelivers, ipOutRequests, + ipOutDiscards, ipOutNoRoutes, + ipReasmTimeout, ipReasmReqds, + ipReasmOKs, ipReasmFails, + ipFragOKs, ipFragFails, + ipFragCreates, ipAdEntAddr, + ipAdEntIfIndex, ipAdEntNetMask, + ipAdEntBcastAddr, ipAdEntReasmMaxSize, + ipNetToMediaIfIndex, ipNetToMediaPhysAddress, + ipNetToMediaNetAddress, ipNetToMediaType, + ipRoutingDiscards +} + STATUS deprecated + DESCRIPTION + "The ip group of objects providing for basic management of IP + entities, exclusive of the management of IP routes. + + + + + As part of the version independence, this group has been + deprecated. " + ::= { ipMIBGroups 1 } + +icmpGroup OBJECT-GROUP + OBJECTS { icmpInMsgs, icmpInErrors, + icmpInDestUnreachs, icmpInTimeExcds, + icmpInParmProbs, icmpInSrcQuenchs, + icmpInRedirects, icmpInEchos, + icmpInEchoReps, icmpInTimestamps, + icmpInTimestampReps, icmpInAddrMasks, + icmpInAddrMaskReps, icmpOutMsgs, + icmpOutErrors, icmpOutDestUnreachs, + icmpOutTimeExcds, icmpOutParmProbs, + icmpOutSrcQuenchs, icmpOutRedirects, + icmpOutEchos, icmpOutEchoReps, + icmpOutTimestamps, icmpOutTimestampReps, + icmpOutAddrMasks, icmpOutAddrMaskReps } + STATUS deprecated + DESCRIPTION + "The icmp group of objects providing ICMP statistics. + + As part of the version independence, this group has been + deprecated. " + ::= { ipMIBGroups 2 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC-1212 b/contrib/apps/LwipMibCompiler/Mibs/RFC-1212 new file mode 100644 index 0000000..4b1bdcf --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC-1212 @@ -0,0 +1,75 @@ +RFC-1212 DEFINITIONS ::= BEGIN + + IMPORTS + ObjectName + FROM RFC1155-SMI; +-- DisplayString +-- FROM RFC1158-MIB; + + OBJECT-TYPE MACRO ::= + BEGIN + TYPE NOTATION ::= + -- must conform to + -- RFC1155's ObjectSyntax + "SYNTAX" type(ObjectSyntax) + "ACCESS" Access + "STATUS" Status + DescrPart + ReferPart + IndexPart + DefValPart + VALUE NOTATION ::= value (VALUE ObjectName) + + Access ::= "read-only" + | "read-write" + | "write-only" + | "not-accessible" + Status ::= "mandatory" + | "optional" + | "obsolete" + | "deprecated" + + DescrPart ::= + "DESCRIPTION" value (description DisplayString) + | empty + + ReferPart ::= + "REFERENCE" value (reference DisplayString) + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | empty + IndexTypes ::= + IndexType | IndexTypes "," IndexType + IndexType ::= + -- if indexobject, use the SYNTAX + -- value of the correspondent + -- OBJECT-TYPE invocation + value (indexobject ObjectName) + -- otherwise use named SMI type + -- must conform to IndexSyntax below + | type (indextype) + + DefValPart ::= + "DEFVAL" "{" value (defvalue ObjectSyntax) "}" + | empty + + END + + IndexSyntax ::= + CHOICE { + number + INTEGER (0..MAX), + string + OCTET STRING, + object + OBJECT IDENTIFIER, + address + NetworkAddress, + ipAddress + IpAddress + } + +END + diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC-1215 b/contrib/apps/LwipMibCompiler/Mibs/RFC-1215 new file mode 100644 index 0000000..3cdcfdf --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC-1215 @@ -0,0 +1,34 @@ +RFC-1215 DEFINITIONS ::= BEGIN + + IMPORTS + ObjectName + FROM RFC1155-SMI; + + TRAP-TYPE MACRO ::= + BEGIN + TYPE NOTATION ::= "ENTERPRISE" value + (enterprise OBJECT IDENTIFIER) + VarPart + DescrPart + ReferPart + VALUE NOTATION ::= value (VALUE INTEGER) + + VarPart ::= + "VARIABLES" "{" VarTypes "}" + | empty + VarTypes ::= + VarType | VarTypes "," VarType + VarType ::= + value (vartype ObjectName) + + DescrPart ::= + "DESCRIPTION" value (description DisplayString) + | empty + + ReferPart ::= + "REFERENCE" value (reference DisplayString) + | empty + + END + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC1065-SMI b/contrib/apps/LwipMibCompiler/Mibs/RFC1065-SMI new file mode 100644 index 0000000..40e55d7 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC1065-SMI @@ -0,0 +1,132 @@ +RFC1065-SMI DEFINITIONS ::= BEGIN + +EXPORTS -- EVERYTHING + internet, directory, mgmt, + experimental, private, enterprises, + OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax, + ApplicationSyntax, NetworkAddress, IpAddress, + Counter, Gauge, TimeTicks, Opaque; + + -- the path to the root + + internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 } + + directory OBJECT IDENTIFIER ::= { internet 1 } + + mgmt OBJECT IDENTIFIER ::= { internet 2 } + + experimental OBJECT IDENTIFIER ::= { internet 3 } + + private OBJECT IDENTIFIER ::= { internet 4 } + enterprises OBJECT IDENTIFIER ::= { private 1 } + + + -- definition of object types + + OBJECT-TYPE MACRO ::= + BEGIN + TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax) + "ACCESS" Access + "STATUS" Status + VALUE NOTATION ::= value (VALUE ObjectName) + + Access ::= "read-only" + | "read-write" + | "write-only" + | "not-accessible" + Status ::= "mandatory" + | "optional" + | "obsolete" + END + + -- names of objects in the MIB + + ObjectName ::= + OBJECT IDENTIFIER + + + + -- syntax of objects in the MIB + + ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + + -- note that simple SEQUENCEs are not directly + -- mentioned here to keep things simple (i.e., + -- prevent mis-use). However, application-wide + -- types which are IMPLICITly encoded simple + -- SEQUENCEs may appear in the following CHOICE + + application-wide + ApplicationSyntax + } + + SimpleSyntax ::= + CHOICE { + number + INTEGER, + + string + OCTET STRING, + + object + OBJECT IDENTIFIER, + + empty + NULL + } + + ApplicationSyntax ::= + CHOICE { + address + NetworkAddress, + + counter + Counter, + + gauge + Gauge, + + ticks + TimeTicks, + + arbitrary + Opaque + + + -- other application-wide types, as they are + -- defined, will be added here + } + + + -- application-wide types + + NetworkAddress ::= + CHOICE { + internet + IpAddress + } + + IpAddress ::= + [APPLICATION 0] -- in network-byte order + IMPLICIT OCTET STRING (SIZE (4)) + + Counter ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + + Gauge ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + + TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER + + Opaque ::= + [APPLICATION 4] -- arbitrary ASN.1 value, + IMPLICIT OCTET STRING -- "double-wrapped" + + END diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC1155-SMI b/contrib/apps/LwipMibCompiler/Mibs/RFC1155-SMI new file mode 100644 index 0000000..a6c3bf6 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC1155-SMI @@ -0,0 +1,129 @@ +RFC1155-SMI DEFINITIONS ::= BEGIN + +EXPORTS -- EVERYTHING + internet, directory, mgmt, + experimental, private, enterprises, + OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax, + ApplicationSyntax, NetworkAddress, IpAddress, + Counter, Gauge, TimeTicks, Opaque; + + -- the path to the root + + internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 } + + directory OBJECT IDENTIFIER ::= { internet 1 } + + mgmt OBJECT IDENTIFIER ::= { internet 2 } + + experimental OBJECT IDENTIFIER ::= { internet 3 } + + private OBJECT IDENTIFIER ::= { internet 4 } + enterprises OBJECT IDENTIFIER ::= { private 1 } + + + -- definition of object types + + OBJECT-TYPE MACRO ::= + BEGIN + TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax) + "ACCESS" Access + "STATUS" Status + VALUE NOTATION ::= value (VALUE ObjectName) + + Access ::= "read-only" + | "read-write" + | "write-only" + | "not-accessible" + Status ::= "mandatory" + | "optional" + | "obsolete" + END + + -- names of objects in the MIB + + ObjectName ::= + OBJECT IDENTIFIER + + -- syntax of objects in the MIB + + ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + + -- note that simple SEQUENCEs are not directly + -- mentioned here to keep things simple (i.e., + -- prevent mis-use). However, application-wide + -- types which are IMPLICITly encoded simple + -- SEQUENCEs may appear in the following CHOICE + + application-wide + ApplicationSyntax + } + + SimpleSyntax ::= + CHOICE { + number + INTEGER, + + string + OCTET STRING, + + object + OBJECT IDENTIFIER, + + empty + NULL + } + + ApplicationSyntax ::= + CHOICE { + address + NetworkAddress, + + counter + Counter, + + gauge + Gauge, + + ticks + TimeTicks, + + arbitrary + Opaque + + -- other application-wide types, as they are + -- defined, will be added here + } + + + -- application-wide types + + NetworkAddress ::= + CHOICE { + internet + IpAddress + } + + IpAddress ::= + [APPLICATION 0] -- in network-byte order + IMPLICIT OCTET STRING (SIZE (4)) + + Counter ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + + Gauge ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + + TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER (0..4294967295) + + Opaque ::= + [APPLICATION 4] -- arbitrary ASN.1 value, + IMPLICIT OCTET STRING -- "double-wrapped" + + END diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC1158-MIB b/contrib/apps/LwipMibCompiler/Mibs/RFC1158-MIB new file mode 100644 index 0000000..4acf34a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC1158-MIB @@ -0,0 +1,1493 @@ +RFC1158-MIB DEFINITIONS ::= BEGIN + +IMPORTS + mgmt, OBJECT-TYPE, NetworkAddress, IpAddress, + Counter, Gauge, TimeTicks + FROM RFC1155-SMI; + +DisplayString ::= + OCTET STRING + +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } -- MIB-II + -- (same prefix as MIB-I) + +system OBJECT IDENTIFIER ::= { mib-2 1 } +interfaces OBJECT IDENTIFIER ::= { mib-2 2 } +at OBJECT IDENTIFIER ::= { mib-2 3 } +ip OBJECT IDENTIFIER ::= { mib-2 4 } +icmp OBJECT IDENTIFIER ::= { mib-2 5 } +tcp OBJECT IDENTIFIER ::= { mib-2 6 } +udp OBJECT IDENTIFIER ::= { mib-2 7 } +egp OBJECT IDENTIFIER ::= { mib-2 8 } +-- cmot OBJECT IDENTIFIER ::= { mib-2 9 } +transmission OBJECT IDENTIFIER ::= { mib-2 10 } +snmp OBJECT IDENTIFIER ::= { mib-2 11 } + + +-- object types + +-- the System group + +sysDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + ::= { system 1 } + +sysObjectID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + ::= { system 2 } + +sysUpTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + ::= { system 3 } + +sysContact OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + ::= { system 4 } + +sysName OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + ::= { system 5 } + +sysLocation OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + ::= { system 6 } + +sysServices OBJECT-TYPE + SYNTAX INTEGER (0..127) + ACCESS read-only + STATUS mandatory + ::= { system 7 } + + +-- the Interfaces group + +ifNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { interfaces 1 } + +-- the Interfaces table + +ifTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfEntry + ACCESS read-only + STATUS mandatory + ::= { interfaces 2 } + +ifEntry OBJECT-TYPE + SYNTAX IfEntry + ACCESS read-only + STATUS mandatory + ::= { ifTable 1 } + +IfEntry ::= SEQUENCE { + ifIndex + INTEGER, + ifDescr + DisplayString, + ifType + INTEGER, + ifMtu + INTEGER, + ifSpeed + Gauge, + ifPhysAddress + OCTET STRING, + ifAdminStatus + INTEGER, + ifOperStatus + INTEGER, + ifLastChange + TimeTicks, + ifInOctets + Counter, + ifInUcastPkts + Counter, + ifInNUcastPkts + Counter, + ifInDiscards + Counter, + ifInErrors + Counter, + ifInUnknownProtos + Counter, + ifOutOctets + Counter, + ifOutUcastPkts + Counter, + ifOutNUcastPkts + Counter, + ifOutDiscards + Counter, + ifOutErrors + Counter, + ifOutQLen + Gauge, + ifSpecific + OBJECT IDENTIFIER +} + +ifIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { ifEntry 1 } + +ifDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + ::= { ifEntry 2 } + +ifType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the + -- following + regular1822(2), + hdh1822(3), + ddn-x25(4), + rfc877-x25(5), + ethernet-csmacd(6), + iso88023-csmacd(7), + iso88024-tokenBus(8), + iso88025-tokenRing(9), + iso88026-man(10), + starLan(11), + proteon-10Mbit(12), + proteon-80Mbit(13), + hyperchannel(14), + fddi(15), + lapb(16), + sdlc(17), + t1-carrier(18), + cept(19), -- european + --equivalent of T-1 + basicISDN(20), + primaryISDN(21), + -- proprietary + -- serial + propPointToPointSerial(22), + terminalServer-asyncPort(23), + softwareLoopback(24), + eon(25), -- CLNP over IP + ethernet-3Mbit(26), + nsip(27), -- XNS over IP + slip(28) -- generic SLIP + } + ACCESS read-only + STATUS mandatory + ::= { ifEntry 3 } + +ifMtu OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { ifEntry 4 } + +ifSpeed OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + ::= { ifEntry 5 } + +ifPhysAddress OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-only + STATUS mandatory + ::= { ifEntry 6 } + +ifAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-write + STATUS mandatory + ::= { ifEntry 7 } + +ifOperStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-only + STATUS mandatory + ::= { ifEntry 8 } + +ifLastChange OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + ::= { ifEntry 9 } + +ifInOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 10 } + +ifInUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 11 } + +ifInNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 12 } + +ifInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 13 } + +ifInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 14 } + +ifInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 15 } + +ifOutOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 16 } + +ifOutUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 17 } + +ifOutNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 18 } + +ifOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 19 } + +ifOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ifEntry 20 } + +ifOutQLen OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + ::= { ifEntry 21 } + +ifSpecific OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + ::= { ifEntry 22 } + +nullSpecific OBJECT IDENTIFIER ::= { 0 0 } + +-- the Address Translation group (deprecated) + +atTable OBJECT-TYPE + SYNTAX SEQUENCE OF AtEntry + ACCESS read-write + STATUS deprecated + ::= { at 1 } + +atEntry OBJECT-TYPE + SYNTAX AtEntry + ACCESS read-write + STATUS deprecated + ::= { atTable 1 } + +AtEntry ::= SEQUENCE { + atIfIndex + INTEGER, + atPhysAddress + OCTET STRING, + atNetAddress + NetworkAddress +} + +atIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS deprecated + ::= { atEntry 1 } + +atPhysAddress OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS deprecated + ::= { atEntry 2 } + +atNetAddress OBJECT-TYPE + SYNTAX NetworkAddress + ACCESS read-write + STATUS deprecated + ::= { atEntry 3 } + + +-- the IP group + +ipForwarding OBJECT-TYPE + SYNTAX INTEGER { + gateway(1), -- entity forwards + -- datagrams + host(2) -- entity does NOT + -- forward datagrams + } + ACCESS read-write + STATUS mandatory + ::= { ip 1 } + +ipDefaultTTL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ip 2 } + +ipInReceives OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 3 } + +ipInHdrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 4 } + +ipInAddrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 5 } + +ipForwDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 6 } + +ipInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 7 } + +ipInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 8 } + +ipInDelivers OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 9 } + +ipOutRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 10 } + +ipOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 11 } + +ipOutNoRoutes OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 12 } + +ipReasmTimeout OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { ip 13 } + +ipReasmReqds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 14 } + +ipReasmOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 15 } + +ipReasmFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 16 } + +ipFragOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 17 } + +ipFragFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 18 } + +ipFragCreates OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { ip 19 } + +-- the IP Interface table + +ipAddrTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddrEntry + ACCESS read-only + STATUS mandatory + ::= { ip 20 } + +ipAddrEntry OBJECT-TYPE + SYNTAX IpAddrEntry + ACCESS read-only + STATUS mandatory + ::= { ipAddrTable 1 } + +IpAddrEntry ::= SEQUENCE { + ipAdEntAddr + IpAddress, + ipAdEntIfIndex + INTEGER, + ipAdEntNetMask + IpAddress, + ipAdEntBcastAddr + INTEGER, + ipAdEntReasmMaxSize + INTEGER (0..65535) +} + +ipAdEntAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { ipAddrEntry 1 } + +ipAdEntIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { ipAddrEntry 2 } + +ipAdEntNetMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { ipAddrEntry 3 } + +ipAdEntBcastAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { ipAddrEntry 4 } + +ipAdEntReasmMaxSize OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + ::= { ipAddrEntry 5 } + +-- the IP Routing table + +ipRoutingTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpRouteEntry + ACCESS read-write + STATUS mandatory + ::= { ip 21 } + +ipRouteEntry OBJECT-TYPE + SYNTAX IpRouteEntry + ACCESS read-write + STATUS mandatory + ::= { ipRoutingTable 1 } + +IpRouteEntry ::= SEQUENCE { + ipRouteDest + IpAddress, + ipRouteIfIndex + INTEGER, + ipRouteMetric1 + INTEGER, + ipRouteMetric2 + INTEGER, + ipRouteMetric3 + INTEGER, + ipRouteMetric4 + INTEGER, + ipRouteNextHop + IpAddress, + ipRouteType + INTEGER, + ipRouteProto + INTEGER, + ipRouteAge + INTEGER, + ipRouteMask + IpAddress +} + +ipRouteDest OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 1 } + +ipRouteIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 2 } + +ipRouteMetric1 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 3 } + +ipRouteMetric2 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 4 } + +ipRouteMetric3 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 5 } + +ipRouteMetric4 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 6 } + +ipRouteNextHop OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 7 } + +ipRouteType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + invalid(2), -- an invalidated route + + -- route to directly + direct(3), -- connected + -- (sub-)network + + -- route to a non-local + remote(4) -- host/network/ + -- sub-network + } + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 8 } + +ipRouteProto OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + -- non-protocol + -- information + + -- e.g., manually + local(2), -- configured entries + + -- set via a network + netmgmt(3), -- management protocol + + -- obtained via ICMP, + icmp(4), -- e.g., Redirect + + -- the following are + -- gateway routing + -- protocols + egp(5), + ggp(6), + hello(7), + rip(8), + is-is(9), + es-is(10), + ciscoIgrp(11), + bbnSpfIgp(12), + ospf(13), + bgp(14) + } + ACCESS read-only + STATUS mandatory + ::= { ipRouteEntry 9 } + +ipRouteAge OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 10 } + +ipRouteMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + ::= { ipRouteEntry 11 } + +-- the IP Address Translation tables + +ipNetToMediaTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpNetToMediaEntry + ACCESS read-write + STATUS mandatory + ::= { ip 22 } + +ipNetToMediaEntry OBJECT-TYPE + SYNTAX IpNetToMediaEntry + ACCESS read-write + STATUS mandatory + ::= { ipNetToMediaTable 1 } + +IpNetToMediaEntry ::= SEQUENCE { + ipNetToMediaIfIndex + INTEGER, + ipNetToMediaPhysAddress + OCTET STRING, + ipNetToMediaNetAddress + IpAddress, + ipNetToMediaType + INTEGER +} + +ipNetToMediaIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + ::= { ipNetToMediaEntry 1 } + +ipNetToMediaPhysAddress OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { ipNetToMediaEntry 2 } + +ipNetToMediaNetAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + ::= { ipNetToMediaEntry 3 } + +ipNetToMediaType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + invalid(2), -- an invalidated mapping + dynamic(3), -- connected (sub-)network + + static(4) + } + ACCESS read-write + STATUS mandatory + ::= { ipNetToMediaEntry 4 } + +-- the ICMP group + +icmpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 1 } + +icmpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 2 } + +icmpInDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 3 } + +icmpInTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 4 } + +icmpInParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 5 } + +icmpInSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 6 } + +icmpInRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 7 } + +icmpInEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 8 } + +icmpInEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 9 } + +icmpInTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 10 } + +icmpInTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 11 } + +icmpInAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 12 } + +icmpInAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 13 } + +icmpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 14 } + +icmpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 15 } + +icmpOutDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 16 } + +icmpOutTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 17 } + +icmpOutParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 18 } + +icmpOutSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 19 } + +icmpOutRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 20 } + +icmpOutEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 21 } + +icmpOutEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 22 } + +icmpOutTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 23 } + +icmpOutTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 24 } + +icmpOutAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 25 } + +icmpOutAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { icmp 26 } + + +-- the TCP group + +tcpRtoAlgorithm OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + constant(2), -- a constant rto + rsre(3), -- MIL-STD-1778, + -- Appendix B + vanj(4) -- Van Jacobson's + -- algorithm + } + ACCESS read-only + STATUS mandatory + ::= { tcp 1 } + +tcpRtoMin OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { tcp 2 } + +tcpRtoMax OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { tcp 3 } + +tcpMaxConn OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { tcp 4 } + +tcpActiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 5 } + +tcpPassiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 6 } + +tcpAttemptFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 7 } + +tcpEstabResets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 8 } + +tcpCurrEstab OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + ::= { tcp 9 } + +tcpInSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 10 } + +tcpOutSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 11 } + +tcpRetransSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 12 } + +-- the TCP connections table + +tcpConnTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnEntry + ACCESS read-only + STATUS mandatory + ::= { tcp 13 } + +tcpConnEntry OBJECT-TYPE + SYNTAX TcpConnEntry + ACCESS read-only + STATUS mandatory + ::= { tcpConnTable 1 } + +TcpConnEntry ::= SEQUENCE { + tcpConnState + INTEGER, + tcpConnLocalAddress + IpAddress, + tcpConnLocalPort + INTEGER (0..65535), + tcpConnRemAddress + IpAddress, + tcpConnRemPort + INTEGER (0..65535) +} + +tcpConnState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11) + } + ACCESS read-only + STATUS mandatory + ::= { tcpConnEntry 1 } + +tcpConnLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { tcpConnEntry 2 } + +tcpConnLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + ::= { tcpConnEntry 3 } + +tcpConnRemAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { tcpConnEntry 4 } + +tcpConnRemPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + ::= { tcpConnEntry 5 } + +-- additional TCP variables + +tcpInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 14 } + +tcpOutRsts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { tcp 15 } + + +-- the UDP group + +udpInDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { udp 1 } + +udpNoPorts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { udp 2 } + +udpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { udp 3 } + +udpOutDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { udp 4 } + +-- the UDP listener table + +udpTable OBJECT-TYPE + SYNTAX SEQUENCE OF UdpEntry + ACCESS read-only + STATUS mandatory + ::= { udp 5 } + +udpEntry OBJECT-TYPE + SYNTAX UdpEntry + ACCESS read-only + STATUS mandatory + ::= { udpTable 1 } + +UdpEntry ::= SEQUENCE { + udpLocalAddress + IpAddress, + udpLocalPort + INTEGER (0..65535) +} + +udpLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { udpEntry 1 } + +udpLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + ::= { udpEntry 2 } + +-- the EGP group + +egpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egp 1 } + +egpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egp 2 } + +egpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egp 3 } + +egpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egp 4 } + +-- the EGP Neighbor table + +egpNeighTable OBJECT-TYPE + SYNTAX SEQUENCE OF EgpNeighEntry + ACCESS read-only + STATUS mandatory + ::= { egp 5 } + +egpNeighEntry OBJECT-TYPE + SYNTAX EgpNeighEntry + ACCESS read-only + STATUS mandatory + ::= { egpNeighTable 1 } + +EgpNeighEntry ::= SEQUENCE { + egpNeighState + INTEGER, + egpNeighAddr + IpAddress, + egpNeighAs + INTEGER, + egpNeighInMsgs + Counter, + egpNeighInErrs + Counter, + egpNeighOutMsgs + Counter, + egpNeighOutErrs + Counter, + egpNeighInErrMsgs + Counter, + egpNeighOutErrMsgs + Counter, + egpNeighStateUps + Counter, + egpNeighStateDowns + Counter, + egpNeighIntervalHello + INTEGER, + egpNeighIntervalPoll + INTEGER, + egpNeighMode + INTEGER, + egpNeighEventTrigger + INTEGER +} + +egpNeighState OBJECT-TYPE + SYNTAX INTEGER { + idle(1), + acquisition(2), + down(3), + up(4), + cease(5) + } + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 1 } + +egpNeighAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 2 } + +egpNeighAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 3 } + +egpNeighInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 4 } + +egpNeighInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 5 } + +egpNeighOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 6 } + +egpNeighOutErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 7 } + +egpNeighInErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 8 } + +egpNeighOutErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 9 } + +egpNeighStateUps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 10 } + +egpNeighStateDowns OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 11 } + +egpNeighIntervalHello OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 12 } + +egpNeighIntervalPoll OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 13 } + +egpNeighMode OBJECT-TYPE + SYNTAX INTEGER { + active(1), + passive(2) + } + ACCESS read-only + STATUS mandatory + ::= { egpNeighEntry 14 } + +egpNeighEventTrigger OBJECT-TYPE + SYNTAX INTEGER { + start(1), + stop(2) + } + ACCESS read-write + STATUS mandatory + ::= { egpNeighEntry 15 } + +-- additional EGP variables + +egpAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + ::= { egp 6 } + + +-- the Transmission group (empty at present) + +-- the SNMP group + +snmpInPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 1 } + +snmpOutPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 2 } + +snmpInBadVersions OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 3 } + +snmpInBadCommunityNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 4 } + +snmpInBadCommunityUses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 5 } + +snmpInASNParseErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 6 } + +snmpInBadTypes OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 7 } + +snmpInTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 8 } + +snmpInNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 9 } + +snmpInBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 10 } + +snmpInReadOnlys OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 11 } + +snmpInGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 12 } + +snmpInTotalReqVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 13 } + +snmpInTotalSetVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 14 } + +snmpInGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 15 } + +snmpInGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 16 } + +snmpInSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 17 } + +snmpInGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 18 } + +snmpInTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 19 } + +snmpOutTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 20 } + +snmpOutNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 21 } + +snmpOutBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 22 } + +snmpOutReadOnlys OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 23 } + +snmpOutGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 24 } + +snmpOutGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 25 } + +snmpOutGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 26 } + +snmpOutSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 27 } + +snmpOutGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 28 } + +snmpOutTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + ::= { snmp 29 } + +snmpEnableAuthTraps OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + ACCESS read-write + STATUS mandatory + ::= { snmp 30 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/RFC1213-MIB b/contrib/apps/LwipMibCompiler/Mibs/RFC1213-MIB new file mode 100644 index 0000000..2a849de --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/RFC1213-MIB @@ -0,0 +1,2621 @@ +RFC1213-MIB DEFINITIONS ::= BEGIN + +IMPORTS + mgmt, NetworkAddress, IpAddress, Counter, Gauge, + TimeTicks + FROM RFC1155-SMI + OBJECT-TYPE + FROM RFC-1212; + +-- This MIB module uses the extended OBJECT-TYPE macro as +-- defined in [14]; + + +-- MIB-II (same prefix as MIB-I) + +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } + +-- textual conventions + +DisplayString ::= + OCTET STRING +-- This data type is used to model textual information taken +-- from the NVT ASCII character set. By convention, objects +-- with this syntax are declared as having + +-- +-- SIZE (0..255) + +PhysAddress ::= + OCTET STRING +-- This data type is used to model media addresses. For many +-- types of media, this will be in a binary representation. +-- For example, an ethernet address would be represented as +-- a string of 6 octets. + + +-- groups in MIB-II + +system OBJECT IDENTIFIER ::= { mib-2 1 } + +interfaces OBJECT IDENTIFIER ::= { mib-2 2 } + +at OBJECT IDENTIFIER ::= { mib-2 3 } + +ip OBJECT IDENTIFIER ::= { mib-2 4 } + +icmp OBJECT IDENTIFIER ::= { mib-2 5 } + +tcp OBJECT IDENTIFIER ::= { mib-2 6 } + +udp OBJECT IDENTIFIER ::= { mib-2 7 } + +egp OBJECT IDENTIFIER ::= { mib-2 8 } + +-- historical (some say hysterical) +-- cmot OBJECT IDENTIFIER ::= { mib-2 9 } + +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +snmp OBJECT IDENTIFIER ::= { mib-2 11 } + + +-- the System group + +-- Implementation of the System group is mandatory for all +-- systems. If an agent is not configured to have a value +-- for any of these variables, a string of length 0 is +-- returned. + +sysDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A textual description of the entity. This value + should include the full name and version + identification of the system's hardware type, + software operating-system, and networking + software. It is mandatory that this only contain + printable ASCII characters." + ::= { system 1 } + +sysObjectID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The vendor's authoritative identification of the + network management subsystem contained in the + entity. This value is allocated within the SMI + enterprises subtree (1.3.6.1.4.1) and provides an + easy and unambiguous means for determining `what + kind of box' is being managed. For example, if + vendor `Flintstones, Inc.' was assigned the + subtree 1.3.6.1.4.1.4242, it could assign the + identifier 1.3.6.1.4.1.4242.1.1 to its `Fred + Router'." + ::= { system 2 } + +sysUpTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time (in hundredths of a second) since the + network management portion of the system was last + re-initialized." + ::= { system 3 } + +sysContact OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The textual identification of the contact person + for this managed node, together with information + on how to contact this person." + ::= { system 4 } + +sysName OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An administratively-assigned name for this + managed node. By convention, this is the node's + fully-qualified domain name." + ::= { system 5 } + +sysLocation OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The physical location of this node (e.g., + `telephone closet, 3rd floor')." + ::= { system 6 } + +sysServices OBJECT-TYPE + SYNTAX INTEGER (0..127) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A value which indicates the set of services that + this entity primarily offers. + + The value is a sum. This sum initially takes the + value zero, Then, for each layer, L, in the range + 1 through 7, that this node performs transactions + for, 2 raised to (L - 1) is added to the sum. For + example, a node which performs primarily routing + functions would have a value of 4 (2^(3-1)). In + contrast, a node which is a host offering + application services would have a value of 72 + (2^(4-1) + 2^(7-1)). Note that in the context of + the Internet suite of protocols, values should be + calculated accordingly: + + layer functionality + 1 physical (e.g., repeaters) + 2 datalink/subnetwork (e.g., bridges) + 3 internet (e.g., IP gateways) + 4 end-to-end (e.g., IP hosts) + 7 applications (e.g., mail relays) + + For systems including OSI protocols, layers 5 and + 6 may also be counted." + ::= { system 7 } + +-- the Interfaces group + +-- Implementation of the Interfaces group is mandatory for +-- all systems. + +ifNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of network interfaces (regardless of + their current state) present on this system." + ::= { interfaces 1 } + + +-- the Interfaces table + +-- The Interfaces table contains information on the entity's +-- interfaces. Each interface is thought of as being +-- attached to a `subnetwork'. Note that this term should +-- not be confused with `subnet' which refers to an +-- addressing partitioning scheme used in the Internet suite +-- of protocols. + +ifTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of interface entries. The number of + entries is given by the value of ifNumber." + ::= { interfaces 2 } + +ifEntry OBJECT-TYPE + SYNTAX IfEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An interface entry containing objects at the + subnetwork layer and below for a particular + interface." + INDEX { ifIndex } + ::= { ifTable 1 } + +IfEntry ::= + SEQUENCE { + ifIndex + INTEGER, + ifDescr + DisplayString, + ifType + INTEGER, + ifMtu + INTEGER, + ifSpeed + Gauge, + ifPhysAddress + PhysAddress, + ifAdminStatus + INTEGER, + ifOperStatus + INTEGER, + ifLastChange + TimeTicks, + ifInOctets + Counter, + ifInUcastPkts + Counter, + ifInNUcastPkts + Counter, + ifInDiscards + Counter, + ifInErrors + Counter, + ifInUnknownProtos + Counter, + ifOutOctets + Counter, + ifOutUcastPkts + Counter, + ifOutNUcastPkts + Counter, + ifOutDiscards + Counter, + ifOutErrors + Counter, + ifOutQLen + Gauge, + ifSpecific + OBJECT IDENTIFIER + } + +ifIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A unique value for each interface. Its value + ranges between 1 and the value of ifNumber. The + value for each interface must remain constant at + least from one re-initialization of the entity's + network management system to the next re- + initialization." + ::= { ifEntry 1 } + +ifDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A textual string containing information about the + interface. This string should include the name of + the manufacturer, the product name and the version + of the hardware interface." + ::= { ifEntry 2 } + +ifType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + regular1822(2), + hdh1822(3), + ddn-x25(4), + rfc877-x25(5), + ethernet-csmacd(6), + iso88023-csmacd(7), + iso88024-tokenBus(8), + iso88025-tokenRing(9), + iso88026-man(10), + starLan(11), + proteon-10Mbit(12), + proteon-80Mbit(13), + hyperchannel(14), + fddi(15), + lapb(16), + sdlc(17), + ds1(18), -- T-1 + e1(19), -- european equiv. of T-1 + basicISDN(20), + primaryISDN(21), -- proprietary serial + propPointToPointSerial(22), + ppp(23), + softwareLoopback(24), + eon(25), -- CLNP over IP [11] + ethernet-3Mbit(26), + nsip(27), -- XNS over IP + slip(28), -- generic SLIP + ultra(29), -- ULTRA technologies + ds3(30), -- T-3 + sip(31), -- SMDS + frame-relay(32) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of interface, distinguished according to + the physical/link protocol(s) immediately `below' + the network layer in the protocol stack." + ::= { ifEntry 3 } + +ifMtu OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The size of the largest datagram which can be + sent/received on the interface, specified in + octets. For interfaces that are used for + transmitting network datagrams, this is the size + of the largest network datagram that can be sent + on the interface." + ::= { ifEntry 4 } + +ifSpeed OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An estimate of the interface's current bandwidth + in bits per second. For interfaces which do not + vary in bandwidth or for those where no accurate + estimation can be made, this object should contain + the nominal bandwidth." + ::= { ifEntry 5 } + +ifPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interface's address at the protocol layer + immediately `below' the network layer in the + protocol stack. For interfaces which do not have + such an address (e.g., a serial line), this object + should contain an octet string of zero length." + ::= { ifEntry 6 } + +ifAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The desired state of the interface. The + testing(3) state indicates that no operational + packets can be passed." + ::= { ifEntry 7 } + +ifOperStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current operational state of the interface. + The testing(3) state indicates that no operational + packets can be passed." + ::= { ifEntry 8 } + +ifLastChange OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The value of sysUpTime at the time the interface + entered its current operational state. If the + current state was entered prior to the last re- + initialization of the local network management + subsystem, then this object contains a zero + value." + ::= { ifEntry 9 } + +ifInOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of octets received on the + interface, including framing characters." + ::= { ifEntry 10 } + +ifInUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of subnetwork-unicast packets + delivered to a higher-layer protocol." + ::= { ifEntry 11 } + +ifInNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of non-unicast (i.e., subnetwork- + broadcast or subnetwork-multicast) packets + delivered to a higher-layer protocol." + ::= { ifEntry 12 } + +ifInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of inbound packets which were chosen + to be discarded even though no errors had been + detected to prevent their being deliverable to a + higher-layer protocol. One possible reason for + discarding such a packet could be to free up + buffer space." + ::= { ifEntry 13 } + +ifInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of inbound packets that contained + errors preventing them from being deliverable to a + higher-layer protocol." + ::= { ifEntry 14 } + +ifInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of packets received via the interface + which were discarded because of an unknown or + unsupported protocol." + ::= { ifEntry 15 } + +ifOutOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of octets transmitted out of the + interface, including framing characters." + ::= { ifEntry 16 } + +ifOutUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of packets that higher-level + protocols requested be transmitted to a + subnetwork-unicast address, including those that + were discarded or not sent." + ::= { ifEntry 17 } + +ifOutNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of packets that higher-level + protocols requested be transmitted to a non- + unicast (i.e., a subnetwork-broadcast or + subnetwork-multicast) address, including those + that were discarded or not sent." + ::= { ifEntry 18 } + +ifOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outbound packets which were chosen + to be discarded even though no errors had been + detected to prevent their being transmitted. One + possible reason for discarding such a packet could + be to free up buffer space." + ::= { ifEntry 19 } + +ifOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outbound packets that could not be + transmitted because of errors." + ::= { ifEntry 20 } + +ifOutQLen OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The length of the output packet queue (in + packets)." + ::= { ifEntry 21 } + +ifSpecific OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A reference to MIB definitions specific to the + particular media being used to realize the + interface. For example, if the interface is + realized by an ethernet, then the value of this + object refers to a document defining objects + specific to ethernet. If this information is not + present, its value should be set to the OBJECT + IDENTIFIER { 0 0 }, which is a syntatically valid + object identifier, and any conformant + implementation of ASN.1 and BER must be able to + generate and recognize this value." + ::= { ifEntry 22 } + + +-- the Address Translation group + +-- Implementation of the Address Translation group is +-- mandatory for all systems. Note however that this group +-- is deprecated by MIB-II. That is, it is being included + +-- solely for compatibility with MIB-I nodes, and will most +-- likely be excluded from MIB-III nodes. From MIB-II and +-- onwards, each network protocol group contains its own +-- address translation tables. + +-- The Address Translation group contains one table which is +-- the union across all interfaces of the translation tables +-- for converting a NetworkAddress (e.g., an IP address) into +-- a subnetwork-specific address. For lack of a better term, +-- this document refers to such a subnetwork-specific address +-- as a `physical' address. + +-- Examples of such translation tables are: for broadcast +-- media where ARP is in use, the translation table is +-- equivalent to the ARP cache; or, on an X.25 network where +-- non-algorithmic translation to X.121 addresses is +-- required, the translation table contains the +-- NetworkAddress to X.121 address equivalences. + +atTable OBJECT-TYPE + SYNTAX SEQUENCE OF AtEntry + ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The Address Translation tables contain the + NetworkAddress to `physical' address equivalences. + Some interfaces do not use translation tables for + determining address equivalences (e.g., DDN-X.25 + has an algorithmic method); if all interfaces are + of this type, then the Address Translation table + is empty, i.e., has zero entries." + ::= { at 1 } + +atEntry OBJECT-TYPE + SYNTAX AtEntry + ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "Each entry contains one NetworkAddress to + `physical' address equivalence." + INDEX { atIfIndex, + atNetAddress } + ::= { atTable 1 } + +AtEntry ::= + SEQUENCE { + atIfIndex + INTEGER, + atPhysAddress + PhysAddress, + atNetAddress + NetworkAddress + } + +atIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The interface on which this entry's equivalence + is effective. The interface identified by a + particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { atEntry 1 } + +atPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The media-dependent `physical' address. + + Setting this object to a null string (one of zero + length) has the effect of invaliding the + corresponding entry in the atTable object. That + is, it effectively dissasociates the interface + identified with said entry from the mapping + identified with said entry. It is an + implementation-specific matter as to whether the + agent removes an invalidated entry from the table. + Accordingly, management stations must be prepared + to receive tabular information from agents that + corresponds to entries not currently in use. + Proper interpretation of such entries requires + examination of the relevant atPhysAddress object." + ::= { atEntry 2 } + +atNetAddress OBJECT-TYPE + SYNTAX NetworkAddress + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The NetworkAddress (e.g., the IP address) + corresponding to the media-dependent `physical' + address." + ::= { atEntry 3 } + + +-- the IP group + +-- Implementation of the IP group is mandatory for all +-- systems. + +ipForwarding OBJECT-TYPE + SYNTAX INTEGER { + forwarding(1), -- acting as a gateway + not-forwarding(2) -- NOT acting as a gateway + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The indication of whether this entity is acting + as an IP gateway in respect to the forwarding of + datagrams received by, but not addressed to, this + entity. IP gateways forward datagrams. IP hosts + do not (except those source-routed via the host). + + Note that for some managed nodes, this object may + take on only a subset of the values possible. + Accordingly, it is appropriate for an agent to + return a `badValue' response if a management + station attempts to change this object to an + inappropriate value." + ::= { ip 1 } + +ipDefaultTTL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The default value inserted into the Time-To-Live + field of the IP header of datagrams originated at + this entity, whenever a TTL value is not supplied + by the transport layer protocol." + ::= { ip 2 } + +ipInReceives OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of input datagrams received from + interfaces, including those received in error." + ::= { ip 3 } + +ipInHdrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams discarded due to + errors in their IP headers, including bad + checksums, version number mismatch, other format + errors, time-to-live exceeded, errors discovered + in processing their IP options, etc." + ::= { ip 4 } + +ipInAddrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams discarded because + the IP address in their IP header's destination + field was not a valid address to be received at + this entity. This count includes invalid + addresses (e.g., 0.0.0.0) and addresses of + unsupported Classes (e.g., Class E). For entities + which are not IP Gateways and therefore do not + forward datagrams, this counter includes datagrams + discarded because the destination address was not + a local address." + ::= { ip 5 } + +ipForwDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams for which this + entity was not their final IP destination, as a + result of which an attempt was made to find a + route to forward them to that final destination. + In entities which do not act as IP Gateways, this + counter will include only those packets which were + Source-Routed via this entity, and the Source- + Route option processing was successful." + ::= { ip 6 } + +ipInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally-addressed datagrams + received successfully but discarded because of an + unknown or unsupported protocol." + ::= { ip 7 } + +ipInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input IP datagrams for which no + problems were encountered to prevent their + continued processing, but which were discarded + (e.g., for lack of buffer space). Note that this + counter does not include any datagrams discarded + while awaiting re-assembly." + ::= { ip 8 } + +ipInDelivers OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of input datagrams successfully + delivered to IP user-protocols (including ICMP)." + ::= { ip 9 } + +ipOutRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of IP datagrams which local IP + user-protocols (including ICMP) supplied to IP in + requests for transmission. Note that this counter + does not include any datagrams counted in + ipForwDatagrams." + ::= { ip 10 } + +ipOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output IP datagrams for which no + problem was encountered to prevent their + transmission to their destination, but which were + discarded (e.g., for lack of buffer space). Note + that this counter would include datagrams counted + in ipForwDatagrams if any such packets met this + (discretionary) discard criterion." + ::= { ip 11 } + +ipOutNoRoutes OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams discarded because no + route could be found to transmit them to their + destination. Note that this counter includes any + packets counted in ipForwDatagrams which meet this + `no-route' criterion. Note that this includes any + datagarms which a host cannot route because all of + its default gateways are down." + ::= { ip 12 } + +ipReasmTimeout OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum number of seconds which received + fragments are held while they are awaiting + reassembly at this entity." + ::= { ip 13 } + +ipReasmReqds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP fragments received which needed + to be reassembled at this entity." + ::= { ip 14 } + +ipReasmOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams successfully re- + assembled." + ::= { ip 15 } + +ipReasmFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of failures detected by the IP re- + assembly algorithm (for whatever reason: timed + out, errors, etc). Note that this is not + necessarily a count of discarded IP fragments + since some algorithms (notably the algorithm in + RFC 815) can lose track of the number of fragments + by combining them as they are received." + ::= { ip 16 } + +ipFragOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams that have been + successfully fragmented at this entity." + ::= { ip 17 } + +ipFragFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams that have been + discarded because they needed to be fragmented at + this entity but could not be, e.g., because their + Don't Fragment flag was set." + ::= { ip 18 } + +ipFragCreates OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagram fragments that have + been generated as a result of fragmentation at + this entity." + ::= { ip 19 } + +-- the IP address table + +-- The IP address table contains this entity's IP addressing +-- information. + +ipAddrTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddrEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The table of addressing information relevant to + this entity's IP addresses." + ::= { ip 20 } + +ipAddrEntry OBJECT-TYPE + SYNTAX IpAddrEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The addressing information for one of this + entity's IP addresses." + INDEX { ipAdEntAddr } + ::= { ipAddrTable 1 } + +IpAddrEntry ::= + SEQUENCE { + ipAdEntAddr + IpAddress, + ipAdEntIfIndex + INTEGER, + ipAdEntNetMask + IpAddress, + ipAdEntBcastAddr + INTEGER, + ipAdEntReasmMaxSize + INTEGER (0..65535) + } + +ipAdEntAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The IP address to which this entry's addressing + information pertains." + ::= { ipAddrEntry 1 } + +ipAdEntIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index value which uniquely identifies the + interface to which this entry is applicable. The + interface identified by a particular value of this + index is the same interface as identified by the + same value of ifIndex." + ::= { ipAddrEntry 2 } + +ipAdEntNetMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The subnet mask associated with the IP address of + this entry. The value of the mask is an IP + address with all the network bits set to 1 and all + the hosts bits set to 0." + ::= { ipAddrEntry 3 } + +ipAdEntBcastAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The value of the least-significant bit in the IP + broadcast address used for sending datagrams on + the (logical) interface associated with the IP + address of this entry. For example, when the + Internet standard all-ones broadcast address is + used, the value will be 1. This value applies to + both the subnet and network broadcasts addresses + used by the entity on this (logical) interface." + ::= { ipAddrEntry 4 } + +ipAdEntReasmMaxSize OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The size of the largest IP datagram which this + entity can re-assemble from incoming IP fragmented + datagrams received on this interface." + ::= { ipAddrEntry 5 } + +-- the IP routing table + +-- The IP routing table contains an entry for each route +-- presently known to this entity. + +ipRouteTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpRouteEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "This entity's IP Routing table." + ::= { ip 21 } + +ipRouteEntry OBJECT-TYPE + SYNTAX IpRouteEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A route to a particular destination." + INDEX { ipRouteDest } + ::= { ipRouteTable 1 } + +IpRouteEntry ::= + SEQUENCE { + ipRouteDest + IpAddress, + ipRouteIfIndex + INTEGER, + ipRouteMetric1 + INTEGER, + ipRouteMetric2 + INTEGER, + ipRouteMetric3 + INTEGER, + ipRouteMetric4 + INTEGER, + ipRouteNextHop + IpAddress, + ipRouteType + INTEGER, + ipRouteProto + INTEGER, + ipRouteAge + INTEGER, + ipRouteMask + IpAddress, + ipRouteMetric5 + INTEGER, + ipRouteInfo + OBJECT IDENTIFIER + } + +ipRouteDest OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The destination IP address of this route. An + entry with a value of 0.0.0.0 is considered a + default route. Multiple routes to a single + destination can appear in the table, but access to + such multiple entries is dependent on the table- + access mechanisms defined by the network + management protocol in use." + ::= { ipRouteEntry 1 } + +ipRouteIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The index value which uniquely identifies the + local interface through which the next hop of this + route should be reached. The interface identified + by a particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { ipRouteEntry 2 } + +ipRouteMetric1 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The primary routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 3 } + +ipRouteMetric2 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 4 } + +ipRouteMetric3 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 5 } + +ipRouteMetric4 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 6 } + +ipRouteNextHop OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP address of the next hop of this route. + (In the case of a route bound to an interface + which is realized via a broadcast media, the value + of this field is the agent's IP address on that + interface.)" + ::= { ipRouteEntry 7 } + +ipRouteType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + invalid(2), -- an invalidated route + + -- route to directly + direct(3), -- connected (sub-)network + + -- route to a non-local + indirect(4) -- host/network/sub-network + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The type of route. Note that the values + direct(3) and indirect(4) refer to the notion of + direct and indirect routing in the IP + architecture. + + Setting this object to the value invalid(2) has + the effect of invalidating the corresponding entry + in the ipRouteTable object. That is, it + effectively dissasociates the destination + identified with said entry from the route + identified with said entry. It is an + implementation-specific matter as to whether the + agent removes an invalidated entry from the table. + Accordingly, management stations must be prepared + to receive tabular information from agents that + corresponds to entries not currently in use. + Proper interpretation of such entries requires + examination of the relevant ipRouteType object." + ::= { ipRouteEntry 8 } + +ipRouteProto OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + -- non-protocol information, + -- e.g., manually configured + local(2), -- entries + + -- set via a network + netmgmt(3), -- management protocol + + -- obtained via ICMP, + icmp(4), -- e.g., Redirect + + -- the remaining values are + -- all gateway routing + -- protocols + egp(5), + ggp(6), + hello(7), + rip(8), + is-is(9), + es-is(10), + ciscoIgrp(11), + bbnSpfIgp(12), + ospf(13), + bgp(14) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The routing mechanism via which this route was + learned. Inclusion of values for gateway routing + protocols is not intended to imply that hosts + should support those protocols." + ::= { ipRouteEntry 9 } + +ipRouteAge OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of seconds since this route was last + updated or otherwise determined to be correct. + Note that no semantics of `too old' can be implied + except through knowledge of the routing protocol + by which the route was learned." + ::= { ipRouteEntry 10 } + +ipRouteMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicate the mask to be logical-ANDed with the + destination address before being compared to the + value in the ipRouteDest field. For those systems + that do not support arbitrary subnet masks, an + agent constructs the value of the ipRouteMask by + determining whether the value of the correspondent + ipRouteDest field belong to a class-A, B, or C + network, and then using one of: + + mask network + 255.0.0.0 class-A + 255.255.0.0 class-B + 255.255.255.0 class-C + If the value of the ipRouteDest is 0.0.0.0 (a + default route), then the mask value is also + 0.0.0.0. It should be noted that all IP routing + subsystems implicitly use this mechanism." + ::= { ipRouteEntry 11 } + +ipRouteMetric5 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 12 } + +ipRouteInfo OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A reference to MIB definitions specific to the + particular routing protocol which is responsible + for this route, as determined by the value + specified in the route's ipRouteProto value. If + this information is not present, its value should + be set to the OBJECT IDENTIFIER { 0 0 }, which is + a syntatically valid object identifier, and any + conformant implementation of ASN.1 and BER must be + able to generate and recognize this value." + ::= { ipRouteEntry 13 } + + +-- the IP Address Translation table + +-- The IP address translation table contain the IpAddress to +-- `physical' address equivalences. Some interfaces do not +-- use translation tables for determining address +-- equivalences (e.g., DDN-X.25 has an algorithmic method); +-- if all interfaces are of this type, then the Address +-- Translation table is empty, i.e., has zero entries. + +ipNetToMediaTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpNetToMediaEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The IP Address Translation table used for mapping + from IP addresses to physical addresses." + ::= { ip 22 } + +ipNetToMediaEntry OBJECT-TYPE + SYNTAX IpNetToMediaEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Each entry contains one IpAddress to `physical' + address equivalence." + INDEX { ipNetToMediaIfIndex, + ipNetToMediaNetAddress } + ::= { ipNetToMediaTable 1 } + +IpNetToMediaEntry ::= + SEQUENCE { + ipNetToMediaIfIndex + INTEGER, + ipNetToMediaPhysAddress + PhysAddress, + ipNetToMediaNetAddress + IpAddress, + ipNetToMediaType + INTEGER + } + +ipNetToMediaIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The interface on which this entry's equivalence + is effective. The interface identified by a + particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { ipNetToMediaEntry 1 } + +ipNetToMediaPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The media-dependent `physical' address." + ::= { ipNetToMediaEntry 2 } + +ipNetToMediaNetAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IpAddress corresponding to the media- + dependent `physical' address." + ::= { ipNetToMediaEntry 3 } + +ipNetToMediaType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + invalid(2), -- an invalidated mapping + dynamic(3), + static(4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The type of mapping. + + Setting this object to the value invalid(2) has + the effect of invalidating the corresponding entry + in the ipNetToMediaTable. That is, it effectively + dissasociates the interface identified with said + entry from the mapping identified with said entry. + It is an implementation-specific matter as to + whether the agent removes an invalidated entry + from the table. Accordingly, management stations + must be prepared to receive tabular information + from agents that corresponds to entries not + currently in use. Proper interpretation of such + entries requires examination of the relevant + ipNetToMediaType object." + ::= { ipNetToMediaEntry 4 } + + +-- additional IP objects + +ipRoutingDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of routing entries which were chosen + to be discarded even though they are valid. One + possible reason for discarding such an entry could + be to free-up buffer space for other routing + entries." + ::= { ip 23 } + + +-- the ICMP group + +-- Implementation of the ICMP group is mandatory for all +-- systems. + +icmpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ICMP messages which the + entity received. Note that this counter includes + all those counted by icmpInErrors." + ::= { icmp 1 } + +icmpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP messages which the entity + received but determined as having ICMP-specific + errors (bad ICMP checksums, bad length, etc.)." + ::= { icmp 2 } + +icmpInDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Destination Unreachable + messages received." + ::= { icmp 3 } + +icmpInTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Time Exceeded messages + received." + ::= { icmp 4 } + +icmpInParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Parameter Problem messages + received." + ::= { icmp 5 } + +icmpInSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Source Quench messages + received." + ::= { icmp 6 } + +icmpInRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Redirect messages received." + ::= { icmp 7 } + +icmpInEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo (request) messages + received." + ::= { icmp 8 } + +icmpInEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo Reply messages received." + ::= { icmp 9 } + +icmpInTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp (request) messages + received." + ::= { icmp 10 } + +icmpInTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp Reply messages + received." + ::= { icmp 11 } + +icmpInAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Request messages + received." + ::= { icmp 12 } + +icmpInAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Reply messages + received." + ::= { icmp 13 } + +icmpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ICMP messages which this + entity attempted to send. Note that this counter + includes all those counted by icmpOutErrors." + ::= { icmp 14 } + +icmpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP messages which this entity did + not send due to problems discovered within ICMP + such as a lack of buffers. This value should not + include errors discovered outside the ICMP layer + such as the inability of IP to route the resultant + datagram. In some implementations there may be no + types of error which contribute to this counter's + value." + ::= { icmp 15 } + +icmpOutDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Destination Unreachable + messages sent." + ::= { icmp 16 } + +icmpOutTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Time Exceeded messages sent." + ::= { icmp 17 } + +icmpOutParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Parameter Problem messages + sent." + ::= { icmp 18 } + +icmpOutSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Source Quench messages sent." + ::= { icmp 19 } + +icmpOutRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Redirect messages sent. For a + host, this object will always be zero, since hosts + do not send redirects." + ::= { icmp 20 } + +icmpOutEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo (request) messages sent." + ::= { icmp 21 } + +icmpOutEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo Reply messages sent." + ::= { icmp 22 } + +icmpOutTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp (request) messages + sent." + ::= { icmp 23 } + +icmpOutTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp Reply messages + sent." + ::= { icmp 24 } + +icmpOutAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Request messages + sent." + ::= { icmp 25 } + +icmpOutAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Reply messages + sent." + ::= { icmp 26 } + + +-- the TCP group + +-- Implementation of the TCP group is mandatory for all +-- systems that implement the TCP. + +-- Note that instances of object types that represent +-- information about a particular TCP connection are +-- transient; they persist only as long as the connection +-- in question. + +tcpRtoAlgorithm OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + constant(2), -- a constant rto + rsre(3), -- MIL-STD-1778, Appendix B + vanj(4) -- Van Jacobson's algorithm [10] + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The algorithm used to determine the timeout value + used for retransmitting unacknowledged octets." + ::= { tcp 1 } + +tcpRtoMin OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum value permitted by a TCP + implementation for the retransmission timeout, + measured in milliseconds. More refined semantics + for objects of this type depend upon the algorithm + used to determine the retransmission timeout. In + particular, when the timeout algorithm is rsre(3), + an object of this type has the semantics of the + LBOUND quantity described in RFC 793." + ::= { tcp 2 } + + +tcpRtoMax OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum value permitted by a TCP + implementation for the retransmission timeout, + measured in milliseconds. More refined semantics + for objects of this type depend upon the algorithm + used to determine the retransmission timeout. In + particular, when the timeout algorithm is rsre(3), + an object of this type has the semantics of the + UBOUND quantity described in RFC 793." + ::= { tcp 3 } + +tcpMaxConn OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The limit on the total number of TCP connections + the entity can support. In entities where the + maximum number of connections is dynamic, this + object should contain the value -1." + ::= { tcp 4 } + +tcpActiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the SYN-SENT state from the + CLOSED state." + ::= { tcp 5 } + +tcpPassiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the SYN-RCVD state from the + LISTEN state." + ::= { tcp 6 } + +tcpAttemptFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the CLOSED state from either + the SYN-SENT state or the SYN-RCVD state, plus the + number of times TCP connections have made a direct + transition to the LISTEN state from the SYN-RCVD + state." + ::= { tcp 7 } + +tcpEstabResets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the CLOSED state from either + the ESTABLISHED state or the CLOSE-WAIT state." + ::= { tcp 8 } + +tcpCurrEstab OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of TCP connections for which the + current state is either ESTABLISHED or CLOSE- + WAIT." + ::= { tcp 9 } + +tcpInSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments received, including + those received in error. This count includes + segments received on currently established + connections." + ::= { tcp 10 } + +tcpOutSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments sent, including + those on current connections but excluding those + containing only retransmitted octets." + ::= { tcp 11 } + +tcpRetransSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments retransmitted - that + is, the number of TCP segments transmitted + containing one or more previously transmitted + octets." + ::= { tcp 12 } + + +-- the TCP Connection table + +-- The TCP connection table contains information about this +-- entity's existing TCP connections. + +tcpConnTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A table containing TCP connection-specific + information." + ::= { tcp 13 } + +tcpConnEntry OBJECT-TYPE + SYNTAX TcpConnEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about a particular current TCP + connection. An object of this type is transient, + in that it ceases to exist when (or soon after) + the connection makes the transition to the CLOSED + state." + INDEX { tcpConnLocalAddress, + tcpConnLocalPort, + tcpConnRemAddress, + tcpConnRemPort } + ::= { tcpConnTable 1 } + +TcpConnEntry ::= + SEQUENCE { + tcpConnState + INTEGER, + tcpConnLocalAddress + IpAddress, + tcpConnLocalPort + INTEGER (0..65535), + tcpConnRemAddress + IpAddress, + tcpConnRemPort + INTEGER (0..65535) + } + +tcpConnState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The state of this TCP connection. + + The only value which may be set by a management + station is deleteTCB(12). Accordingly, it is + appropriate for an agent to return a `badValue' + response if a management station attempts to set + this object to any other value. + + If a management station sets this object to the + value deleteTCB(12), then this has the effect of + deleting the TCB (as defined in RFC 793) of the + corresponding connection on the managed node, + resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST + segment may be sent from the managed node to the + other TCP endpoint (note however that RST segments + are not sent reliably)." + ::= { tcpConnEntry 1 } + +tcpConnLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local IP address for this TCP connection. In + the case of a connection in the listen state which + is willing to accept connections for any IP + interface associated with the node, the value + 0.0.0.0 is used." + ::= { tcpConnEntry 2 } + +tcpConnLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnEntry 3 } + +tcpConnRemAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote IP address for this TCP connection." + ::= { tcpConnEntry 4 } + +tcpConnRemPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnEntry 5 } + + +-- additional TCP objects + +tcpInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments received in error + (e.g., bad TCP checksums)." + ::= { tcp 14 } + +tcpOutRsts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of TCP segments sent containing the + RST flag." + ::= { tcp 15 } + + +-- the UDP group + +-- Implementation of the UDP group is mandatory for all +-- systems which implement the UDP. + +udpInDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of UDP datagrams delivered to + UDP users." + ::= { udp 1 } + +udpNoPorts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of received UDP datagrams for + which there was no application at the destination + port." + ::= { udp 2 } + +udpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of received UDP datagrams that could + not be delivered for reasons other than the lack + of an application at the destination port." + ::= { udp 3 } + +udpOutDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of UDP datagrams sent from this + entity." + ::= { udp 4 } + + +-- the UDP Listener table + +-- The UDP listener table contains information about this +-- entity's UDP end-points on which a local application is +-- currently accepting datagrams. + +udpTable OBJECT-TYPE + SYNTAX SEQUENCE OF UdpEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A table containing UDP listener information." + ::= { udp 5 } + +udpEntry OBJECT-TYPE + SYNTAX UdpEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about a particular current UDP + listener." + INDEX { udpLocalAddress, udpLocalPort } + ::= { udpTable 1 } + +UdpEntry ::= + SEQUENCE { + udpLocalAddress + IpAddress, + udpLocalPort + INTEGER (0..65535) + } + +udpLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local IP address for this UDP listener. In + the case of a UDP listener which is willing to + accept datagrams for any IP interface associated + with the node, the value 0.0.0.0 is used." + ::= { udpEntry 1 } + +udpLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local port number for this UDP listener." + ::= { udpEntry 2 } + + +-- the EGP group + +-- Implementation of the EGP group is mandatory for all +-- systems which implement the EGP. + +egpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received without + error." + ::= { egp 1 } + +egpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received that proved + to be in error." + ::= { egp 2 } + +egpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of locally generated EGP + messages." + ::= { egp 3 } + +egpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages not + sent due to resource limitations within an EGP + entity." + ::= { egp 4 } + + +-- the EGP Neighbor table + +-- The EGP neighbor table contains information about this +-- entity's EGP neighbors. + +egpNeighTable OBJECT-TYPE + SYNTAX SEQUENCE OF EgpNeighEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The EGP neighbor table." + ::= { egp 5 } + +egpNeighEntry OBJECT-TYPE + SYNTAX EgpNeighEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about this entity's relationship with + a particular EGP neighbor." + INDEX { egpNeighAddr } + ::= { egpNeighTable 1 } + +EgpNeighEntry ::= + SEQUENCE { + egpNeighState + INTEGER, + egpNeighAddr + IpAddress, + egpNeighAs + INTEGER, + egpNeighInMsgs + Counter, + egpNeighInErrs + Counter, + egpNeighOutMsgs + Counter, + egpNeighOutErrs + Counter, + egpNeighInErrMsgs + Counter, + egpNeighOutErrMsgs + Counter, + egpNeighStateUps + Counter, + egpNeighStateDowns + Counter, + egpNeighIntervalHello + INTEGER, + egpNeighIntervalPoll + INTEGER, + egpNeighMode + INTEGER, + egpNeighEventTrigger + INTEGER + } + +egpNeighState OBJECT-TYPE + SYNTAX INTEGER { + idle(1), + acquisition(2), + down(3), + up(4), + cease(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The EGP state of the local system with respect to + this entry's EGP neighbor. Each EGP state is + represented by a value that is one greater than + the numerical value associated with said state in + RFC 904." + ::= { egpNeighEntry 1 } + +egpNeighAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The IP address of this entry's EGP neighbor." + ::= { egpNeighEntry 2 } + +egpNeighAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The autonomous system of this EGP peer. Zero + should be specified if the autonomous system + number of the neighbor is not yet known." + ::= { egpNeighEntry 3 } + +egpNeighInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received without error + from this EGP peer." + ::= { egpNeighEntry 4 } + +egpNeighInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received from this EGP + peer that proved to be in error (e.g., bad EGP + checksum)." + ::= { egpNeighEntry 5 } + +egpNeighOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages to + this EGP peer." + ::= { egpNeighEntry 6 } + +egpNeighOutErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages not + sent to this EGP peer due to resource limitations + within an EGP entity." + ::= { egpNeighEntry 7 } + +egpNeighInErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP-defined error messages received + from this EGP peer." + ::= { egpNeighEntry 8 } + +egpNeighOutErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP-defined error messages sent to + this EGP peer." + ::= { egpNeighEntry 9 } + +egpNeighStateUps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP state transitions to the UP + state with this EGP peer." + ::= { egpNeighEntry 10 } + +egpNeighStateDowns OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP state transitions from the UP + state to any other state with this EGP peer." + ::= { egpNeighEntry 11 } + +egpNeighIntervalHello OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interval between EGP Hello command + retransmissions (in hundredths of a second). This + represents the t1 timer as defined in RFC 904." + ::= { egpNeighEntry 12 } + +egpNeighIntervalPoll OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interval between EGP poll command + retransmissions (in hundredths of a second). This + represents the t3 timer as defined in RFC 904." + ::= { egpNeighEntry 13 } + +egpNeighMode OBJECT-TYPE + SYNTAX INTEGER { active(1), passive(2) } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The polling mode of this EGP entity, either + passive or active." + ::= { egpNeighEntry 14 } + +egpNeighEventTrigger OBJECT-TYPE + SYNTAX INTEGER { start(1), stop(2) } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A control variable used to trigger operator- + initiated Start and Stop events. When read, this + variable always returns the most recent value that + egpNeighEventTrigger was set to. If it has not + been set since the last initialization of the + network management subsystem on the node, it + returns a value of `stop'. + + When set, this variable causes a Start or Stop + event on the specified neighbor, as specified on + pages 8-10 of RFC 904. Briefly, a Start event + causes an Idle peer to begin neighbor acquisition + and a non-Idle peer to reinitiate neighbor + acquisition. A stop event causes a non-Idle peer + to return to the Idle state until a Start event + occurs, either via egpNeighEventTrigger or + otherwise." + ::= { egpNeighEntry 15 } + + +-- additional EGP objects + +egpAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The autonomous system number of this EGP entity." + ::= { egp 6 } + +-- the Transmission group + +-- Based on the transmission media underlying each interface +-- on a system, the corresponding portion of the Transmission +-- group is mandatory for that system. + +-- When Internet-standard definitions for managing +-- transmission media are defined, the transmission group is +-- used to provide a prefix for the names of those objects. + +-- Typically, such definitions reside in the experimental +-- portion of the MIB until they are "proven", then as a +-- part of the Internet standardization process, the +-- definitions are accordingly elevated and a new object +-- identifier, under the transmission group is defined. By +-- convention, the name assigned is: +-- +-- type OBJECT IDENTIFIER ::= { transmission number } +-- +-- where "type" is the symbolic value used for the media in +-- the ifType column of the ifTable object, and "number" is +-- the actual integer value corresponding to the symbol. + + +-- the SNMP group + +-- Implementation of the SNMP group is mandatory for all +-- systems which support an SNMP protocol entity. Some of +-- the objects defined below will be zero-valued in those +-- SNMP implementations that are optimized to support only +-- those functions specific to either a management agent or +-- a management station. In particular, it should be +-- observed that the objects below refer to an SNMP entity, +-- and there may be several SNMP entities residing on a +-- managed node (e.g., if the node is hosting acting as +-- a management station). + +snmpInPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of Messages delivered to the + SNMP entity from the transport service." + ::= { snmp 1 } + +snmpOutPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages which were + passed from the SNMP protocol entity to the + transport service." + ::= { snmp 2 } + +snmpInBadVersions OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages which were + delivered to the SNMP protocol entity and were for + an unsupported SNMP version." + ::= { snmp 3 } + +snmpInBadCommunityNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages delivered to + the SNMP protocol entity which used a SNMP + community name not known to said entity." + ::= { snmp 4 } + +snmpInBadCommunityUses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages delivered to + the SNMP protocol entity which represented an SNMP + operation which was not allowed by the SNMP + community named in the Message." + ::= { snmp 5 } + +snmpInASNParseErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ASN.1 or BER errors + encountered by the SNMP protocol entity when + decoding received SNMP Messages." + ::= { snmp 6 } + +-- { snmp 7 } is not used + +snmpInTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `tooBig'." + ::= { snmp 8 } + +snmpInNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `noSuchName'." + ::= { snmp 9 } + +snmpInBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `badValue'." + ::= { snmp 10 } + +snmpInReadOnlys OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number valid SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `readOnly'. It should be noted that it is a + protocol error to generate an SNMP PDU which + contains the value `readOnly' in the error-status + field, as such this object is provided as a means + of detecting incorrect implementations of the + SNMP." + ::= { snmp 11 } + +snmpInGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `genErr'." + ::= { snmp 12 } + +snmpInTotalReqVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of MIB objects which have been + retrieved successfully by the SNMP protocol entity + as the result of receiving valid SNMP Get-Request + and Get-Next PDUs." + ::= { snmp 13 } + +snmpInTotalSetVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of MIB objects which have been + altered successfully by the SNMP protocol entity + as the result of receiving valid SNMP Set-Request + PDUs." + ::= { snmp 14 } + +snmpInGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 15 } + +snmpInGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have + been accepted and processed by the SNMP protocol + entity." + ::= { snmp 16 } + +snmpInSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 17 } + +snmpInGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 18 } + +snmpInTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Trap PDUs which have + been accepted and processed by the SNMP protocol + entity." + ::= { snmp 19 } + +snmpOutTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `tooBig.'" + ::= { snmp 20 } + +snmpOutNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status is + `noSuchName'." + ::= { snmp 21 } + +snmpOutBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `badValue'." + ::= { snmp 22 } + +-- { snmp 23 } is not used + +snmpOutGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `genErr'." + ::= { snmp 24 } + +snmpOutGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 25 } + +snmpOutGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 26 } + +snmpOutSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 27 } + +snmpOutGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 28 } + +snmpOutTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Trap PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 29 } + +snmpEnableAuthenTraps OBJECT-TYPE + SYNTAX INTEGER { enabled(1), disabled(2) } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates whether the SNMP agent process is + permitted to generate authentication-failure + traps. The value of this object overrides any + configuration information; as such, it provides a + means whereby all authentication-failure traps may + be disabled. + + Note that it is strongly recommended that this + object be stored in non-volatile memory so that it + remains constant between re-initializations of the + network management system." + ::= { snmp 30 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-CONF b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-CONF new file mode 100644 index 0000000..904dbbb --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-CONF @@ -0,0 +1,318 @@ +SNMPv2-CONF DEFINITIONS ::= BEGIN + +IMPORTS ObjectName, NotificationName, ObjectSyntax + FROM SNMPv2-SMI; + +-- definitions for conformance groups + +OBJECT-GROUP MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + Objects ::= + Object + | Objects "," Object + Object ::= + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +-- more definitions for conformance groups + +NOTIFICATION-GROUP MACRO ::= +BEGIN + TYPE NOTATION ::= + NotificationsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + NotificationsPart ::= + "NOTIFICATIONS" "{" Notifications "}" + Notifications ::= + Notification + | Notifications "," Notification + Notification ::= + value(NotificationName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +-- definitions for compliance statements + +MODULE-COMPLIANCE MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + ReferPart + ModulePart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + ModulePart ::= + Modules + Modules ::= + Module + | Modules Module + Module ::= + -- name of module -- + "MODULE" ModuleName + MandatoryPart + CompliancePart + + ModuleName ::= + -- identifier must start with uppercase letter + identifier ModuleIdentifier + -- must not be empty unless contained + -- in MIB Module + | empty + ModuleIdentifier ::= + value(OBJECT IDENTIFIER) + | empty + + MandatoryPart ::= + "MANDATORY-GROUPS" "{" Groups "}" + | empty + + Groups ::= + Group + | Groups "," Group + Group ::= + value(OBJECT IDENTIFIER) + + CompliancePart ::= + Compliances + | empty + + Compliances ::= + Compliance + | Compliances Compliance + Compliance ::= + ComplianceGroup + | Object + + ComplianceGroup ::= + "GROUP" value(OBJECT IDENTIFIER) + "DESCRIPTION" Text + + Object ::= + "OBJECT" value(ObjectName) + SyntaxPart + WriteSyntaxPart + AccessPart + "DESCRIPTION" Text + + -- must be a refinement for object's SYNTAX clause + SyntaxPart ::= "SYNTAX" Syntax + | empty + + -- must be a refinement for object's SYNTAX clause + WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax + | empty + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + AccessPart ::= + "MIN-ACCESS" Access + | empty + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +-- definitions for capabilities statements + +AGENT-CAPABILITIES MACRO ::= +BEGIN + TYPE NOTATION ::= + "PRODUCT-RELEASE" Text + "STATUS" Status + "DESCRIPTION" Text + ReferPart + ModulePart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + ModulePart ::= + Modules + | empty + Modules ::= + Module + | Modules Module + Module ::= + -- name of module -- + "SUPPORTS" ModuleName + "INCLUDES" "{" Groups "}" + VariationPart + + ModuleName ::= + -- identifier must start with uppercase letter + identifier ModuleIdentifier + ModuleIdentifier ::= + value(OBJECT IDENTIFIER) + | empty + + Groups ::= + Group + | Groups "," Group + Group ::= + value(OBJECT IDENTIFIER) + + VariationPart ::= + Variations + | empty + Variations ::= + Variation + | Variations Variation + + Variation ::= + ObjectVariation + | NotificationVariation + + NotificationVariation ::= + "VARIATION" value(NotificationName) + AccessPart + "DESCRIPTION" Text + + ObjectVariation ::= + "VARIATION" value(ObjectName) + SyntaxPart + WriteSyntaxPart + AccessPart + CreationPart + DefValPart + "DESCRIPTION" Text + + -- must be a refinement for object's SYNTAX clause + SyntaxPart ::= "SYNTAX" Syntax + | empty + + WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax + | empty + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + AccessPart ::= + "ACCESS" Access + | empty + + Access ::= + "not-implemented" + -- only "not-implemented" for notifications + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + -- following is for backward-compatibility only + | "write-only" + + CreationPart ::= + "CREATION-REQUIRES" "{" Cells "}" + | empty + Cells ::= + Cell + | Cells "," Cell + Cell ::= + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + Defvalue ::= -- must be valid for the object's syntax + -- in this macro's SYNTAX clause, if present, + -- or if not, in object's OBJECT-TYPE macro + value(ObjectSyntax) + | "{" BitsValue "}" + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-MIB b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-MIB new file mode 100644 index 0000000..9494e42 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-MIB @@ -0,0 +1,903 @@ +SNMPv2-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + TimeTicks, Counter32, snmpModules, mib-2 + FROM SNMPv2-SMI + DisplayString, TestAndIncr, TimeStamp + + + + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF; + +snmpMIB MODULE-IDENTITY + LAST-UPDATED "200210160000Z" + ORGANIZATION "IETF SNMPv3 Working Group" + CONTACT-INFO + "WG-EMail: snmpv3@lists.tislabs.com + Subscribe: snmpv3-request@lists.tislabs.com + + Co-Chair: Russ Mundy + Network Associates Laboratories + postal: 15204 Omega Drive, Suite 300 + Rockville, MD 20850-4601 + USA + EMail: mundy@tislabs.com + phone: +1 301 947-7107 + + Co-Chair: David Harrington + Enterasys Networks + postal: 35 Industrial Way + P. O. Box 5005 + Rochester, NH 03866-5005 + USA + EMail: dbh@enterasys.com + phone: +1 603 337-2614 + + Editor: Randy Presuhn + BMC Software, Inc. + postal: 2141 North First Street + San Jose, CA 95131 + USA + EMail: randy_presuhn@bmc.com + phone: +1 408 546-1006" + DESCRIPTION + "The MIB module for SNMP entities. + + Copyright (C) The Internet Society (2002). This + version of this MIB module is part of RFC 3418; + see the RFC itself for full legal notices. + " + REVISION "200210160000Z" + DESCRIPTION + "This revision of this MIB module was published as + RFC 3418." + REVISION "199511090000Z" + DESCRIPTION + + + + "This revision of this MIB module was published as + RFC 1907." + REVISION "199304010000Z" + DESCRIPTION + "The initial revision of this MIB module was published + as RFC 1450." + ::= { snmpModules 1 } + +snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 } + +-- ::= { snmpMIBObjects 1 } this OID is obsolete +-- ::= { snmpMIBObjects 2 } this OID is obsolete +-- ::= { snmpMIBObjects 3 } this OID is obsolete + +-- the System group +-- +-- a collection of objects common to all managed systems. + +system OBJECT IDENTIFIER ::= { mib-2 1 } + +sysDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A textual description of the entity. This value should + include the full name and version identification of + the system's hardware type, software operating-system, + and networking software." + ::= { system 1 } + +sysObjectID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The vendor's authoritative identification of the + network management subsystem contained in the entity. + This value is allocated within the SMI enterprises + subtree (1.3.6.1.4.1) and provides an easy and + unambiguous means for determining `what kind of box' is + being managed. For example, if vendor `Flintstones, + Inc.' was assigned the subtree 1.3.6.1.4.1.424242, + it could assign the identifier 1.3.6.1.4.1.424242.1.1 + to its `Fred Router'." + ::= { system 2 } + +sysUpTime OBJECT-TYPE + + + + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The time (in hundredths of a second) since the + network management portion of the system was last + re-initialized." + ::= { system 3 } + +sysContact OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The textual identification of the contact person for + this managed node, together with information on how + to contact this person. If no contact information is + known, the value is the zero-length string." + ::= { system 4 } + +sysName OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "An administratively-assigned name for this managed + node. By convention, this is the node's fully-qualified + domain name. If the name is unknown, the value is + the zero-length string." + ::= { system 5 } + +sysLocation OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The physical location of this node (e.g., 'telephone + closet, 3rd floor'). If the location is unknown, the + value is the zero-length string." + ::= { system 6 } + +sysServices OBJECT-TYPE + SYNTAX INTEGER (0..127) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A value which indicates the set of services that this + entity may potentially offer. The value is a sum. + + + + This sum initially takes the value zero. Then, for + each layer, L, in the range 1 through 7, that this node + performs transactions for, 2 raised to (L - 1) is added + to the sum. For example, a node which performs only + routing functions would have a value of 4 (2^(3-1)). + In contrast, a node which is a host offering application + services would have a value of 72 (2^(4-1) + 2^(7-1)). + Note that in the context of the Internet suite of + protocols, values should be calculated accordingly: + + layer functionality + 1 physical (e.g., repeaters) + 2 datalink/subnetwork (e.g., bridges) + 3 internet (e.g., supports the IP) + 4 end-to-end (e.g., supports the TCP) + 7 applications (e.g., supports the SMTP) + + For systems including OSI protocols, layers 5 and 6 + may also be counted." + ::= { system 7 } + +-- object resource information +-- +-- a collection of objects which describe the SNMP entity's +-- (statically and dynamically configurable) support of +-- various MIB modules. + +sysORLastChange OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime at the time of the most recent + change in state or value of any instance of sysORID." + ::= { system 8 } + +sysORTable OBJECT-TYPE + SYNTAX SEQUENCE OF SysOREntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The (conceptual) table listing the capabilities of + the local SNMP application acting as a command + responder with respect to various MIB modules. + SNMP entities having dynamically-configurable support + of MIB modules will have a dynamically-varying number + of conceptual rows." + ::= { system 9 } + + + +sysOREntry OBJECT-TYPE + SYNTAX SysOREntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry (conceptual row) in the sysORTable." + INDEX { sysORIndex } + ::= { sysORTable 1 } + +SysOREntry ::= SEQUENCE { + sysORIndex INTEGER, + sysORID OBJECT IDENTIFIER, + sysORDescr DisplayString, + sysORUpTime TimeStamp +} + +sysORIndex OBJECT-TYPE + SYNTAX INTEGER (1..2147483647) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The auxiliary variable used for identifying instances + of the columnar objects in the sysORTable." + ::= { sysOREntry 1 } + +sysORID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An authoritative identification of a capabilities + statement with respect to various MIB modules supported + by the local SNMP application acting as a command + responder." + ::= { sysOREntry 2 } + +sysORDescr OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A textual description of the capabilities identified + by the corresponding instance of sysORID." + ::= { sysOREntry 3 } + +sysORUpTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + + + + STATUS current + DESCRIPTION + "The value of sysUpTime at the time this conceptual + row was last instantiated." + ::= { sysOREntry 4 } + + +-- the SNMP group +-- +-- a collection of objects providing basic instrumentation and +-- control of an SNMP entity. + +snmp OBJECT IDENTIFIER ::= { mib-2 11 } + +snmpInPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of messages delivered to the SNMP + entity from the transport service." + ::= { snmp 1 } + +snmpInBadVersions OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of SNMP messages which were delivered + to the SNMP entity and were for an unsupported SNMP + version." + ::= { snmp 3 } + +snmpInBadCommunityNames OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of community-based SNMP messages (for + example, SNMPv1) delivered to the SNMP entity which + used an SNMP community name not known to said entity. + Also, implementations which authenticate community-based + SNMP messages using check(s) in addition to matching + the community name (for example, by also checking + whether the message originated from a transport address + allowed to use a specified community name) MAY include + in this value the number of messages which failed the + additional check(s). It is strongly RECOMMENDED that + + + + the documentation for any security model which is used + to authenticate community-based SNMP messages specify + the precise conditions that contribute to this value." + ::= { snmp 4 } + +snmpInBadCommunityUses OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of community-based SNMP messages (for + example, SNMPv1) delivered to the SNMP entity which + represented an SNMP operation that was not allowed for + the SNMP community named in the message. The precise + conditions under which this counter is incremented + (if at all) depend on how the SNMP entity implements + its access control mechanism and how its applications + interact with that access control mechanism. It is + strongly RECOMMENDED that the documentation for any + access control mechanism which is used to control access + to and visibility of MIB instrumentation specify the + precise conditions that contribute to this value." + ::= { snmp 5 } + +snmpInASNParseErrs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of ASN.1 or BER errors encountered by + the SNMP entity when decoding received SNMP messages." + ::= { snmp 6 } + +snmpEnableAuthenTraps OBJECT-TYPE + SYNTAX INTEGER { enabled(1), disabled(2) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Indicates whether the SNMP entity is permitted to + generate authenticationFailure traps. The value of this + object overrides any configuration information; as such, + it provides a means whereby all authenticationFailure + traps may be disabled. + + Note that it is strongly recommended that this object + be stored in non-volatile memory so that it remains + constant across re-initializations of the network + management system." + + + + ::= { snmp 30 } + +snmpSilentDrops OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Confirmed Class PDUs (such as + GetRequest-PDUs, GetNextRequest-PDUs, + GetBulkRequest-PDUs, SetRequest-PDUs, and + InformRequest-PDUs) delivered to the SNMP entity which + were silently dropped because the size of a reply + containing an alternate Response Class PDU (such as a + Response-PDU) with an empty variable-bindings field + was greater than either a local constraint or the + maximum message size associated with the originator of + the request." + ::= { snmp 31 } + +snmpProxyDrops OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Confirmed Class PDUs + (such as GetRequest-PDUs, GetNextRequest-PDUs, + GetBulkRequest-PDUs, SetRequest-PDUs, and + InformRequest-PDUs) delivered to the SNMP entity which + were silently dropped because the transmission of + the (possibly translated) message to a proxy target + failed in a manner (other than a time-out) such that + no Response Class PDU (such as a Response-PDU) could + be returned." + ::= { snmp 32 } + +-- information for notifications +-- +-- a collection of objects which allow the SNMP entity, when +-- supporting a notification originator application, +-- to be configured to generate SNMPv2-Trap-PDUs. + +snmpTrap OBJECT IDENTIFIER ::= { snmpMIBObjects 4 } + +snmpTrapOID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + + + + "The authoritative identification of the notification + currently being sent. This variable occurs as + the second varbind in every SNMPv2-Trap-PDU and + InformRequest-PDU." + ::= { snmpTrap 1 } + +-- ::= { snmpTrap 2 } this OID is obsolete + +snmpTrapEnterprise OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "The authoritative identification of the enterprise + associated with the trap currently being sent. When an + SNMP proxy agent is mapping an RFC1157 Trap-PDU + into a SNMPv2-Trap-PDU, this variable occurs as the + last varbind." + ::= { snmpTrap 3 } + +-- ::= { snmpTrap 4 } this OID is obsolete + + +-- well-known traps + +snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 } + +coldStart NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "A coldStart trap signifies that the SNMP entity, + supporting a notification originator application, is + reinitializing itself and that its configuration may + have been altered." + ::= { snmpTraps 1 } + +warmStart NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "A warmStart trap signifies that the SNMP entity, + supporting a notification originator application, + is reinitializing itself such that its configuration + is unaltered." + ::= { snmpTraps 2 } + +-- Note the linkDown NOTIFICATION-TYPE ::= { snmpTraps 3 } +-- and the linkUp NOTIFICATION-TYPE ::= { snmpTraps 4 } +-- are defined in RFC 2863 [RFC2863] + + + +authenticationFailure NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "An authenticationFailure trap signifies that the SNMP + entity has received a protocol message that is not + properly authenticated. While all implementations + of SNMP entities MAY be capable of generating this + trap, the snmpEnableAuthenTraps object indicates + whether this trap will be generated." + ::= { snmpTraps 5 } + +-- Note the egpNeighborLoss notification is defined +-- as { snmpTraps 6 } in RFC 1213 + +-- the set group +-- +-- a collection of objects which allow several cooperating +-- command generator applications to coordinate their use of the +-- set operation. + +snmpSet OBJECT IDENTIFIER ::= { snmpMIBObjects 6 } + +snmpSetSerialNo OBJECT-TYPE + SYNTAX TestAndIncr + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "An advisory lock used to allow several cooperating + command generator applications to coordinate their + use of the SNMP set operation. + + This object is used for coarse-grain coordination. + To achieve fine-grain coordination, one or more similar + objects might be defined within each MIB group, as + appropriate." + ::= { snmpSet 1 } + +-- conformance information + +snmpMIBConformance + OBJECT IDENTIFIER ::= { snmpMIB 2 } + +snmpMIBCompliances + OBJECT IDENTIFIER ::= { snmpMIBConformance 1 } +snmpMIBGroups OBJECT IDENTIFIER ::= { snmpMIBConformance 2 } + +-- compliance statements + + + + +-- ::= { snmpMIBCompliances 1 } this OID is obsolete +snmpBasicCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for SNMPv2 entities which + implement the SNMPv2 MIB. + + This compliance statement is replaced by + snmpBasicComplianceRev2." + MODULE -- this module + MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup, + snmpBasicNotificationsGroup } + + GROUP snmpCommunityGroup + DESCRIPTION + "This group is mandatory for SNMPv2 entities which + support community-based authentication." + + ::= { snmpMIBCompliances 2 } + +snmpBasicComplianceRev2 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for SNMP entities which + implement this MIB module." + MODULE -- this module + MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup, + snmpBasicNotificationsGroup } + + GROUP snmpCommunityGroup + DESCRIPTION + "This group is mandatory for SNMP entities which + support community-based authentication." + + GROUP snmpWarmStartNotificationGroup + DESCRIPTION + "This group is mandatory for an SNMP entity which + supports command responder applications, and is + able to reinitialize itself such that its + configuration is unaltered." + + ::= { snmpMIBCompliances 3 } + +-- units of conformance + +-- ::= { snmpMIBGroups 1 } this OID is obsolete +-- ::= { snmpMIBGroups 2 } this OID is obsolete +-- ::= { snmpMIBGroups 3 } this OID is obsolete + + + +-- ::= { snmpMIBGroups 4 } this OID is obsolete + +snmpGroup OBJECT-GROUP + OBJECTS { snmpInPkts, + snmpInBadVersions, + snmpInASNParseErrs, + snmpSilentDrops, + snmpProxyDrops, + snmpEnableAuthenTraps } + STATUS current + DESCRIPTION + "A collection of objects providing basic instrumentation + and control of an SNMP entity." + ::= { snmpMIBGroups 8 } + +snmpCommunityGroup OBJECT-GROUP + OBJECTS { snmpInBadCommunityNames, + snmpInBadCommunityUses } + STATUS current + DESCRIPTION + "A collection of objects providing basic instrumentation + of a SNMP entity which supports community-based + authentication." + ::= { snmpMIBGroups 9 } + +snmpSetGroup OBJECT-GROUP + OBJECTS { snmpSetSerialNo } + STATUS current + DESCRIPTION + "A collection of objects which allow several cooperating + command generator applications to coordinate their + use of the set operation." + ::= { snmpMIBGroups 5 } + +systemGroup OBJECT-GROUP + OBJECTS { sysDescr, sysObjectID, sysUpTime, + sysContact, sysName, sysLocation, + sysServices, + sysORLastChange, sysORID, + sysORUpTime, sysORDescr } + STATUS current + DESCRIPTION + "The system group defines objects which are common to all + managed systems." + ::= { snmpMIBGroups 6 } + +snmpBasicNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { coldStart, authenticationFailure } + + + + STATUS current + DESCRIPTION + "The basic notifications implemented by an SNMP entity + supporting command responder applications." + ::= { snmpMIBGroups 7 } + +snmpWarmStartNotificationGroup NOTIFICATION-GROUP + NOTIFICATIONS { warmStart } + STATUS current + DESCRIPTION + "An additional notification for an SNMP entity supporting + command responder applications, if it is able to reinitialize + itself such that its configuration is unaltered." + ::= { snmpMIBGroups 11 } + +snmpNotificationGroup OBJECT-GROUP + OBJECTS { snmpTrapOID, snmpTrapEnterprise } + STATUS current + DESCRIPTION + "These objects are required for entities + which support notification originator applications." + ::= { snmpMIBGroups 12 } + +-- definitions in RFC 1213 made obsolete by the inclusion of a +-- subset of the snmp group in this MIB + +snmpOutPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Messages which were + passed from the SNMP protocol entity to the + transport service." + ::= { snmp 2 } + +-- { snmp 7 } is not used + +snmpInTooBigs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field was + `tooBig'." + ::= { snmp 8 } + + + +snmpInNoSuchNames OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field was + `noSuchName'." + ::= { snmp 9 } + +snmpInBadValues OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field was + `badValue'." + ::= { snmp 10 } + +snmpInReadOnlys OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number valid SNMP PDUs which were delivered + to the SNMP protocol entity and for which the value + of the error-status field was `readOnly'. It should + be noted that it is a protocol error to generate an + SNMP PDU which contains the value `readOnly' in the + error-status field, as such this object is provided + as a means of detecting incorrect implementations of + the SNMP." + ::= { snmp 11 } + +snmpInGenErrs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were delivered + to the SNMP protocol entity and for which the value + of the error-status field was `genErr'." + ::= { snmp 12 } + +snmpInTotalReqVars OBJECT-TYPE + + + + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of MIB objects which have been + retrieved successfully by the SNMP protocol entity + as the result of receiving valid SNMP Get-Request + and Get-Next PDUs." + ::= { snmp 13 } + +snmpInTotalSetVars OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of MIB objects which have been + altered successfully by the SNMP protocol entity as + the result of receiving valid SNMP Set-Request PDUs." + ::= { snmp 14 } + +snmpInGetRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 15 } + +snmpInGetNexts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have been + accepted and processed by the SNMP protocol entity." + ::= { snmp 16 } + +snmpInSetRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been accepted and processed by the SNMP protocol + entity." + ::= { snmp 17 } + + + +snmpInGetResponses OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been accepted and processed by the SNMP protocol + entity." + ::= { snmp 18 } + +snmpInTraps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Trap PDUs which have been + accepted and processed by the SNMP protocol entity." + ::= { snmp 19 } + +snmpOutTooBigs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were generated + by the SNMP protocol entity and for which the value + of the error-status field was `tooBig.'" + ::= { snmp 20 } + +snmpOutNoSuchNames OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were generated + by the SNMP protocol entity and for which the value + of the error-status was `noSuchName'." + ::= { snmp 21 } + +snmpOutBadValues OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were generated + by the SNMP protocol entity and for which the value + of the error-status field was `badValue'." + ::= { snmp 22 } + + + +-- { snmp 23 } is not used + +snmpOutGenErrs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP PDUs which were generated + by the SNMP protocol entity and for which the value + of the error-status field was `genErr'." + ::= { snmp 24 } + +snmpOutGetRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 25 } + +snmpOutGetNexts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 26 } + +snmpOutSetRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 27 } + +snmpOutGetResponses OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 28 } + + + + +snmpOutTraps OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The total number of SNMP Trap PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 29 } + +snmpObsoleteGroup OBJECT-GROUP + OBJECTS { snmpOutPkts, snmpInTooBigs, snmpInNoSuchNames, + snmpInBadValues, snmpInReadOnlys, snmpInGenErrs, + snmpInTotalReqVars, snmpInTotalSetVars, + snmpInGetRequests, snmpInGetNexts, snmpInSetRequests, + snmpInGetResponses, snmpInTraps, snmpOutTooBigs, + snmpOutNoSuchNames, snmpOutBadValues, + snmpOutGenErrs, snmpOutGetRequests, snmpOutGetNexts, + snmpOutSetRequests, snmpOutGetResponses, snmpOutTraps + } + STATUS obsolete + DESCRIPTION + "A collection of objects from RFC 1213 made obsolete + by this MIB module." + ::= { snmpMIBGroups 10 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-SMI b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-SMI new file mode 100644 index 0000000..2132646 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-SMI @@ -0,0 +1,352 @@ +SNMPv2-SMI DEFINITIONS ::= BEGIN + + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 6 } +internet OBJECT IDENTIFIER ::= { dod 1 } + +directory OBJECT IDENTIFIER ::= { internet 1 } + +mgmt OBJECT IDENTIFIER ::= { internet 2 } +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +experimental OBJECT IDENTIFIER ::= { internet 3 } + +private OBJECT IDENTIFIER ::= { internet 4 } +enterprises OBJECT IDENTIFIER ::= { private 1 } + +security OBJECT IDENTIFIER ::= { internet 5 } + +snmpV2 OBJECT IDENTIFIER ::= { internet 6 } + +-- transport domains +snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 } + +-- transport proxies +snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 } + +-- module identities +snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 } + +-- Extended UTCTime, to allow dates with four-digit years +-- (Note that this definition of ExtUTCTime is not to be IMPORTed +-- by MIB modules.) +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + +-- syntax of objects + +-- the "base types" defined here are: +-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER +-- 8 application-defined types: Integer32, IpAddress, Counter32, +-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64 + +ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + + -- note that SEQUENCEs for conceptual tables and + -- rows are not mentioned here... + + application-wide + ApplicationSyntax + } + +-- built-in ASN.1 types + +SimpleSyntax ::= + CHOICE { + -- INTEGERs with a more restrictive range + -- may also be used + integer-value -- includes Integer32 + INTEGER (-2147483648..2147483647), + + -- OCTET STRINGs with a more restrictive size + -- may also be used + string-value + OCTET STRING (SIZE (0..65535)), + + objectID-value + OBJECT IDENTIFIER + } + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + + +-- application-wide types + +ApplicationSyntax ::= + CHOICE { + ipAddress-value + IpAddress, + + counter-value + Counter32, + + timeticks-value + TimeTicks, + + arbitrary-value + Opaque, + + big-counter-value + Counter64, + + unsigned-integer-value -- includes Gauge32 + Unsigned32 + } + +-- in network-byte order +-- (this is a tagged type for historical reasons) +IpAddress ::= + [APPLICATION 0] + IMPLICIT OCTET STRING (SIZE (4)) + +-- this wraps +Counter32 ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + +-- this doesn't wrap +Gauge32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- an unsigned 32-bit quantity +-- indistinguishable from Gauge32 +Unsigned32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- hundredths of seconds since an epoch +TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER (0..4294967295) + +-- for backward-compatibility only +Opaque ::= + [APPLICATION 4] + IMPLICIT OCTET STRING + +-- for counters that wrap in less than one hour with only 32 bits +Counter64 ::= + [APPLICATION 6] + IMPLICIT INTEGER (0..18446744073709551615) + + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + "SYNTAX" Syntax + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + Index ::= + -- use the SYNTAX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + Defvalue ::= -- must be valid for the type specified in + -- SYNTAX clause of same OBJECT-TYPE macro + value(ObjectSyntax) + | "{" BitsValue "}" + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + + +-- definitions for notifications + +NOTIFICATION-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE NotificationName) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + | empty + Objects ::= + Object + | Objects "," Object + Object ::= + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- definitions of administrative identifiers + +zeroDotZero OBJECT-IDENTITY + STATUS current + DESCRIPTION + "A value used for null identifiers." + ::= { 0 0 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TC b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TC new file mode 100644 index 0000000..a68f969 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TC @@ -0,0 +1,786 @@ +SNMPv2-TC DEFINITIONS ::= BEGIN + +IMPORTS + TimeTicks FROM SNMPv2-SMI; + + +-- definition of textual conventions + +TEXTUAL-CONVENTION MACRO ::= +BEGIN + TYPE NOTATION ::= + DisplayPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + "SYNTAX" Syntax + + VALUE NOTATION ::= + value(VALUE Syntax) -- adapted ASN.1 + + DisplayPart ::= + "DISPLAY-HINT" Text + | empty + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + +END + + + + +DisplayString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS current + DESCRIPTION + "Represents textual information taken from the NVT ASCII + character set, as defined in pages 4, 10-11 of RFC 854. + + To summarize RFC 854, the NVT ASCII repertoire specifies: + + - the use of character codes 0-127 (decimal) + + - the graphics characters (32-126) are interpreted as + US ASCII + + - NUL, LF, CR, BEL, BS, HT, VT and FF have the special + meanings specified in RFC 854 + + - the other 25 codes have no standard interpretation + + - the sequence 'CR LF' means newline + + - the sequence 'CR NUL' means carriage-return + + - an 'LF' not preceded by a 'CR' means moving to the + same column on the next line. + + - the sequence 'CR x' for any x other than LF or NUL is + illegal. (Note that this also means that a string may + end with either 'CR LF' or 'CR NUL', but not with CR.) + + Any object defined using this syntax may not exceed 255 + characters in length." + SYNTAX OCTET STRING (SIZE (0..255)) + +PhysAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1x:" + STATUS current + DESCRIPTION + "Represents media- or physical-level addresses." + SYNTAX OCTET STRING + + +MacAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1x:" + STATUS current + DESCRIPTION + "Represents an 802 MAC address represented in the + `canonical' order defined by IEEE 802.1a, i.e., as if it + were transmitted least significant bit first, even though + 802.5 (in contrast to other 802.x protocols) requires MAC + addresses to be transmitted most significant bit first." + SYNTAX OCTET STRING (SIZE (6)) + +TruthValue ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents a boolean value." + SYNTAX INTEGER { true(1), false(2) } + +TestAndIncr ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents integer-valued information used for atomic + operations. When the management protocol is used to specify + that an object instance having this syntax is to be + modified, the new value supplied via the management protocol + must precisely match the value presently held by the + instance. If not, the management protocol set operation + fails with an error of `inconsistentValue'. Otherwise, if + the current value is the maximum value of 2^31-1 (2147483647 + decimal), then the value held by the instance is wrapped to + zero; otherwise, the value held by the instance is + incremented by one. (Note that regardless of whether the + management protocol set operation succeeds, the variable- + binding in the request and response PDUs are identical.) + + The value of the ACCESS clause for objects having this + syntax is either `read-write' or `read-create'. When an + instance of a columnar object having this syntax is created, + any value may be supplied via the management protocol. + + When the network management portion of the system is re- + initialized, the value of every object instance having this + syntax must either be incremented from its value prior to + the re-initialization, or (if the value prior to the re- + initialization is unknown) be set to a pseudo-randomly + generated value." + SYNTAX INTEGER (0..2147483647) + +AutonomousType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents an independently extensible type identification + value. It may, for example, indicate a particular sub-tree + with further MIB definitions, or define a particular type of + protocol or hardware." + SYNTAX OBJECT IDENTIFIER + + +InstancePointer ::= TEXTUAL-CONVENTION + STATUS obsolete + DESCRIPTION + "A pointer to either a specific instance of a MIB object or + a conceptual row of a MIB table in the managed device. In + the latter case, by convention, it is the name of the + particular instance of the first accessible columnar object + in the conceptual row. + + The two uses of this textual convention are replaced by + VariablePointer and RowPointer, respectively." + SYNTAX OBJECT IDENTIFIER + + +VariablePointer ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A pointer to a specific object instance. For example, + sysContact.0 or ifInOctets.3." + SYNTAX OBJECT IDENTIFIER + + +RowPointer ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents a pointer to a conceptual row. The value is the + name of the instance of the first accessible columnar object + in the conceptual row. + + For example, ifIndex.3 would point to the 3rd row in the + ifTable (note that if ifIndex were not-accessible, then + ifDescr.3 would be used instead)." + SYNTAX OBJECT IDENTIFIER + +RowStatus ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The RowStatus textual convention is used to manage the + creation and deletion of conceptual rows, and is used as the + value of the SYNTAX clause for the status column of a + conceptual row (as described in Section 7.7.1 of [2].) + The status column has six defined values: + + - `active', which indicates that the conceptual row is + available for use by the managed device; + + - `notInService', which indicates that the conceptual + row exists in the agent, but is unavailable for use by + the managed device (see NOTE below); 'notInService' has + no implication regarding the internal consistency of + the row, availability of resources, or consistency with + the current state of the managed device; + + - `notReady', which indicates that the conceptual row + exists in the agent, but is missing information + necessary in order to be available for use by the + managed device (i.e., one or more required columns in + the conceptual row have not been instanciated); + + - `createAndGo', which is supplied by a management + station wishing to create a new instance of a + conceptual row and to have its status automatically set + to active, making it available for use by the managed + device; + + - `createAndWait', which is supplied by a management + station wishing to create a new instance of a + conceptual row (but not make it available for use by + the managed device); and, + + - `destroy', which is supplied by a management station + wishing to delete all of the instances associated with + an existing conceptual row. + + Whereas five of the six values (all except `notReady') may + be specified in a management protocol set operation, only + three values will be returned in response to a management + protocol retrieval operation: `notReady', `notInService' or + `active'. That is, when queried, an existing conceptual row + has only three states: it is either available for use by + the managed device (the status column has value `active'); + it is not available for use by the managed device, though + the agent has sufficient information to attempt to make it + so (the status column has value `notInService'); or, it is + not available for use by the managed device, and an attempt + to make it so would fail because the agent has insufficient + information (the state column has value `notReady'). + + NOTE WELL + + This textual convention may be used for a MIB table, + irrespective of whether the values of that table's + conceptual rows are able to be modified while it is + active, or whether its conceptual rows must be taken + out of service in order to be modified. That is, it is + the responsibility of the DESCRIPTION clause of the + status column to specify whether the status column must + not be `active' in order for the value of some other + column of the same conceptual row to be modified. If + such a specification is made, affected columns may be + changed by an SNMP set PDU if the RowStatus would not + be equal to `active' either immediately before or after + processing the PDU. In other words, if the PDU also + contained a varbind that would change the RowStatus + value, the column in question may be changed if the + RowStatus was not equal to `active' as the PDU was + received, or if the varbind sets the status to a value + other than 'active'. + + + Also note that whenever any elements of a row exist, the + RowStatus column must also exist. + + To summarize the effect of having a conceptual row with a + status column having a SYNTAX clause value of RowStatus, + consider the following state diagram: + + + STATE + +--------------+-----------+-------------+------------- + | A | B | C | D + | |status col.|status column| + |status column | is | is |status column + ACTION |does not exist| notReady | notInService| is active +--------------+--------------+-----------+-------------+------------- +set status |noError ->D|inconsist- |inconsistent-|inconsistent- +column to | or | entValue| Value| Value +createAndGo |inconsistent- | | | + | Value| | | +--------------+--------------+-----------+-------------+------------- +set status |noError see 1|inconsist- |inconsistent-|inconsistent- +column to | or | entValue| Value| Value +createAndWait |wrongValue | | | +--------------+--------------+-----------+-------------+------------- +set status |inconsistent- |inconsist- |noError |noError +column to | Value| entValue| | +active | | | | + | | or | | + | | | | + | |see 2 ->D|see 8 ->D| ->D +--------------+--------------+-----------+-------------+------------- +set status |inconsistent- |inconsist- |noError |noError ->C +column to | Value| entValue| | +notInService | | | | + | | or | | or + | | | | + | |see 3 ->C| ->C|see 6 +--------------+--------------+-----------+-------------+------------- +set status |noError |noError |noError |noError ->A +column to | | | | or +destroy | ->A| ->A| ->A|see 7 +--------------+--------------+-----------+-------------+------------- +set any other |see 4 |noError |noError |see 5 +column to some| | | | +value | | see 1| ->C| ->D +--------------+--------------+-----------+-------------+------------- + + (1) goto B or C, depending on information available to the + agent. + + (2) if other variable bindings included in the same PDU, + provide values for all columns which are missing but + required, and all columns have acceptable values, then + return noError and goto D. + + (3) if other variable bindings included in the same PDU, + provide legal values for all columns which are missing but + required, then return noError and goto C. + + (4) at the discretion of the agent, the return value may be + either: + + inconsistentName: because the agent does not choose to + create such an instance when the corresponding + RowStatus instance does not exist, or + + inconsistentValue: if the supplied value is + inconsistent with the state of some other MIB object's + value, or + + noError: because the agent chooses to create the + instance. + + If noError is returned, then the instance of the status + column must also be created, and the new state is B or C, + depending on the information available to the agent. If + inconsistentName or inconsistentValue is returned, the row + remains in state A. + + (5) depending on the MIB definition for the column/table, + either noError or inconsistentValue may be returned. + + (6) the return value can indicate one of the following + errors: + + wrongValue: because the agent does not support + notInService (e.g., an agent which does not support + createAndWait), or + + inconsistentValue: because the agent is unable to take + the row out of service at this time, perhaps because it + is in use and cannot be de-activated. + + (7) the return value can indicate the following error: + + inconsistentValue: because the agent is unable to + remove the row at this time, perhaps because it is in + use and cannot be de-activated. + + (8) the transition to D can fail, e.g., if the values of the + conceptual row are inconsistent, then the error code would + be inconsistentValue. + + NOTE: Other processing of (this and other varbinds of) the + set request may result in a response other than noError + being returned, e.g., wrongValue, noCreation, etc. + + + Conceptual Row Creation + + There are four potential interactions when creating a + conceptual row: selecting an instance-identifier which is + not in use; creating the conceptual row; initializing any + objects for which the agent does not supply a default; and, + making the conceptual row available for use by the managed + device. + + Interaction 1: Selecting an Instance-Identifier + + The algorithm used to select an instance-identifier varies + for each conceptual row. In some cases, the instance- + identifier is semantically significant, e.g., the + destination address of a route, and a management station + selects the instance-identifier according to the semantics. + + In other cases, the instance-identifier is used solely to + distinguish conceptual rows, and a management station + without specific knowledge of the conceptual row might + examine the instances present in order to determine an + unused instance-identifier. (This approach may be used, but + it is often highly sub-optimal; however, it is also a + questionable practice for a naive management station to + attempt conceptual row creation.) + + Alternately, the MIB module which defines the conceptual row + might provide one or more objects which provide assistance + in determining an unused instance-identifier. For example, + if the conceptual row is indexed by an integer-value, then + an object having an integer-valued SYNTAX clause might be + defined for such a purpose, allowing a management station to + issue a management protocol retrieval operation. In order + to avoid unnecessary collisions between competing management + stations, `adjacent' retrievals of this object should be + different. + + Finally, the management station could select a pseudo-random + number to use as the index. In the event that this index + was already in use and an inconsistentValue was returned in + response to the management protocol set operation, the + management station should simply select a new pseudo-random + number and retry the operation. + + A MIB designer should choose between the two latter + algorithms based on the size of the table (and therefore the + efficiency of each algorithm). For tables in which a large + number of entries are expected, it is recommended that a MIB + object be defined that returns an acceptable index for + creation. For tables with small numbers of entries, it is + recommended that the latter pseudo-random index mechanism be + used. + + Interaction 2: Creating the Conceptual Row + + Once an unused instance-identifier has been selected, the + management station determines if it wishes to create and + activate the conceptual row in one transaction or in a + negotiated set of interactions. + + Interaction 2a: Creating and Activating the Conceptual Row + + The management station must first determine the column + requirements, i.e., it must determine those columns for + which it must or must not provide values. Depending on the + complexity of the table and the management station's + knowledge of the agent's capabilities, this determination + can be made locally by the management station. Alternately, + the management station issues a management protocol get + operation to examine all columns in the conceptual row that + it wishes to create. In response, for each column, there + are three possible outcomes: + + - a value is returned, indicating that some other + management station has already created this conceptual + row. We return to interaction 1. + + - the exception `noSuchInstance' is returned, + indicating that the agent implements the object-type + associated with this column, and that this column in at + least one conceptual row would be accessible in the MIB + view used by the retrieval were it to exist. For those + columns to which the agent provides read-create access, + the `noSuchInstance' exception tells the management + station that it should supply a value for this column + when the conceptual row is to be created. + + - the exception `noSuchObject' is returned, indicating + that the agent does not implement the object-type + associated with this column or that there is no + conceptual row for which this column would be + accessible in the MIB view used by the retrieval. As + such, the management station can not issue any + management protocol set operations to create an + instance of this column. + + Once the column requirements have been determined, a + management protocol set operation is accordingly issued. + This operation also sets the new instance of the status + column to `createAndGo'. + + When the agent processes the set operation, it verifies that + it has sufficient information to make the conceptual row + available for use by the managed device. The information + available to the agent is provided by two sources: the + management protocol set operation which creates the + conceptual row, and, implementation-specific defaults + supplied by the agent (note that an agent must provide + implementation-specific defaults for at least those objects + which it implements as read-only). If there is sufficient + information available, then the conceptual row is created, a + `noError' response is returned, the status column is set to + `active', and no further interactions are necessary (i.e., + interactions 3 and 4 are skipped). If there is insufficient + information, then the conceptual row is not created, and the + set operation fails with an error of `inconsistentValue'. + On this error, the management station can issue a management + protocol retrieval operation to determine if this was + because it failed to specify a value for a required column, + or, because the selected instance of the status column + already existed. In the latter case, we return to + interaction 1. In the former case, the management station + can re-issue the set operation with the additional + information, or begin interaction 2 again using + `createAndWait' in order to negotiate creation of the + conceptual row. + + NOTE WELL + + Regardless of the method used to determine the column + requirements, it is possible that the management + station might deem a column necessary when, in fact, + the agent will not allow that particular columnar + instance to be created or written. In this case, the + management protocol set operation will fail with an + error such as `noCreation' or `notWritable'. In this + case, the management station decides whether it needs + to be able to set a value for that particular columnar + instance. If not, the management station re-issues the + management protocol set operation, but without setting + a value for that particular columnar instance; + otherwise, the management station aborts the row + creation algorithm. + + Interaction 2b: Negotiating the Creation of the Conceptual + Row + + The management station issues a management protocol set + operation which sets the desired instance of the status + column to `createAndWait'. If the agent is unwilling to + process a request of this sort, the set operation fails with + an error of `wrongValue'. (As a consequence, such an agent + must be prepared to accept a single management protocol set + operation, i.e., interaction 2a above, containing all of the + columns indicated by its column requirements.) Otherwise, + the conceptual row is created, a `noError' response is + returned, and the status column is immediately set to either + `notInService' or `notReady', depending on whether it has + sufficient information to (attempt to) make the conceptual + row available for use by the managed device. If there is + sufficient information available, then the status column is + set to `notInService'; otherwise, if there is insufficient + information, then the status column is set to `notReady'. + Regardless, we proceed to interaction 3. + + Interaction 3: Initializing non-defaulted Objects + + The management station must now determine the column + requirements. It issues a management protocol get operation + to examine all columns in the created conceptual row. In + the response, for each column, there are three possible + outcomes: + + - a value is returned, indicating that the agent + implements the object-type associated with this column + and had sufficient information to provide a value. For + those columns to which the agent provides read-create + access (and for which the agent allows their values to + be changed after their creation), a value return tells + the management station that it may issue additional + management protocol set operations, if it desires, in + order to change the value associated with this column. + + - the exception `noSuchInstance' is returned, + indicating that the agent implements the object-type + associated with this column, and that this column in at + least one conceptual row would be accessible in the MIB + view used by the retrieval were it to exist. However, + the agent does not have sufficient information to + provide a value, and until a value is provided, the + conceptual row may not be made available for use by the + managed device. For those columns to which the agent + provides read-create access, the `noSuchInstance' + exception tells the management station that it must + issue additional management protocol set operations, in + order to provide a value associated with this column. + + - the exception `noSuchObject' is returned, indicating + that the agent does not implement the object-type + associated with this column or that there is no + conceptual row for which this column would be + accessible in the MIB view used by the retrieval. As + such, the management station can not issue any + management protocol set operations to create an + instance of this column. + + If the value associated with the status column is + `notReady', then the management station must first deal with + all `noSuchInstance' columns, if any. Having done so, the + value of the status column becomes `notInService', and we + proceed to interaction 4. + + Interaction 4: Making the Conceptual Row Available + + Once the management station is satisfied with the values + associated with the columns of the conceptual row, it issues + a management protocol set operation to set the status column + to `active'. If the agent has sufficient information to + make the conceptual row available for use by the managed + device, the management protocol set operation succeeds (a + `noError' response is returned). Otherwise, the management + protocol set operation fails with an error of + `inconsistentValue'. + + NOTE WELL + + A conceptual row having a status column with value + `notInService' or `notReady' is unavailable to the + managed device. As such, it is possible for the + managed device to create its own instances during the + time between the management protocol set operation + which sets the status column to `createAndWait' and the + management protocol set operation which sets the status + column to `active'. In this case, when the management + protocol set operation is issued to set the status + column to `active', the values held in the agent + supersede those used by the managed device. + + If the management station is prevented from setting the + status column to `active' (e.g., due to management station + or network failure) the conceptual row will be left in the + `notInService' or `notReady' state, consuming resources + indefinitely. The agent must detect conceptual rows that + have been in either state for an abnormally long period of + time and remove them. It is the responsibility of the + DESCRIPTION clause of the status column to indicate what an + abnormally long period of time would be. This period of + time should be long enough to allow for human response time + (including `think time') between the creation of the + conceptual row and the setting of the status to `active'. + In the absence of such information in the DESCRIPTION + clause, it is suggested that this period be approximately 5 + minutes in length. This removal action applies not only to + newly-created rows, but also to previously active rows which + are set to, and left in, the notInService state for a + prolonged period exceeding that which is considered normal + for such a conceptual row. + + Conceptual Row Suspension + + When a conceptual row is `active', the management station + may issue a management protocol set operation which sets the + instance of the status column to `notInService'. If the + agent is unwilling to do so, the set operation fails with an + error of `wrongValue' or `inconsistentValue'. Otherwise, + the conceptual row is taken out of service, and a `noError' + response is returned. It is the responsibility of the + DESCRIPTION clause of the status column to indicate under + what circumstances the status column should be taken out of + service (e.g., in order for the value of some other column + of the same conceptual row to be modified). + + + Conceptual Row Deletion + + For deletion of conceptual rows, a management protocol set + operation is issued which sets the instance of the status + column to `destroy'. This request may be made regardless of + the current value of the status column (e.g., it is possible + to delete conceptual rows which are either `notReady', + `notInService' or `active'.) If the operation succeeds, + then all instances associated with the conceptual row are + immediately removed." + SYNTAX INTEGER { + -- the following two values are states: + -- these values may be read or written + active(1), + notInService(2), + + -- the following value is a state: + -- this value may be read, but not written + notReady(3), + + -- the following three values are + -- actions: these values may be written, + -- but are never read + createAndGo(4), + createAndWait(5), + destroy(6) + } + +TimeStamp ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The value of the sysUpTime object at which a specific + occurrence happened. The specific occurrence must be + defined in the description of any object defined using this + type. + + If sysUpTime is reset to zero as a result of a re- + initialization of the network management (sub)system, then + the values of all TimeStamp objects are also reset. + However, after approximately 497 days without a re- + initialization, the sysUpTime object will reach 2^^32-1 and + then increment around to zero; in this case, existing values + of TimeStamp objects do not change. This can lead to + ambiguities in the value of TimeStamp objects." + SYNTAX TimeTicks + + +TimeInterval ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A period of time, measured in units of 0.01 seconds." + SYNTAX INTEGER (0..2147483647) + +DateAndTime ::= TEXTUAL-CONVENTION + DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d" + STATUS current + DESCRIPTION + "A date-time specification. + + field octets contents range + ----- ------ -------- ----- + 1 1-2 year* 0..65536 + 2 3 month 1..12 + 3 4 day 1..31 + 4 5 hour 0..23 + 5 6 minutes 0..59 + 6 7 seconds 0..60 + (use 60 for leap-second) + 7 8 deci-seconds 0..9 + 8 9 direction from UTC '+' / '-' + 9 10 hours from UTC* 0..13 + 10 11 minutes from UTC 0..59 + + * Notes: + - the value of year is in network-byte order + - daylight saving time in New Zealand is +13 + + For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be + displayed as: + + 1992-5-26,13:30:15.0,-4:0 + + Note that if only local time is known, then timezone + information (fields 8-10) is not present." + SYNTAX OCTET STRING (SIZE (8 | 11)) + + +StorageType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Describes the memory realization of a conceptual row. A + row which is volatile(2) is lost upon reboot. A row which + is either nonVolatile(3), permanent(4) or readOnly(5), is + backed up by stable storage. A row which is permanent(4) + can be changed but not deleted. A row which is readOnly(5) + cannot be changed nor deleted. + + If the value of an object with this syntax is either + permanent(4) or readOnly(5), it cannot be written. + Conversely, if the value is either other(1), volatile(2) or + nonVolatile(3), it cannot be modified to be permanent(4) or + readOnly(5). (All illegal modifications result in a + 'wrongValue' error.) + + Every usage of this textual convention is required to + specify the columnar objects which a permanent(4) row must + at a minimum allow to be writable." + SYNTAX INTEGER { + other(1), -- eh? + volatile(2), -- e.g., in RAM + nonVolatile(3), -- e.g., in NVRAM + permanent(4), -- e.g., partially in ROM + readOnly(5) -- e.g., completely in ROM + } + +TDomain ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Denotes a kind of transport service. + + Some possible values, such as snmpUDPDomain, are defined in + the SNMPv2-TM MIB module. Other possible values are defined + in other MIB modules." + REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906." + SYNTAX OBJECT IDENTIFIER + + +TAddress ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Denotes a transport service address. + + A TAddress value is always interpreted within the context of a + TDomain value. Thus, each definition of a TDomain value must + be accompanied by a definition of a textual convention for use + with that TDomain. Some possible textual conventions, such as + SnmpUDPAddress for snmpUDPDomain, are defined in the SNMPv2-TM + MIB module. Other possible textual conventions are defined in + other MIB modules." + REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906." + SYNTAX OCTET STRING (SIZE (1..255)) + + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TM b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TM new file mode 100644 index 0000000..dadbc4a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/SNMPv2-TM @@ -0,0 +1,194 @@ +SNMPv2-TM DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-IDENTITY, + snmpModules, snmpDomains, snmpProxys + FROM SNMPv2-SMI + TEXTUAL-CONVENTION + FROM SNMPv2-TC; + +snmpv2tm MODULE-IDENTITY + LAST-UPDATED "200210160000Z" + ORGANIZATION "IETF SNMPv3 Working Group" + CONTACT-INFO + "WG-EMail: snmpv3@lists.tislabs.com + Subscribe: snmpv3-request@lists.tislabs.com + + Co-Chair: Russ Mundy + Network Associates Laboratories + postal: 15204 Omega Drive, Suite 300 + Rockville, MD 20850-4601 + USA + EMail: mundy@tislabs.com + phone: +1 301 947-7107 + + + + Co-Chair: David Harrington + Enterasys Networks + postal: 35 Industrial Way + P. O. Box 5005 + Rochester, NH 03866-5005 + USA + EMail: dbh@enterasys.com + phone: +1 603 337-2614 + + Editor: Randy Presuhn + BMC Software, Inc. + postal: 2141 North First Street + San Jose, CA 95131 + USA + EMail: randy_presuhn@bmc.com + phone: +1 408 546-1006" + DESCRIPTION + "The MIB module for SNMP transport mappings. + + Copyright (C) The Internet Society (2002). This + version of this MIB module is part of RFC 3417; + see the RFC itself for full legal notices. + " + REVISION "200210160000Z" + DESCRIPTION + "Clarifications, published as RFC 3417." + REVISION "199601010000Z" + DESCRIPTION + "Clarifications, published as RFC 1906." + REVISION "199304010000Z" + DESCRIPTION + "The initial version, published as RFC 1449." + ::= { snmpModules 19 } + +-- SNMP over UDP over IPv4 + +snmpUDPDomain OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP over UDP over IPv4 transport domain. + The corresponding transport address is of type + SnmpUDPAddress." + ::= { snmpDomains 1 } + + + + + + + + +SnmpUDPAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1d.1d.1d.1d/2d" + STATUS current + DESCRIPTION + "Represents a UDP over IPv4 address: + + octets contents encoding + 1-4 IP-address network-byte order + 5-6 UDP-port network-byte order + " + SYNTAX OCTET STRING (SIZE (6)) + +-- SNMP over OSI + +snmpCLNSDomain OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP over CLNS transport domain. + The corresponding transport address is of type + SnmpOSIAddress." + ::= { snmpDomains 2 } + +snmpCONSDomain OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP over CONS transport domain. + The corresponding transport address is of type + SnmpOSIAddress." + ::= { snmpDomains 3 } + +SnmpOSIAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "*1x:/1x:" + STATUS current + DESCRIPTION + "Represents an OSI transport-address: + + octets contents encoding + 1 length of NSAP 'n' as an unsigned-integer + (either 0 or from 3 to 20) + 2..(n+1) NSAP concrete binary representation + (n+2)..m TSEL string of (up to 64) octets + " + SYNTAX OCTET STRING (SIZE (1 | 4..85)) + + + + + + + + +-- SNMP over DDP + +snmpDDPDomain OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP over DDP transport domain. The corresponding + transport address is of type SnmpNBPAddress." + ::= { snmpDomains 4 } + +SnmpNBPAddress ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents an NBP name: + + octets contents encoding + 1 length of object 'n' as an unsigned integer + 2..(n+1) object string of (up to 32) octets + n+2 length of type 'p' as an unsigned integer + (n+3)..(n+2+p) type string of (up to 32) octets + n+3+p length of zone 'q' as an unsigned integer + (n+4+p)..(n+3+p+q) zone string of (up to 32) octets + + For comparison purposes, strings are + case-insensitive. All strings may contain any octet + other than 255 (hex ff)." + SYNTAX OCTET STRING (SIZE (3..99)) + +-- SNMP over IPX + +snmpIPXDomain OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The SNMP over IPX transport domain. The corresponding + transport address is of type SnmpIPXAddress." + ::= { snmpDomains 5 } + +SnmpIPXAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "4x.1x:1x:1x:1x:1x:1x.2d" + STATUS current + DESCRIPTION + "Represents an IPX address: + + octets contents encoding + 1-4 network-number network-byte order + 5-10 physical-address network-byte order + 11-12 socket-number network-byte order + " + SYNTAX OCTET STRING (SIZE (12)) + + + +-- for proxy to SNMPv1 (RFC 1157) + +rfc1157Proxy OBJECT IDENTIFIER ::= { snmpProxys 1 } + +rfc1157Domain OBJECT-IDENTITY + STATUS deprecated + DESCRIPTION + "The transport domain for SNMPv1 over UDP over IPv4. + The corresponding transport address is of type + SnmpUDPAddress." + ::= { rfc1157Proxy 1 } + +-- ::= { rfc1157Proxy 2 } this OID is obsolete + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/TCP-MIB b/contrib/apps/LwipMibCompiler/Mibs/TCP-MIB new file mode 100644 index 0000000..5b9e0bf --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/TCP-MIB @@ -0,0 +1,829 @@ +TCP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32, Unsigned32, + Gauge32, Counter32, Counter64, IpAddress, mib-2 + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + InetAddress, InetAddressType, + InetPortNumber FROM INET-ADDRESS-MIB; + +tcpMIB MODULE-IDENTITY + LAST-UPDATED "200502180000Z" -- 18 February 2005 + ORGANIZATION + "IETF IPv6 MIB Revision Team + http://www.ietf.org/html.charters/ipv6-charter.html" + CONTACT-INFO + "Rajiv Raghunarayan (editor) + + Cisco Systems Inc. + 170 West Tasman Drive + San Jose, CA 95134 + + Phone: +1 408 853 9612 + Email: + + Send comments to " + DESCRIPTION + "The MIB module for managing TCP implementations. + + Copyright (C) The Internet Society (2005). This version + of this MIB module is a part of RFC 4022; see the RFC + itself for full legal notices." + REVISION "200502180000Z" -- 18 February 2005 + DESCRIPTION + "IP version neutral revision, published as RFC 4022." + REVISION "9411010000Z" + DESCRIPTION + "Initial SMIv2 version, published as RFC 2012." + REVISION "9103310000Z" + DESCRIPTION + "The initial revision of this MIB module was part of + MIB-II." + ::= { mib-2 49 } + +-- the TCP base variables group + + + + +tcp OBJECT IDENTIFIER ::= { mib-2 6 } + +-- Scalars + +tcpRtoAlgorithm OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + constant(2), -- a constant rto + rsre(3), -- MIL-STD-1778, Appendix B + vanj(4), -- Van Jacobson's algorithm + rfc2988(5) -- RFC 2988 + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The algorithm used to determine the timeout value used for + retransmitting unacknowledged octets." + ::= { tcp 1 } + +tcpRtoMin OBJECT-TYPE + SYNTAX Integer32 (0..2147483647) + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The minimum value permitted by a TCP implementation for + the retransmission timeout, measured in milliseconds. + More refined semantics for objects of this type depend + on the algorithm used to determine the retransmission + timeout; in particular, the IETF standard algorithm + rfc2988(5) provides a minimum value." + ::= { tcp 2 } + +tcpRtoMax OBJECT-TYPE + SYNTAX Integer32 (0..2147483647) + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The maximum value permitted by a TCP implementation for + the retransmission timeout, measured in milliseconds. + More refined semantics for objects of this type depend + on the algorithm used to determine the retransmission + timeout; in particular, the IETF standard algorithm + rfc2988(5) provides an upper bound (as part of an + adaptive backoff algorithm)." + ::= { tcp 3 } + + + + +tcpMaxConn OBJECT-TYPE + SYNTAX Integer32 (-1 | 0..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The limit on the total number of TCP connections the entity + can support. In entities where the maximum number of + connections is dynamic, this object should contain the + value -1." + ::= { tcp 4 } + +tcpActiveOpens OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the SYN-SENT state from the CLOSED state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 5 } + +tcpPassiveOpens OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times TCP connections have made a direct + transition to the SYN-RCVD state from the LISTEN state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 6 } + +tcpAttemptFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the CLOSED state from either the SYN-SENT + state or the SYN-RCVD state, plus the number of times that + TCP connections have made a direct transition to the + LISTEN state from the SYN-RCVD state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + + + + ::= { tcp 7 } + +tcpEstabResets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the CLOSED state from either the ESTABLISHED + state or the CLOSE-WAIT state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 8 } + +tcpCurrEstab OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of TCP connections for which the current state + is either ESTABLISHED or CLOSE-WAIT." + ::= { tcp 9 } + +tcpInSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received, including those + received in error. This count includes segments received + on currently established connections. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 10 } + +tcpOutSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments sent, including those on + current connections but excluding those containing only + retransmitted octets. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + + + + ::= { tcp 11 } + +tcpRetransSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments retransmitted; that is, the + number of TCP segments transmitted containing one or more + previously transmitted octets. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 12 } + +tcpInErrs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received in error (e.g., bad + TCP checksums). + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 14 } + +tcpOutRsts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of TCP segments sent containing the RST flag. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 15 } + +-- { tcp 16 } was used to represent the ipv6TcpConnTable in RFC 2452, +-- which has since been obsoleted. It MUST not be used. + +tcpHCInSegs OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received, including those + received in error. This count includes segments received + + + + on currently established connections. This object is + the 64-bit equivalent of tcpInSegs. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 17 } + +tcpHCOutSegs OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments sent, including those on + current connections but excluding those containing only + retransmitted octets. This object is the 64-bit + equivalent of tcpOutSegs. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 18 } + + +-- The TCP Connection table + +tcpConnectionTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnectionEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing information about existing TCP + connections. Note that unlike earlier TCP MIBs, there + is a separate table for connections in the LISTEN state." + ::= { tcp 19 } + +tcpConnectionEntry OBJECT-TYPE + SYNTAX TcpConnectionEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row of the tcpConnectionTable containing + information about a particular current TCP connection. + Each row of this table is transient in that it ceases to + exist when (or soon after) the connection makes the + transition to the CLOSED state." + INDEX { tcpConnectionLocalAddressType, + tcpConnectionLocalAddress, + tcpConnectionLocalPort, + tcpConnectionRemAddressType, + + + + tcpConnectionRemAddress, + tcpConnectionRemPort } + ::= { tcpConnectionTable 1 } + +TcpConnectionEntry ::= SEQUENCE { + tcpConnectionLocalAddressType InetAddressType, + tcpConnectionLocalAddress InetAddress, + tcpConnectionLocalPort InetPortNumber, + tcpConnectionRemAddressType InetAddressType, + tcpConnectionRemAddress InetAddress, + tcpConnectionRemPort InetPortNumber, + tcpConnectionState INTEGER, + tcpConnectionProcess Unsigned32 + } + +tcpConnectionLocalAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of tcpConnectionLocalAddress." + ::= { tcpConnectionEntry 1 } + +tcpConnectionLocalAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local IP address for this TCP connection. The type + of this address is determined by the value of + tcpConnectionLocalAddressType. + + As this object is used in the index for the + tcpConnectionTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpConnectionEntry 2 } + +tcpConnectionLocalPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnectionEntry 3 } + +tcpConnectionRemAddressType OBJECT-TYPE + + + + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of tcpConnectionRemAddress." + ::= { tcpConnectionEntry 4 } + +tcpConnectionRemAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote IP address for this TCP connection. The type + of this address is determined by the value of + tcpConnectionRemAddressType. + + As this object is used in the index for the + tcpConnectionTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpConnectionEntry 5 } + +tcpConnectionRemPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnectionEntry 6 } + +tcpConnectionState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + MAX-ACCESS read-write + STATUS current + + + + DESCRIPTION + "The state of this TCP connection. + + The value listen(2) is included only for parallelism to the + old tcpConnTable and should not be used. A connection in + LISTEN state should be present in the tcpListenerTable. + + The only value that may be set by a management station is + deleteTCB(12). Accordingly, it is appropriate for an agent + to return a `badValue' response if a management station + attempts to set this object to any other value. + + If a management station sets this object to the value + deleteTCB(12), then the TCB (as defined in [RFC793]) of + the corresponding connection on the managed node is + deleted, resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST segment may be + sent from the managed node to the other TCP endpoint (note, + however, that RST segments are not sent reliably)." + ::= { tcpConnectionEntry 7 } + +tcpConnectionProcess OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The system's process ID for the process associated with + this connection, or zero if there is no such process. This + value is expected to be the same as HOST-RESOURCES-MIB:: + hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some + row in the appropriate tables." + ::= { tcpConnectionEntry 8 } + +-- The TCP Listener table + +tcpListenerTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpListenerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing information about TCP listeners. A + listening application can be represented in three + possible ways: + + 1. An application that is willing to accept both IPv4 and + IPv6 datagrams is represented by + + + + a tcpListenerLocalAddressType of unknown (0) and + a tcpListenerLocalAddress of ''h (a zero-length + octet-string). + + 2. An application that is willing to accept only IPv4 or + IPv6 datagrams is represented by a + tcpListenerLocalAddressType of the appropriate address + type and a tcpListenerLocalAddress of '0.0.0.0' or '::' + respectively. + + 3. An application that is listening for data destined + only to a specific IP address, but from any remote + system, is represented by a tcpListenerLocalAddressType + of an appropriate address type, with + tcpListenerLocalAddress as the specific local address. + + NOTE: The address type in this table represents the + address type used for the communication, irrespective + of the higher-layer abstraction. For example, an + application using IPv6 'sockets' to communicate via + IPv4 between ::ffff:10.0.0.1 and ::ffff:10.0.0.2 would + use InetAddressType ipv4(1))." + ::= { tcp 20 } + +tcpListenerEntry OBJECT-TYPE + SYNTAX TcpListenerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row of the tcpListenerTable containing + information about a particular TCP listener." + INDEX { tcpListenerLocalAddressType, + tcpListenerLocalAddress, + tcpListenerLocalPort } + ::= { tcpListenerTable 1 } + +TcpListenerEntry ::= SEQUENCE { + tcpListenerLocalAddressType InetAddressType, + tcpListenerLocalAddress InetAddress, + tcpListenerLocalPort InetPortNumber, + tcpListenerProcess Unsigned32 + } + +tcpListenerLocalAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + + + + "The address type of tcpListenerLocalAddress. The value + should be unknown (0) if connection initiations to all + local IP addresses are accepted." + ::= { tcpListenerEntry 1 } + +tcpListenerLocalAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local IP address for this TCP connection. + + The value of this object can be represented in three + possible ways, depending on the characteristics of the + listening application: + + 1. For an application willing to accept both IPv4 and + IPv6 datagrams, the value of this object must be + ''h (a zero-length octet-string), with the value + of the corresponding tcpListenerLocalAddressType + object being unknown (0). + + 2. For an application willing to accept only IPv4 or + IPv6 datagrams, the value of this object must be + '0.0.0.0' or '::' respectively, with + tcpListenerLocalAddressType representing the + appropriate address type. + + 3. For an application which is listening for data + destined only to a specific IP address, the value + of this object is the specific local address, with + tcpListenerLocalAddressType representing the + appropriate address type. + + As this object is used in the index for the + tcpListenerTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed, using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpListenerEntry 2 } + +tcpListenerLocalPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpListenerEntry 3 } + + + +tcpListenerProcess OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The system's process ID for the process associated with + this listener, or zero if there is no such process. This + value is expected to be the same as HOST-RESOURCES-MIB:: + hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some + row in the appropriate tables." + ::= { tcpListenerEntry 4 } + + +-- The deprecated TCP Connection table + +tcpConnTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A table containing information about existing IPv4-specific + TCP connections or listeners. This table has been + deprecated in favor of the version neutral + tcpConnectionTable." + ::= { tcp 13 } + +tcpConnEntry OBJECT-TYPE + SYNTAX TcpConnEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A conceptual row of the tcpConnTable containing information + about a particular current IPv4 TCP connection. Each row + of this table is transient in that it ceases to exist when + (or soon after) the connection makes the transition to the + CLOSED state." + INDEX { tcpConnLocalAddress, + tcpConnLocalPort, + tcpConnRemAddress, + tcpConnRemPort } + ::= { tcpConnTable 1 } + +TcpConnEntry ::= SEQUENCE { + tcpConnState INTEGER, + tcpConnLocalAddress IpAddress, + tcpConnLocalPort Integer32, + tcpConnRemAddress IpAddress, + tcpConnRemPort Integer32 + + + + } + +tcpConnState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "The state of this TCP connection. + + The only value that may be set by a management station is + deleteTCB(12). Accordingly, it is appropriate for an agent + to return a `badValue' response if a management station + attempts to set this object to any other value. + + If a management station sets this object to the value + deleteTCB(12), then the TCB (as defined in [RFC793]) of + the corresponding connection on the managed node is + deleted, resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST segment may be + sent from the managed node to the other TCP endpoint (note, + however, that RST segments are not sent reliably)." + ::= { tcpConnEntry 1 } + +tcpConnLocalAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local IP address for this TCP connection. In the case + of a connection in the listen state willing to + accept connections for any IP interface associated with the + node, the value 0.0.0.0 is used." + ::= { tcpConnEntry 2 } + + + +tcpConnLocalPort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnEntry 3 } + +tcpConnRemAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The remote IP address for this TCP connection." + ::= { tcpConnEntry 4 } + +tcpConnRemPort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnEntry 5 } + +-- conformance information + +tcpMIBConformance OBJECT IDENTIFIER ::= { tcpMIB 2 } + +tcpMIBCompliances OBJECT IDENTIFIER ::= { tcpMIBConformance 1 } +tcpMIBGroups OBJECT IDENTIFIER ::= { tcpMIBConformance 2 } + +-- compliance statements + +tcpMIBCompliance2 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for systems that implement TCP. + + A number of INDEX objects cannot be + represented in the form of OBJECT clauses in SMIv2 but + have the following compliance requirements, + expressed in OBJECT clause form in this description + clause: + + -- OBJECT tcpConnectionLocalAddressType + -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + + + + -- and IPv6 address types. + -- + -- OBJECT tcpConnectionRemAddressType + -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + -- and IPv6 address types. + -- + -- OBJECT tcpListenerLocalAddressType + -- SYNTAX InetAddressType { unknown(0), ipv4(1), + -- ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + -- and IPv6 address types. The type unknown also + -- needs to be supported to identify a special + -- case in the listener table: a listen using + -- both IPv4 and IPv6 addresses on the device. + -- + " + MODULE -- this module + MANDATORY-GROUPS { tcpBaseGroup, tcpConnectionGroup, + tcpListenerGroup } + GROUP tcpHCGroup + DESCRIPTION + "This group is mandatory for systems that are capable + of receiving or transmitting more than 1 million TCP + segments per second. 1 million segments per second will + cause a Counter32 to wrap in just over an hour." + OBJECT tcpConnectionState + SYNTAX INTEGER { closed(1), listen(2), synSent(3), + synReceived(4), established(5), + finWait1(6), finWait2(7), closeWait(8), + lastAck(9), closing(10), timeWait(11) } + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, nor is support for the value + deleteTCB (12)." + ::= { tcpMIBCompliances 2 } + +tcpMIBCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IPv4-only systems that + implement TCP. In order to be IP version independent, this + compliance statement is deprecated in favor of + tcpMIBCompliance2. However, agents are still encouraged + to implement these objects in order to interoperate with + the deployed base of managers." + + + + MODULE -- this module + MANDATORY-GROUPS { tcpGroup } + OBJECT tcpConnState + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + ::= { tcpMIBCompliances 1 } + + +-- units of conformance + +tcpGroup OBJECT-GROUP + OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, + tcpMaxConn, tcpActiveOpens, + tcpPassiveOpens, tcpAttemptFails, + tcpEstabResets, tcpCurrEstab, tcpInSegs, + tcpOutSegs, tcpRetransSegs, tcpConnState, + tcpConnLocalAddress, tcpConnLocalPort, + tcpConnRemAddress, tcpConnRemPort, + tcpInErrs, tcpOutRsts } + STATUS deprecated + DESCRIPTION + "The tcp group of objects providing for management of TCP + entities." + ::= { tcpMIBGroups 1 } + +tcpBaseGroup OBJECT-GROUP + OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, + tcpMaxConn, tcpActiveOpens, + tcpPassiveOpens, tcpAttemptFails, + tcpEstabResets, tcpCurrEstab, tcpInSegs, + tcpOutSegs, tcpRetransSegs, + tcpInErrs, tcpOutRsts } + STATUS current + DESCRIPTION + "The group of counters common to TCP entities." + ::= { tcpMIBGroups 2 } + +tcpConnectionGroup OBJECT-GROUP + OBJECTS { tcpConnectionState, tcpConnectionProcess } + STATUS current + DESCRIPTION + "The group provides general information about TCP + connections." + ::= { tcpMIBGroups 3 } + +tcpListenerGroup OBJECT-GROUP + OBJECTS { tcpListenerProcess } + + + + STATUS current + DESCRIPTION + "This group has objects providing general information about + TCP listeners." + ::= { tcpMIBGroups 4 } + +tcpHCGroup OBJECT-GROUP + OBJECTS { tcpHCInSegs, tcpHCOutSegs } + STATUS current + DESCRIPTION + "The group of objects providing for counters of high speed + TCP implementations." + ::= { tcpMIBGroups 5 } + +END diff --git a/contrib/apps/LwipMibCompiler/Mibs/UDP-MIB b/contrib/apps/LwipMibCompiler/Mibs/UDP-MIB new file mode 100644 index 0000000..b947b81 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/Mibs/UDP-MIB @@ -0,0 +1,579 @@ +UDP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32, Counter32, Counter64, + Unsigned32, IpAddress, mib-2 FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + InetAddress, InetAddressType, + InetPortNumber FROM INET-ADDRESS-MIB; + +udpMIB MODULE-IDENTITY + LAST-UPDATED "200505200000Z" -- May 20, 2005 + ORGANIZATION + "IETF IPv6 Working Group + http://www.ietf.org/html.charters/ipv6-charter.html" + CONTACT-INFO + "Bill Fenner (editor) + + AT&T Labs -- Research + 75 Willow Rd. + Menlo Park, CA 94025 + + Phone: +1 650 330-7893 + Email: + + John Flick (editor) + + Hewlett-Packard Company + 8000 Foothills Blvd. M/S 5557 + Roseville, CA 95747 + + Phone: +1 916 785 4018 + Email: + + Send comments to " + + + + DESCRIPTION + "The MIB module for managing UDP implementations. + Copyright (C) The Internet Society (2005). This + version of this MIB module is part of RFC 4113; + see the RFC itself for full legal notices." + REVISION "200505200000Z" -- May 20, 2005 + DESCRIPTION + "IP version neutral revision, incorporating the + following revisions: + + - Added udpHCInDatagrams and udpHCOutDatagrams in order + to provide high-capacity counters for fast networks. + - Added text to the descriptions of all counter objects + to indicate how discontinuities are detected. + - Deprecated the IPv4-specific udpTable and replaced it + with the version neutral udpEndpointTable. This + table includes support for connected UDP endpoints + and support for identification of the operating + system process associated with a UDP endpoint. + - Deprecated the udpGroup and replaced it with object + groups representing the current set of objects. + - Deprecated udpMIBCompliance and replaced it with + udpMIBCompliance2, which includes the compliance + information for the new object groups. + + This version published as RFC 4113." + REVISION "199411010000Z" -- November 1, 1994 + DESCRIPTION + "Initial SMIv2 version, published as RFC 2013." + REVISION "199103310000Z" -- March 31, 1991 + DESCRIPTION + "The initial revision of this MIB module was part of + MIB-II, published as RFC 1213." + ::= { mib-2 50 } + +-- the UDP group + +udp OBJECT IDENTIFIER ::= { mib-2 7 } + +udpInDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of UDP datagrams delivered to UDP + users. + + + + + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 1 } + +udpNoPorts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of received UDP datagrams for which + there was no application at the destination port. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 2 } + +udpInErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received UDP datagrams that could not be + delivered for reasons other than the lack of an + application at the destination port. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 3 } + +udpOutDatagrams OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of UDP datagrams sent from this + entity. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 4 } + + + +udpHCInDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of UDP datagrams delivered to UDP + users, for devices that can receive more than 1 + million UDP datagrams per second. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 8 } + +udpHCOutDatagrams OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of UDP datagrams sent from this + entity, for devices that can transmit more than 1 + million UDP datagrams per second. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by discontinuities in the + value of sysUpTime." + ::= { udp 9 } + +-- +-- { udp 6 } was defined as the ipv6UdpTable in RFC2454's +-- IPV6-UDP-MIB. This RFC obsoletes RFC 2454, so { udp 6 } is +-- obsoleted. +-- + +-- The UDP "Endpoint" table. + +udpEndpointTable OBJECT-TYPE + SYNTAX SEQUENCE OF UdpEndpointEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing information about this entity's UDP + endpoints on which a local application is currently + accepting or sending datagrams. + + + + + + The address type in this table represents the address + type used for the communication, irrespective of the + higher-layer abstraction. For example, an application + using IPv6 'sockets' to communicate via IPv4 between + ::ffff:10.0.0.1 and ::ffff:10.0.0.2 would use + InetAddressType ipv4(1). + + Unlike the udpTable in RFC 2013, this table also allows + the representation of an application that completely + specifies both local and remote addresses and ports. A + listening application is represented in three possible + ways: + + 1) An application that is willing to accept both IPv4 + and IPv6 datagrams is represented by a + udpEndpointLocalAddressType of unknown(0) and a + udpEndpointLocalAddress of ''h (a zero-length + octet-string). + + 2) An application that is willing to accept only IPv4 + or only IPv6 datagrams is represented by a + udpEndpointLocalAddressType of the appropriate + address type and a udpEndpointLocalAddress of + '0.0.0.0' or '::' respectively. + + 3) An application that is listening for datagrams only + for a specific IP address but from any remote + system is represented by a + udpEndpointLocalAddressType of the appropriate + address type, with udpEndpointLocalAddress + specifying the local address. + + In all cases where the remote is a wildcard, the + udpEndpointRemoteAddressType is unknown(0), the + udpEndpointRemoteAddress is ''h (a zero-length + octet-string), and the udpEndpointRemotePort is 0. + + If the operating system is demultiplexing UDP packets + by remote address and port, or if the application has + 'connected' the socket specifying a default remote + address and port, the udpEndpointRemote* values should + be used to reflect this." + ::= { udp 7 } + +udpEndpointEntry OBJECT-TYPE + SYNTAX UdpEndpointEntry + MAX-ACCESS not-accessible + STATUS current + + + + DESCRIPTION + "Information about a particular current UDP endpoint. + + Implementers need to be aware that if the total number + of elements (octets or sub-identifiers) in + udpEndpointLocalAddress and udpEndpointRemoteAddress + exceeds 111, then OIDs of column instances in this table + will have more than 128 sub-identifiers and cannot be + accessed using SNMPv1, SNMPv2c, or SNMPv3." + INDEX { udpEndpointLocalAddressType, + udpEndpointLocalAddress, + udpEndpointLocalPort, + udpEndpointRemoteAddressType, + udpEndpointRemoteAddress, + udpEndpointRemotePort, + udpEndpointInstance } + ::= { udpEndpointTable 1 } + +UdpEndpointEntry ::= SEQUENCE { + udpEndpointLocalAddressType InetAddressType, + udpEndpointLocalAddress InetAddress, + udpEndpointLocalPort InetPortNumber, + udpEndpointRemoteAddressType InetAddressType, + udpEndpointRemoteAddress InetAddress, + udpEndpointRemotePort InetPortNumber, + udpEndpointInstance Unsigned32, + udpEndpointProcess Unsigned32 + } + +udpEndpointLocalAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of udpEndpointLocalAddress. Only + IPv4, IPv4z, IPv6, and IPv6z addresses are expected, or + unknown(0) if datagrams for all local IP addresses are + accepted." + ::= { udpEndpointEntry 1 } + +udpEndpointLocalAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local IP address for this UDP endpoint. + + The value of this object can be represented in three + + + + possible ways, depending on the characteristics of the + listening application: + + 1. For an application that is willing to accept both + IPv4 and IPv6 datagrams, the value of this object + must be ''h (a zero-length octet-string), with + the value of the corresponding instance of the + udpEndpointLocalAddressType object being unknown(0). + + 2. For an application that is willing to accept only IPv4 + or only IPv6 datagrams, the value of this object + must be '0.0.0.0' or '::', respectively, while the + corresponding instance of the + udpEndpointLocalAddressType object represents the + appropriate address type. + + 3. For an application that is listening for data + destined only to a specific IP address, the value + of this object is the specific IP address for which + this node is receiving packets, with the + corresponding instance of the + udpEndpointLocalAddressType object representing the + appropriate address type. + + As this object is used in the index for the + udpEndpointTable, implementors of this table should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; else the information + cannot be accessed using SNMPv1, SNMPv2c, or SNMPv3." + ::= { udpEndpointEntry 2 } + +udpEndpointLocalPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local port number for this UDP endpoint." + ::= { udpEndpointEntry 3 } + +udpEndpointRemoteAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of udpEndpointRemoteAddress. Only + IPv4, IPv4z, IPv6, and IPv6z addresses are expected, or + unknown(0) if datagrams for all remote IP addresses are + accepted. Also, note that some combinations of + + + + udpEndpointLocalAdressType and + udpEndpointRemoteAddressType are not supported. In + particular, if the value of this object is not + unknown(0), it is expected to always refer to the + same IP version as udpEndpointLocalAddressType." + ::= { udpEndpointEntry 4 } + +udpEndpointRemoteAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote IP address for this UDP endpoint. If + datagrams from any remote system are to be accepted, + this value is ''h (a zero-length octet-string). + Otherwise, it has the type described by + udpEndpointRemoteAddressType and is the address of the + remote system from which datagrams are to be accepted + (or to which all datagrams will be sent). + + As this object is used in the index for the + udpEndpointTable, implementors of this table should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; else the information + cannot be accessed using SNMPv1, SNMPv2c, or SNMPv3." + ::= { udpEndpointEntry 5 } + +udpEndpointRemotePort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote port number for this UDP endpoint. If + datagrams from any remote system are to be accepted, + this value is zero." + ::= { udpEndpointEntry 6 } + +udpEndpointInstance OBJECT-TYPE + SYNTAX Unsigned32 (1..'ffffffff'h) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The instance of this tuple. This object is used to + distinguish among multiple processes 'connected' to + the same UDP endpoint. For example, on a system + implementing the BSD sockets interface, this would be + used to support the SO_REUSEADDR and SO_REUSEPORT + socket options." + + + + ::= { udpEndpointEntry 7 } + +udpEndpointProcess OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The system's process ID for the process associated with + this endpoint, or zero if there is no such process. + This value is expected to be the same as + HOST-RESOURCES-MIB::hrSWRunIndex or SYSAPPL-MIB:: + sysApplElmtRunIndex for some row in the appropriate + tables." + ::= { udpEndpointEntry 8 } + +-- The deprecated UDP Listener table + +-- The deprecated UDP listener table only contains information +-- about this entity's IPv4 UDP end-points on which a local +-- application is currently accepting datagrams. It does not +-- provide more detailed connection information, or information +-- about IPv6 endpoints. + +udpTable OBJECT-TYPE + SYNTAX SEQUENCE OF UdpEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A table containing IPv4-specific UDP listener + information. It contains information about all local + IPv4 UDP end-points on which an application is + currently accepting datagrams. This table has been + deprecated in favor of the version neutral + udpEndpointTable." + ::= { udp 5 } + +udpEntry OBJECT-TYPE + SYNTAX UdpEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "Information about a particular current UDP listener." + INDEX { udpLocalAddress, udpLocalPort } + ::= { udpTable 1 } + +UdpEntry ::= SEQUENCE { + udpLocalAddress IpAddress, + udpLocalPort Integer32 + + + +} + +udpLocalAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local IP address for this UDP listener. In the + case of a UDP listener that is willing to accept + datagrams for any IP interface associated with the + node, the value 0.0.0.0 is used." + ::= { udpEntry 1 } + +udpLocalPort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local port number for this UDP listener." + ::= { udpEntry 2 } + +-- conformance information + +udpMIBConformance OBJECT IDENTIFIER ::= { udpMIB 2 } +udpMIBCompliances OBJECT IDENTIFIER ::= { udpMIBConformance 1 } +udpMIBGroups OBJECT IDENTIFIER ::= { udpMIBConformance 2 } + +-- compliance statements + +udpMIBCompliance2 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for systems that implement + UDP. + + There are a number of INDEX objects that cannot be + represented in the form of OBJECT clauses in SMIv2, but + for which we have the following compliance + requirements, expressed in OBJECT clause form in this + description clause: + + -- OBJECT udpEndpointLocalAddressType + -- SYNTAX InetAddressType { unknown(0), ipv4(1), + -- ipv6(2), ipv4z(3), + -- ipv6z(4) } + -- DESCRIPTION + -- Support for dns(5) is not required. + -- OBJECT udpEndpointLocalAddress + + + + -- SYNTAX InetAddress (SIZE(0|4|8|16|20)) + -- DESCRIPTION + -- Support is only required for zero-length + -- octet-strings, and for scoped and unscoped + -- IPv4 and IPv6 addresses. + -- OBJECT udpEndpointRemoteAddressType + -- SYNTAX InetAddressType { unknown(0), ipv4(1), + -- ipv6(2), ipv4z(3), + -- ipv6z(4) } + -- DESCRIPTION + -- Support for dns(5) is not required. + -- OBJECT udpEndpointRemoteAddress + -- SYNTAX InetAddress (SIZE(0|4|8|16|20)) + -- DESCRIPTION + -- Support is only required for zero-length + -- octet-strings, and for scoped and unscoped + -- IPv4 and IPv6 addresses. + " + MODULE -- this module + MANDATORY-GROUPS { udpBaseGroup, udpEndpointGroup } + GROUP udpHCGroup + DESCRIPTION + "This group is mandatory for systems that + are capable of receiving or transmitting more than + 1 million UDP datagrams per second. 1 million + datagrams per second will cause a Counter32 to + wrap in just over an hour." + ::= { udpMIBCompliances 2 } + +udpMIBCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IPv4-only systems that + implement UDP. For IP version independence, this + compliance statement is deprecated in favor of + udpMIBCompliance2. However, agents are still + encouraged to implement these objects in order to + interoperate with the deployed base of managers." + MODULE -- this module + MANDATORY-GROUPS { udpGroup } + ::= { udpMIBCompliances 1 } + +-- units of conformance + +udpGroup OBJECT-GROUP + OBJECTS { udpInDatagrams, udpNoPorts, + udpInErrors, udpOutDatagrams, + udpLocalAddress, udpLocalPort } + + + + STATUS deprecated + DESCRIPTION + "The deprecated group of objects providing for + management of UDP over IPv4." + ::= { udpMIBGroups 1 } + +udpBaseGroup OBJECT-GROUP + OBJECTS { udpInDatagrams, udpNoPorts, udpInErrors, + udpOutDatagrams } + STATUS current + DESCRIPTION + "The group of objects providing for counters of UDP + statistics." + ::= { udpMIBGroups 2 } + +udpHCGroup OBJECT-GROUP + OBJECTS { udpHCInDatagrams, udpHCOutDatagrams } + STATUS current + DESCRIPTION + "The group of objects providing for counters of high + speed UDP implementations." + ::= { udpMIBGroups 3 } + +udpEndpointGroup OBJECT-GROUP + OBJECTS { udpEndpointProcess } + STATUS current + DESCRIPTION + "The group of objects providing for the IP version + independent management of UDP 'endpoints'." + ::= { udpMIBGroups 4 } + +END diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/DisplayHint.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/DisplayHint.cs new file mode 100644 index 0000000..831f117 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/DisplayHint.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Collections; + +namespace Lextm.SharpSnmpLib.Mib +{ + public class DisplayHint + { + private enum NumType { + dec, + hex, + oct, + bin, + str + } + + private string _str; + private NumType _type; + private int _decimalPoints = 0; + + public DisplayHint(string str) + { + _str = str; + if (str.StartsWith("d")) + { + _type = NumType.dec; + if (str.StartsWith("d-")) + { + _decimalPoints = Convert.ToInt32(str.Substring(2)); + } + } + else if (str.StartsWith("o")) + { + _type = NumType.oct; + } + else if (str.StartsWith("h")) + { + _type = NumType.hex; + } + else if (str.StartsWith("b")) + { + _type = NumType.bin; + } + else + { + _type = NumType.str; + foreach (char c in str) + { + + } + } + + } + + public override string ToString() + { + return _str; + } + + internal object Decode(int i) + { + switch (_type) + { + case NumType.dec: + if (_decimalPoints == 0) + { + return i; + } + else + { + return i / Math.Pow(10.0, _decimalPoints); + } + case NumType.hex: + return System.Convert.ToString(i, 16); + case NumType.oct: + return System.Convert.ToString(i, 8); + case NumType.bin: + return System.Convert.ToString(i, 2); + default: + return null; + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/AgentCapabilities.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/AgentCapabilities.cs new file mode 100644 index 0000000..2f79cce --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/AgentCapabilities.cs @@ -0,0 +1,29 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/31 + * Time: 13:18 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// The AGENT-CAPABILITIES construct is used to specify implementation characteristics of an SNMP agent sub-system with respect to object types and events. + /// + public sealed class AgentCapabilities : EntityBase + { + /// + /// Creates an instance. + /// + /// + /// + /// + public AgentCapabilities(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/EntityBase.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/EntityBase.cs new file mode 100644 index 0000000..6da9b18 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/EntityBase.cs @@ -0,0 +1,46 @@ +using System; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + public abstract class EntityBase: IEntity + { + private readonly IModule _module; + private string _parent; + private readonly uint _value; + private readonly string _name; + + public EntityBase(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + { + _module = module; + _name = preAssignSymbols[0].ToString(); + + Lexer.ParseOidValue(symbols, out _parent, out _value); + } + + public IModule Module + { + get { return _module; } + } + + public string Parent + { + get { return _parent; } + set { _parent = value; } + } + + public uint Value + { + get { return _value; } + } + + public string Name + { + get { return _name; } + } + + public virtual string Description + { + get { return string.Empty; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/IEntity.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/IEntity.cs new file mode 100644 index 0000000..7360a47 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/IEntity.cs @@ -0,0 +1,62 @@ +// Entity interface. +// Copyright (C) 2008-2010 Malcolm Crowe, Lex Li, and other contributors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/19 + * Time: 20:10 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Basic interface for all elements building up the MIB tree, thus having an OID as value. + /// + public interface IEntity : IDeclaration + { + /// + /// Parent name. + /// + string Parent + { + get; + set; + } + + /// + /// Value. + /// + uint Value + { + get; + } + + /// + /// Gets the description. + /// + /// The description. + string Description + { + get; + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleCompliance.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleCompliance.cs new file mode 100644 index 0000000..008c354 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleCompliance.cs @@ -0,0 +1,23 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/21 + * Time: 19:35 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Description of ModuleComplianceNode. + /// + public sealed class ModuleCompliance : EntityBase + { + public ModuleCompliance(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleIdentity.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleIdentity.cs new file mode 100644 index 0000000..6de28ce --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ModuleIdentity.cs @@ -0,0 +1,10 @@ +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + public sealed class ModuleIdentity : EntityBase + { + public ModuleIdentity(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationGroup.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationGroup.cs new file mode 100644 index 0000000..27d3e4c --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationGroup.cs @@ -0,0 +1,22 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/21 + * Time: 19:34 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Description of NotificationGroupNode. + /// + public sealed class NotificationGroup : EntityBase + { + public NotificationGroup(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationType.cs new file mode 100644 index 0000000..7386e21 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/NotificationType.cs @@ -0,0 +1,11 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + public sealed class NotificationType : EntityBase + { + public NotificationType(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectGroup.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectGroup.cs new file mode 100644 index 0000000..d846cdb --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectGroup.cs @@ -0,0 +1,22 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/21 + * Time: 19:27 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Description of ObjectGroupNode. + /// + public sealed class ObjectGroup : EntityBase + { + public ObjectGroup(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectIdentity.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectIdentity.cs new file mode 100644 index 0000000..9c1e084 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectIdentity.cs @@ -0,0 +1,21 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Object identifier node. + /// + public sealed class ObjectIdentity : EntityBase + { + + /// + /// Creates a . + /// + /// Module name + /// Header + /// Lexer + public ObjectIdentity(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectType.cs new file mode 100644 index 0000000..3a8b567 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/ObjectType.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + public sealed class ObjectType : EntityBase, ITypeReferrer + { + private ITypeAssignment _syntax; + private string _units; + private MaxAccess _access; + private Status _status; + private string _description; + private string _reference; + private IList _indices; + private string _augments; + private string _defVal; + + public ObjectType(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + ParseProperties(preAssignSymbols); + } + + private void ParseProperties(SymbolList header) + { + ISymbolEnumerator headerSymbols = header.GetSymbolEnumerator(); + Symbol temp = headerSymbols.NextNonEOLSymbol(); + + // Skip name + temp = headerSymbols.NextNonEOLSymbol(); + temp.Expect(Symbol.ObjectType); + + _syntax = ParseSyntax (Module, headerSymbols); + _units = ParseUnits (headerSymbols); + _access = ParseAccess (headerSymbols); + _status = ParseStatus (headerSymbols); + _description = ParseDescription (headerSymbols); + _reference = ParseReference (headerSymbols); + _indices = ParseIndices (headerSymbols); + _augments = ParseAugments (headerSymbols); + _defVal = ParseDefVal (headerSymbols); + } + + private static string ParseAugments(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Augments) + { + string augment = null; + + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenBracket); + + current = symbols.NextNonEOLSymbol(); + augment = current.ToString(); + + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseBracket); + + return augment; + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static string ParseDefVal(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.DefVal) + { + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenBracket); + + string defVal = null; + current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.OpenBracket) + { + int depth = 1; + // TODO: decode this. + while (depth > 0) + { + current = symbols.NextNonEOLSymbol(); + if (current == Symbol.OpenBracket) + { + depth++; + } + else if (current == Symbol.CloseBracket) + { + depth--; + } + } + } + else + { + defVal = current.ToString(); + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseBracket); + } + + return defVal; + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static IList ParseIndices(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Index) + { + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenBracket); + + List indices = new List(); + + while (current != Symbol.CloseBracket) + { + current = symbols.NextNonEOLSymbol(); + + bool lastIndex = false; + if (current == Symbol.Implied) + { + current = symbols.NextNonEOLSymbol(); + lastIndex = true; // 'IMPLIED' may only be used for last index + } + + current.Assert((current != Symbol.Comma) && (current != Symbol.CloseBracket), "Expected index name but found symbol!"); + indices.Add(current.ToString()); + + current = symbols.NextNonEOLSymbol(); + if (lastIndex) + { + current.Expect(Symbol.CloseBracket); + } + else + { + current.Expect(Symbol.Comma, Symbol.CloseBracket); + } + } + + return indices; + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static string ParseReference(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Reference) + { + return symbols.NextNonEOLSymbol().ToString(); + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static string ParseDescription(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Description) + { + return symbols.NextNonEOLSymbol().ToString().Trim(new char[] { '"' }); + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static Status ParseStatus(ISymbolEnumerator symbols) + { + Status status = Status.obsolete; + + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.Status); + + current = symbols.NextNonEOLSymbol(); + try + { + status = (Status)Enum.Parse(typeof(Status), current.ToString()); + } + catch (ArgumentException) + { + current.Assert(false, "Invalid/Unknown status"); + } + + return status; + } + + private static MaxAccess ParseAccess(ISymbolEnumerator symbols) + { + MaxAccess access = MaxAccess.notAccessible; + + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.MaxAccess, Symbol.Access); + + current = symbols.NextNonEOLSymbol(); + switch (current.ToString()) + { + case "not-accessible": + access = MaxAccess.notAccessible; + break; + case "accessible-for-notify": + access = MaxAccess.accessibleForNotify; + break; + case "read-only": + access = MaxAccess.readOnly; + break; + case "read-write": + access = MaxAccess.readWrite; + break; + case "read-create": + access = MaxAccess.readCreate; + break; + case "write-only": + access = MaxAccess.readWrite; + break; + default: + current.Assert(false, "Invalid/Unknown access"); + break; + } + + return access; + } + + private static string ParseUnits(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Units) + { + return symbols.NextNonEOLSymbol().ToString(); + } + else if (current != null) + { + symbols.PutBack(current); + } + + return null; + } + + private static ITypeAssignment ParseSyntax(IModule module, ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.Syntax); + + return Lexer.ParseBasicTypeDef(module, String.Empty, symbols, isMacroSyntax: true); + } + + private static bool IsProperty(Symbol sym) + { + string s = sym.ToString(); + return s == "SYNTAX" || s == "MAX-ACCESS" || s == "STATUS" || s == "DESCRIPTION"; + } + + public ITypeAssignment Syntax + { + get { return _syntax; } + internal set { _syntax = value; } + } + + public override string Description + { + get { return _description; } + } + + public MaxAccess Access + { + get { return _access; } + } + + public IList Indices + { + get { return _indices; } + } + + public string Augments + { + get { return _augments; } + } + + #region ITypeReferrer Member + + public ITypeAssignment ReferredType + { + get { return _syntax; } + set { _syntax = value; } + } + + public ITypeAssignment BaseType + { + get + { + ITypeReferrer tr = this; + ITypeAssignment result = null; + + while ((tr != null) && (tr.ReferredType != null)) + { + result = tr.ReferredType; + tr = tr.ReferredType as ITypeReferrer; + } + + return result; + } + } + + #endregion + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/OidValueAssignment.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/OidValueAssignment.cs new file mode 100644 index 0000000..3c65940 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Entities/OidValueAssignment.cs @@ -0,0 +1,30 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 20:49 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Entities +{ + /// + /// Object identifier node. + /// + public sealed class OidValueAssignment : EntityBase + { + /// + /// Creates a . + /// + /// Module + /// Name + /// Lexer + public OidValueAssignment(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + : base(module, preAssignSymbols, symbols) + { + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Exports.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Exports.cs new file mode 100644 index 0000000..c1e66e3 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Exports.cs @@ -0,0 +1,56 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/6/7 + * Time: 17:34 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + /// + /// Description of Exports. + /// + public sealed class Exports: IElement + { + private IModule _module; + private readonly IList _types = new List(); + + public Exports(IModule module, ISymbolEnumerator s) + { + _module = module; + + Symbol previous = null; + Symbol current; + do + { + current = s.NextSymbol(); + + if (current == Symbol.EOL) + { + continue; + } + else if (((current == Symbol.Comma) || (current == Symbol.Semicolon)) && (previous != null)) + { + previous.AssertIsValidIdentifier(); + _types.Add(previous.ToString()); + } + + previous = current; + } + while (current != Symbol.Semicolon); + } + + #region IElement Member + + public IModule Module + { + get { return _module; } + } + + #endregion + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IDeclaration.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IDeclaration.cs new file mode 100644 index 0000000..0958ac6 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IDeclaration.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + public interface IDeclaration: IElement + { + /// + /// Name. + /// + string Name + { + get; + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IElement.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IElement.cs new file mode 100644 index 0000000..e2db7fd --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/IElement.cs @@ -0,0 +1,35 @@ +// Construct interface. +// Copyright (C) 2008-2010 Malcolm Crowe, Lex Li, and other contributors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + /// + /// Construct interface. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")] + public interface IElement + { + /// + /// Containing module. + /// + IModule Module + { + get; + } + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ITypeReferrer.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ITypeReferrer.cs new file mode 100644 index 0000000..f0f5705 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ITypeReferrer.cs @@ -0,0 +1,10 @@ +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + public interface ITypeReferrer + { + ITypeAssignment ReferredType { get; set; } + ITypeAssignment BaseType { get; } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Imports.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Imports.cs new file mode 100644 index 0000000..3a4ec6e --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Imports.cs @@ -0,0 +1,81 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/31 + * Time: 12:07 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + /// + /// The IMPORTS construct is used to specify items used in the current MIB module which are defined in another MIB module or ASN.1 module. + /// + public sealed class Imports : List, IElement + { + private IModule _module; + + /// + /// Creates an instance. + /// + /// + public Imports(IModule module, ISymbolEnumerator symbols) + { + _module = module; + + Symbol current; + while ((current = symbols.NextSymbol()) != Symbol.Semicolon) + { + if (current == Symbol.EOL) + { + continue; + } + + ImportsFrom imports = new ImportsFrom(current, symbols); + + this.Add(imports); + } + } + + public IList Dependents + { + get + { + List result = new List(); + + foreach (ImportsFrom import in this) + { + result.Add(import.Module); + } + + return result; + } + } + + public ImportsFrom GetImportFromType(string type) + { + foreach (ImportsFrom import in this) + { + if (import.Types.Contains(type)) + { + return import; + } + } + + return null; + } + + #region IElement Member + + public IModule Module + { + get { return _module; } + } + + #endregion + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ImportsFrom.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ImportsFrom.cs new file mode 100644 index 0000000..cd5154b --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/ImportsFrom.cs @@ -0,0 +1,60 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/31 + * Time: 12:07 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + public sealed class ImportsFrom + { + private readonly string _module; + private readonly List _types = new List(); + + public ImportsFrom(Symbol last, ISymbolEnumerator symbols) + { + Symbol previous = last; + Symbol current; + while ((current = symbols.NextSymbol()) != Symbol.From) + { + if (current == Symbol.EOL) + { + continue; + } + + if (current == Symbol.Comma) + { + previous.AssertIsValidIdentifier(); + _types.Add(previous.ToString()); + } + + previous = current; + } + + previous.AssertIsValidIdentifier(); + _types.Add(previous.ToString()); + + _module = symbols.NextSymbol().ToString().ToUpperInvariant(); // module names are uppercase + } + + public string Module + { + get { return _module; } + } + + public IList Types + { + get { return _types; } + } + + public override string ToString() + { + return string.Join(", ", _types.ToArray()) + " FROM " + _module; + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/TrapType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/TrapType.cs new file mode 100644 index 0000000..9c5ca45 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/TrapType.cs @@ -0,0 +1,48 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/31 + * Time: 12:20 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements +{ + public sealed class TrapType : IDeclaration + { + private readonly IModule _module; + private readonly string _name; + private readonly int _value; + + public TrapType(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + { + _module = module; + _name = preAssignSymbols[0].ToString(); + + Symbol valueSymbol = symbols.NextNonEOLSymbol(); + + bool succeeded = int.TryParse(valueSymbol.ToString(), out _value); + valueSymbol.Assert(succeeded, "not a decimal"); + } + + public int Value + { + get { return _value; } + } + + #region IDeclaration Member + + public IModule Module + { + get { return _module; } + } + + public string Name + { + get { return _name; } + } + + #endregion + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BaseType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BaseType.cs new file mode 100644 index 0000000..a441281 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BaseType.cs @@ -0,0 +1,54 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public abstract class BaseType : ITypeAssignment + { + private IModule _module; + private string _name; + + protected BaseType(IModule module, string name) + { + _module = module; + _name = name; + } + + public virtual IModule Module + { + // differentiate between: + // FddiTimeNano ::= INTEGER (0..2147483647) + // which is an IntegerType which appears under Types in a MibModule and therefore has a name and module + // and + // SYNTAX INTEGER (0..2147483647) + // which is also an IntegerType but not defined as a separate type and therefore has NO name and NO module + get + { + if (!string.IsNullOrEmpty(_name)) + { + return _module; + } + else + { + return null; + } + } + protected set { _module = value; } + } + + public virtual string Name + { + get + { + if (!string.IsNullOrEmpty(_name)) + { + return _name; + } + else + { + return "{ Implicit Base Type }"; + } + } + protected set { _name = value; } + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BitsType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BitsType.cs new file mode 100644 index 0000000..a64c8db --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/BitsType.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public class BitsType : BaseType + { + private ValueMap _map; + + public BitsType(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name) + { + _map = Lexer.DecodeEnumerations(symbols); + } + + public ValueMap Map + { + get { return _map; } + } + + public string this[int value] + { + get { return _map[value]; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Choice.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Choice.cs new file mode 100644 index 0000000..c66d1f3 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Choice.cs @@ -0,0 +1,35 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/31 + * Time: 11:39 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /// + /// The CHOICE type represents a list of alternatives.. + /// + public sealed class Choice : BaseType + { + /// + /// Creates a instance. + /// + /// + /// + /// + public Choice(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name) + { + while (symbols.NextNonEOLSymbol() != Symbol.OpenBracket) + { + } + + while (symbols.NextNonEOLSymbol() != Symbol.CloseBracket) + { + } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ITypeAssignment.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ITypeAssignment.cs new file mode 100644 index 0000000..e962f9d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ITypeAssignment.cs @@ -0,0 +1,6 @@ +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public interface ITypeAssignment : IDeclaration + { + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IntegerType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IntegerType.cs new file mode 100644 index 0000000..4841ad5 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IntegerType.cs @@ -0,0 +1,117 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/7/25 + * Time: 20:41 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /// + /// The INTEGER type represents a list of alternatives, or a range of numbers.. + /// Includes Integer32 as it's indistinguishable from INTEGER. + /// + /** + * As this type is used for Integer32 as well as INTEGER it incorrectly + * allows enumeration sub-typing of Integer32. This is ok as currently we + * do not care about detecting incorrect MIBs and this doesn't block the + * decoding of correct MIBs. + */ + public sealed class IntegerType : BaseType + { + public enum Types + { + Integer, + Integer32 + } + + private Types _type; + private bool _isEnumeration; + private ValueMap _map; + private ValueRanges _ranges; + + /// + /// Creates an instance. + /// + /// + /// + /// + public IntegerType(IModule module, string name, Symbol type, ISymbolEnumerator symbols) + : base (module, name) + { + Types? t = GetExactType(type); + type.Assert(t.HasValue, "Unknown symbol for unsigned type!"); + _type = t.Value; + + _isEnumeration = false; + + Symbol current = symbols.NextNonEOLSymbol(); + if (current == Symbol.OpenBracket) + { + _isEnumeration = true; + symbols.PutBack(current); + _map = Lexer.DecodeEnumerations(symbols); + } + else if (current == Symbol.OpenParentheses) + { + symbols.PutBack(current); + _ranges = Lexer.DecodeRanges(symbols); + current.Assert(!_ranges.IsSizeDeclaration, "SIZE keyword is not allowed for ranges of integer types!"); + } + else + { + symbols.PutBack(current); + } + } + + public Types Type + { + get { return _type; } + } + + public ValueRanges Ranges + { + get { return _ranges; } + } + + public bool IsEnumeration + { + get + { + return _isEnumeration; + } + } + + public ValueMap Enumeration + { + get { return _isEnumeration ? _map : null; } + } + + internal static Types? GetExactType(Symbol symbol) + { + if (symbol == Symbol.Integer) + { + // represents the ASN.1 builtin INTEGER type: + // may be represent any arbitrary (signed/unsigned) integer (in theory may have any size) + return Types.Integer; + } + else if (symbol == Symbol.Integer32) + { + // Integer32 ::= INTEGER (-2147483648..2147483647) // from SNMPv2-SMI + return Types.Integer32; + } + + return null; + } + + internal static bool IsIntegerType(Symbol symbol) + { + return GetExactType(symbol).HasValue; + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IpAddressType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IpAddressType.cs new file mode 100644 index 0000000..84d78d6 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/IpAddressType.cs @@ -0,0 +1,21 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public class IpAddressType : OctetStringType + { + public IpAddressType(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name, symbols) + { + if (this.Size.Count != 0) + { + throw new MibException("Size definition not allowed for IpAddress type!"); + } + + // IpAddress type is defined as: + // IpAddress ::= + // [APPLICATION 0] + // IMPLICIT OCTET STRING (SIZE (4)) + this.Size.Add(new ValueRange(4, null)); + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Macro.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Macro.cs new file mode 100644 index 0000000..9f911ac --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Macro.cs @@ -0,0 +1,34 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public sealed class Macro : ITypeAssignment + { + private IModule _module; + private string _name; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "temp")] + public Macro(IModule module, SymbolList preAssignSymbols, ISymbolEnumerator symbols) + { + _module = module; + _name = preAssignSymbols[0].ToString(); + + while (symbols.NextNonEOLSymbol() != Symbol.Begin) + { + } + + while (symbols.NextNonEOLSymbol() != Symbol.End) + { + } + } + + public IModule Module + { + get { return _module; } + } + + public string Name + { + get { return _name; } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ObjectIdentifierType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ObjectIdentifierType.cs new file mode 100644 index 0000000..cacd415 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/ObjectIdentifierType.cs @@ -0,0 +1,11 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public class ObjectIdentifierType : BaseType + { + public ObjectIdentifierType(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name) + { + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OctetStringType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OctetStringType.cs new file mode 100644 index 0000000..f6453ce --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OctetStringType.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public class OctetStringType : BaseType + { + private ValueRanges _size; + + public OctetStringType(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name) + { + Symbol current = symbols.NextNonEOLSymbol(); + if (current == Symbol.OpenParentheses) + { + symbols.PutBack(current); + _size = Lexer.DecodeRanges(symbols); + current.Assert(_size.IsSizeDeclaration, "SIZE keyword is required for ranges of octet string!"); + } + else + { + symbols.PutBack(current); + _size = new ValueRanges(isSizeDecl: true); + } + } + + public ValueRanges Size + { + get { return _size; } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OpaqueType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OpaqueType.cs new file mode 100644 index 0000000..5a7eda3 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/OpaqueType.cs @@ -0,0 +1,11 @@ + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public class OpaqueType : OctetStringType + { + public OpaqueType(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name, symbols) + { + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Sequence.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Sequence.cs new file mode 100644 index 0000000..62912a5 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/Sequence.cs @@ -0,0 +1,46 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/21 + * Time: 19:43 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /// + /// The SEQUENCE type represents a set of specified types. This is roughly analogous to a struct in C. + /// + public sealed class Sequence : BaseType + { + /// + /// Creates a instance. + /// + /// The module. + /// The name. + /// The enumerator. + public Sequence(IModule module, string name, ISymbolEnumerator symbols) + : base(module, name) + { + // parse between ( ) + Symbol temp = symbols.NextNonEOLSymbol(); + int bracketSection = 0; + temp.Expect(Symbol.OpenBracket); + bracketSection++; + while (bracketSection > 0) + { + temp = symbols.NextNonEOLSymbol(); + if (temp == Symbol.OpenBracket) + { + bracketSection++; + } + else if (temp == Symbol.CloseBracket) + { + bracketSection--; + } + } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/SequenceOf.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/SequenceOf.cs new file mode 100644 index 0000000..4160ca4 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/SequenceOf.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /// + /// The SEQUENCE OF type represents a list of data sets.. + /// + public sealed class SequenceOf : BaseType + { + private string _type; + + public SequenceOf(IModule module, string name, ISymbolEnumerator sym) + : base(module, name) + { + _type = sym.NextNonEOLSymbol().ToString(); + } + + public string Type + { + get { return _type; } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TextualConvention.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TextualConvention.cs new file mode 100644 index 0000000..ab47731 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TextualConvention.cs @@ -0,0 +1,238 @@ +using System; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + public sealed class TextualConvention : ITypeAssignment, ITypeReferrer + { + private IModule _module; + private string _name; + private DisplayHint _displayHint; + private Status _status; + private string _description; + private string _reference; + private ITypeAssignment _syntax; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "module")] + public TextualConvention(IModule module, string name, ISymbolEnumerator symbols) + { + _module = module; + _name = name; + + _displayHint = ParseDisplayHint(symbols); + _status = ParseStatus(symbols); + _description = ParseDescription(symbols); + _reference = ParseReference(symbols); + _syntax = ParseSyntax(module, symbols); + } + + private static DisplayHint ParseDisplayHint(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.DisplayHint) + { + return new DisplayHint(symbols.NextNonEOLSymbol().ToString().Trim(new char[] { '"' })); + } + + symbols.PutBack(current); + return null; + } + + private static Status ParseStatus(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.Status); + + try + { + return (Status)Enum.Parse(typeof(Status), symbols.NextNonEOLSymbol().ToString()); + } + catch (ArgumentException) + { + current.Assert(false, "Invalid/Unknown status"); + } + + return Status.current; + } + + private static string ParseDescription(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.Description); + + return symbols.NextNonEOLSymbol().ToString().Trim(new char[] { '"' }); + } + + private static string ParseReference(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Reference) + { + string reference = symbols.NextNonEOLSymbol().ToString(); + if ((reference.Length >= 2) && reference.StartsWith("\"") && reference.EndsWith("\"")) + { + return reference.Substring(1, reference.Length-2); + } + + return reference; + } + + symbols.PutBack(current); + return null; + } + + private static ITypeAssignment ParseSyntax(IModule module, ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.Syntax); + + /* + * RFC2579 definition: + * Syntax ::= -- Must be one of the following: + * -- a base type (or its refinement), or + * -- a BITS pseudo-type + * type + * | "BITS" "{" NamedBits "}" + * + * From section 3.5: + * The data structure must be one of the alternatives defined + * in the ObjectSyntax CHOICE or the BITS construct. Note + * that this means that the SYNTAX clause of a Textual + * Convention can not refer to a previously defined Textual + * Convention. + * + * The SYNTAX clause of a TEXTUAL CONVENTION macro may be + * sub-typed in the same way as the SYNTAX clause of an + * OBJECT-TYPE macro. + * + * Therefore the possible values are (grouped by underlying type): + * INTEGER, Integer32 + * OCTET STRING, Opaque + * OBJECT IDENTIFIER + * IpAddress + * Counter64 + * Unsigned32, Counter32, Gauge32, TimeTicks + * BITS + * With appropriate sub-typing. + */ + + return Lexer.ParseBasicTypeDef(module, String.Empty, symbols, isMacroSyntax: true); + } + + public IModule Module + { + get { return _module; } + } + + public string Name + { + get { return _name; } + } + + public string DisplayHint + { + get { return _displayHint == null ? null : _displayHint.ToString(); } + } + + public Status Status + { + get { return _status; } + } + + public string Description + { + get { return _description; } + } + + public string Reference + { + get { return _reference; } + } + + public ITypeAssignment Syntax + { + get { return _syntax; } + } + + //internal object Decode(Variable v) + //{ + // if (_syntax is IntegerType) + // { + // Integer32 i = v.Data as Integer32; + // if (i == null || (_syntax as IntegerType).IsEnumeration) + // { + // return null; + // } + // else if (_displayHint != null) + // { + // return _displayHint.Decode(i.ToInt32()); + // } + // else + // { + // return i.ToInt32(); + // } + // } + // else if (_syntax is UnsignedType) + // { + // Integer32 i = v.Data as Integer32; + // if (i == null) + // { + // return null; + // } + // else if (_displayHint != null) + // { + // return _displayHint.Decode(i.ToInt32()); + // } + // else + // { + // return i.ToInt32(); + // } + // } + // else if (_syntax is OctetStringType) + // { + // OctetString o = v.Data as OctetString; + // if (o == null) + // { + // return null; + // } + // else + // { + // // TODO: Follow the format specifier for octet strings. + // return null; + // } + // } + // else + // { + // return null; + // } + //} + + #region ITypeReferrer Member + + public ITypeAssignment ReferredType + { + get { return _syntax; } + set { _syntax = value; } + } + + public ITypeAssignment BaseType + { + get + { + ITypeReferrer tr = this; + ITypeAssignment result = this; + + while ((tr != null) && (tr.ReferredType != null)) + { + result = tr.ReferredType; + tr = tr.ReferredType as ITypeReferrer; + } + + return result; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TypeAssignment.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TypeAssignment.cs new file mode 100644 index 0000000..b074ef6 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/TypeAssignment.cs @@ -0,0 +1,147 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/18 + * Time: 13:24 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System; +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /* Please be aware of the following possible constructs: + * + * isnsRegEntityIndex OBJECT-TYPE + * SYNTAX IsnsEntityIndexIdOrZero + * ( 1 .. 4294967295 ) + * MAX-ACCESS not-accessible + * + * + */ + + /// + /// + public sealed class TypeAssignment : ITypeAssignment + { + private IModule _module; + private string _name; + private string _type; + private ValueRanges _ranges; + private ValueMap _map; + + /// + /// Creates an . + /// + /// The module. + /// The name. + /// The type. + /// The symbols. + /// if set to true indicates that the syntax clause of a macro is parsed (e.g. OBJECT-TYPE, TEXTUAL-CONVENTION). + public TypeAssignment(IModule module, string name, Symbol type, ISymbolEnumerator symbols, bool isMacroSyntax) + { + _module = module; + _name = name; + + SymbolList typeSymbols = new SymbolList(); + typeSymbols.Add(type); + + Symbol current = symbols.NextSymbol(); + while (current != Symbol.EOL) + { + if (current == Symbol.OpenParentheses) + { + // parse range of unknown type + symbols.PutBack(current); + _ranges = Lexer.DecodeRanges(symbols); + break; + } + else if (current == Symbol.OpenBracket) + { + symbols.PutBack(current); + _map = Lexer.DecodeEnumerations(symbols); + break; + } + + typeSymbols.Add(current); + current = symbols.NextSymbol(); + } + + _type = typeSymbols.Join(" "); + + if ((_ranges == null) && (_map == null)) + { + current = symbols.NextNonEOLSymbol(); + if (current == Symbol.OpenParentheses) + { + // parse range of unknown type + symbols.PutBack(current); + _ranges = Lexer.DecodeRanges(symbols); + } + else if (current == Symbol.OpenBracket) + { + symbols.PutBack(current); + _map = Lexer.DecodeEnumerations(symbols); + } + else if (current != null) + { + symbols.PutBack(current); + } + } + + if (isMacroSyntax) + { + // inside a macro the syntax is limited to one line, except there are brackets used for ranges/enums + return; + } + + // outside macro Syntax clause we wait for two consecutive linebreaks with a following valid identifier as end condition + Symbol previous = current; + Symbol veryPrevious = null; + + while ((current = symbols.NextSymbol()) != null) + { + if ((veryPrevious == Symbol.EOL) && (previous == Symbol.EOL) && current.IsValidIdentifier()) + { + symbols.PutBack(current); + return; + } + + veryPrevious = previous; + previous = current; + } + + previous.Assert(false, "end of file reached"); + } + + public string Type + { + get { return _type; } + } + + public ValueRanges Ranges + { + get { return _ranges; } + } + + public IDictionary Map + { + get { return _map; } + } + + #region ITypeAssignment Member + + public IModule Module + { + get { return _module; } + } + + public string Name + { + get { return _name; } + } + + #endregion + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/UnsignedType.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/UnsignedType.cs new file mode 100644 index 0000000..4866fc9 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Elements/Types/UnsignedType.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib.Elements.Types +{ + /** + * As this type is used for Counter32 and TimeTicks as well as Unsigned32 + * and Gauge32 it incorrectly allows range restrictions of Counter32 and + * TimeTicks. This is ok as currently we do not care about detecting + * incorrect MIBs and this doesn't block the decoding of correct MIBs. + */ + public class UnsignedType : BaseType + { + public enum Types + { + Unsigned32, + Gauge32, + Counter32, + TimeTicks, + Counter64, + } + + private Types _type; + private ValueRanges _ranges; + + public UnsignedType(IModule module, string name, Symbol type, ISymbolEnumerator symbols) + : base(module, name) + { + Types? t = GetExactType(type); + type.Assert(t.HasValue, "Unknown symbol for unsigned type!"); + _type = t.Value; + + Symbol current = symbols.NextNonEOLSymbol(); + if (current == Symbol.OpenParentheses) + { + current.Assert((_type != Types.Counter64), "Ranges are not supported for Counter64 type!"); // our internal struct can only hold int64 values + + symbols.PutBack(current); + _ranges = Lexer.DecodeRanges(symbols); + current.Assert(!_ranges.IsSizeDeclaration, "SIZE keyword is not allowed for ranges of unsigned types!"); + } + else + { + symbols.PutBack(current); + } + } + + public Types Type + { + get { return _type; } + } + + public ValueRanges Ranges + { + get { return _ranges; } + } + + internal static Types? GetExactType(Symbol symbol) + { + if (symbol == Symbol.Unsigned32) + { + // [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) // from SNMPv2-SMI + return Types.Unsigned32; + } + else if (symbol == Symbol.Gauge32) + { + // [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) // from SNMPv2-SMI + return Types.Gauge32; + } + else if (symbol == Symbol.Counter32) + { + // [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) // from SNMPv2-SMI + return Types.Counter32; + } + else if (symbol == Symbol.TimeTicks) + { + // [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) // from SNMPv2-SMI + RFC1155-SMI + return Types.TimeTicks; + } + else if (symbol == Symbol.Gauge) + { + // [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) // from RFC1155-SMI + return Types.Gauge32; + } + else if (symbol == Symbol.Counter) + { + // [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) // from RFC1155-SMI + return Types.Counter32; + } + else if (symbol == Symbol.Counter64) + { + // [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) // from SNMPv2-SMI + return Types.Counter64; + } + + return null; + } + + internal static bool IsUnsignedType(Symbol symbol) + { + return GetExactType(symbol).HasValue; + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/IModule.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/IModule.cs new file mode 100644 index 0000000..d41ab12 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/IModule.cs @@ -0,0 +1,81 @@ +// Module interface. +// Copyright (C) 2008-2010 Malcolm Crowe, Lex Li, and other contributors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +/* + * Created by SharpDevelop. + * User: lextm + * Date: 5/1/2009 + * Time: 10:40 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System.Collections.Generic; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using Lextm.SharpSnmpLib.Mib.Elements.Types; +using Lextm.SharpSnmpLib.Mib.Elements; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// MIB Module interface. + /// + public interface IModule + { + /// + /// Module name. + /// + string Name + { + get; + } + + Exports Exports + { + get; + } + + Imports Imports + { + get; + } + + /// + /// Entities + Types + all other elements implementing IDeclaration + /// + IList Declarations + { + get; + } + + /// + /// Entities. + /// + IList Entities + { + get; + } + + /// + /// Known types. + /// + IList Types + { + get; + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ISymbolEnumerator.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ISymbolEnumerator.cs new file mode 100644 index 0000000..e9dd592 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ISymbolEnumerator.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib +{ + public interface ISymbolEnumerator: IEnumerator + { + bool PutBack(Symbol item); + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Lexer.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Lexer.cs new file mode 100644 index 0000000..5bf2844 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Lexer.cs @@ -0,0 +1,581 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 16:50 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// Lexer class that parses MIB files into symbol list. + /// + public sealed class Lexer + { + private readonly SymbolList _symbols = new SymbolList(); + + public Lexer(string file) + : this(file, new StreamReader(file)) + { + } + + public Lexer(string file, TextReader stream) + { + this.Parse(file, stream); + } + + + public ISymbolEnumerator GetEnumerator() + { + return _symbols.GetSymbolEnumerator(); + } + + + #region Parsing of MIB File + + private class ParseParams + { + public string File; + public StringBuilder Temp = new StringBuilder(); + public bool StringSection = false; + public bool AssignSection = false; + public bool AssignAhead = false; + public bool DotSection = false; + + } + + /// + /// Parses MIB file to symbol list. + /// + /// File + /// File stream + private void Parse(string file, TextReader stream) + { + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + ParseParams pp = new ParseParams(); + pp.File = file; + + string line; + int row = 0; + while ((line = stream.ReadLine()) != null) + { + if (!pp.StringSection && line.TrimStart().StartsWith("--", StringComparison.Ordinal)) + { + row++; + continue; // commented line + } + + ParseLine(pp, line, row); + row++; + } + } + + private void ParseLine(ParseParams pp, string line, int row) + { + line = line + "\n"; + int count = line.Length; + for (int i = 0; i < count; i++) + { + char current = line[i]; + bool moveNext = Parse(pp, current, row, i); + if (moveNext) + { + break; + } + } + } + + private bool Parse(ParseParams pp, char current, int row, int column) + { + switch (current) + { + case '\n': + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + case ';': + case ',': + case '|': + if (!pp.StringSection) + { + bool moveNext = ParseLastSymbol(pp, row, column); + if (moveNext) + { + _symbols.Add(CreateSpecialSymbol(pp.File, '\n', row, column)); + return true; + } + + _symbols.Add(CreateSpecialSymbol(pp.File, current, row, column)); + return false; + } + + break; + case '"': + pp.StringSection = !pp.StringSection; + break; + case '\r': + return false; + default: + if ((int)current == 0x1A) + { + // IMPORTANT: ignore invisible characters such as SUB. + return false; + } + + if (Char.IsWhiteSpace(current) && !pp.AssignSection && !pp.StringSection) + { + bool moveNext = ParseLastSymbol(pp, row, column); + if (moveNext) + { + _symbols.Add(CreateSpecialSymbol(pp.File, '\n', row, column)); + return true; + } + + return false; + } + + if (pp.AssignAhead) + { + pp.AssignAhead = false; + ParseLastSymbol(pp, row, column); + break; + } + + if (pp.DotSection && current != '.') + { + ParseLastSymbol(pp, row, column); + pp.DotSection = false; + } + + if (current == '.' && !pp.StringSection) + { + if (!pp.DotSection) + { + ParseLastSymbol(pp, row, column); + pp.DotSection = true; + } + } + + if (current == ':' && !pp.StringSection) + { + if (!pp.AssignSection) + { + ParseLastSymbol(pp, row, column); + } + + pp.AssignSection = true; + } + + if (current == '=' && !pp.StringSection) + { + pp.AssignSection = false; + pp.AssignAhead = true; + } + + break; + } + + pp.Temp.Append(current); + return false; + } + + private bool ParseLastSymbol(ParseParams pp, int row, int column) + { + if (pp.Temp.Length > 0) + { + Symbol s = new Symbol(pp.File, pp.Temp.ToString(), row, column); + + pp.Temp.Length = 0; + + if (s.ToString().StartsWith(Symbol.Comment.ToString())) + { + // ignore the rest symbols on this line because they are in comment. + return true; + } + + _symbols.Add(s); + } + + return false; + } + + private static Symbol CreateSpecialSymbol(string file, char value, int row, int column) + { + string str; + switch (value) + { + case '\n': + str = Environment.NewLine; + break; + case '{': + str = "{"; + break; + case '}': + str = "}"; + break; + case '(': + str = "("; + break; + case ')': + str = ")"; + break; + case '[': + str = "["; + break; + case ']': + str = "]"; + break; + case ';': + str = ";"; + break; + case ',': + str = ","; + break; + case '|': + str = "|"; + break; + default: + throw new ArgumentException("value is not a special character"); + } + + return new Symbol(file, str, row, column); + } + + #endregion + + #region Static Parse Helper + + public static ITypeAssignment ParseBasicTypeDef(IModule module, string name, ISymbolEnumerator symbols, bool isMacroSyntax = false) + { + Symbol current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.Bits) + { + return new BitsType(module, name, symbols); + } + if (IntegerType.IsIntegerType(current)) + { + return new IntegerType(module, name, current, symbols); + } + if (UnsignedType.IsUnsignedType(current)) + { + return new UnsignedType(module, name, current, symbols); + } + if (current == Symbol.Opaque) + { + return new OpaqueType(module, name, symbols); + } + if (current == Symbol.IpAddress) + { + return new IpAddressType(module, name, symbols); + } + if (current == Symbol.TextualConvention) + { + return new TextualConvention(module, name, symbols); + } + if (current == Symbol.Octet) + { + Symbol next = symbols.NextNonEOLSymbol(); + + if (next == Symbol.String) + { + return new OctetStringType(module, name, symbols); + } + + symbols.PutBack(next); + } + if (current == Symbol.Object) + { + Symbol next = symbols.NextNonEOLSymbol(); + + if (next == Symbol.Identifier) + { + return new ObjectIdentifierType(module, name, symbols); + } + + symbols.PutBack(next); + } + if (current == Symbol.Sequence) + { + Symbol next = symbols.NextNonEOLSymbol(); + + if (next == Symbol.Of) + { + return new SequenceOf(module, name, symbols); + } + else + { + symbols.PutBack(next); + return new Sequence(module, name, symbols); + } + } + if (current == Symbol.Choice) + { + return new Choice(module, name, symbols); + } + + + return new TypeAssignment(module, name, current, symbols, isMacroSyntax); + } + + public static void ParseOidValue(ISymbolEnumerator symbols, out string parent, out uint value) + { + parent = null; + value = 0; + + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenBracket); + + Symbol previous = null; + StringBuilder longParent = new StringBuilder(); + + current = symbols.NextNonEOLSymbol(); + longParent.Append(current); + + while ((current = symbols.NextNonEOLSymbol()) != null) + { + bool succeeded; + + if (current == Symbol.OpenParentheses) + { + longParent.Append(current); + + current = symbols.NextNonEOLSymbol(); + succeeded = UInt32.TryParse(current.ToString(), out value); + current.Assert(succeeded, "not a decimal"); + longParent.Append(current); + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseParentheses); + longParent.Append(current); + continue; + } + + if (current == Symbol.CloseBracket) + { + parent = longParent.ToString(); + return; + } + + succeeded = UInt32.TryParse(current.ToString(), out value); + if (succeeded) + { + // numerical way + while ((current = symbols.NextNonEOLSymbol()) != Symbol.CloseBracket) + { + longParent.Append(".").Append(value); + succeeded = UInt32.TryParse(current.ToString(), out value); + current.Assert(succeeded, "not a decimal"); + } + + current.Expect(Symbol.CloseBracket); + parent = longParent.ToString(); + return; + } + + longParent.Append("."); + longParent.Append(current); + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenParentheses); + longParent.Append(current); + current = symbols.NextNonEOLSymbol(); + succeeded = UInt32.TryParse(current.ToString(), out value); + current.Assert(succeeded, "not a decimal"); + longParent.Append(current); + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseParentheses); + longParent.Append(current); + previous = current; + } + + throw MibException.Create("end of file reached", previous); + } + + + public static ValueRanges DecodeRanges(ISymbolEnumerator symbols) + { + ValueRanges result = new ValueRanges(); + + Symbol startSymbol = symbols.NextNonEOLSymbol(); + Symbol current = startSymbol; + current.Expect(Symbol.OpenParentheses); + + while (current != Symbol.CloseParentheses) + { + Symbol value1Symbol = symbols.NextNonEOLSymbol(); + + if ((value1Symbol == Symbol.Size) && !result.IsSizeDeclaration) + { + result.IsSizeDeclaration = true; + symbols.NextNonEOLSymbol().Expect(Symbol.OpenParentheses); + continue; + } + + // check for valid number + Int64? value1 = DecodeNumber(value1Symbol); + if (!value1.HasValue) + { + value1Symbol.Assert(false, "Invalid range declaration!"); + } + + // process next symbol + ValueRange range; + current = symbols.NextNonEOLSymbol(); + + if (current == Symbol.DoubleDot) + { + // its a continuous range + Symbol value2Symbol = symbols.NextNonEOLSymbol(); + Int64? value2 = DecodeNumber(value2Symbol); + value2Symbol.Assert(value2.HasValue && (value2.Value >= value1.Value), "Invalid range declaration!"); + + if (value2.Value == value1.Value) + { + range = new ValueRange(value1.Value, null); + } + else + { + range = new ValueRange(value1.Value, value2.Value); + } + + current = symbols.NextNonEOLSymbol(); + } + else + { + // its a single number + range = new ValueRange(value1.Value, null); + } + + // validate range + if (result.IsSizeDeclaration) + { + value1Symbol.Assert(range.Start >= 0, "Invalid range declaration! Size must be greater than 0"); + } + + result.Add(range); + + // check next symbol + current.Expect(Symbol.Pipe, Symbol.CloseParentheses); + } + + if (result.IsSizeDeclaration) + { + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseParentheses); + } + + // validate ranges in between + for (int i=0; i 3)) + { + // search second apostrophe + int end = numString.IndexOf('\'', 1); + if (end == (numString.Length - 2)) + { + try + { + switch (numString[numString.Length - 1]) + { + case 'b': + case 'B': + result = Convert.ToInt64(numString.Substring(1, numString.Length - 3), 2); + return result; + case 'h': + case 'H': + result = Convert.ToInt64(numString.Substring(1, numString.Length - 3), 16); + return result; + } + } + catch + { + } + } + } + else if (Int64.TryParse(numString, out result)) + { + return result; + } + } + + return null; + } + + public static ValueMap DecodeEnumerations(ISymbolEnumerator symbols) + { + Symbol current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenBracket); + + ValueMap map = new ValueMap(); + do + { + current = symbols.NextNonEOLSymbol(); + string identifier = current.ToString(); + + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.OpenParentheses); + + current = symbols.NextNonEOLSymbol(); + Int64 enumValue; + if (Int64.TryParse(current.ToString(), out enumValue)) + { + try + { + // Have to include the number as it seems repeated identifiers are allowed ?? + map.Add(enumValue, String.Format("{0}({1})", identifier, enumValue)); + } + catch (ArgumentException ex) + { + current.Assert(false, ex.Message); + } + } + else + { + // Need to get "DefinedValue". + } + + current = symbols.NextNonEOLSymbol(); + current.Expect(Symbol.CloseParentheses); + + current = symbols.NextNonEOLSymbol(); + } while (current == Symbol.Comma); + + current.Expect(Symbol.CloseBracket); + + return map; + } + + #endregion + + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MaxAccess.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MaxAccess.cs new file mode 100644 index 0000000..f802990 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MaxAccess.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib +{ + public enum MaxAccess + { + notAccessible, + accessibleForNotify, + readOnly, + readWrite, + readCreate + } + +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibDocument.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibDocument.cs new file mode 100644 index 0000000..aac3b28 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibDocument.cs @@ -0,0 +1,57 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 17:38 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// MIB document. + /// + public sealed class MibDocument + { + private readonly List _modules = new List(); + + /// + /// Initializes a new instance of the class. + /// + /// The file. + public MibDocument(string file) + : this(new Lexer(file)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The lexer. + public MibDocument(Lexer lexer) + { + ISymbolEnumerator symbols = lexer.GetEnumerator(); + + Symbol current; + while ((current = symbols.NextNonEOLSymbol()) != null) + { + symbols.PutBack(current); + _modules.Add(new MibModule(symbols)); + } + } + + /// + /// containing in this document. + /// + public IList Modules + { + get + { + return _modules; + } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibException.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibException.cs new file mode 100644 index 0000000..efd89b3 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibException.cs @@ -0,0 +1,113 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 16:33 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Globalization; +#if (!SILVERLIGHT) +using System.Runtime.Serialization; +using System.Security.Permissions; +#endif + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// Description of MibException. + /// + [Serializable] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mib")] + public sealed class MibException : Exception + { + /// + /// Symbol. + /// + public Symbol Symbol { get; private set; } + + /// + /// Creates a . + /// + public MibException() + { + } + + /// + /// Creates a instance with a specific . + /// + /// Message + public MibException(string message) : base(message) + { + } + + /// + /// Creates a instance with a specific and an . + /// + /// Message + /// Inner exception + public MibException(string message, Exception inner) + : base(message, inner) + { + } +#if (!SILVERLIGHT) + /// + /// Creates a instance. + /// + /// Info + /// Context + private MibException(SerializationInfo info, StreamingContext context) : base(info, context) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + Symbol = (Symbol)info.GetValue("Symbol", typeof(Symbol)); + } + + /// + /// Gets object data. + /// + /// Info + /// Context + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("Symbol", Symbol); + } +#endif + + /// + /// Creates a with a specific . + /// + /// Message + /// Symbol + /// + public static MibException Create(string message, Symbol symbol) + { + if (symbol == null) + { + throw new ArgumentNullException("symbol"); + } + + if (String.IsNullOrEmpty(message)) + { + message = "Unknown MIB Exception"; + } + + message = String.Format( + "{0} (file: \"{1}\"; row: {2}; column: {3})", + message, + symbol.File, + symbol.Row + 1, + symbol.Column + 1); + + MibException ex = new MibException(message) { Symbol = symbol }; + return ex; + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibModule.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibModule.cs new file mode 100644 index 0000000..cacfd04 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibModule.cs @@ -0,0 +1,294 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 17:38 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Collections.Generic; +using Lextm.SharpSnmpLib.Mib.Elements; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// MIB module class. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mib")] + public sealed class MibModule : IModule + { + private readonly string _name; + private readonly Imports _imports; + private readonly Exports _exports; + private readonly List _tokens = new List(); + + /// + /// Creates a with a specific . + /// + /// Module name + /// Lexer + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "lexer")] + public MibModule(ISymbolEnumerator symbols) + { + if (symbols == null) + { + throw new ArgumentNullException("lexer"); + } + + Symbol temp = symbols.NextNonEOLSymbol(); + temp.AssertIsValidIdentifier(); + _name = temp.ToString().ToUpperInvariant(); // all module names are uppercase + + temp = symbols.NextNonEOLSymbol(); + temp.Expect(Symbol.Definitions); + + temp = symbols.NextNonEOLSymbol(); + temp.Expect(Symbol.Assign); + + temp = symbols.NextSymbol(); + temp.Expect(Symbol.Begin); + + temp = symbols.NextNonEOLSymbol(); + if (temp == Symbol.Imports) + { + _imports = ParseDependents(symbols); + } + else if (temp == Symbol.Exports) + { + _exports = ParseExports(symbols); + } + else + { + symbols.PutBack(temp); + } + + ParseEntities(symbols); + } + + #region Accessors + + /// + /// Module name. + /// + public string Name + { + get { return _name; } + } + + public Exports Exports + { + get { return _exports; } + } + + public Imports Imports + { + get { return _imports; } + } + + public List Tokens + { + get { return this._tokens; } + } + + /// + /// Entities + Types + all other elements implementing IDeclaration + /// + public IList Declarations + { + get + { + IList result = new List(); + foreach (IElement e in _tokens) + { + IDeclaration decl = e as IDeclaration; + if (decl != null) + { + result.Add(decl); + } + } + + return result; + } + } + + /// + /// OID nodes. + /// + public IList Entities + { + get + { + IList result = new List(); + foreach (IElement e in _tokens) + { + IEntity entity = e as IEntity; + if (entity != null) + { + result.Add(entity); + } + } + + return result; + } + } + + public IList Types + { + get + { + IList result = new List(); + foreach (IElement e in _tokens) + { + ITypeAssignment type = e as ITypeAssignment; + if (type != null) + { + result.Add(type); + } + } + + return result; + } + } + + #endregion + + #region Parsing of Symbols + + private Exports ParseExports(ISymbolEnumerator symbols) + { + return new Exports(this, symbols); + } + + private Imports ParseDependents(ISymbolEnumerator symbols) + { + return new Imports(this, symbols); + } + + private void ParseEntities(ISymbolEnumerator symbols) + { + Symbol temp = symbols.NextNonEOLSymbol(); + SymbolList buffer = new SymbolList(); + + while (temp != Symbol.End) + { + if (temp == Symbol.Assign) + { + ParseEntity(buffer, symbols); + buffer.Clear(); + // skip linebreaks behind an entity + temp = symbols.NextNonEOLSymbol(); + } + else + { + buffer.Add(temp); + temp = symbols.NextSymbol(); + } + } + } + + private void ParseEntity(SymbolList preAssignSymbols, ISymbolEnumerator symbols) + { + if ((preAssignSymbols == null) || (preAssignSymbols.Count == 0)) + { + Symbol s = symbols.NextSymbol(); + if (s != null) + { + s.Assert(false, "Invalid Entity declaration"); + } + else + { + throw new MibException("Invalid Entity declaration"); + } + } + + // check for a valid identifier + preAssignSymbols[0].AssertIsValidIdentifier(); + + if (preAssignSymbols.Count == 1) + { + // its a typedef + _tokens.Add(Lexer.ParseBasicTypeDef(this, preAssignSymbols[0].ToString(), symbols, isMacroSyntax: false)); + return; + } + + ISymbolEnumerator preAssignSymbolsEnumerator = preAssignSymbols.GetSymbolEnumerator(); + preAssignSymbolsEnumerator.NextNonEOLSymbol(); // returns identifier + Symbol type = preAssignSymbolsEnumerator.NextNonEOLSymbol(); + + // parse declarations + if (type == Symbol.Object) + { + Symbol next = preAssignSymbolsEnumerator.NextNonEOLSymbol(); + + if (next == Symbol.Identifier) + { + _tokens.Add(new OidValueAssignment(this, preAssignSymbols, symbols)); + return; + } + else if (next != null) + { + preAssignSymbolsEnumerator.PutBack(next); + } + } + if (type == Symbol.ModuleIdentity) + { + _tokens.Add(new ModuleIdentity(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.ObjectType) + { + _tokens.Add(new ObjectType(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.ObjectGroup) + { + _tokens.Add(new ObjectGroup(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.NotificationGroup) + { + _tokens.Add(new NotificationGroup(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.ModuleCompliance) + { + _tokens.Add(new ModuleCompliance(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.NotificationType) + { + _tokens.Add(new NotificationType(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.ObjectIdentity) + { + _tokens.Add(new ObjectIdentity(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.Macro) + { + _tokens.Add(new Macro(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.TrapType) + { + _tokens.Add(new TrapType(this, preAssignSymbols, symbols)); + return; + } + if (type == Symbol.AgentCapabilities) + { + _tokens.Add(new AgentCapabilities(this, preAssignSymbols, symbols)); + return; + } + + preAssignSymbols[1].Assert(false, "Unknown/Invalid declaration"); + } + + #endregion + + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibResolver.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibResolver.cs new file mode 100644 index 0000000..96978e1 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibResolver.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; + +namespace Lextm.SharpSnmpLib.Mib +{ + public interface IMibResolver + { + IModule Resolve(string moduleName); + } + + public class FileSystemMibResolver : IMibResolver + { + private string _path; + private bool _recursive; + + public FileSystemMibResolver(string path, bool recursive) + { + _path = path; + _recursive = recursive; + } + + #region IMibResolver Member + + public IModule Resolve(string moduleName) + { + if (Directory.Exists(_path)) + { + string[] matchedFiles = Directory.GetFiles( + _path, + "*", + (_recursive) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + + if ((matchedFiles != null) && (matchedFiles.Length >= 1)) + { + foreach (string matchedFile in matchedFiles) + { + if (Path.GetFileNameWithoutExtension(matchedFile.ToLowerInvariant()) == moduleName.ToLowerInvariant()) + { + try + { + MibDocument md = new MibDocument (matchedFile); + if (md.Modules.Count > 0) + { + return md.Modules [0]; + } + } catch + { + } + } + } + } + } + + return null; + } + + #endregion + + } + + // earlier code for search of versioned MIBs: + // + //private const string Pattern = "-V[0-9]+$"; + //public static bool AllDependentsAvailable(MibModule module, IDictionary modules) + //{ + // foreach (string dependent in module.Dependents) + // { + // if (!DependentFound(dependent, modules)) + // { + // return false; + // } + // } + + // return true; + //} + + //private static bool DependentFound(string dependent, IDictionary modules) + //{ + // if (!Regex.IsMatch(dependent, Pattern)) + // { + // return modules.ContainsKey(dependent); + // } + + // if (modules.ContainsKey(dependent)) + // { + // return true; + // } + + // string dependentNonVersion = Regex.Replace(dependent, Pattern, string.Empty); + // return modules.ContainsKey(dependentNonVersion); + //} + +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTree.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTree.cs new file mode 100644 index 0000000..a5174bc --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTree.cs @@ -0,0 +1,130 @@ +using System.Collections.Generic; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// Builds up a tree from a single MIB + /// + public class MibTree + { + private readonly List _root = new List(); + + public MibTree(MibModule module) + { + IList entities = module.Entities; + + if (entities.Count > 0) + { + // try to find module identity as root + foreach (IEntity element in entities) + { + ModuleIdentity mi = element as ModuleIdentity; + + if (mi != null) + { + _root.Add(new MibTreeNode(null, mi)); + } + } + + // find OID assignments as root, if there are any that are not below ModuleIdentity + foreach (IEntity element in entities) + { + OidValueAssignment oa = element as OidValueAssignment; + + if (oa != null) + { + _root.Add(new MibTreeNode(null, oa)); + } + } + + FilterRealRoots (entities); + + foreach (MibTreeNode mibTreeNode in _root) + { + entities.Remove (mibTreeNode.Entity); + } + + if (_root.Count == 0) + { + //no module identity, assume first entity is root + _root.Add(new MibTreeNode(null, entities[0])); + } + + foreach (MibTreeNode mibTreeNode in _root) + { + if (entities.Contains (mibTreeNode.Entity)) + { + entities.Remove (mibTreeNode.Entity); + } + BuildTree(mibTreeNode, entities); + UpdateTreeNodeTypes(mibTreeNode); + } + } + } + + public IList Root + { + get { return _root; } + } + + private bool EntityExists(IList entities, string name) + { + foreach(IEntity entity in entities) + { + if (entity.Name == name) + { + return true; + } + } + return false; + } + + private void FilterRealRoots(IList entities) + { + int i = 0; + while (i < _root.Count) + { + if (EntityExists(entities, _root[i].Entity.Parent)) + { + _root.RemoveAt(i); + } + else + { + i++; + } + } + } + + private void BuildTree(MibTreeNode node, IList entities) + { + int i = 0; + while (i < entities.Count) + { + if (entities[i].Parent == node.Entity.Name) + { + node.AddChild(entities[i]); + entities.RemoveAt(i); + } + else + { + i++; + } + } + + foreach (MibTreeNode childNode in node.ChildNodes) + { + BuildTree(childNode, entities); + } + } + + private void UpdateTreeNodeTypes(MibTreeNode node) + { + node.UpdateNodeType(); + foreach (MibTreeNode childNode in node.ChildNodes) + { + UpdateTreeNodeTypes(childNode); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTreeNode.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTreeNode.cs new file mode 100644 index 0000000..386c8e5 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTreeNode.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib +{ + [Flags] + public enum MibTreeNodeType + { + Unknown = 0, + Container = (1 << 0), + Scalar = (1 << 1), + Table = (1 << 2), + TableRow = (1 << 3), + TableCell = (1 << 4), + NotificationRelated = (1 << 5), + ConformanceRelated = (1 << 6) + } + + + public class MibTreeNode + { + private MibTreeNode _parent = null; + private List _childNodes = new List(); + private IEntity _entity = null; + private MibTreeNodeType _nodeType = MibTreeNodeType.Unknown; + + public MibTreeNode(MibTreeNode parent, IEntity entity) + { + _parent = parent; + _entity = entity; + } + + public MibTreeNode Parent + { + get { return _parent; } + } + + public IEntity Entity + { + get { return _entity; } + } + + public MibTreeNodeType NodeType + { + get { return _nodeType; } + } + + public List ChildNodes + { + get { return _childNodes; } + } + + public MibTreeNode AddChild(IEntity element) + { + MibTreeNode result = new MibTreeNode(this, element); + this.ChildNodes.Add(result); + + return result; + } + + public void UpdateNodeType() + { + _nodeType = MibTreeNodeType.Unknown; + + if (_entity != null) + { + if ((_entity is OidValueAssignment) || (_entity is ObjectIdentity)) + { + _nodeType |= MibTreeNodeType.Container; + return; + } + else if (_childNodes.Count > 0) + { + _nodeType |= MibTreeNodeType.Container; + } + + if (_entity is ObjectType) + { + ObjectType ot = _entity as ObjectType; + + if (ot.Syntax is SequenceOf) + { + _nodeType |= MibTreeNodeType.Table; + } + else if (ot.Syntax is Sequence) + { + _nodeType |= MibTreeNodeType.TableRow; + } + else if ((_parent != null) && ((_parent.NodeType & MibTreeNodeType.TableRow) != 0)) + { + _nodeType |= MibTreeNodeType.TableCell; + _nodeType |= MibTreeNodeType.Scalar; + } + else + { + _nodeType |= MibTreeNodeType.Scalar; + } + } + else if ((_entity is ModuleCompliance) || (_entity is ObjectGroup) || (_entity is NotificationGroup)) + { + _nodeType |= MibTreeNodeType.ConformanceRelated; + } + else if ((_entity is NotificationGroup) || (_entity is NotificationType)) + { + _nodeType |= MibTreeNodeType.NotificationRelated; + } + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTypesResolver.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTypesResolver.cs new file mode 100644 index 0000000..1e7529a --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/MibTypesResolver.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Lextm.SharpSnmpLib.Mib.Elements; +using Lextm.SharpSnmpLib.Mib.Elements.Entities; +using Lextm.SharpSnmpLib.Mib.Elements.Types; + +namespace Lextm.SharpSnmpLib.Mib +{ + public static class MibTypesResolver + { + private static readonly Regex _namedOidPathRegex = new Regex(@"^(?[^\(]+)\((?\d+)\)$"); + private static readonly List _resolver = new List(); + private static readonly List _cachedModules = new List(); + + public static void RegisterResolver(IMibResolver resolver) + { + if (resolver != null) + { + _resolver.Add(resolver); + } + } + + public static IModule ResolveModule(string moduleName) + { + // check if module is already cached + foreach (MibModule cachedModule in _cachedModules) + { + if (cachedModule.Name == moduleName) + { + return cachedModule; + } + } + + foreach (IMibResolver resolver in _resolver) + { + IModule resolvedModule = resolver.Resolve(moduleName); + if (resolvedModule != null) + { + ResolveTypes(resolvedModule); + _cachedModules.Add(resolvedModule); + return resolvedModule; + } + } + + return null; + } + + public static void ResolveTypes(IModule module) + { + foreach (IEntity entity in module.Entities) + { + ITypeReferrer typeReferringEntity = entity as ITypeReferrer; + + if (typeReferringEntity != null) + { + CheckTypeReferrer(module, typeReferringEntity); + } + } + + if (!_cachedModules.Contains(module)) + { + _cachedModules.Add(module); + } + } + + private static void CheckTypeReferrer(IModule module, ITypeReferrer typeReferringEntity) + { + TypeAssignment unknownType = typeReferringEntity.ReferredType as TypeAssignment; + if (unknownType != null) + { + typeReferringEntity.ReferredType = ResolveType(module, unknownType); + + if (typeReferringEntity.ReferredType is TypeAssignment) + { + Console.WriteLine(String.Format("Could not resolve type '{0}' declared in module '{1}'", (typeReferringEntity.ReferredType as TypeAssignment).Type, typeReferringEntity.ReferredType.Module.Name)); + } + } + + ITypeReferrer nextTypeReferringEntity = typeReferringEntity.ReferredType as ITypeReferrer; + if (nextTypeReferringEntity != null) + { + CheckTypeReferrer(module, nextTypeReferringEntity); + } + } + + public static ITypeAssignment ResolveType(IModule module, TypeAssignment type) + { + ITypeAssignment result = ResolveDeclaration(module, type.Type) as ITypeAssignment; + + return (result != null) ? result : type; + } + + public static IDeclaration ResolveDeclaration(IModule module, string name) + { + if ((module == null) || String.IsNullOrEmpty(name)) + { + return null; + } + + // check module internal types + foreach (IDeclaration decl in module.Declarations) + { + if (decl.Name == name) + { + return decl; + } + } + + // check if type is imported + if (module.Imports != null) + { + ImportsFrom imports = module.Imports.GetImportFromType(name); + if (imports != null) + { + IModule importedModule = ResolveModule(imports.Module); + if (importedModule != null) + { + return ResolveDeclaration(importedModule, name); + } + } + } + + return null; + } + + public static ObjectIdentifier ResolveOid(IEntity entity) + { + ObjectIdentifier result = new ObjectIdentifier(); + + if (entity != null) + { + ResolveOid(entity, result); + } + + return result; + } + + private static void ResolveOid(IEntity entity, ObjectIdentifier result) + { + result.Prepend(entity.Name, entity.Value); + + // check parent + if (!String.IsNullOrEmpty(entity.Parent)) + { + string[] pathParts = entity.Parent.Split('.'); + uint value; + + // all parts except the first should have their value directly or indirectly with them + if (pathParts.Length > 1) + { + for (int i=pathParts.Length-1; i>=1; i--) + { + if (uint.TryParse(pathParts[i], out value)) + { + result.Prepend("", value); + } + else + { + Match m = _namedOidPathRegex.Match(pathParts[i]); + if (m.Success) + { + result.Prepend(m.Groups["Name"].Value, uint.Parse(m.Groups["Value"].Value)); + } + else + { + throw new MibException("Invalid OID path detected for entity '" + entity.Name + "' in module '" + entity.Module + "'!"); + } + } + } + } + + // parse root part: either another entity or a standard root object + if (IsOidRoot(pathParts[0], out value)) + { + result.Prepend(pathParts[0], value); + } + else + { + // try to find entity inside this module + if (entity.Module != null) + { + entity = ResolveDeclaration(entity.Module, pathParts[0]) as IEntity; + + if (entity != null) + { + ResolveOid(entity, result); + } + else + { + result.Prepend("", uint.MaxValue); + } + } + else + { + result.Prepend("", uint.MaxValue); + } + } + } + } + + public static bool IsOidRoot(string name, out uint value) + { + value = uint.MaxValue; + + switch (name) + { + case "ccitt": value = 0; return true; + case "iso": value = 1; return true; + case "joint-iso-ccitt": value = 2; return true; + } + + return false; + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ObjectIdentifier.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ObjectIdentifier.cs new file mode 100644 index 0000000..0424804 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ObjectIdentifier.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib +{ + public class ObjectIdentifier: List> + { + public void Add(string name, uint oid) + { + this.Add(new KeyValuePair(name, oid)); + } + + public void Prepend(string name, uint oid) + { + this.Insert(0, new KeyValuePair(name, oid)); + } + + public void Insert(int index, string name, uint oid) + { + this.Insert(index, new KeyValuePair(name, oid)); + } + + public string GetOidString() + { + StringBuilder result = new StringBuilder(); + + foreach (KeyValuePair level in this) + { + result.Append(level.Value); + result.Append('.'); + } + + if (result.Length > 0) + { + result.Length--; + } + + return result.ToString(); + } + + public uint[] GetOidValues() + { + List result = new List(); + + foreach (KeyValuePair level in this) + { + result.Add(level.Value); + } + + return result.ToArray(); + } + + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Status.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Status.cs new file mode 100644 index 0000000..4ddd3ba --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Status.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib +{ + public enum Status + { + current, + deprecated, + obsolete, + mandatory, + optional + } + +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Symbol.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Symbol.cs new file mode 100644 index 0000000..b11386d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/Symbol.cs @@ -0,0 +1,357 @@ +/* + * Created by SharpDevelop. + * User: lextm + * Date: 2008/5/17 + * Time: 17:14 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Configuration; +using System.Globalization; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib +{ + /// + /// Description of Symbol. + /// + public sealed class Symbol : IEquatable + { + private readonly string _text; + private readonly int _row; + private readonly int _column; + private readonly string _file; + + private Symbol(string text) : this(null, text, -1, -1) + { + } + + /// + /// Creates a . + /// + /// File + /// Text + /// Row number + /// column number + public Symbol(string file, string text, int row, int column) + { + _file = file; + _text = text; + _row = row; + _column = column; + } + + /// + /// File. + /// + public string File + { + get + { + return _file; + } + } + + /// + /// Row number. + /// + public int Row + { + get + { + return _row; + } + } + + /// + /// Column number. + /// + public int Column + { + get + { + return _column; + } + } + + /// + /// Returns a that represents this . + /// + /// + public override string ToString() + { + return _text; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current ; otherwise, false. + /// + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + return GetType() == obj.GetType() && Equals((Symbol)obj); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// A hash code for the current . + public override int GetHashCode() + { + return _text.GetHashCode(); + } + + /// + /// The equality operator. + /// + /// Left object + /// Right object + /// + /// Returns true if the values of its operands are equal, false otherwise. + public static bool operator ==(Symbol left, Symbol right) + { + return Equals(left, right); + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// Left object + /// Right object + /// + /// Returns true if the values of its operands are equal, false otherwise. + public static bool Equals(Symbol left, Symbol right) + { + object l = left; + object r = right; + if (l == r) + { + return true; + } + + if (l == null || r == null) + { + return false; + } + + return left._text.Equals(right._text); + } + + /// + /// The inequality operator. + /// + /// Left object + /// Right object + /// + /// Returns true if the values of its operands are not equal, false otherwise. + public static bool operator !=(Symbol left, Symbol right) + { + return !(left == right); + } + + #region IEquatable Members + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + /// + public bool Equals(Symbol other) + { + return Equals(this, other); + } + + #endregion + + public static readonly Symbol Definitions = new Symbol("DEFINITIONS"); + public static readonly Symbol Begin = new Symbol("BEGIN"); + public static readonly Symbol Object = new Symbol("OBJECT"); + public static readonly Symbol Identifier = new Symbol("IDENTIFIER"); + public static readonly Symbol Assign = new Symbol("::="); + public static readonly Symbol OpenBracket = new Symbol("{"); + public static readonly Symbol CloseBracket = new Symbol("}"); + public static readonly Symbol Comment = new Symbol("--"); + public static readonly Symbol Imports = new Symbol("IMPORTS"); + public static readonly Symbol Semicolon = new Symbol(";"); + public static readonly Symbol From = new Symbol("FROM"); + public static readonly Symbol ModuleIdentity = new Symbol("MODULE-IDENTITY"); + public static readonly Symbol ObjectType = new Symbol("OBJECT-TYPE"); + public static readonly Symbol ObjectGroup = new Symbol("OBJECT-GROUP"); + public static readonly Symbol NotificationGroup = new Symbol("NOTIFICATION-GROUP"); + public static readonly Symbol ModuleCompliance = new Symbol("MODULE-COMPLIANCE"); + public static readonly Symbol Sequence = new Symbol("SEQUENCE"); + public static readonly Symbol NotificationType = new Symbol("NOTIFICATION-TYPE"); + public static readonly Symbol EOL = new Symbol(Environment.NewLine); + public static readonly Symbol ObjectIdentity = new Symbol("OBJECT-IDENTITY"); + public static readonly Symbol End = new Symbol("END"); + public static readonly Symbol Macro = new Symbol("MACRO"); + public static readonly Symbol Choice = new Symbol("CHOICE"); + public static readonly Symbol TrapType = new Symbol("TRAP-TYPE"); + public static readonly Symbol AgentCapabilities = new Symbol("AGENT-CAPABILITIES"); + public static readonly Symbol Comma = new Symbol(","); + public static readonly Symbol TextualConvention = new Symbol("TEXTUAL-CONVENTION"); + public static readonly Symbol Syntax = new Symbol("SYNTAX"); + public static readonly Symbol Bits = new Symbol("BITS"); + public static readonly Symbol Octet = new Symbol("OCTET"); + public static readonly Symbol String = new Symbol("STRING"); + public static readonly Symbol OpenParentheses = new Symbol("("); + public static readonly Symbol CloseParentheses = new Symbol(")"); + public static readonly Symbol Exports = new Symbol("EXPORTS"); + public static readonly Symbol DisplayHint = new Symbol("DISPLAY-HINT"); + public static readonly Symbol Status = new Symbol("STATUS"); + public static readonly Symbol Description = new Symbol("DESCRIPTION"); + public static readonly Symbol Reference = new Symbol("REFERENCE"); + public static readonly Symbol DoubleDot = new Symbol(".."); + public static readonly Symbol Pipe = new Symbol("|"); + public static readonly Symbol Size = new Symbol("SIZE"); + public static readonly Symbol Units = new Symbol("UNITS"); + public static readonly Symbol MaxAccess = new Symbol("MAX-ACCESS"); + public static readonly Symbol Access = new Symbol("ACCESS"); + public static readonly Symbol Index = new Symbol("INDEX"); + public static readonly Symbol Augments = new Symbol("AUGMENTS"); + public static readonly Symbol DefVal = new Symbol("DEFVAL"); + public static readonly Symbol Of = new Symbol("OF"); + public static readonly Symbol Integer = new Symbol("INTEGER"); + public static readonly Symbol Integer32 = new Symbol("Integer32"); + public static readonly Symbol IpAddress = new Symbol("IpAddress"); + public static readonly Symbol Counter32 = new Symbol("Counter32"); + public static readonly Symbol Counter = new Symbol("Counter"); + public static readonly Symbol TimeTicks = new Symbol("TimeTicks"); + public static readonly Symbol Opaque = new Symbol("Opaque"); + public static readonly Symbol Counter64 = new Symbol("Counter64"); + public static readonly Symbol Unsigned32 = new Symbol("Unsigned32"); + public static readonly Symbol Gauge32 = new Symbol("Gauge32"); + public static readonly Symbol Gauge = new Symbol("Gauge"); + public static readonly Symbol TruthValue = new Symbol("TruthValue"); + public static readonly Symbol Implied = new Symbol("IMPLIED"); + + internal void Expect(Symbol expected, params Symbol[] orExpected) + { + bool isExpected = (this == expected); + + if (!isExpected && (orExpected != null) && (orExpected.Length > 0)) + { + // check the alternatives + for (int i=0; i 64)) + { + message = "an identifier must consist of 1 to 64 letters, digits, and hyphens"; + return false; + } + + if (!Char.IsLetter(name[0])) + { + message = "the initial character must be a letter"; + return false; + } + + if (name.EndsWith("-", StringComparison.Ordinal)) + { + message = "a hyphen cannot be the last character of an identifier"; + return false; + } + + if (name.Contains("--")) + { + message = "a hyphen cannot be immediately followed by another hyphen in an identifier"; + return false; + } + + if (UseStricterValidation && name.Contains("_")) + { + message = "underscores are not allowed in identifiers"; + return false; + } + + // TODO: SMIv2 forbids "-" except in module names and keywords + message = null; + return true; + } + + private static bool? _useStricterValidation; + + private static bool UseStricterValidation + { + get + { + if (_useStricterValidation == null) + { + object setting = ConfigurationManager.AppSettings["StricterValidationEnabled"]; + _useStricterValidation = setting != null && Convert.ToBoolean(setting.ToString(), CultureInfo.InvariantCulture); + } + + return _useStricterValidation.Value; + } + } + } +} \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/SymbolList.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/SymbolList.cs new file mode 100644 index 0000000..5b2218e --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/SymbolList.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lextm.SharpSnmpLib.Mib +{ + public class SymbolList : List + { + public class SymbolEnumerator : ISymbolEnumerator + { + private SymbolList _list = null; + private int _index = -1; + + internal SymbolEnumerator(SymbolList list) + { + if (list == null) + { + throw new ArgumentNullException("lexer"); + } + + _list = list; + } + + #region ISymbolEnumerator Member + + public bool PutBack(Symbol item) + { + if ((_index < 0) || (_index >= _list.Count) || (item != _list[_index])) + { + throw new ArgumentException(@"wrong last symbol", "last"); + //return false; + } + + _index--; + return true; + } + + #endregion + + #region IEnumerator Member + + public Symbol Current + { + get + { + if ((_index >= 0) && (_index <= _list.Count)) + { + return _list[_index]; + } + + return null; + } + } + + #endregion + + #region IDisposable Member + + public void Dispose() + { + } + + #endregion + + #region IEnumerator Member + + object System.Collections.IEnumerator.Current + { + get { return this.Current; } + } + + public bool MoveNext() + { + _index++; + return (_index >= 0) && (_index < _list.Count); + } + + public void Reset() + { + _index = -1; + } + + #endregion + } + + /// + /// Initializes a new instance of the class. + /// + public SymbolList() + { + } + + public ISymbolEnumerator GetSymbolEnumerator() + { + return new SymbolEnumerator(this); + } + + public string Join(string separator) + { + if (separator == null) + separator = ""; + + StringBuilder result = new StringBuilder(); + + foreach (Symbol s in this) + { + result.Append(s); + result.Append(separator); + } + + if (result.Length > 0) + { + result.Length -= separator.Length; + } + + return result.ToString(); + } + } + + public static class SymbolEnumeratorExtension + { + public static Symbol NextSymbol(this IEnumerator enumerator) + { + if (enumerator.MoveNext()) + { + return enumerator.Current; + } + + return null; + } + + public static Symbol NextNonEOLSymbol(this IEnumerator enumerator) + { + while (enumerator.MoveNext()) + { + if (enumerator.Current != Symbol.EOL) + { + return enumerator.Current; + } + } + + return null; + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueMap.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueMap.cs new file mode 100644 index 0000000..4884235 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueMap.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib +{ + public class ValueMap : Dictionary + { + public ValueMap() + { + } + + /// + /// Returns the values of the map as continuous range. At best as one range. + /// + /// + public ValueRanges GetContinousRanges() + { + ValueRanges result = new ValueRanges(); + + if (this.Count > 0) + { + List values = new List(this.Keys); + values.Sort(); + + Int64 last = values[0]; + Int64 offset = values[0]; + for (int i=1; i + /// Gets the highest value contained in this value map. + /// + /// + public Int64 GetHighestValue() + { + Int64 result = 0; + + foreach (Int64 value in this.Keys) + { + if (value > result) + { + result = value; + } + } + + return result; + } + + /// + /// Interprets the single values as bit positions and creates a mask of it. + /// + /// + public UInt32 GetBitMask() + { + UInt32 result = 0; + + foreach (Int64 key in this.Keys) + { + if (key < 0) + { + throw new NotSupportedException("Negative numbers are not allowed for Bits!"); + } + if (key > 31) + { + throw new NotSupportedException("Bits with more than 32 bits are not supported!"); + } + + result |= (UInt32)(1 << (int)key); + } + + return result; + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueRange.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueRange.cs new file mode 100644 index 0000000..3ff5bcb --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Mib/ValueRange.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; + +namespace Lextm.SharpSnmpLib.Mib +{ + public class ValueRanges: List + { + public bool IsSizeDeclaration { get; internal set; } + + public ValueRanges(bool isSizeDecl = false) + { + IsSizeDeclaration = isSizeDecl; + } + + public bool Contains(Int64 value) + { + foreach (ValueRange range in this) + { + if (range.Contains(value)) + { + return true; + } + } + + return false; + } + } + + public class ValueRange + { + private readonly Int64 _start; + private readonly Int64? _end; + + public ValueRange(Int64 first, Int64? second) + { + _start = first; + _end = second; + } + + public Int64 Start + { + get { return _start; } + } + + public Int64? End + { + get { return _end; } + } + + public bool IntersectsWith(ValueRange other) + { + if (this._end == null) + { + return other.Contains(this._start); + } + else if (other._end == null) + { + return this.Contains(other._start); + } + + return (this._start <= other.End) && (this._end >= other._start); + } + + public bool Contains(Int64 value) + { + if (_end == null) + { + return value == _start; + } + else + { + return (_start <= value) && (value <= _end); + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/AssemblyInfo.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f96080d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/AssemblyInfo.cs @@ -0,0 +1,61 @@ +// #SNMP Library. An open source SNMP implementation for .NET. +// Copyright (C) 2008 Lex Y. Li +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#region Using directives + +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpSnmpLib")] +[assembly: AssemblyDescription("#SNMP Library for .NET")] +[assembly: AssemblyConfiguration("Lesser GPL 2.1+")] +[assembly: AssemblyCompany("LeXtudio")] +[assembly: AssemblyProduct("#SNMPLib")] +[assembly: AssemblyCopyright("(C) 2008-2010 Malcolm Crowe, Lex Li, Steve Santacroce, and other contributors.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose index type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("7.0.011207.31")] +#if (!CF) +[assembly: AssemblyFileVersion("7.0.011207.31")] +#endif +[assembly: NeutralResourcesLanguage("en-US")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Lextm")] + +[assembly: InternalsVisibleTo("SharpSnmpLib.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.Designer.cs b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.Designer.cs new file mode 100644 index 0000000..38bc6bb --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.225 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Lextm.SharpSnmpLib.Mib { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lextm.SharpSnmpLib.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.resx b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.resx new file mode 100644 index 0000000..7080a7d --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/SharpSnmpLib.Mib.csproj b/contrib/apps/LwipMibCompiler/SharpSnmpLib/SharpSnmpLib.Mib.csproj new file mode 100644 index 0000000..2cf8657 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/SharpSnmpLib.Mib.csproj @@ -0,0 +1,140 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {CBE20411-5DB7-487D-825D-7694267BB6F5} + Library + Properties + Lextm.SharpSnmpLib + SharpSnmpLib.Mib + ..\bin\SharpSnmpLib.Mib.xml + 512 + + True + sharpsnmplib.snk + False + File + + + + + + + + + False + v4.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Lextm.SharpSnmpLib.Mib + Designer + + + + + + + + \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/license.txt b/contrib/apps/LwipMibCompiler/SharpSnmpLib/license.txt new file mode 100644 index 0000000..27946de --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/license.txt @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/readme.txt b/contrib/apps/LwipMibCompiler/SharpSnmpLib/readme.txt new file mode 100644 index 0000000..67b5a65 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/SharpSnmpLib/readme.txt @@ -0,0 +1 @@ +See docs in src/apps/snmp/snmp_core.c. diff --git a/contrib/apps/LwipMibCompiler/SharpSnmpLib/sharpsnmplib.snk b/contrib/apps/LwipMibCompiler/SharpSnmpLib/sharpsnmplib.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/contrib/apps/LwipMibCompiler/example/compile_udp_mib.cmd b/contrib/apps/LwipMibCompiler/example/compile_udp_mib.cmd new file mode 100644 index 0000000..1c84dbf --- /dev/null +++ b/contrib/apps/LwipMibCompiler/example/compile_udp_mib.cmd @@ -0,0 +1 @@ +..\LwipMibCompiler\bin\Debug\LwipMibCompiler.exe ..\Mibs\UDP-MIB .\ ..\Mibs\ diff --git a/contrib/apps/LwipMibCompiler/example/compile_udp_mib.sh b/contrib/apps/LwipMibCompiler/example/compile_udp_mib.sh new file mode 100644 index 0000000..93798c0 --- /dev/null +++ b/contrib/apps/LwipMibCompiler/example/compile_udp_mib.sh @@ -0,0 +1 @@ +../LwipMibCompiler/bin/Debug/LwipMibCompiler.exe ../Mibs/UDP-MIB ./ ../Mibs/ diff --git a/contrib/apps/chargen/README b/contrib/apps/chargen/README new file mode 100644 index 0000000..7dc2ee5 --- /dev/null +++ b/contrib/apps/chargen/README @@ -0,0 +1,52 @@ + + CHARGEN + +This file implements a nice example of handling multiple tcp sockets in a +server environment. Just call chargen_init() from your application after +you have initialized lwip and added your network interfaces. Change the +MAX_SERV option to increase or decrease the number of sessions supported. + +chargen will jam as much data as possible into the output socket, so it +will take up a lot of CPU time. Therefore it will be a good idea to run it +as the lowest possible priority (just ahead of any idle task). + +This is also a good example of how to support multiple sessions in an +embedded system where you might not have fork(). The multiple sessions are +all handled by the same thread and select() is used for demultiplexing. + +No makefile is provided, just add chargen to the makefile for your +application. It is OS and HW independent. + +Once the chargen server is running in your application, go to another system +and open a telnet session to your lwip platform at port 19. You should see an +ASCII pattern start to stream on you screen. + +As an example, lets say that your system running lwip is at IP address +192.168.10.244 and you have a linux system connected to it at IP address +192.168.10.59. Issue the following command at a terminal prompt on the linux system: + +telnet 192.168.10.244 19 + +You will see a pattern similar to the following on streaming by on your +screen: + +ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{ +BCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{| +CDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} +DEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~! +FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!" +GHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"# +HIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$ +IJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$% +JKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%& +KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&' +LMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'( + +It even works from windows: At a dos prompt you can also issue the same +telnet command and you will get a similar (but much slower, at least on W98) +data stream. + +David Haas + + diff --git a/contrib/apps/chargen/chargen.c b/contrib/apps/chargen/chargen.c new file mode 100644 index 0000000..94a70b9 --- /dev/null +++ b/contrib/apps/chargen/chargen.c @@ -0,0 +1,274 @@ +/** @file + * + * chargen server for lwip + */ +/* + * Copyright (c) 2003 NBS Card Technology, Paramus, NJ. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: David Haas + * + * Purpose: chargen server for testing and demonstration purposes + * + * This file implements a nice example of handling multiple tcp sockets in a + * server environment. Just call chargen_init() from your application after + * you have initialized lwip and added your network interfaces. Change the + * MAX_SERV option to increase or decrease the number of sessions supported. + * + * chargen will jam as much data as possible into the output socket, so it + * will take up a lot of CPU time. Therefore it will be a good idea to run it + * as the lowest possible priority (just ahead of any idle task). + * + * This is also a good example of how to support multiple sessions in an + * embedded system where you might not have fork(). + */ + +#include "lwip/opt.h" +#include "lwip/sys.h" +#include "lwip/sockets.h" +#include "lwip/mem.h" + +#include + +#include "chargen.h" + +#if LWIP_SOCKET && LWIP_SOCKET_SELECT + +#define MAX_SERV 5 /* Maximum number of chargen services. Don't need too many */ +#define CHARGEN_THREAD_NAME "chargen" +#define CHARGEN_PRIORITY 254 /* Really low priority */ +#define CHARGEN_THREAD_STACKSIZE 0 +#define SEND_SIZE TCP_SNDLOWAT /* If we only send this much, then when select + says we can send, we know we won't block */ + +struct charcb { + struct charcb *next; + int socket; + struct sockaddr_storage cliaddr; + socklen_t clilen; + char nextchar; +}; + +static struct charcb *charcb_list = NULL; + +/************************************************************** + * void close_chargen(struct charcb *p_charcb) + * + * Close the socket and remove this charcb from the list. + **************************************************************/ +static void +close_chargen(struct charcb *p_charcb) +{ + struct charcb *p_search_charcb; + + /* Either an error or tcp connection closed on other + * end. Close here */ + lwip_close(p_charcb->socket); + /* Free charcb */ + if (charcb_list == p_charcb) { + charcb_list = p_charcb->next; + } else { + for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next) { + if (p_search_charcb->next == p_charcb) { + p_search_charcb->next = p_charcb->next; + break; + } + } + } + mem_free(p_charcb); +} + +/************************************************************** + * void do_read(struct charcb *p_charcb) + * + * Socket definitely is ready for reading. Read a buffer from the socket and + * discard the data. If no data is read, then the socket is closed and the + * charcb is removed from the list and freed. + **************************************************************/ +static int +do_read(struct charcb *p_charcb) +{ + char buffer[80]; + int readcount; + + /* Read some data */ + readcount = lwip_read(p_charcb->socket, &buffer, 80); + if (readcount <= 0) { + close_chargen(p_charcb); + return -1; + } + return 0; +} + +/************************************************************** + * void chargen_thread(void *arg) + * + * chargen task. This server will wait for connections on well + * known TCP port number: 19. For every connection, the server will + * write as much data as possible to the tcp port. + **************************************************************/ +static void +chargen_thread(void *arg) +{ + int listenfd; +#if LWIP_IPV6 + struct sockaddr_in6 chargen_saddr; +#else /* LWIP_IPV6 */ + struct sockaddr_in chargen_saddr; +#endif /* LWIP_IPV6 */ + fd_set readset; + fd_set writeset; + int i, maxfdp1; + struct charcb *p_charcb; + LWIP_UNUSED_ARG(arg); + + memset(&chargen_saddr, 0, sizeof (chargen_saddr)); +#if LWIP_IPV6 + /* First acquire our socket for listening for connections */ + listenfd = lwip_socket(AF_INET6, SOCK_STREAM, 0); + chargen_saddr.sin6_family = AF_INET6; + chargen_saddr.sin6_addr = in6addr_any; + chargen_saddr.sin6_port = lwip_htons(19); /* Chargen server port */ +#else /* LWIP_IPV6 */ + /* First acquire our socket for listening for connections */ + listenfd = lwip_socket(AF_INET, SOCK_STREAM, 0); + chargen_saddr.sin_family = AF_INET; + chargen_saddr.sin_addr.s_addr = PP_HTONL(INADDR_ANY); + chargen_saddr.sin_port = lwip_htons(19); /* Chargen server port */ +#endif /* LWIP_IPV6 */ + + LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0); + + if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof (chargen_saddr)) == -1) { + LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0); + } + + /* Put socket into listening mode */ + if (lwip_listen(listenfd, MAX_SERV) == -1) { + LWIP_ASSERT("chargen_thread(): Listen failed.", 0); + } + + + /* Wait forever for network input: This could be connections or data */ + for (;;) { + maxfdp1 = listenfd + 1; + + /* Determine what sockets need to be in readset */ + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_SET(listenfd, &readset); + for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) { + if (maxfdp1 < p_charcb->socket + 1) { + maxfdp1 = p_charcb->socket + 1; + } + FD_SET(p_charcb->socket, &readset); + FD_SET(p_charcb->socket, &writeset); + } + + /* Wait for data or a new connection */ + i = lwip_select(maxfdp1, &readset, &writeset, NULL, NULL); + + if (i == 0) { + continue; + } + /* At least one descriptor is ready */ + if (FD_ISSET(listenfd, &readset)) { + /* We have a new connection request!!! */ + /* Lets create a new control block */ + p_charcb = (struct charcb *) mem_malloc(sizeof (struct charcb)); + if (p_charcb) { + p_charcb->socket = lwip_accept(listenfd, + (struct sockaddr *) &p_charcb->cliaddr, + &p_charcb->clilen); + if (p_charcb->socket < 0) { + mem_free(p_charcb); + } else { + /* Keep this tecb in our list */ + p_charcb->next = charcb_list; + charcb_list = p_charcb; + p_charcb->nextchar = 0x21; + } + } else { + /* No memory to accept connection. Just accept and then close */ + int sock; + struct sockaddr cliaddr; + socklen_t clilen; + + sock = lwip_accept(listenfd, &cliaddr, &clilen); + if (sock >= 0) { + lwip_close(sock); + } + } + } + /* Go through list of connected clients and process data */ + for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) { + if (FD_ISSET(p_charcb->socket, &readset)) { + /* This socket is ready for reading. This could be because someone typed + * some characters or it could be because the socket is now closed. Try reading + * some data to see. */ + if (do_read(p_charcb) < 0) { + break; + } + } + if (FD_ISSET(p_charcb->socket, &writeset)) { + char line[80]; + char setchar = p_charcb->nextchar; + + for (i = 0; i < 59; i++) { + line[i] = setchar; + if (++setchar == 0x7f) { + setchar = 0x21; + } + } + line[i] = 0; + strcat(line, "\n\r"); + if (lwip_write(p_charcb->socket, line, strlen(line)) < 0) { + close_chargen(p_charcb); + break; + } + if (++p_charcb->nextchar == 0x7f) { + p_charcb->nextchar = 0x21; + } + } + } + } +} + + +/************************************************************** + * void chargen_init(void) + * + * This function initializes the chargen service. This function + * may only be called either before or after tasking has started. + **************************************************************/ +void +chargen_init(void) +{ + sys_thread_new(CHARGEN_THREAD_NAME, chargen_thread, NULL, CHARGEN_THREAD_STACKSIZE, CHARGEN_PRIORITY); +} + +#endif /* LWIP_SOCKET && LWIP_SOCKET_SELECT */ diff --git a/contrib/apps/chargen/chargen.h b/contrib/apps/chargen/chargen.h new file mode 100644 index 0000000..eb83e4f --- /dev/null +++ b/contrib/apps/chargen/chargen.h @@ -0,0 +1,12 @@ +#ifndef LWIP_CHARGEN_H +#define LWIP_CHARGEN_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET + +void chargen_init(void); + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_CHARGEN_H */ diff --git a/contrib/apps/httpserver/README b/contrib/apps/httpserver/README new file mode 100644 index 0000000..1f18bb8 --- /dev/null +++ b/contrib/apps/httpserver/README @@ -0,0 +1,12 @@ +HTTPSERVER + +This is a demonstration of how to make the most basic kind +of server using lWIP. + +* httpserver-raw.c - uses raw TCP calls (coming soon!) + +* httpserver-netconn.c - uses netconn and netbuf API + +This code updates the examples in Adam Dunkel's original +lwIP documentation to match changes in the code since that +PDF release. diff --git a/contrib/apps/httpserver/httpserver-netconn.c b/contrib/apps/httpserver/httpserver-netconn.c new file mode 100644 index 0000000..051584e --- /dev/null +++ b/contrib/apps/httpserver/httpserver-netconn.c @@ -0,0 +1,103 @@ + +#include "lwip/opt.h" +#include "lwip/arch.h" +#include "lwip/api.h" + +#include "httpserver-netconn.h" + +#if LWIP_NETCONN + +#ifndef HTTPD_DEBUG +#define HTTPD_DEBUG LWIP_DBG_OFF +#endif + +static const char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n"; +static const char http_index_html[] = "Congrats!

Welcome to our lwIP HTTP server!

This is a small test page, served by httpserver-netconn."; + +/** Serve one HTTP connection accepted in the http thread */ +static void +http_server_netconn_serve(struct netconn *conn) +{ + struct netbuf *inbuf; + char *buf; + u16_t buflen; + err_t err; + + /* Read the data from the port, blocking if nothing yet there. + We assume the request (the part we care about) is in one netbuf */ + err = netconn_recv(conn, &inbuf); + + if (err == ERR_OK) { + netbuf_data(inbuf, (void**)&buf, &buflen); + + /* Is this an HTTP GET command? (only check the first 5 chars, since + there are other formats for GET, and we're keeping it very simple )*/ + if (buflen>=5 && + buf[0]=='G' && + buf[1]=='E' && + buf[2]=='T' && + buf[3]==' ' && + buf[4]=='/' ) { + + /* Send the HTML header + * subtract 1 from the size, since we don't send the \0 in the string + * NETCONN_NOCOPY: our data is const static, so no need to copy it + */ + netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY); + + /* Send our HTML page */ + netconn_write(conn, http_index_html, sizeof(http_index_html)-1, NETCONN_NOCOPY); + } + } + /* Close the connection (server closes in HTTP) */ + netconn_close(conn); + + /* Delete the buffer (netconn_recv gives us ownership, + so we have to make sure to deallocate the buffer) */ + netbuf_delete(inbuf); +} + +/** The main function, never returns! */ +static void +http_server_netconn_thread(void *arg) +{ + struct netconn *conn, *newconn; + err_t err; + LWIP_UNUSED_ARG(arg); + + /* Create a new TCP connection handle */ + /* Bind to port 80 (HTTP) with default IP address */ +#if LWIP_IPV6 + conn = netconn_new(NETCONN_TCP_IPV6); + netconn_bind(conn, IP6_ADDR_ANY, 80); +#else /* LWIP_IPV6 */ + conn = netconn_new(NETCONN_TCP); + netconn_bind(conn, IP_ADDR_ANY, 80); +#endif /* LWIP_IPV6 */ + LWIP_ERROR("http_server: invalid conn", (conn != NULL), return;); + + /* Put the connection into LISTEN state */ + netconn_listen(conn); + + do { + err = netconn_accept(conn, &newconn); + if (err == ERR_OK) { + http_server_netconn_serve(newconn); + netconn_delete(newconn); + } + } while(err == ERR_OK); + LWIP_DEBUGF(HTTPD_DEBUG, + ("http_server_netconn_thread: netconn_accept received error %d, shutting down\n", + err)); + netconn_close(conn); + netconn_delete(conn); +} + +/** Initialize the HTTP server (start its thread) */ +void +http_server_netconn_init(void) +{ + sys_thread_new("http_server_netconn", http_server_netconn_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +#endif /* LWIP_NETCONN*/ diff --git a/contrib/apps/httpserver/httpserver-netconn.h b/contrib/apps/httpserver/httpserver-netconn.h new file mode 100644 index 0000000..d84b103 --- /dev/null +++ b/contrib/apps/httpserver/httpserver-netconn.h @@ -0,0 +1,6 @@ +#ifndef LWIP_HTTPSERVER_NETCONN_H +#define LWIP_HTTPSERVER_NETCONN_H + +void http_server_netconn_init(void); + +#endif /* LWIP_HTTPSERVER_NETCONN_H */ diff --git a/contrib/apps/netio/netio.c b/contrib/apps/netio/netio.c new file mode 100644 index 0000000..7d12ac8 --- /dev/null +++ b/contrib/apps/netio/netio.c @@ -0,0 +1,55 @@ +#include "netio.h" + +#include "lwip/opt.h" +#include "lwip/tcp.h" + +/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */ + +#if LWIP_TCP && LWIP_CALLBACK_API +static err_t +netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + + if (err == ERR_OK && p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } else { + pbuf_free(p); + } + + if (err == ERR_OK && p == NULL) { + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_close(pcb); + } + + return ERR_OK; +} + +static err_t +netio_accept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + if (pcb != NULL) { + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, netio_recv); + } + return ERR_OK; +} + +void +netio_init(void) +{ + struct tcp_pcb *pcb; + + pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + tcp_bind(pcb, IP_ANY_TYPE, 18767); + pcb = tcp_listen(pcb); + tcp_accept(pcb, netio_accept); +} +#endif /* LWIP_TCP && LWIP_CALLBACK_API */ diff --git a/contrib/apps/netio/netio.h b/contrib/apps/netio/netio.h new file mode 100644 index 0000000..11d7730 --- /dev/null +++ b/contrib/apps/netio/netio.h @@ -0,0 +1,6 @@ +#ifndef LWIP_NETIO_H +#define LWIP_NETIO_H + +void netio_init(void); + +#endif /* LWIP_NETIO_H */ diff --git a/contrib/apps/ping/ping.c b/contrib/apps/ping/ping.c new file mode 100644 index 0000000..ceb9739 --- /dev/null +++ b/contrib/apps/ping/ping.c @@ -0,0 +1,428 @@ +/** + * @file + * Ping sender module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/** + * This is an example of a "ping" sender (with raw API and socket API). + * It can be used as a start point to maintain opened a network connection, or + * like a network "watchdog" for your device. + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "ping.h" + +#include "lwip/mem.h" +#include "lwip/raw.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/inet_chksum.h" +#include "lwip/prot/ip4.h" + +#if PING_USE_SOCKETS +#include "lwip/sockets.h" +#include "lwip/inet.h" +#include +#endif /* PING_USE_SOCKETS */ + + +/** + * PING_DEBUG: Enable debugging for PING. + */ +#ifndef PING_DEBUG +#define PING_DEBUG LWIP_DBG_ON +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_DELAY +#define PING_DELAY 1000 +#endif + +/** ping identifier - must fit on a u16_t */ +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +/** ping additional data size to include in the packet */ +#ifndef PING_DATA_SIZE +#define PING_DATA_SIZE 32 +#endif + +/** ping result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#endif + +/* ping variables */ +static const ip_addr_t* ping_target; +static u16_t ping_seq_num; +#ifdef LWIP_DEBUG +static u32_t ping_time; +#endif /* LWIP_DEBUG */ +#if !PING_USE_SOCKETS +static struct raw_pcb *ping_pcb; +#endif /* PING_USE_SOCKETS */ + +/** Prepare a echo ICMP request */ +static void +ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) +{ + size_t i; + size_t data_len = len - sizeof(struct icmp_echo_hdr); + + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + iecho->seqno = lwip_htons(++ping_seq_num); + + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, len); +} + +#if PING_USE_SOCKETS + +/* Ping using the socket ip */ +static err_t +ping_send(int s, const ip_addr_t *addr) +{ + int err; + struct icmp_echo_hdr *iecho; + struct sockaddr_storage to; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); + +#if LWIP_IPV6 + if(IP_IS_V6(addr) && !ip6_addr_isipv4mappedipv6(ip_2_ip6(addr))) { + /* todo: support ICMP6 echo */ + return ERR_VAL; + } +#endif /* LWIP_IPV6 */ + + iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size); + if (!iecho) { + return ERR_MEM; + } + + ping_prepare_echo(iecho, (u16_t)ping_size); + +#if LWIP_IPV4 + if(IP_IS_V4(addr)) { + struct sockaddr_in *to4 = (struct sockaddr_in*)&to; + to4->sin_len = sizeof(*to4); + to4->sin_family = AF_INET; + inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(addr)); + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 + if(IP_IS_V6(addr)) { + struct sockaddr_in6 *to6 = (struct sockaddr_in6*)&to; + to6->sin6_len = sizeof(*to6); + to6->sin6_family = AF_INET6; + inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(addr)); + } +#endif /* LWIP_IPV6 */ + + err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); + + mem_free(iecho); + + return (err ? ERR_OK : ERR_VAL); +} + +static void +ping_recv(int s) +{ + char buf[64]; + int len; + struct sockaddr_storage from; + int fromlen = sizeof(from); + + while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { + if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { + ip_addr_t fromaddr; + memset(&fromaddr, 0, sizeof(fromaddr)); + +#if LWIP_IPV4 + if(from.ss_family == AF_INET) { + struct sockaddr_in *from4 = (struct sockaddr_in*)&from; + inet_addr_to_ip4addr(ip_2_ip4(&fromaddr), &from4->sin_addr); + IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 + if(from.ss_family == AF_INET6) { + struct sockaddr_in6 *from6 = (struct sockaddr_in6*)&from; + inet6_addr_to_ip6addr(ip_2_ip6(&fromaddr), &from6->sin6_addr); + IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV6 */ + + LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print_val(PING_DEBUG, fromaddr); + LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now() - ping_time))); + + /* todo: support ICMP6 echo */ +#if LWIP_IPV4 + if (IP_IS_V4_VAL(fromaddr)) { + struct ip_hdr *iphdr; + struct icmp_echo_hdr *iecho; + + iphdr = (struct ip_hdr *)buf; + iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); + if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { + /* do some ping result processing */ + PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); + return; + } else { + LWIP_DEBUGF( PING_DEBUG, ("ping: drop\n")); + } + } +#endif /* LWIP_IPV4 */ + } + fromlen = sizeof(from); + } + + if (len == 0) { + LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\n", (sys_now()-ping_time))); + } + + /* do some ping result processing */ + PING_RESULT(0); +} + +static void +ping_thread(void *arg) +{ + int s; + int ret; + +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + int timeout = PING_RCV_TIMEO; +#else + struct timeval timeout; + timeout.tv_sec = PING_RCV_TIMEO/1000; + timeout.tv_usec = (PING_RCV_TIMEO%1000)*1000; +#endif + LWIP_UNUSED_ARG(arg); + +#if LWIP_IPV6 + if(IP_IS_V4(ping_target) || ip6_addr_isipv4mappedipv6(ip_2_ip6(ping_target))) { + s = lwip_socket(AF_INET6, SOCK_RAW, IP_PROTO_ICMP); + } else { + s = lwip_socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6); + } +#else + s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP); +#endif + if (s < 0) { + return; + } + + ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + LWIP_ASSERT("setting receive timeout failed", ret == 0); + LWIP_UNUSED_ARG(ret); + + while (ping_target != NULL) { + if (ping_send(s, ping_target) == ERR_OK) { + LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, ping_target); + LWIP_DEBUGF( PING_DEBUG, ("\n")); + +#ifdef LWIP_DEBUG + ping_time = sys_now(); +#endif /* LWIP_DEBUG */ + ping_recv(s); + } else { + LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, ping_target); + LWIP_DEBUGF( PING_DEBUG, (" - error\n")); + } + sys_msleep(PING_DELAY); + } + lwip_close(s); +} + +#else /* PING_USE_SOCKETS */ + +/* Ping using the raw ip */ +static u8_t +ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) +{ + struct icmp_echo_hdr *iecho; + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_ASSERT("addr != NULL", addr != NULL); + LWIP_ASSERT("p != NULL", p != NULL); + + if ((p->tot_len >= (IP_HLEN + sizeof(struct icmp_echo_hdr))) && + pbuf_remove_header(p, IP_HLEN) == 0) { + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { + LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); + + /* do some ping result processing */ + PING_RESULT(1); + pbuf_free(p); + return 1; /* eat the packet */ + } + /* not eaten, restore original packet */ + pbuf_add_header(p, IP_HLEN); + } + + return 0; /* don't eat the packet */ +} + +static void +ping_send(struct raw_pcb *raw, const ip_addr_t *addr) +{ + struct pbuf *p; + struct icmp_echo_hdr *iecho; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + + LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF( PING_DEBUG, ("\n")); + LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); + + p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); + if (!p) { + return; + } + if ((p->len == p->tot_len) && (p->next == NULL)) { + iecho = (struct icmp_echo_hdr *)p->payload; + + ping_prepare_echo(iecho, (u16_t)ping_size); + + raw_sendto(raw, p, addr); +#ifdef LWIP_DEBUG + ping_time = sys_now(); +#endif /* LWIP_DEBUG */ + } + pbuf_free(p); +} + +static void +ping_timeout(void *arg) +{ + struct raw_pcb *pcb = (struct raw_pcb*)arg; + + LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL); + + ping_send(pcb, ping_target); + + sys_timeout(PING_DELAY, ping_timeout, pcb); +} + +static void +ping_raw_init(void) +{ + ping_pcb = raw_new(IP_PROTO_ICMP); + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + + raw_recv(ping_pcb, ping_recv, NULL); + raw_bind(ping_pcb, IP_ADDR_ANY); + sys_timeout(PING_DELAY, ping_timeout, ping_pcb); +} + +void +ping_send_now(void) +{ + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + LWIP_ASSERT("ping_target != NULL", ping_target != NULL); + ping_send(ping_pcb, ping_target); +} + +static void +ping_raw_stop(void) +{ + sys_untimeout(ping_timeout, ping_pcb); + if (ping_pcb != NULL) { + raw_remove(ping_pcb); + ping_pcb = NULL; + } +} + +#endif /* PING_USE_SOCKETS */ + +/** + * Initialize thread (socket mode) or timer (callback mode) to cyclically send pings + * to a target. + * Running ping is implicitly stopped. + */ +void +ping_init(const ip_addr_t* ping_addr) +{ + ping_stop(); + + LWIP_ASSERT("ping_addr != NULL", ping_addr != NULL); + ping_target = ping_addr; + +#if PING_USE_SOCKETS + sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +#else /* PING_USE_SOCKETS */ + ping_raw_init(); +#endif /* PING_USE_SOCKETS */ +} + +/** + * Stop sending more pings. + */ +void ping_stop(void) +{ +#if !PING_USE_SOCKETS + ping_raw_stop(); +#endif /* !PING_USE_SOCKETS */ + ping_target = NULL; +} + +#endif /* LWIP_RAW */ diff --git a/contrib/apps/ping/ping.h b/contrib/apps/ping/ping.h new file mode 100644 index 0000000..b6e0608 --- /dev/null +++ b/contrib/apps/ping/ping.h @@ -0,0 +1,20 @@ +#ifndef LWIP_PING_H +#define LWIP_PING_H + +#include "lwip/ip_addr.h" + +/** + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used + */ +#ifndef PING_USE_SOCKETS +#define PING_USE_SOCKETS LWIP_SOCKET +#endif + +void ping_init(const ip_addr_t* ping_addr); +void ping_stop(void); + +#if !PING_USE_SOCKETS +void ping_send_now(void); +#endif /* !PING_USE_SOCKETS */ + +#endif /* LWIP_PING_H */ diff --git a/contrib/apps/rtp/rtp.c b/contrib/apps/rtp/rtp.c new file mode 100644 index 0000000..4be6973 --- /dev/null +++ b/contrib/apps/rtp/rtp.c @@ -0,0 +1,308 @@ +/** + * @file + * RTP client/server module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/sockets.h" + +#include "rtp.h" + +#include "rtpdata.h" + +#include + +/** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API). + */ + +/** + * RTP_DEBUG: Enable debugging for RTP. + */ +#ifndef RTP_DEBUG +#define RTP_DEBUG LWIP_DBG_ON +#endif + +/** RTP stream port */ +#ifndef RTP_STREAM_PORT +#define RTP_STREAM_PORT 4000 +#endif + +/** RTP stream multicast address as IPv4 address in "u32_t" format */ +#ifndef RTP_STREAM_ADDRESS +#define RTP_STREAM_ADDRESS inet_addr("232.0.0.0") +#endif + +/** RTP send delay - in milliseconds */ +#ifndef RTP_SEND_DELAY +#define RTP_SEND_DELAY 40 +#endif + +/** RTP receive timeout - in milliseconds */ +#ifndef RTP_RECV_TIMEOUT +#define RTP_RECV_TIMEOUT 2000 +#endif + +/** RTP stats display period - in received packets */ +#ifndef RTP_RECV_STATS +#define RTP_RECV_STATS 50 +#endif + +/** RTP macro to let the application process the data */ +#ifndef RTP_RECV_PROCESSING +#define RTP_RECV_PROCESSING(p,s) +#endif + +/** RTP packet/payload size */ +#define RTP_PACKET_SIZE 1500 +#define RTP_PAYLOAD_SIZE 1024 + +/** RTP header constants */ +#define RTP_VERSION 0x80 +#define RTP_TIMESTAMP_INCREMENT 3600 +#define RTP_SSRC 0 +#define RTP_PAYLOADTYPE 96 +#define RTP_MARKER_MASK 0x80 + +/** RTP message header */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rtp_hdr { + PACK_STRUCT_FLD_8(u8_t version); + PACK_STRUCT_FLD_8(u8_t payloadtype); + PACK_STRUCT_FIELD(u16_t seqNum); + PACK_STRUCT_FIELD(u32_t timestamp); + PACK_STRUCT_FIELD(u32_t ssrc); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** RTP packets */ +static u8_t rtp_send_packet[RTP_PACKET_SIZE]; +static u8_t rtp_recv_packet[RTP_PACKET_SIZE]; + +/** + * RTP send packets + */ +static void +rtp_send_packets( int sock, struct sockaddr_in* to) +{ + struct rtp_hdr* rtphdr; + u8_t* rtp_payload; + size_t rtp_payload_size; + size_t rtp_data_index; + + /* prepare RTP packet */ + rtphdr = (struct rtp_hdr*)rtp_send_packet; + rtphdr->version = RTP_VERSION; + rtphdr->payloadtype = 0; + rtphdr->ssrc = PP_HTONL(RTP_SSRC); + rtphdr->timestamp = lwip_htonl(lwip_ntohl(rtphdr->timestamp) + RTP_TIMESTAMP_INCREMENT); + + /* send RTP stream packets */ + rtp_data_index = 0; + do { + rtp_payload = rtp_send_packet+sizeof(struct rtp_hdr); + rtp_payload_size = LWIP_MIN(RTP_PAYLOAD_SIZE, sizeof(rtp_data) - rtp_data_index); + + MEMCPY(rtp_payload, rtp_data + rtp_data_index, rtp_payload_size); + + /* set MARKER bit in RTP header on the last packet of an image */ + if ((rtp_data_index + rtp_payload_size) >= sizeof(rtp_data)) { + rtphdr->payloadtype = RTP_PAYLOADTYPE | RTP_MARKER_MASK; + } else { + rtphdr->payloadtype = RTP_PAYLOADTYPE; + } + + /* send RTP stream packet */ + if (lwip_sendto(sock, rtp_send_packet, sizeof(struct rtp_hdr) + rtp_payload_size, + 0, (struct sockaddr *)to, sizeof(struct sockaddr)) >= 0) { + rtphdr->seqNum = lwip_htons((u16_t)(lwip_ntohs(rtphdr->seqNum) + 1)); + rtp_data_index += rtp_payload_size; + } else { + LWIP_DEBUGF(RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno)); + } + }while (rtp_data_index < sizeof(rtp_data)); +} + +/** + * RTP send thread + */ +static void +rtp_send_thread(void *arg) +{ + int sock; + struct sockaddr_in local; + struct sockaddr_in to; + u32_t rtp_stream_address; + + LWIP_UNUSED_ARG(arg); + + /* initialize RTP stream address */ + rtp_stream_address = RTP_STREAM_ADDRESS; + + /* if we got a valid RTP stream address... */ + if (rtp_stream_address != 0) { + /* create new socket */ + sock = lwip_socket(AF_INET, SOCK_DGRAM, 0); + if (sock >= 0) { + /* prepare local address */ + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = PP_HTONS(INADDR_ANY); + local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); + + /* bind to local address */ + if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { + /* prepare RTP stream address */ + memset(&to, 0, sizeof(to)); + to.sin_family = AF_INET; + to.sin_port = PP_HTONS(RTP_STREAM_PORT); + to.sin_addr.s_addr = rtp_stream_address; + + /* send RTP packets */ + memset(rtp_send_packet, 0, sizeof(rtp_send_packet)); + while (1) { + rtp_send_packets( sock, &to); + sys_msleep(RTP_SEND_DELAY); + } + } + + /* close the socket */ + lwip_close(sock); + } + } +} + +/** + * RTP recv thread + */ +static void +rtp_recv_thread(void *arg) +{ + int sock; + struct sockaddr_in local; + struct sockaddr_in from; + int fromlen; + struct ip_mreq ipmreq; + struct rtp_hdr* rtphdr; + u32_t rtp_stream_address; + int timeout; + int result; + int recvrtppackets = 0; + int lostrtppackets = 0; + u16_t lastrtpseq = 0; + + LWIP_UNUSED_ARG(arg); + + /* initialize RTP stream address */ + rtp_stream_address = RTP_STREAM_ADDRESS; + + /* if we got a valid RTP stream address... */ + if (rtp_stream_address != 0) { + /* create new socket */ + sock = lwip_socket(AF_INET, SOCK_DGRAM, 0); + if (sock >= 0) { + /* prepare local address */ + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = PP_HTONS(RTP_STREAM_PORT); + local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); + + /* bind to local address */ + if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { + /* set recv timeout */ + timeout = RTP_RECV_TIMEOUT; + result = lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + if (result) { + LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: setsockopt(SO_RCVTIMEO) failed: errno=%d\n", errno)); + } + + /* prepare multicast "ip_mreq" struct */ + ipmreq.imr_multiaddr.s_addr = rtp_stream_address; + ipmreq.imr_interface.s_addr = PP_HTONL(INADDR_ANY); + + /* join multicast group */ + if (lwip_setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq)) == 0) { + /* receive RTP packets */ + while(1) { + fromlen = sizeof(from); + result = lwip_recvfrom(sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, + (struct sockaddr *)&from, (socklen_t *)&fromlen); + if ((result > 0) && ((size_t)result >= sizeof(struct rtp_hdr))) { + size_t recved = (size_t)result; + rtphdr = (struct rtp_hdr *)rtp_recv_packet; + recvrtppackets++; + if ((lastrtpseq == 0) || ((lastrtpseq + 1) == lwip_ntohs(rtphdr->seqNum))) { + RTP_RECV_PROCESSING((rtp_recv_packet + sizeof(rtp_hdr)), (recved-sizeof(rtp_hdr))); + LWIP_UNUSED_ARG(recved); /* just in case... */ + } else { + lostrtppackets++; + } + lastrtpseq = lwip_ntohs(rtphdr->seqNum); + if ((recvrtppackets % RTP_RECV_STATS) == 0) { + LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets)); + } + } else { + LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n")); + } + } + + /* leave multicast group */ + /* TODO: this code is never reached + result = lwip_setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq)); + if (result) { + LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: setsockopt(IP_DROP_MEMBERSHIP) failed: errno=%d\n", errno)); + }*/ + } + } + + /* close the socket */ + lwip_close(sock); + } + } +} + +void +rtp_init(void) +{ + sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); + sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +#endif /* LWIP_SOCKET && LWIP_IGMP */ diff --git a/contrib/apps/rtp/rtp.h b/contrib/apps/rtp/rtp.h new file mode 100644 index 0000000..c53d89b --- /dev/null +++ b/contrib/apps/rtp/rtp.h @@ -0,0 +1,8 @@ +#ifndef LWIP_RTP_H +#define LWIP_RTP_H + +#if LWIP_SOCKET && LWIP_IGMP +void rtp_init(void); +#endif /* LWIP_SOCKET && LWIP_IGMP */ + +#endif /* LWIP_RTP_H */ diff --git a/contrib/apps/rtp/rtpdata.h b/contrib/apps/rtp/rtpdata.h new file mode 100644 index 0000000..76ff344 --- /dev/null +++ b/contrib/apps/rtp/rtpdata.h @@ -0,0 +1,2040 @@ +const unsigned char rtp_data[] = { + 0x00, 0x00, 0x01, 0xb0, 0xf5, 0x00, 0x00, 0x01, + 0xb5, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x20, 0x00, 0x86, 0x84, 0x00, 0x67, 0x0c, + 0x2c, 0x10, 0x90, 0x51, 0x8f, 0x00, 0x00, 0x01, + 0xb2, 0x44, 0x69, 0x76, 0x58, 0x35, 0x30, 0x33, + 0x62, 0x31, 0x33, 0x39, 0x33, 0x70, 0x00, 0x00, + 0x01, 0xb2, 0x58, 0x76, 0x69, 0x44, 0x30, 0x30, + 0x33, 0x39, 0x00, 0x00, 0x01, 0xb6, 0x18, 0x60, + 0xab, 0x94, 0x03, 0xc0, 0xca, 0xc0, 0x3e, 0xd0, + 0x78, 0x4f, 0xf9, 0x44, 0x91, 0xe9, 0xfa, 0xc9, + 0xfe, 0xa1, 0xa4, 0xc1, 0x66, 0x03, 0x2e, 0x39, + 0x0c, 0x7e, 0x0e, 0xaa, 0x02, 0x92, 0xf8, 0xd5, + 0xec, 0xe2, 0x35, 0xb9, 0x35, 0x0c, 0xb3, 0x82, + 0xa6, 0xad, 0xd0, 0xd1, 0xca, 0xb8, 0xe8, 0x10, + 0x55, 0x78, 0x03, 0xc0, 0x38, 0x15, 0xba, 0xce, + 0xe2, 0xea, 0x00, 0xc3, 0x60, 0xb1, 0x70, 0xf4, + 0x14, 0x6c, 0x35, 0x4d, 0xe8, 0x5a, 0x1e, 0x58, + 0xdf, 0x03, 0x01, 0xfd, 0x2a, 0x45, 0x54, 0xca, + 0x0f, 0x05, 0x00, 0xbd, 0xd0, 0xcc, 0xb4, 0x90, + 0x4c, 0x24, 0x6b, 0x20, 0x30, 0x95, 0xf1, 0x2f, + 0xb4, 0xa7, 0x83, 0xdc, 0xce, 0x03, 0x05, 0x02, + 0x1a, 0x5d, 0x1a, 0x2c, 0xbf, 0x51, 0x28, 0x8b, + 0xd7, 0x6b, 0xdd, 0xf9, 0x44, 0xbb, 0x0e, 0x91, + 0x64, 0xb9, 0xa6, 0x33, 0xd3, 0x6e, 0x34, 0xa4, + 0xac, 0xac, 0x53, 0x0d, 0x79, 0xbe, 0xae, 0x5b, + 0x47, 0x2e, 0xde, 0x62, 0xa1, 0x53, 0xcd, 0x7d, + 0xfe, 0x66, 0xa1, 0x2b, 0x9c, 0xe1, 0xca, 0xbc, + 0xea, 0x84, 0x1c, 0x68, 0xff, 0xbb, 0x28, 0xa1, + 0x26, 0x18, 0x99, 0xb1, 0x4f, 0x68, 0x80, 0x28, + 0x0e, 0x20, 0xc3, 0xbf, 0x0f, 0x80, 0xf8, 0x90, + 0x3b, 0x1f, 0x16, 0xe4, 0xb0, 0x6f, 0x44, 0x16, + 0x38, 0xb8, 0xc3, 0x81, 0x22, 0xfa, 0xe3, 0x09, + 0xf6, 0x61, 0x6d, 0xef, 0x67, 0x56, 0x3b, 0x57, + 0xb5, 0x23, 0x03, 0x1f, 0x6d, 0x0d, 0xb9, 0x08, + 0xc6, 0x43, 0xba, 0xd1, 0x40, 0x5a, 0xe8, 0xca, + 0x9e, 0x17, 0x1f, 0x6d, 0x5d, 0x16, 0x98, 0xab, + 0xe6, 0x99, 0xf6, 0x37, 0xc6, 0x1b, 0xdc, 0xb9, + 0xb3, 0xfe, 0x9a, 0x4b, 0x1e, 0xec, 0xf9, 0x5f, + 0xb8, 0xc7, 0xfc, 0xbe, 0x6c, 0xd5, 0xf3, 0x9b, + 0x17, 0x8b, 0x89, 0x82, 0xff, 0x30, 0x19, 0x20, + 0x30, 0xe6, 0x29, 0x96, 0x75, 0x75, 0xeb, 0x00, + 0x3f, 0xa1, 0x20, 0x5b, 0x06, 0x11, 0x98, 0x1f, + 0xb2, 0xad, 0x3a, 0x59, 0xe6, 0x7d, 0x38, 0xa4, + 0xb1, 0x4f, 0xfe, 0xdf, 0x3a, 0x4b, 0xdb, 0x69, + 0xc3, 0x93, 0xcc, 0xdf, 0x5e, 0xf7, 0x2a, 0x38, + 0x2a, 0x89, 0x84, 0x80, 0x6c, 0x12, 0x44, 0x95, + 0x78, 0xd8, 0x7e, 0x3f, 0x4e, 0xcf, 0x3f, 0x39, + 0xba, 0x9f, 0xfa, 0x8f, 0x2f, 0x62, 0xfa, 0xf0, + 0xb6, 0x20, 0xa7, 0x06, 0x02, 0x3f, 0x28, 0x96, + 0x80, 0xf0, 0x99, 0x8e, 0x82, 0x15, 0x11, 0x87, + 0x35, 0xa4, 0xfd, 0x53, 0xcb, 0xcd, 0x68, 0x38, + 0xe8, 0xdb, 0x8d, 0xc2, 0x71, 0xbc, 0x65, 0x3e, + 0xac, 0x5b, 0x0d, 0xae, 0xc0, 0x3c, 0x77, 0xfe, + 0xe8, 0xde, 0x3c, 0xbd, 0xdb, 0xb3, 0x39, 0x09, + 0x56, 0x0a, 0xa2, 0xfe, 0x40, 0xd7, 0x6f, 0x56, + 0x07, 0x02, 0xec, 0xd6, 0xed, 0x06, 0x5e, 0x2f, + 0xb6, 0xce, 0xf1, 0x4f, 0x16, 0x88, 0x04, 0x41, + 0x79, 0x0e, 0x98, 0xbe, 0x54, 0x75, 0x1a, 0xd6, + 0x50, 0xcf, 0x82, 0x6a, 0xf7, 0xaf, 0x7f, 0xfb, + 0x6d, 0x88, 0x97, 0x24, 0x40, 0x68, 0xa0, 0x57, + 0x79, 0x57, 0xe9, 0x6b, 0xaa, 0xe5, 0xe4, 0x2b, + 0xaa, 0x14, 0x64, 0x90, 0x6c, 0x50, 0x4a, 0xe3, + 0x97, 0x43, 0xf6, 0x81, 0x90, 0xa9, 0xa6, 0xba, + 0xb1, 0x21, 0x12, 0x5f, 0xe0, 0xdf, 0x88, 0x86, + 0x03, 0x30, 0x94, 0xb2, 0x6d, 0xd2, 0xdc, 0x45, + 0x14, 0x54, 0x1d, 0xe8, 0x38, 0x8d, 0xbe, 0x8a, + 0xaf, 0x20, 0xa2, 0x3e, 0xa2, 0x5c, 0xc6, 0xae, + 0xe6, 0xc4, 0x48, 0xec, 0xea, 0xc7, 0x4e, 0x17, + 0xb2, 0x91, 0x52, 0xb4, 0xe9, 0x8b, 0x15, 0xfb, + 0x99, 0x7c, 0xda, 0xb8, 0xad, 0x57, 0x31, 0x5b, + 0x5b, 0x67, 0xaa, 0x1e, 0x93, 0x76, 0xa5, 0x25, + 0xd9, 0x0d, 0x70, 0xd8, 0xb9, 0x11, 0x34, 0xfd, + 0xaf, 0x0e, 0x0d, 0x42, 0x57, 0x97, 0x26, 0x06, + 0xdf, 0x29, 0x7e, 0x79, 0x72, 0x22, 0x36, 0xa5, + 0x9f, 0x6a, 0x16, 0x24, 0x6f, 0x10, 0x56, 0xec, + 0x5b, 0x46, 0x50, 0x94, 0x88, 0xc4, 0xfa, 0x9e, + 0xd8, 0x5b, 0xb7, 0x50, 0x72, 0x62, 0x25, 0xaa, + 0x39, 0x84, 0x69, 0xaa, 0xfc, 0xbf, 0x9b, 0x45, + 0xf7, 0xc5, 0x41, 0x97, 0x41, 0xc7, 0xac, 0x7f, + 0x68, 0x92, 0xab, 0x64, 0xaa, 0x46, 0x32, 0x84, + 0x77, 0x1b, 0xfc, 0xbc, 0x5a, 0x42, 0x28, 0xfa, + 0x3e, 0x55, 0xf4, 0xe9, 0x44, 0xac, 0xc5, 0x4a, + 0x6c, 0x93, 0xde, 0x03, 0x6d, 0xdc, 0xb8, 0x5b, + 0xb7, 0x83, 0x7e, 0xc2, 0xaa, 0x33, 0x70, 0x34, + 0x41, 0x46, 0x25, 0xa5, 0x6f, 0xdb, 0x96, 0x0f, + 0xd3, 0xab, 0xd4, 0x17, 0x65, 0x96, 0x0c, 0x1e, + 0x39, 0x4c, 0x9d, 0x90, 0x3f, 0x5b, 0x8d, 0xaa, + 0xce, 0xac, 0xa6, 0x50, 0xf0, 0x66, 0xb2, 0x30, + 0xce, 0x42, 0x61, 0xaa, 0xb6, 0x7e, 0xca, 0xbf, + 0xfd, 0xbf, 0xef, 0x51, 0xed, 0xdf, 0x95, 0x0b, + 0xa7, 0x34, 0x24, 0x13, 0x62, 0x44, 0x81, 0xdf, + 0x3a, 0x8e, 0x95, 0x91, 0x67, 0xd7, 0x57, 0x54, + 0x92, 0x1d, 0x79, 0xa3, 0x2a, 0xf3, 0x0c, 0x7a, + 0x12, 0xa8, 0x33, 0xf9, 0x05, 0x02, 0x7b, 0xef, + 0x12, 0x18, 0xab, 0x8b, 0x40, 0x38, 0x7e, 0x0c, + 0x1f, 0x04, 0x30, 0x62, 0xa8, 0xd5, 0xd9, 0x78, + 0xdd, 0x1c, 0xb4, 0x57, 0xc1, 0x83, 0xc4, 0x41, + 0x08, 0x72, 0x5c, 0xc2, 0xb6, 0xd3, 0xd4, 0x85, + 0x4a, 0x7e, 0x58, 0xc3, 0x19, 0xfa, 0xdd, 0x51, + 0x03, 0x85, 0x1d, 0xe9, 0x10, 0x5e, 0x8c, 0x8f, + 0x41, 0x03, 0xe9, 0xbc, 0xa8, 0xba, 0xeb, 0x73, + 0x7d, 0x85, 0x69, 0xc7, 0x3b, 0xd9, 0x49, 0x0b, + 0x39, 0x03, 0x12, 0x11, 0x8b, 0x72, 0x97, 0x62, + 0x5f, 0xfe, 0x59, 0x4d, 0xc0, 0x3a, 0xdf, 0xcb, + 0x3e, 0x80, 0x39, 0xd5, 0x7a, 0xb1, 0x45, 0x86, + 0x06, 0xf6, 0xb6, 0xda, 0x98, 0xa1, 0x41, 0xae, + 0x12, 0xd3, 0xd1, 0x71, 0x5a, 0xa5, 0x40, 0xc0, + 0x8a, 0x3f, 0x4e, 0xac, 0x78, 0x93, 0x55, 0x31, + 0xfc, 0xcf, 0x67, 0x93, 0x52, 0xc4, 0x53, 0x0d, + 0xdf, 0x49, 0xd7, 0x83, 0x00, 0x18, 0x4b, 0xcd, + 0x65, 0xaf, 0xb5, 0xd5, 0x6c, 0xc4, 0x14, 0xb7, + 0xdb, 0x9d, 0x06, 0x17, 0xca, 0xe1, 0x60, 0x07, + 0x6d, 0x57, 0xd0, 0xfb, 0x1a, 0xf5, 0xb2, 0x56, + 0xca, 0xea, 0x21, 0x77, 0x41, 0xc0, 0x46, 0xc8, + 0x85, 0xe3, 0x15, 0x6a, 0xdb, 0x80, 0x47, 0x6d, + 0x05, 0x44, 0x06, 0x04, 0xf6, 0x92, 0x24, 0xdb, + 0x9b, 0x6f, 0xfa, 0x8d, 0x72, 0x2d, 0x75, 0x7e, + 0x33, 0x9c, 0xe7, 0x06, 0xbb, 0x3d, 0xa4, 0xb7, + 0xee, 0x31, 0x46, 0x4b, 0x91, 0xe2, 0xb0, 0x54, + 0x5c, 0x78, 0x9e, 0x45, 0x90, 0xe4, 0x76, 0xbe, + 0xe1, 0x4c, 0xae, 0x89, 0x20, 0x6e, 0x77, 0x76, + 0x94, 0x63, 0x93, 0xaa, 0x62, 0x0e, 0x28, 0x7b, + 0xec, 0xc9, 0xc5, 0x25, 0x64, 0x5a, 0xe9, 0xcc, + 0x91, 0x1a, 0x9c, 0xcf, 0x91, 0x47, 0x32, 0x12, + 0x9f, 0x8b, 0x36, 0x07, 0x33, 0x4c, 0x45, 0x06, + 0x19, 0xdb, 0x61, 0xc5, 0x68, 0xb7, 0xab, 0x2e, + 0x7b, 0x5c, 0xa6, 0x4c, 0x6e, 0x08, 0x5f, 0xc1, + 0xc4, 0x99, 0x64, 0xef, 0xd8, 0x05, 0x5c, 0x0f, + 0x76, 0xdd, 0xab, 0x4f, 0x8e, 0x29, 0x54, 0x59, + 0x1d, 0x30, 0x33, 0xfb, 0x3b, 0x43, 0x96, 0xf4, + 0x52, 0x47, 0x2c, 0x66, 0x81, 0xca, 0xa6, 0x73, + 0x51, 0xc1, 0xc0, 0x32, 0x98, 0xa3, 0x41, 0x1c, + 0x40, 0x5e, 0x22, 0x05, 0xa0, 0xdb, 0xb0, 0x88, + 0xdf, 0xee, 0x2f, 0x3a, 0xbb, 0xe2, 0xef, 0x79, + 0x09, 0xa6, 0x0c, 0x0f, 0x4c, 0xdc, 0x81, 0xcc, + 0x3d, 0x36, 0x52, 0x4e, 0xbd, 0x44, 0x0d, 0x0d, + 0x84, 0xf5, 0x74, 0x33, 0x14, 0x1a, 0x87, 0xcb, + 0xcc, 0x93, 0xa3, 0x69, 0x21, 0x20, 0x26, 0x23, + 0xd9, 0x95, 0x0c, 0x22, 0x2b, 0x2f, 0x0d, 0xf4, + 0x34, 0x74, 0x53, 0x16, 0x5d, 0x60, 0x96, 0x3e, + 0x53, 0xd3, 0xcc, 0xc5, 0x72, 0x49, 0xc2, 0x4d, + 0xea, 0x02, 0x21, 0x7f, 0xbd, 0x80, 0x1d, 0xf0, + 0x87, 0xe6, 0xdb, 0xcc, 0x92, 0xdd, 0xfe, 0x78, + 0x4a, 0xd2, 0xf9, 0x77, 0x24, 0xed, 0x5a, 0x31, + 0x6c, 0xec, 0x71, 0x5d, 0x85, 0xad, 0xb3, 0xb9, + 0x6f, 0x11, 0x2d, 0xfa, 0x42, 0x2b, 0xcb, 0x01, + 0x08, 0x18, 0x11, 0x56, 0xcb, 0x01, 0xe1, 0xe0, + 0x1f, 0x06, 0xe8, 0x3c, 0x6c, 0x01, 0xaa, 0x49, + 0x86, 0xbf, 0x63, 0x79, 0x03, 0xbe, 0xd8, 0x47, + 0x4f, 0x26, 0x0d, 0x11, 0xe3, 0x76, 0x27, 0x0e, + 0xf1, 0x79, 0x44, 0x46, 0xc3, 0x3b, 0x4f, 0x05, + 0x20, 0x40, 0xff, 0x59, 0x6f, 0xaa, 0x17, 0xf4, + 0x40, 0xa1, 0x15, 0x0a, 0x4c, 0x0f, 0x94, 0x81, + 0xb8, 0x0c, 0x8e, 0x8d, 0xc3, 0x80, 0xc1, 0xeb, + 0x02, 0x16, 0xf4, 0xbe, 0xca, 0xa4, 0x3a, 0xa8, + 0xec, 0x0c, 0x89, 0xc4, 0x59, 0xe4, 0x8b, 0x9a, + 0x40, 0x7e, 0xae, 0xea, 0xa0, 0xeb, 0x6a, 0x99, + 0x95, 0x73, 0x79, 0x62, 0x18, 0xb8, 0x38, 0x64, + 0x73, 0x97, 0xb7, 0x58, 0xd1, 0x2d, 0x8d, 0xbe, + 0xf3, 0x13, 0x2f, 0x7c, 0xc0, 0x1d, 0x61, 0x4e, + 0x4c, 0xe6, 0x95, 0xce, 0x97, 0xf9, 0xbc, 0xf4, + 0x5a, 0xce, 0xa1, 0x3b, 0x39, 0xef, 0xc5, 0x39, + 0x4b, 0x72, 0x1b, 0xa5, 0x41, 0x92, 0x27, 0xda, + 0x72, 0xc2, 0xbb, 0xd4, 0x8d, 0x34, 0x97, 0x9d, + 0xb7, 0xde, 0xe7, 0xb0, 0x64, 0x8a, 0x0a, 0x0c, + 0x0e, 0x60, 0x30, 0x62, 0xb8, 0xbb, 0x9f, 0x96, + 0x05, 0x31, 0x33, 0xfa, 0x3c, 0x1f, 0xf4, 0x3d, + 0x04, 0x3c, 0x5c, 0x1e, 0x1b, 0xfe, 0xf1, 0xfe, + 0xa1, 0xb1, 0x03, 0x54, 0x99, 0x50, 0x61, 0xc5, + 0xbc, 0x2d, 0x00, 0xfe, 0xaf, 0x01, 0xe1, 0x7f, + 0xeb, 0xd4, 0x77, 0x0d, 0xb4, 0x0a, 0x9c, 0x18, + 0x92, 0x3d, 0x5a, 0xbf, 0xc0, 0x98, 0x66, 0xcc, + 0x06, 0x09, 0x6a, 0x50, 0xe9, 0x18, 0x32, 0x00, + 0x78, 0xc8, 0x06, 0x68, 0xac, 0x8b, 0x3f, 0x38, + 0xbf, 0x4a, 0x33, 0x30, 0x1c, 0x4f, 0xae, 0x16, + 0x44, 0x98, 0x24, 0x08, 0xc9, 0x07, 0xed, 0x62, + 0xbb, 0x89, 0x15, 0xca, 0x0f, 0x09, 0x00, 0x7a, + 0x51, 0xc5, 0x93, 0x54, 0x45, 0xfb, 0x73, 0xdf, + 0xe9, 0x42, 0x07, 0x90, 0x10, 0xcb, 0xdb, 0x2b, + 0x47, 0x20, 0x2b, 0xaa, 0xf4, 0x5c, 0xa4, 0x28, + 0x38, 0x9d, 0x5a, 0x44, 0x22, 0x0d, 0x54, 0x81, + 0x1d, 0x07, 0x0a, 0x37, 0xee, 0x49, 0x8b, 0xfb, + 0x3a, 0x8d, 0x7e, 0x83, 0x84, 0xfd, 0xf7, 0x98, + 0xad, 0xac, 0xa7, 0x46, 0x07, 0x62, 0x72, 0x56, + 0x1c, 0x03, 0x05, 0x4d, 0x70, 0xd8, 0x60, 0x62, + 0x8a, 0x8d, 0xe8, 0x23, 0x03, 0x04, 0x6d, 0x60, + 0xdc, 0x2a, 0x27, 0x92, 0x08, 0x8f, 0x65, 0xed, + 0xbd, 0xca, 0xa5, 0x1d, 0x80, 0x8d, 0x11, 0x03, + 0x83, 0xc7, 0x05, 0x04, 0x85, 0xcd, 0x2f, 0x3a, + 0xd4, 0x83, 0x02, 0x91, 0x91, 0xc5, 0x76, 0xb5, + 0x79, 0xcb, 0xfb, 0x29, 0x22, 0x90, 0x1e, 0x09, + 0x9f, 0x2c, 0x07, 0x77, 0xa0, 0x38, 0xf8, 0x63, + 0xf5, 0x2a, 0xd4, 0xc5, 0x0f, 0xd7, 0x43, 0x38, + 0xb5, 0xe8, 0x38, 0x94, 0x29, 0x71, 0x68, 0xb4, + 0x99, 0x0a, 0x4d, 0xf6, 0x94, 0x9d, 0x8e, 0x96, + 0x58, 0x88, 0x63, 0x46, 0x02, 0x9d, 0x64, 0x83, + 0x70, 0x72, 0x32, 0x6f, 0x90, 0x1d, 0x0e, 0xd5, + 0xf5, 0xd9, 0x0d, 0xe8, 0x0f, 0xa3, 0x20, 0x5f, + 0x26, 0x59, 0xc3, 0x50, 0x33, 0x04, 0xc9, 0x0c, + 0xc8, 0xa2, 0xce, 0x12, 0x43, 0x44, 0xa3, 0x55, + 0xe5, 0x07, 0x05, 0x1a, 0x69, 0xa8, 0xc4, 0x39, + 0x92, 0xa2, 0x44, 0x0e, 0x08, 0xe0, 0xa2, 0x4a, + 0x28, 0xd7, 0x80, 0xe1, 0x37, 0x96, 0x0c, 0x49, + 0x28, 0x0f, 0x3c, 0xc8, 0xe2, 0xc1, 0x5d, 0x4f, + 0xd4, 0x48, 0xa2, 0x21, 0x59, 0xf1, 0x0d, 0x9f, + 0xaa, 0xc6, 0x77, 0xc8, 0xe5, 0xce, 0x0d, 0xca, + 0x02, 0x87, 0x4a, 0x49, 0x01, 0xc8, 0x48, 0xc8, + 0xf3, 0x1b, 0x2f, 0xdf, 0x6c, 0xcb, 0x88, 0x66, + 0xf1, 0x40, 0xbd, 0x6a, 0x34, 0xfc, 0xb0, 0x89, + 0xde, 0x11, 0xc5, 0xc6, 0xa2, 0x44, 0xc6, 0xdb, + 0x67, 0xff, 0xd1, 0x79, 0x01, 0xa4, 0x9e, 0xf0, + 0x1f, 0x10, 0x57, 0x2b, 0x24, 0xc5, 0x1c, 0x09, + 0x45, 0x7e, 0xcc, 0x55, 0xe5, 0x0d, 0x64, 0xe2, + 0x2c, 0xe4, 0xea, 0xe4, 0x81, 0x31, 0xfd, 0x61, + 0x38, 0x8f, 0xba, 0x1f, 0xb4, 0xd9, 0x6c, 0xa8, + 0xac, 0xe4, 0xe8, 0xca, 0x9e, 0xee, 0xa9, 0x51, + 0xd7, 0xe9, 0x9d, 0xcc, 0xb0, 0x7c, 0x24, 0xc5, + 0x13, 0xa0, 0x89, 0x78, 0x0b, 0x15, 0xd1, 0x09, + 0xe4, 0xbf, 0x34, 0x6f, 0xcf, 0x0b, 0x82, 0x51, + 0xb3, 0x70, 0x7d, 0x83, 0xe1, 0x24, 0x0d, 0x33, + 0xad, 0xda, 0x5d, 0xfe, 0xe7, 0x38, 0x54, 0x52, + 0x0e, 0x3d, 0xd5, 0xec, 0xef, 0x0b, 0x05, 0xe1, + 0x16, 0xa9, 0x45, 0xec, 0x5f, 0x81, 0xb9, 0xc8, + 0xff, 0x36, 0x0e, 0x0e, 0x01, 0x81, 0x31, 0xae, + 0x4b, 0x35, 0xd8, 0x18, 0x17, 0x8c, 0x33, 0x7a, + 0xa2, 0xee, 0x06, 0x5b, 0xd8, 0x0b, 0x07, 0xb0, + 0x52, 0xbe, 0xf6, 0xf4, 0x38, 0xec, 0x35, 0x6e, + 0x45, 0xc1, 0x5e, 0x51, 0xd3, 0x67, 0x93, 0x6d, + 0xaf, 0xd0, 0xe0, 0x2a, 0xea, 0x6a, 0x1e, 0x03, + 0x0c, 0x38, 0xa4, 0x38, 0xea, 0x34, 0x41, 0x99, + 0xcb, 0xe0, 0xcd, 0xda, 0xf2, 0xee, 0x86, 0x28, + 0x83, 0x38, 0x0b, 0x13, 0xd1, 0x73, 0x1e, 0x4f, + 0xb5, 0x18, 0x7d, 0xef, 0xed, 0x09, 0xdf, 0xf7, + 0x4a, 0x91, 0xdb, 0x41, 0x84, 0xf7, 0x07, 0x14, + 0x15, 0x3b, 0x01, 0xc5, 0x28, 0x41, 0x78, 0x9f, + 0xf6, 0x92, 0xce, 0x06, 0xe0, 0xb9, 0x9d, 0xa0, + 0xee, 0xf0, 0x25, 0xa9, 0xd4, 0xe0, 0x71, 0xb4, + 0x66, 0x0c, 0x11, 0x47, 0x01, 0x89, 0x34, 0x62, + 0x11, 0x60, 0x27, 0xa0, 0xfb, 0x1f, 0xfe, 0xd1, + 0x50, 0x6e, 0x0e, 0x23, 0xc3, 0xd8, 0x0e, 0xe8, + 0x53, 0xa7, 0x94, 0x03, 0x12, 0x41, 0x9a, 0x90, + 0x97, 0xce, 0x87, 0x0d, 0x42, 0x9d, 0x07, 0xce, + 0xff, 0xef, 0x4e, 0x07, 0x1a, 0x31, 0x08, 0x92, + 0x98, 0x0c, 0x49, 0x46, 0x74, 0x22, 0x2a, 0xf1, + 0x01, 0x51, 0x48, 0x26, 0xe9, 0xf5, 0xcd, 0xb0, + 0x0c, 0x2e, 0xa1, 0x3d, 0x29, 0x05, 0x4f, 0xa0, + 0x12, 0x06, 0x08, 0x9c, 0x94, 0x08, 0x60, 0xce, + 0xd0, 0x96, 0x81, 0x81, 0x18, 0x62, 0x03, 0xcc, + 0xba, 0x15, 0xd6, 0x91, 0x11, 0x14, 0x7e, 0xb2, + 0x7e, 0xd4, 0x56, 0x74, 0x37, 0xdc, 0x82, 0xfb, + 0x21, 0xa1, 0x93, 0x91, 0x60, 0x3d, 0xcb, 0x28, + 0x4b, 0x52, 0xe9, 0x26, 0x4a, 0x0c, 0x32, 0xca, + 0x31, 0xab, 0x10, 0x19, 0x6e, 0x76, 0x50, 0x1e, + 0x7c, 0x89, 0x2f, 0x42, 0x4a, 0x46, 0xf8, 0xb1, + 0x5e, 0xdc, 0xbe, 0x81, 0x4a, 0x0c, 0x4e, 0x6a, + 0x31, 0x70, 0xd4, 0x17, 0x62, 0x30, 0xf8, 0xbb, + 0xaa, 0xba, 0x06, 0x98, 0xf4, 0x05, 0x40, 0x7c, + 0x8e, 0x81, 0x22, 0xc7, 0x8b, 0xf2, 0x67, 0x49, + 0x64, 0x58, 0x1c, 0xb8, 0xa0, 0x6d, 0xb9, 0xea, + 0x5b, 0x11, 0x47, 0x18, 0xe7, 0xd0, 0xbc, 0xce, + 0xf3, 0x9d, 0x19, 0x10, 0x92, 0x95, 0x45, 0x47, + 0x78, 0x87, 0x81, 0x32, 0x6b, 0xc0, 0xe5, 0x7a, + 0x79, 0x25, 0x37, 0x0d, 0x05, 0x06, 0x73, 0x39, + 0x50, 0x9f, 0x8f, 0x5d, 0x09, 0x24, 0x34, 0x32, + 0x18, 0x04, 0x62, 0x9c, 0xe8, 0x1e, 0x06, 0x52, + 0x88, 0x1e, 0x26, 0x01, 0x30, 0x36, 0x81, 0x60, + 0x63, 0x41, 0x6a, 0x77, 0xa8, 0x42, 0xd4, 0xba, + 0x1f, 0x0e, 0x79, 0x06, 0x2d, 0x16, 0x83, 0x00, + 0xe3, 0xe6, 0xcb, 0xba, 0x82, 0x4a, 0x27, 0xd7, + 0x5e, 0xdc, 0x58, 0x44, 0x19, 0x28, 0x0c, 0xc7, + 0x2f, 0x57, 0xb2, 0x83, 0x83, 0x40, 0xcc, 0x1c, + 0xb8, 0x99, 0x41, 0xb9, 0xb0, 0xc8, 0x1f, 0x36, + 0x00, 0x75, 0x14, 0xa9, 0x25, 0x34, 0x87, 0x83, + 0x05, 0x13, 0x16, 0x7d, 0x91, 0x40, 0x3b, 0x9c, + 0xe8, 0x38, 0x57, 0x17, 0xd2, 0x03, 0xc0, 0xff, + 0x4e, 0x0c, 0x1f, 0x16, 0x96, 0xc0, 0xe3, 0x8d, + 0x62, 0x75, 0xb8, 0x04, 0xae, 0x03, 0x80, 0x88, + 0xa1, 0x56, 0x31, 0x57, 0x66, 0x2d, 0x8a, 0xef, + 0x11, 0x6f, 0xca, 0xe9, 0x47, 0x79, 0xd0, 0x9d, + 0x0c, 0xb0, 0x18, 0x47, 0x06, 0x03, 0x57, 0x2c, + 0xda, 0x8f, 0x4a, 0x80, 0xd9, 0xa0, 0x62, 0x80, + 0x60, 0x4d, 0x95, 0x18, 0x8c, 0x18, 0x45, 0xcb, + 0x17, 0xad, 0x34, 0xa3, 0xd2, 0xa1, 0xb5, 0xd3, + 0x32, 0xd9, 0xdb, 0xd1, 0x82, 0x98, 0x18, 0x83, + 0xa9, 0xcd, 0xb5, 0x20, 0x77, 0x03, 0x5c, 0x5f, + 0xa6, 0xdb, 0x48, 0x12, 0xd7, 0x46, 0xc8, 0xd1, + 0x78, 0x1c, 0x1d, 0x17, 0x04, 0x91, 0xe8, 0xbc, + 0x2a, 0xa0, 0x53, 0x83, 0x11, 0x29, 0xff, 0x18, + 0xfe, 0x8d, 0x98, 0x6e, 0xad, 0x11, 0x65, 0xa0, + 0xc8, 0x3c, 0x48, 0x48, 0x13, 0x55, 0x28, 0xf5, + 0x61, 0x9d, 0xe0, 0x38, 0x5e, 0x12, 0xc0, 0x70, + 0x44, 0xbf, 0x6f, 0x25, 0x9d, 0x2b, 0xcf, 0xb6, + 0x79, 0x3d, 0xcf, 0x45, 0x32, 0xa8, 0x19, 0x67, + 0x3a, 0x14, 0x43, 0x6d, 0x7d, 0xa1, 0x04, 0xb7, + 0x3e, 0xd3, 0x75, 0x45, 0x2a, 0x6a, 0x6d, 0xb2, + 0x12, 0x87, 0x90, 0xa0, 0x6b, 0xbf, 0x1a, 0x5b, + 0xb7, 0x14, 0xd0, 0x26, 0x88, 0x5e, 0xb8, 0x4d, + 0x70, 0x19, 0x65, 0x36, 0xdd, 0x9c, 0x40, 0x7a, + 0xbf, 0x21, 0xc8, 0x38, 0x38, 0x01, 0xca, 0x1e, + 0xc5, 0xee, 0xb3, 0x40, 0xc0, 0x9a, 0xd6, 0x24, + 0xa7, 0xb4, 0x6b, 0x06, 0x18, 0xfc, 0x1c, 0x11, + 0xaf, 0x6d, 0xcc, 0xbd, 0x5e, 0xc8, 0x8e, 0x07, + 0xbc, 0xe0, 0x52, 0x8f, 0x9a, 0xb1, 0x74, 0x40, + 0xe4, 0x63, 0x20, 0x99, 0x4f, 0xa8, 0xbc, 0x0e, + 0xf2, 0x86, 0x80, 0xea, 0x09, 0x8a, 0xec, 0xdd, + 0xe7, 0x39, 0x49, 0x6e, 0xc4, 0x5c, 0x5d, 0x0d, + 0x45, 0xd1, 0x7b, 0x8b, 0xd5, 0xaf, 0x43, 0x17, + 0xe9, 0x49, 0xac, 0x6d, 0x10, 0xa6, 0x4e, 0x5e, + 0xa8, 0xc8, 0x20, 0xca, 0x54, 0x8e, 0xa1, 0x15, + 0xb5, 0x0d, 0xa0, 0x66, 0x70, 0x93, 0x6f, 0x01, + 0xc4, 0x2b, 0xc1, 0x46, 0xbd, 0x74, 0x96, 0x05, + 0x75, 0x50, 0xc0, 0xc3, 0x8b, 0x22, 0x25, 0x07, + 0x1d, 0xf6, 0x70, 0x92, 0x2d, 0x17, 0x09, 0xcb, + 0xef, 0xbd, 0x88, 0xd6, 0x46, 0x7b, 0xbd, 0xa0, + 0xe7, 0xe9, 0xc7, 0x09, 0x01, 0xc0, 0xb1, 0x29, + 0x3a, 0xc1, 0xdd, 0x05, 0xd2, 0x6a, 0x60, 0x73, + 0x06, 0x54, 0x26, 0x84, 0x0b, 0x22, 0x42, 0x7e, + 0x0d, 0x62, 0xfe, 0xc5, 0xb8, 0x30, 0x3a, 0xa2, + 0x5f, 0x5b, 0xee, 0x6c, 0xc2, 0x50, 0x7a, 0x18, + 0x00, 0xdf, 0x86, 0x41, 0x97, 0x16, 0x3d, 0xd9, + 0xcb, 0x09, 0x46, 0x40, 0xb0, 0x04, 0xe5, 0xa0, + 0xbb, 0xa9, 0x8d, 0x84, 0xa6, 0xd4, 0xb7, 0x53, + 0xb2, 0xdf, 0x33, 0x16, 0x41, 0x38, 0x2f, 0x3c, + 0xa8, 0x21, 0xef, 0x3e, 0xd6, 0xcd, 0x8b, 0xf9, + 0x1f, 0x03, 0x7a, 0x29, 0x18, 0x84, 0x26, 0x7f, + 0xe1, 0xdf, 0x98, 0x1c, 0x36, 0x58, 0xdc, 0x51, + 0xde, 0x2d, 0x35, 0x1f, 0x69, 0xa7, 0x0a, 0x82, + 0x08, 0xe9, 0x59, 0x7f, 0x2b, 0x4a, 0x39, 0x25, + 0x96, 0x5f, 0xf1, 0x08, 0xa6, 0x5b, 0x4b, 0x67, + 0x51, 0x12, 0xf0, 0xf2, 0xae, 0x68, 0xbb, 0x72, + 0xef, 0x0a, 0xb6, 0x02, 0xbd, 0x14, 0x42, 0x37, + 0x1b, 0x80, 0xe2, 0x3a, 0xb7, 0xb4, 0x1c, 0x0a, + 0x9b, 0xa0, 0xea, 0x11, 0x21, 0x4b, 0x07, 0xc9, + 0x93, 0xb7, 0x7b, 0xd1, 0x13, 0x8d, 0x62, 0xfd, + 0x28, 0xbd, 0x44, 0x0e, 0x0f, 0x4e, 0x49, 0xb4, + 0x43, 0x11, 0xc0, 0x38, 0x38, 0x08, 0xd2, 0xd9, + 0x2e, 0x2c, 0x03, 0x9f, 0xa7, 0xd6, 0x37, 0x46, + 0x01, 0x1f, 0x58, 0x56, 0xc0, 0x9c, 0x07, 0x0c, + 0x9d, 0xba, 0x0a, 0x9a, 0x15, 0xd4, 0x63, 0x6a, + 0x13, 0x69, 0xe0, 0x6f, 0x4c, 0xd0, 0x53, 0xc0, + 0xf6, 0x6f, 0x3c, 0xb7, 0x7d, 0xcb, 0x3b, 0x40, + 0x8e, 0xfa, 0x04, 0x48, 0x16, 0x35, 0x8b, 0x7d, + 0xbc, 0x81, 0xaa, 0xb2, 0xe8, 0xbf, 0x7a, 0x0c, + 0x1c, 0xfe, 0x86, 0x26, 0x8e, 0x86, 0x25, 0x83, + 0x9d, 0x07, 0x11, 0xcf, 0xb8, 0x5b, 0x88, 0xe9, + 0x5e, 0x12, 0x21, 0x13, 0xed, 0xb1, 0xfa, 0x0c, + 0x87, 0xf0, 0xa3, 0x96, 0x05, 0x75, 0x33, 0x7a, + 0x3d, 0x1f, 0x09, 0x49, 0x58, 0x56, 0x9d, 0x95, + 0x5e, 0x52, 0x9b, 0x30, 0x3d, 0x64, 0x3d, 0xe4, + 0xde, 0xcb, 0x3c, 0x59, 0x56, 0x0d, 0xd4, 0x94, + 0x43, 0xf6, 0x24, 0xb7, 0x19, 0x1f, 0xa5, 0x6f, + 0xd7, 0xc5, 0x9f, 0x56, 0xde, 0xe7, 0x38, 0x8a, + 0xed, 0x3c, 0x15, 0xc1, 0x9b, 0x6b, 0x55, 0xab, + 0x11, 0xa4, 0xce, 0xef, 0xd2, 0x4c, 0x88, 0x00, + 0xad, 0x15, 0x18, 0xff, 0xb5, 0xad, 0xdf, 0x6f, + 0xa4, 0xdc, 0xbc, 0xab, 0x84, 0x65, 0x30, 0xab, + 0x09, 0x6b, 0xf4, 0xff, 0x43, 0x78, 0x30, 0x08, + 0xa7, 0xa0, 0xa9, 0xa2, 0xf0, 0x8b, 0x72, 0x82, + 0xa0, 0x5c, 0x12, 0xb0, 0x27, 0xe1, 0x84, 0x09, + 0x27, 0x6e, 0x2d, 0x62, 0xc6, 0xd1, 0x85, 0x1a, + 0x72, 0xb1, 0xbf, 0x83, 0xcc, 0x7f, 0xfa, 0x13, + 0x54, 0xe0, 0x71, 0xfa, 0x0e, 0x23, 0x7d, 0x06, + 0x25, 0x18, 0x4a, 0x11, 0x69, 0x43, 0x76, 0xe8, + 0xc8, 0x18, 0x23, 0x96, 0x15, 0x2c, 0x7f, 0x4e, + 0x8b, 0x01, 0x83, 0x6d, 0x18, 0x83, 0x04, 0x5b, + 0x80, 0xa8, 0xc1, 0x9d, 0x01, 0xfa, 0xe2, 0xa3, + 0x8d, 0x4f, 0xe9, 0x63, 0x0d, 0xfe, 0xe7, 0x7b, + 0xcc, 0x5e, 0x86, 0xf5, 0x1b, 0xae, 0x0e, 0x93, + 0xa0, 0x1f, 0x36, 0x33, 0xe8, 0x0e, 0x74, 0xcf, + 0xa0, 0x43, 0x11, 0x82, 0x6d, 0x5a, 0xa8, 0xa6, + 0x1a, 0xcb, 0xa1, 0xb4, 0x99, 0x6a, 0x08, 0x8f, + 0x68, 0x30, 0x2c, 0x5f, 0x51, 0xfd, 0x10, 0x1a, + 0xff, 0xd6, 0xec, 0xe7, 0x7a, 0xc7, 0xaf, 0x49, + 0x16, 0xbb, 0x51, 0x50, 0xad, 0xbf, 0x8b, 0x76, + 0x86, 0x20, 0x9b, 0x11, 0x81, 0xc5, 0x1b, 0x6f, + 0x06, 0xdf, 0xfc, 0x28, 0xda, 0xe9, 0x03, 0x6a, + 0xc1, 0x83, 0x96, 0xc1, 0x86, 0x3a, 0x12, 0xd2, + 0x8a, 0x8c, 0x83, 0x85, 0xd0, 0xa0, 0xf3, 0x2e, + 0x86, 0xee, 0xe1, 0xb7, 0xa1, 0x6d, 0x16, 0x2e, + 0xf4, 0x46, 0xc1, 0x45, 0x99, 0xd2, 0x6d, 0x72, + 0xd2, 0xe6, 0x52, 0x84, 0x07, 0x84, 0xf3, 0xc0, + 0xe0, 0x0e, 0xa2, 0x1f, 0x6c, 0xce, 0xf6, 0x83, + 0xc1, 0xc0, 0x3f, 0x47, 0xb9, 0x68, 0xc8, 0x11, + 0x04, 0x14, 0x40, 0xc3, 0x43, 0x13, 0xa0, 0xf3, + 0xff, 0xff, 0xbe, 0xfe, 0x58, 0xd4, 0x51, 0x7b, + 0x0a, 0x01, 0x62, 0x48, 0xe1, 0x9b, 0x6b, 0x65, + 0x8b, 0x54, 0x41, 0xc8, 0x9d, 0x57, 0x57, 0x64, + 0xf7, 0x51, 0x83, 0x0c, 0x47, 0x25, 0x01, 0xc8, + 0xad, 0x4a, 0x58, 0x4b, 0x05, 0xe0, 0xc0, 0x3d, + 0x10, 0x4e, 0xb5, 0x85, 0xb8, 0xbc, 0xb0, 0x1e, + 0x2a, 0x00, 0xb0, 0x58, 0xbd, 0x5e, 0xca, 0x4a, + 0x0c, 0x2e, 0x19, 0x82, 0xe5, 0x3e, 0x8b, 0xa0, + 0xe0, 0xc8, 0x8a, 0xae, 0xe7, 0xbe, 0x55, 0xbc, + 0x45, 0x4a, 0x60, 0x60, 0x09, 0xcb, 0x89, 0x4c, + 0x32, 0x08, 0x6d, 0x09, 0x0d, 0xb4, 0xd2, 0x54, + 0xf8, 0xa8, 0xab, 0xca, 0x6f, 0xc4, 0xbf, 0x00, + 0xe6, 0xb6, 0x8c, 0x4f, 0xc6, 0x16, 0xf7, 0x67, + 0x1a, 0x9b, 0x2a, 0x1c, 0xe0, 0x0e, 0x44, 0x80, + 0x80, 0x34, 0xb2, 0x9d, 0x59, 0x58, 0x17, 0xd1, + 0x87, 0x81, 0x60, 0x2c, 0xf8, 0x0a, 0xad, 0x69, + 0x49, 0x5d, 0x40, 0x43, 0x1b, 0x4e, 0x83, 0x7c, + 0x48, 0x88, 0x92, 0x09, 0x3f, 0x05, 0x78, 0xf6, + 0xc0, 0x60, 0xc9, 0xea, 0xd0, 0x66, 0xd3, 0x20, + 0x08, 0x5b, 0xa0, 0xaf, 0x1d, 0xb3, 0xa1, 0x35, + 0x2e, 0x1c, 0xc8, 0x33, 0x09, 0x1a, 0x34, 0x6d, + 0x83, 0x06, 0x61, 0x21, 0x5a, 0x99, 0x57, 0xd1, + 0xcc, 0xa2, 0x96, 0xed, 0x05, 0xc3, 0x61, 0x84, + 0x1e, 0x07, 0xfc, 0x3e, 0x55, 0x2d, 0x01, 0xe4, + 0x92, 0xc4, 0x56, 0xd6, 0xff, 0xc0, 0xa0, 0x6a, + 0x23, 0x89, 0x29, 0xc4, 0x76, 0x43, 0xf6, 0x7c, + 0xd6, 0x55, 0x0a, 0x0a, 0xb1, 0x00, 0x13, 0xaf, + 0xa2, 0xa0, 0xe4, 0x5c, 0x11, 0xb2, 0xa2, 0x51, + 0x80, 0x46, 0x98, 0xc3, 0x1e, 0x1b, 0x35, 0xc2, + 0x5c, 0xb5, 0xf4, 0xfb, 0xf2, 0x1c, 0x83, 0x83, + 0x80, 0x7c, 0xf8, 0x01, 0xfd, 0x9a, 0x85, 0x49, + 0x69, 0xc7, 0xd8, 0x1a, 0xc3, 0x0f, 0xa3, 0x27, + 0xb5, 0xa6, 0xc5, 0xdb, 0x3a, 0x15, 0x6e, 0x5e, + 0xdb, 0x93, 0x60, 0x8b, 0x28, 0x31, 0x48, 0xc0, + 0x35, 0x09, 0x3b, 0x5f, 0x28, 0x18, 0x54, 0x01, + 0x80, 0x66, 0x8c, 0x8e, 0x7e, 0xd6, 0xaa, 0x8d, + 0xa9, 0x9c, 0xa6, 0xe3, 0x10, 0xb6, 0x8c, 0x16, + 0xd0, 0x97, 0x4f, 0x78, 0x15, 0x21, 0x88, 0xb8, + 0x85, 0xb9, 0x01, 0xd1, 0x67, 0x69, 0xfd, 0xbe, + 0xe4, 0x52, 0xd6, 0xc4, 0x6a, 0x24, 0x07, 0x54, + 0x28, 0x08, 0xa6, 0x6f, 0x94, 0x03, 0x22, 0xf8, + 0x67, 0x46, 0x20, 0x9a, 0x4c, 0x93, 0x90, 0x1c, + 0x09, 0x90, 0x32, 0x46, 0x32, 0x0a, 0x2d, 0xe8, + 0x27, 0xc5, 0xdc, 0xf6, 0xc9, 0xde, 0x4e, 0x1a, + 0x45, 0x02, 0x5b, 0xab, 0xeb, 0x4a, 0x2f, 0x4d, + 0x95, 0x29, 0xe8, 0x0f, 0x04, 0xcc, 0xb8, 0xbc, + 0x6b, 0x32, 0x06, 0x08, 0x0d, 0xc0, 0x5f, 0xdb, + 0x24, 0x46, 0xb1, 0xbe, 0x85, 0x5a, 0xeb, 0x4a, + 0xa0, 0x40, 0x42, 0x48, 0x59, 0x37, 0xbd, 0x18, + 0x82, 0x72, 0x63, 0xfd, 0xa5, 0x12, 0x83, 0x90, + 0x85, 0x1e, 0xd5, 0x83, 0x35, 0xe0, 0xb9, 0x02, + 0xc7, 0xcd, 0x88, 0x23, 0x86, 0xe7, 0xc7, 0x12, + 0x4b, 0xcd, 0x1c, 0x59, 0x51, 0x29, 0x0c, 0x3b, + 0xc9, 0xd0, 0x4d, 0xf9, 0x6a, 0x33, 0xba, 0xef, + 0x2e, 0xe5, 0xd8, 0x69, 0x1a, 0x14, 0x44, 0x29, + 0xe6, 0xcb, 0xee, 0x7f, 0xd6, 0x9b, 0x25, 0x0c, + 0x51, 0x05, 0x48, 0xe4, 0xf9, 0x6a, 0xfd, 0xc9, + 0x9d, 0x8b, 0xd9, 0xd1, 0x3a, 0x14, 0x7d, 0xa9, + 0x38, 0x5a, 0x55, 0xd4, 0x57, 0x7f, 0xfb, 0x62, + 0x11, 0x80, 0x30, 0x61, 0x1d, 0x6a, 0x00, 0x92, + 0x2e, 0x9a, 0x7b, 0x82, 0x4a, 0x75, 0x77, 0x3b, + 0x61, 0xb6, 0xbe, 0x36, 0xa1, 0x87, 0x67, 0x46, + 0x0f, 0x30, 0xaf, 0x70, 0xbd, 0x8d, 0xc8, 0x31, + 0x53, 0x37, 0xc0, 0xc1, 0x8c, 0x15, 0x1d, 0x4d, + 0x38, 0xb5, 0x5c, 0x1c, 0x0b, 0xc1, 0x53, 0x17, + 0xe0, 0x75, 0xb6, 0x68, 0x19, 0x9d, 0x2b, 0xf4, + 0xe2, 0x09, 0x41, 0x30, 0xbe, 0xd0, 0xf7, 0xb2, + 0x2c, 0x69, 0xd1, 0x33, 0x83, 0xa6, 0x59, 0x66, + 0x17, 0xcb, 0x59, 0x6c, 0x18, 0x0c, 0x27, 0x1b, + 0xfe, 0xd4, 0x72, 0xac, 0x75, 0x25, 0x65, 0xca, + 0xfa, 0x0c, 0x05, 0xac, 0x29, 0x06, 0x04, 0xe1, + 0x78, 0xe8, 0x79, 0x4a, 0xf2, 0xa9, 0xe6, 0xfb, + 0xf1, 0x0e, 0x7e, 0xcd, 0x95, 0x6c, 0xed, 0x5a, + 0x9a, 0xa6, 0xc5, 0x01, 0x4d, 0x38, 0x36, 0x24, + 0x6b, 0xac, 0xe8, 0xf0, 0x77, 0xb9, 0xe9, 0x6f, + 0x55, 0x8f, 0x52, 0x48, 0xb2, 0xeb, 0xe6, 0x29, + 0xb7, 0xa6, 0xa5, 0x71, 0xbe, 0x57, 0x9e, 0xd0, + 0xda, 0xa1, 0xe5, 0x08, 0xaa, 0x65, 0xc1, 0x13, + 0xe8, 0x43, 0xef, 0x06, 0xac, 0xf8, 0x1f, 0x37, + 0xff, 0xb7, 0x53, 0x7e, 0x65, 0xd9, 0xf4, 0xdf, + 0x99, 0xc5, 0x25, 0x9b, 0x9b, 0x5c, 0x71, 0x90, + 0x6c, 0x49, 0xbe, 0x55, 0xff, 0x69, 0x70, 0xfa, + 0xff, 0xca, 0x7f, 0xe4, 0xe2, 0x4c, 0x42, 0x84, + 0x3a, 0x7d, 0xb0, 0x07, 0x07, 0x8c, 0x29, 0x80, + 0xc5, 0xa3, 0xc6, 0xee, 0xe1, 0x66, 0xe3, 0x1f, + 0xdf, 0xd5, 0x15, 0x08, 0x89, 0x16, 0x3c, 0x30, + 0x39, 0xcf, 0xaf, 0x35, 0x10, 0x2a, 0x38, 0x19, + 0xbe, 0x26, 0xb8, 0x13, 0x83, 0x00, 0x1c, 0xe4, + 0xda, 0xc5, 0x2b, 0xcf, 0xd2, 0xad, 0xc2, 0xa9, + 0x37, 0xb7, 0xb5, 0x01, 0x41, 0x0d, 0x40, 0x38, + 0x01, 0x9d, 0xe5, 0x12, 0x7f, 0xb4, 0x38, 0x54, + 0x5c, 0xdb, 0x7c, 0x02, 0x73, 0x7e, 0x2c, 0x17, + 0x2a, 0x1e, 0x09, 0x0a, 0xb3, 0x7c, 0x5d, 0x07, + 0xbb, 0xf5, 0xfb, 0xff, 0xa6, 0x9e, 0xef, 0x29, + 0xb5, 0x0b, 0x70, 0x6a, 0xa0, 0x6d, 0x01, 0x67, + 0xe9, 0x2d, 0x98, 0x72, 0xa6, 0x44, 0x47, 0x12, + 0xa2, 0x58, 0x25, 0x2b, 0xdc, 0x67, 0x71, 0xa5, + 0x57, 0x0b, 0x15, 0x65, 0xba, 0xa6, 0x07, 0xb3, + 0xb6, 0x22, 0x35, 0xde, 0x13, 0x09, 0xda, 0x08, + 0x0d, 0xb3, 0xad, 0x83, 0xc1, 0x40, 0x42, 0x3b, + 0xb7, 0x22, 0x90, 0xf5, 0xbe, 0x5d, 0xea, 0xcb, + 0x01, 0x88, 0xa5, 0x72, 0x60, 0xbe, 0x23, 0x64, + 0x6d, 0x57, 0xbb, 0x10, 0x7f, 0x94, 0x41, 0xac, + 0x73, 0x84, 0xb1, 0x75, 0xc1, 0x38, 0xeb, 0x25, + 0xbe, 0x6e, 0xf4, 0xb9, 0x8f, 0xa9, 0xd5, 0x84, + 0x14, 0xad, 0xfe, 0xc3, 0x48, 0x11, 0x52, 0x99, + 0x3a, 0x4e, 0x70, 0xe7, 0x65, 0x5a, 0x29, 0x85, + 0x2a, 0x02, 0x68, 0x99, 0xaf, 0xaa, 0xfa, 0xad, + 0x2c, 0xd1, 0x09, 0x46, 0xc4, 0x0d, 0xfd, 0xba, + 0x0c, 0x18, 0x98, 0x6d, 0x97, 0x5a, 0xd3, 0x0d, + 0xf9, 0x57, 0xbd, 0x75, 0x4e, 0x7f, 0x3b, 0xd5, + 0xf2, 0xa3, 0x9d, 0xde, 0xaf, 0x10, 0x13, 0x97, + 0xd5, 0x1c, 0xdb, 0xa3, 0xa2, 0xe9, 0x50, 0x7d, + 0x44, 0xdd, 0xe4, 0x0d, 0xea, 0x08, 0x27, 0x33, + 0x41, 0xba, 0xd5, 0xda, 0xc4, 0x2c, 0xec, 0xe7, + 0x66, 0x35, 0xc9, 0x3b, 0xd9, 0x27, 0x73, 0x83, + 0x17, 0x0d, 0x08, 0x3d, 0x35, 0x34, 0xa6, 0x9e, + 0xd7, 0xea, 0x84, 0xb2, 0xcf, 0x87, 0x95, 0x94, + 0xd5, 0x8b, 0x2e, 0x11, 0x89, 0x02, 0x06, 0x25, + 0x6a, 0x46, 0xd5, 0xe5, 0xa5, 0xb9, 0x54, 0x67, + 0x22, 0x9d, 0x2b, 0x92, 0xa0, 0x3c, 0x5e, 0xc5, + 0x78, 0x38, 0xac, 0xc2, 0xff, 0xe1, 0x57, 0xbc, + 0xb2, 0xd5, 0x48, 0xc7, 0x85, 0x10, 0x81, 0x54, + 0x89, 0x3d, 0xbb, 0xdc, 0xb8, 0xd8, 0xf5, 0x9c, + 0x8c, 0xa7, 0xe9, 0x46, 0x45, 0xd7, 0x40, 0x88, + 0x8c, 0xdc, 0x56, 0xdc, 0x46, 0xa3, 0x06, 0xfc, + 0xce, 0x91, 0x69, 0x8a, 0x55, 0x02, 0x8b, 0x72, + 0xe7, 0xdb, 0x1f, 0xa5, 0x2b, 0x06, 0x40, 0x55, + 0x31, 0x45, 0x9d, 0x40, 0xdd, 0x90, 0x54, 0x9a, + 0x70, 0x64, 0x89, 0x15, 0xc9, 0xbe, 0x4f, 0xb3, + 0x6d, 0xe5, 0x1c, 0xab, 0xc2, 0xc8, 0x30, 0x94, + 0xea, 0x5e, 0x54, 0xab, 0x14, 0x7b, 0xfe, 0xce, + 0x9b, 0xe6, 0xae, 0x50, 0xa6, 0xe9, 0x18, 0xb6, + 0xb1, 0x95, 0x44, 0x53, 0xcf, 0x7b, 0x96, 0x7b, + 0x98, 0x59, 0x43, 0x8e, 0x95, 0x0c, 0x21, 0x3b, + 0x95, 0xc2, 0xb5, 0xe1, 0x42, 0x80, 0xc0, 0xf6, + 0x99, 0xa4, 0xe0, 0x19, 0x83, 0xe1, 0x29, 0x28, + 0xf3, 0xd4, 0x72, 0xdb, 0x77, 0xd4, 0x3c, 0xaa, + 0x70, 0x3c, 0x45, 0xbd, 0x1b, 0x76, 0xf4, 0x80, + 0x30, 0x60, 0x34, 0x12, 0x6f, 0xe2, 0x84, 0x96, + 0xaf, 0x36, 0x29, 0xfb, 0x52, 0x73, 0xa8, 0xff, + 0x2d, 0xe9, 0xe3, 0x3f, 0xf4, 0xa8, 0xb2, 0xf7, + 0x4d, 0x15, 0x45, 0x83, 0x9b, 0x38, 0x33, 0x8b, + 0x8a, 0xf0, 0x80, 0xd4, 0x5e, 0x79, 0x7e, 0xf2, + 0xd1, 0xb8, 0xbe, 0x2f, 0xb2, 0x94, 0x9e, 0x24, + 0x73, 0xfe, 0x02, 0x63, 0x26, 0x79, 0xa4, 0xdd, + 0x4a, 0xda, 0x4a, 0xb5, 0xbb, 0x7c, 0x55, 0xdb, + 0xee, 0xca, 0x1b, 0x4b, 0xd9, 0xd8, 0x02, 0x0e, + 0xfd, 0xaa, 0xd7, 0xee, 0x6c, 0xb3, 0x86, 0xfb, + 0x28, 0x56, 0x0c, 0x1a, 0xab, 0xf8, 0x24, 0xb3, + 0xf5, 0x51, 0x46, 0xc6, 0x5b, 0xbd, 0x5a, 0xc9, + 0x26, 0xd9, 0xb5, 0x75, 0xb9, 0xc3, 0x7c, 0x3c, + 0x48, 0x43, 0x08, 0x5a, 0x3f, 0x6f, 0x4b, 0xfb, + 0x41, 0x86, 0xc5, 0xad, 0xf1, 0x78, 0xa7, 0x24, + 0xce, 0x45, 0xe8, 0xa4, 0x5e, 0x33, 0xcb, 0x3b, + 0x39, 0xd4, 0x67, 0x55, 0x72, 0x63, 0xc2, 0xd6, + 0x1b, 0x45, 0x29, 0xbb, 0xd8, 0x81, 0x00, 0xcc, + 0x63, 0xd3, 0xc5, 0x12, 0x73, 0xfe, 0xf6, 0xde, + 0x6e, 0x41, 0x89, 0x5f, 0xaf, 0x65, 0x5a, 0x9b, + 0x21, 0x59, 0x5c, 0xc1, 0x0b, 0xc5, 0x7a, 0xbe, + 0x28, 0xdf, 0x40, 0xf6, 0x2c, 0x8a, 0xc2, 0xa5, + 0x2b, 0x74, 0xf9, 0x3d, 0x63, 0x13, 0xd8, 0x98, + 0x71, 0x6f, 0x73, 0xb6, 0x88, 0x0d, 0xb3, 0x66, + 0x5a, 0x56, 0x22, 0x77, 0x9b, 0x88, 0x08, 0x64, + 0x2d, 0xff, 0x50, 0x42, 0x0d, 0x35, 0x47, 0x1b, + 0x93, 0x2d, 0x42, 0x88, 0x50, 0x2f, 0x06, 0xcf, + 0x29, 0x4a, 0x3e, 0xa5, 0x5d, 0xc4, 0xea, 0xbb, + 0x03, 0xde, 0xf0, 0x73, 0x2f, 0x51, 0xa8, 0x13, + 0x11, 0x64, 0x03, 0x14, 0xfb, 0xb3, 0xe1, 0xe2, + 0x65, 0x18, 0xcd, 0xd9, 0x51, 0x72, 0xf3, 0x72, + 0xd1, 0x12, 0xa3, 0x42, 0x8c, 0x4d, 0x00, 0x79, + 0x9f, 0x36, 0x24, 0x8e, 0x95, 0x2a, 0xcc, 0x06, + 0x02, 0xea, 0xad, 0x2b, 0xaa, 0x43, 0xcf, 0xe5, + 0xd3, 0x4b, 0x2c, 0x4a, 0x34, 0x76, 0xdb, 0x9b, + 0x97, 0x80, 0xe1, 0x56, 0xba, 0x6d, 0xe5, 0xf7, + 0x40, 0x70, 0x3a, 0x05, 0x91, 0xca, 0x8f, 0x9b, + 0xc1, 0x88, 0x2c, 0x0f, 0x0b, 0xb2, 0x50, 0x42, + 0x06, 0x2d, 0xbb, 0x98, 0x4b, 0xc6, 0x22, 0x90, + 0x78, 0xcf, 0xfd, 0xe6, 0x50, 0x60, 0x9d, 0x16, + 0xda, 0xd1, 0xd2, 0x6f, 0xb3, 0xf9, 0x21, 0xab, + 0x38, 0xc2, 0x30, 0xd4, 0xb7, 0xea, 0x1d, 0xfa, + 0xf6, 0xe7, 0x01, 0xc1, 0xde, 0xc0, 0xb3, 0x4f, + 0x03, 0x0f, 0xe7, 0x40, 0x39, 0x3a, 0x3a, 0xbb, + 0x08, 0x81, 0x5f, 0x10, 0x10, 0x94, 0x4c, 0x5d, + 0x3f, 0x9f, 0xd0, 0x34, 0x9d, 0x3e, 0xad, 0x31, + 0x8f, 0x66, 0xf6, 0xf4, 0x45, 0x2a, 0x9b, 0x78, + 0xe2, 0x02, 0x3f, 0xbc, 0x3f, 0x2e, 0xfb, 0x01, + 0xf8, 0x1a, 0x9b, 0xc0, 0xf6, 0xe5, 0xb5, 0x65, + 0xf8, 0xa2, 0xce, 0x3c, 0x23, 0xb4, 0x25, 0x17, + 0x2a, 0xb5, 0xa0, 0x60, 0xfd, 0x5f, 0x2f, 0xa5, + 0x0f, 0xd5, 0x28, 0x6b, 0xf6, 0xf4, 0x3a, 0xe4, + 0xf2, 0x28, 0x8c, 0xd8, 0xac, 0xe4, 0xdf, 0x51, + 0x0b, 0x14, 0x6a, 0x32, 0x5e, 0x0b, 0x9d, 0x5f, + 0xf8, 0x9d, 0x27, 0xfd, 0x36, 0xfb, 0xfa, 0x59, + 0xe0, 0x33, 0xce, 0xf1, 0x63, 0xb6, 0xd9, 0x6f, + 0x41, 0xe1, 0x20, 0x15, 0xba, 0x5e, 0x42, 0x57, + 0xed, 0x09, 0x1a, 0x59, 0xed, 0x1e, 0x8f, 0x4b, + 0xea, 0x56, 0x94, 0x6f, 0x33, 0xba, 0x2f, 0x14, + 0x74, 0x9e, 0x08, 0x51, 0x08, 0x8d, 0xbf, 0xf3, + 0x7d, 0x57, 0x2a, 0xf1, 0x01, 0xf2, 0x59, 0xd2, + 0xd9, 0xce, 0xe4, 0x97, 0xa4, 0xf8, 0x3f, 0x9c, + 0x00, 0x6b, 0xa3, 0x1a, 0xfe, 0x82, 0x26, 0xd6, + 0x26, 0x67, 0xb6, 0xf2, 0xab, 0xad, 0x7c, 0x3d, + 0x9c, 0x06, 0x34, 0xa3, 0x61, 0x55, 0x29, 0x42, + 0xe3, 0xac, 0xea, 0x52, 0x4a, 0xc6, 0x1c, 0x32, + 0x21, 0xa5, 0x69, 0xbf, 0x7f, 0x1a, 0xc6, 0x04, + 0xaa, 0x92, 0x0e, 0x54, 0x79, 0xac, 0xa5, 0xbb, + 0xe4, 0x32, 0xc5, 0x2a, 0x38, 0x69, 0x67, 0x91, + 0x57, 0xf1, 0xfa, 0xa0, 0xe9, 0xa5, 0x43, 0xea, + 0x9e, 0x6c, 0xe4, 0x1b, 0x72, 0xef, 0x1c, 0x5a, + 0xac, 0xcc, 0xf7, 0xae, 0x41, 0xcc, 0xa6, 0xcf, + 0xaa, 0xe5, 0xd5, 0x77, 0xc1, 0xdc, 0x6e, 0x7f, + 0xb9, 0xad, 0x62, 0xe5, 0x56, 0xf0, 0xd3, 0xca, + 0x35, 0x1a, 0x55, 0x3f, 0xa0, 0xc1, 0xef, 0x9b, + 0x6a, 0x59, 0xba, 0x59, 0x35, 0x6f, 0x72, 0xd3, + 0x48, 0x86, 0xa5, 0x41, 0x4e, 0x25, 0xa3, 0x06, + 0x0f, 0x55, 0xa6, 0x9b, 0xb3, 0x26, 0x03, 0x8e, + 0x2d, 0xe6, 0x75, 0x3b, 0x38, 0xd4, 0xe7, 0xfe, + 0xa3, 0xdd, 0xe5, 0xd9, 0x2a, 0x20, 0x71, 0x29, + 0x39, 0xec, 0xab, 0xdc, 0xda, 0xa5, 0x47, 0xae, + 0x59, 0x05, 0xb5, 0x71, 0x2b, 0x0a, 0x84, 0x25, + 0x51, 0x9f, 0xa9, 0x6d, 0x2f, 0x9b, 0x8a, 0x1b, + 0x4f, 0xc9, 0xfd, 0xe6, 0x4e, 0x74, 0x3b, 0x5c, + 0x8b, 0xf3, 0x6e, 0x4a, 0x18, 0xc0, 0x74, 0x3f, + 0x72, 0xee, 0x48, 0xa7, 0x75, 0xb6, 0x7f, 0x6a, + 0x2e, 0x49, 0x6a, 0xd3, 0xa1, 0x40, 0xd4, 0x47, + 0xd8, 0xce, 0x59, 0x2c, 0x43, 0xc5, 0xe5, 0x5d, + 0xfa, 0x66, 0x3f, 0xfa, 0x86, 0xf5, 0x7c, 0x3d, + 0x17, 0x32, 0xa2, 0x0f, 0xf1, 0xa5, 0x3d, 0xb4, + 0x11, 0xf8, 0x6c, 0x96, 0x22, 0x18, 0xb9, 0xe9, + 0x56, 0xee, 0x15, 0x28, 0x44, 0x84, 0x91, 0x11, + 0x09, 0xab, 0x75, 0xb6, 0x3d, 0xd9, 0x38, 0xb9, + 0x6a, 0x10, 0x1c, 0x35, 0x19, 0xb3, 0x89, 0xd9, + 0x95, 0x16, 0xfa, 0x92, 0x2f, 0x45, 0xdc, 0x3f, + 0x25, 0x2c, 0xd0, 0x74, 0xd0, 0xc8, 0xf6, 0x9a, + 0x31, 0x3f, 0xb8, 0x5a, 0x80, 0xd2, 0xc8, 0x39, + 0x10, 0x04, 0xb1, 0x12, 0xf9, 0x19, 0x5a, 0xe6, + 0xa0, 0xd1, 0x7d, 0x00, 0xdd, 0xed, 0x2b, 0x49, + 0xa0, 0x48, 0x07, 0x3c, 0x69, 0x00, 0x34, 0x43, + 0x5e, 0xc6, 0xf1, 0xa4, 0x12, 0x73, 0x06, 0xc8, + 0x0e, 0x97, 0x18, 0xdb, 0xd5, 0x82, 0xbd, 0x78, + 0xf2, 0x3f, 0x5e, 0xa1, 0x5f, 0x88, 0x88, 0x92, + 0xfe, 0x5f, 0x5b, 0xe9, 0xda, 0x04, 0xe5, 0x04, + 0xc2, 0x23, 0xf6, 0x95, 0x49, 0x92, 0x40, 0xfd, + 0x58, 0x31, 0xbd, 0xc8, 0x83, 0xd2, 0xd4, 0x76, + 0x21, 0x0a, 0x82, 0x40, 0xf0, 0x21, 0x26, 0x69, + 0x40, 0x19, 0x12, 0xcb, 0x95, 0x37, 0xd1, 0xc6, + 0x82, 0xbb, 0x56, 0xab, 0x8d, 0x86, 0xcf, 0xb2, + 0x83, 0xba, 0x43, 0x53, 0xa6, 0x95, 0x7e, 0x52, + 0xb6, 0x6e, 0xac, 0x8a, 0xa1, 0x29, 0x38, 0x58, + 0x77, 0xbe, 0xf2, 0x46, 0x77, 0x65, 0x2c, 0xc8, + 0xa6, 0xac, 0xba, 0x88, 0x8e, 0xc3, 0x74, 0x5c, + 0x41, 0x70, 0x20, 0x8f, 0xf6, 0x16, 0x87, 0xc3, + 0xa4, 0xc6, 0xe1, 0x78, 0x97, 0xef, 0x51, 0x87, + 0x17, 0xea, 0xc8, 0xe9, 0xc5, 0x04, 0x31, 0xe9, + 0x68, 0x84, 0xde, 0x26, 0x56, 0x3a, 0xf8, 0xfc, + 0xb3, 0x8a, 0x12, 0x33, 0xe6, 0x57, 0x43, 0x32, + 0x6f, 0xd1, 0x0d, 0x6a, 0x8d, 0x83, 0x7e, 0x70, + 0x1c, 0x7a, 0x26, 0xbe, 0x02, 0x94, 0x03, 0x98, + 0x6e, 0x6b, 0x0c, 0x0e, 0xdb, 0xdc, 0x44, 0x55, + 0x80, 0xc0, 0x3c, 0x26, 0x33, 0xf0, 0x41, 0xd6, + 0xdb, 0x97, 0xc3, 0xa5, 0x77, 0xd7, 0x26, 0xf7, + 0x6e, 0x79, 0x47, 0x67, 0x78, 0xbe, 0x55, 0xc5, + 0x41, 0x9d, 0x5a, 0xb0, 0x65, 0x6a, 0x0a, 0xd2, + 0x0f, 0xfd, 0xe0, 0xe7, 0xc3, 0xa5, 0x00, 0xf1, + 0x5f, 0xfb, 0xb4, 0xc0, 0x30, 0x4e, 0x3d, 0x6d, + 0x94, 0xb6, 0x83, 0x2f, 0xf6, 0xed, 0x06, 0x25, + 0xbb, 0xd0, 0x60, 0xaf, 0xea, 0x64, 0x2b, 0x86, + 0x9b, 0x68, 0x66, 0x79, 0x91, 0x8f, 0x7c, 0x10, + 0xd5, 0x8e, 0x73, 0xaa, 0x8b, 0x95, 0x67, 0x54, + 0x52, 0xd1, 0xeb, 0x5d, 0x9e, 0x42, 0x22, 0xf9, + 0x73, 0xd0, 0x3d, 0x11, 0xc1, 0x09, 0xa1, 0x15, + 0x33, 0x7f, 0x99, 0x54, 0x28, 0xdf, 0xb7, 0xcb, + 0x50, 0x8d, 0xff, 0x0f, 0xad, 0xd7, 0xf3, 0x37, + 0xed, 0x20, 0xf6, 0x82, 0x3a, 0x80, 0xc8, 0xfe, + 0x91, 0x1a, 0x0d, 0xa0, 0xa0, 0xc9, 0x20, 0x2a, + 0xa3, 0x76, 0x64, 0x9d, 0x04, 0x4f, 0x5e, 0x83, + 0x0c, 0x78, 0xf1, 0x82, 0x70, 0x66, 0x47, 0xd6, + 0x71, 0x50, 0x8d, 0x06, 0x31, 0x89, 0xd4, 0x05, + 0x4d, 0x4b, 0xde, 0x03, 0x0a, 0x59, 0x46, 0x04, + 0x81, 0x2d, 0x38, 0x30, 0xd8, 0x74, 0x3f, 0x64, + 0x18, 0xa1, 0x33, 0x3f, 0x83, 0x1c, 0xc7, 0x8f, + 0xd6, 0xf8, 0x49, 0x09, 0x7f, 0xfa, 0x19, 0x99, + 0xd7, 0x30, 0xd8, 0x41, 0x4a, 0xc2, 0x6e, 0x35, + 0x3d, 0xac, 0xfe, 0xd2, 0xa6, 0xa1, 0xbb, 0x33, + 0x3c, 0xe3, 0x7c, 0xc0, 0x60, 0x3f, 0x3c, 0xdc, + 0x5a, 0x02, 0xa5, 0x26, 0x37, 0x94, 0x11, 0xbb, + 0xf6, 0xb4, 0x91, 0x1c, 0xc8, 0xe1, 0x60, 0x28, + 0x04, 0x36, 0x15, 0x2b, 0x0f, 0x23, 0x05, 0xe5, + 0xcc, 0xe3, 0x6c, 0x36, 0x15, 0x98, 0xbf, 0x07, + 0x81, 0x81, 0xcd, 0xb0, 0x51, 0xe8, 0x3c, 0x6c, + 0x01, 0x63, 0xcf, 0xc1, 0x88, 0x7f, 0x75, 0xa1, + 0x70, 0xe3, 0xe6, 0x4c, 0xb1, 0x4d, 0xaa, 0x4b, + 0x1a, 0x6b, 0x39, 0x02, 0x9d, 0x31, 0xe8, 0x8c, + 0x08, 0x21, 0x09, 0x9c, 0xf7, 0x9b, 0x1e, 0xb4, + 0xab, 0x85, 0xb7, 0xf1, 0x9c, 0xe7, 0x50, 0xe4, + 0xee, 0xf2, 0x0c, 0x00, 0x58, 0xb9, 0xa4, 0xf1, + 0xbf, 0xcd, 0x62, 0x2a, 0xf8, 0xe6, 0x8e, 0x65, + 0x94, 0xb5, 0x4e, 0xcb, 0xcc, 0x2c, 0x34, 0x6c, + 0x44, 0x88, 0x09, 0xd4, 0x68, 0x1e, 0x02, 0x08, + 0x32, 0xfe, 0x75, 0x58, 0x43, 0x63, 0xc4, 0x9e, + 0x4d, 0xbf, 0x17, 0xeb, 0x6c, 0x0c, 0x78, 0x78, + 0xd2, 0x40, 0x60, 0x0e, 0x2e, 0x4d, 0xfb, 0xa0, + 0xc1, 0xf8, 0xee, 0x56, 0x8a, 0xee, 0xaa, 0x6f, + 0xc9, 0x29, 0x4e, 0x07, 0x8d, 0xac, 0x1b, 0x96, + 0x9c, 0x2b, 0x13, 0xe7, 0x78, 0xba, 0xe8, 0x79, + 0xb6, 0x40, 0x71, 0xdd, 0x34, 0x1b, 0x4c, 0x9e, + 0x5e, 0xa9, 0x53, 0xba, 0xba, 0xc1, 0xd4, 0x81, + 0xc0, 0x15, 0x51, 0x50, 0xed, 0xbc, 0xef, 0x24, + 0x3c, 0x2b, 0xba, 0x39, 0x2a, 0xef, 0x27, 0xa7, + 0x2f, 0x27, 0x7b, 0x62, 0x3a, 0x6d, 0x70, 0xdf, + 0x86, 0xcf, 0x16, 0xf0, 0x18, 0x63, 0xf8, 0xd6, + 0x37, 0xb6, 0x4b, 0x23, 0x6a, 0xdb, 0x6d, 0xbb, + 0x7f, 0x9c, 0x5b, 0x79, 0x24, 0xe5, 0xe9, 0xae, + 0x22, 0xa7, 0x6c, 0x3e, 0x4b, 0x36, 0x58, 0xa3, + 0xd8, 0xcb, 0x15, 0x49, 0x6e, 0xef, 0x3b, 0x11, + 0xac, 0xb4, 0xd5, 0x8d, 0xd0, 0xa5, 0x56, 0x0e, + 0x65, 0x07, 0x13, 0x54, 0xff, 0xb3, 0x7f, 0x3e, + 0xa2, 0xee, 0xf0, 0xac, 0xd0, 0xc9, 0x79, 0x87, + 0xd5, 0x52, 0xa5, 0x49, 0x65, 0x44, 0x55, 0xaa, + 0x2c, 0x96, 0x1b, 0xe9, 0x36, 0x1f, 0x5c, 0x54, + 0xdb, 0x7e, 0x6e, 0x8e, 0x7f, 0x99, 0xd9, 0x24, + 0x51, 0x67, 0xaf, 0x64, 0x2a, 0xbc, 0xbc, 0xff, + 0x16, 0xe4, 0x40, 0x42, 0x4f, 0x5a, 0x92, 0x29, + 0x69, 0x15, 0x6f, 0xbb, 0x16, 0xe1, 0xbb, 0xd5, + 0x39, 0x38, 0xa0, 0x97, 0xa2, 0x65, 0x15, 0xe9, + 0xa6, 0x59, 0xec, 0x92, 0xed, 0xd5, 0x1b, 0x79, + 0x2d, 0x51, 0x2f, 0x56, 0x37, 0xbd, 0x24, 0x36, + 0x52, 0x43, 0x76, 0x28, 0xeb, 0x6a, 0x24, 0x6f, + 0x79, 0xd0, 0xe4, 0xaa, 0xf3, 0x27, 0x6a, 0xc8, + 0x91, 0xa2, 0xa6, 0x8e, 0xab, 0x92, 0xb3, 0xed, + 0xd0, 0xef, 0x11, 0xb4, 0xa0, 0xab, 0x60, 0xcb, + 0x3a, 0x52, 0xbd, 0x1a, 0xae, 0xc8, 0xe7, 0x56, + 0x9c, 0x53, 0x85, 0x8a, 0x77, 0x57, 0xcd, 0xa2, + 0xe5, 0xe1, 0xb3, 0x67, 0xa0, 0x9f, 0x4c, 0xbc, + 0xda, 0x39, 0xc2, 0xb9, 0x27, 0x11, 0xc3, 0x7a, + 0xb7, 0x17, 0xec, 0x1a, 0xc7, 0xf7, 0x3c, 0xd4, + 0xdf, 0xe6, 0x95, 0xf3, 0x25, 0x37, 0xb5, 0x04, + 0x50, 0xb7, 0x45, 0xc2, 0x72, 0x49, 0xb9, 0xbe, + 0xb3, 0xeb, 0x6e, 0x64, 0x8a, 0x6d, 0x80, 0xc1, + 0x9d, 0xe0, 0xc5, 0xf4, 0xad, 0x86, 0xdb, 0x51, + 0x2d, 0xbf, 0x68, 0xa9, 0x78, 0x83, 0x22, 0x1b, + 0xab, 0x9b, 0x28, 0x26, 0x36, 0xac, 0x84, 0xe6, + 0x98, 0x56, 0xf8, 0x84, 0x05, 0xdb, 0x94, 0x71, + 0x9d, 0xba, 0xdc, 0x5f, 0xcb, 0x2f, 0xbc, 0xd8, + 0x8e, 0xed, 0x24, 0x51, 0xd5, 0xfa, 0x4e, 0x2f, + 0x08, 0x5a, 0xc8, 0x96, 0x5c, 0xad, 0x86, 0x36, + 0xcd, 0x80, 0x60, 0xb7, 0x67, 0x3f, 0xc5, 0x25, + 0x45, 0x9d, 0x11, 0x26, 0x20, 0xed, 0xe7, 0x7a, + 0x7c, 0x4e, 0x3d, 0x51, 0x07, 0x29, 0x33, 0xfd, + 0xad, 0xa3, 0xc5, 0x02, 0x09, 0x62, 0xd9, 0x3a, + 0x55, 0x66, 0xd9, 0x16, 0x5e, 0x45, 0xad, 0x5d, + 0xe6, 0xc7, 0x43, 0xcd, 0x1e, 0x36, 0xdf, 0xcb, + 0x51, 0x4c, 0xf6, 0x60, 0x7b, 0x3b, 0x14, 0xa3, + 0x8b, 0xf1, 0x4a, 0x0b, 0x3a, 0x54, 0x46, 0x38, + 0xa7, 0x14, 0x1a, 0xe1, 0x3a, 0xa6, 0xa4, 0x08, + 0x5f, 0xf3, 0x3d, 0x6b, 0xf6, 0x5c, 0xc2, 0xc5, + 0x16, 0xdb, 0x69, 0xb5, 0x30, 0xac, 0x0b, 0xaf, + 0x56, 0xe1, 0x24, 0x3c, 0x2f, 0x69, 0x33, 0x3b, + 0xbd, 0xd6, 0x14, 0x28, 0x5b, 0x24, 0x9d, 0x46, + 0xb5, 0x5e, 0xa0, 0xb2, 0x73, 0x51, 0x0d, 0x04, + 0x6c, 0x0f, 0x38, 0x97, 0xed, 0xcd, 0xaa, 0x55, + 0xa3, 0xb5, 0x7e, 0x96, 0x22, 0xc1, 0x16, 0x2d, + 0xd4, 0x7c, 0xe9, 0xd4, 0xd9, 0xf3, 0x63, 0x86, + 0xfc, 0xd2, 0x82, 0xdd, 0x44, 0x86, 0xf5, 0x05, + 0xe5, 0x5f, 0x82, 0xe2, 0x47, 0xb9, 0x69, 0xb5, + 0x03, 0x4d, 0x31, 0xc0, 0x43, 0xa3, 0xb0, 0xfa, + 0xcb, 0x6b, 0x09, 0x23, 0x3f, 0x6b, 0x72, 0x28, + 0x97, 0xf2, 0xaf, 0x9c, 0x9c, 0x1b, 0x48, 0xb4, + 0x8b, 0x1f, 0x3a, 0x0d, 0x15, 0x2b, 0x82, 0x18, + 0xf9, 0x96, 0x0a, 0xfc, 0x06, 0xf3, 0x3e, 0x89, + 0x4c, 0x8a, 0x64, 0xaa, 0x43, 0x84, 0x7d, 0x82, + 0xe3, 0xa2, 0xc5, 0x62, 0x32, 0x51, 0xda, 0xa1, + 0xc0, 0xe0, 0xac, 0x73, 0x91, 0x9b, 0xfe, 0x49, + 0x9a, 0xc7, 0x43, 0xd9, 0x32, 0xd0, 0x2f, 0x2a, + 0x25, 0xa8, 0x99, 0x22, 0xe5, 0x4d, 0x08, 0xcc, + 0xa4, 0xf4, 0x6a, 0x34, 0x1f, 0x8f, 0xd8, 0x5f, + 0x8a, 0x57, 0xad, 0xc8, 0x8d, 0x4f, 0x27, 0x50, + 0x05, 0x12, 0xb6, 0x83, 0x83, 0x35, 0x82, 0x2d, + 0x30, 0x89, 0x78, 0x68, 0x5c, 0x09, 0x95, 0xd1, + 0x90, 0x38, 0x17, 0xb6, 0x88, 0xa0, 0x1c, 0x30, + 0x0a, 0x6c, 0x94, 0x16, 0x20, 0xb0, 0x0a, 0x8f, + 0x0c, 0xc9, 0xaa, 0xe6, 0x84, 0x82, 0xff, 0x6a, + 0x25, 0xc1, 0x1c, 0x1c, 0xbc, 0x05, 0xc1, 0x61, + 0xeb, 0x63, 0xce, 0x2b, 0x1e, 0x2a, 0x4b, 0x04, + 0x7c, 0x61, 0x9f, 0x8e, 0x99, 0xfd, 0x49, 0xa0, + 0x78, 0x43, 0xff, 0xb2, 0xe1, 0x5f, 0x3d, 0xec, + 0x06, 0xe8, 0x94, 0xbf, 0x67, 0x43, 0xdb, 0xfc, + 0xf3, 0x7c, 0xed, 0xc3, 0xf8, 0xa5, 0x11, 0xa0, + 0x58, 0x04, 0x5e, 0xab, 0x54, 0x99, 0x29, 0x53, + 0x0a, 0x87, 0xf1, 0x20, 0x78, 0xac, 0x18, 0x3d, + 0x2e, 0x12, 0xc4, 0x86, 0xd1, 0x28, 0xfc, 0x03, + 0x71, 0x38, 0xf8, 0x15, 0xb1, 0xad, 0x47, 0x03, + 0xa6, 0xcc, 0x7d, 0x53, 0x16, 0x94, 0x1d, 0x17, + 0x22, 0xdf, 0xe3, 0xef, 0x89, 0x77, 0xa3, 0xd6, + 0x87, 0x98, 0x9b, 0xf7, 0x1a, 0x1f, 0xb3, 0xad, + 0xb0, 0x5c, 0x23, 0x24, 0x4e, 0xca, 0x46, 0x13, + 0xeb, 0x71, 0xaa, 0x23, 0x46, 0x5a, 0xf8, 0x93, + 0xf6, 0x37, 0xf7, 0x26, 0x82, 0xb5, 0x3b, 0x7d, + 0xf4, 0xf5, 0xc9, 0x98, 0x01, 0x65, 0xb5, 0x50, + 0xf5, 0x4d, 0xcf, 0x36, 0xad, 0xb1, 0xd4, 0xff, + 0x9b, 0x4c, 0xc7, 0xef, 0x80, 0xcb, 0x0a, 0xd3, + 0x2b, 0xf3, 0x6c, 0x7f, 0x22, 0xd7, 0x2e, 0x01, + 0x5f, 0x59, 0xb9, 0x2c, 0xbf, 0xf6, 0xc8, 0xf3, + 0xd1, 0x85, 0x40, 0x7d, 0x30, 0x06, 0x08, 0x0c, + 0xb5, 0x78, 0xc0, 0x2a, 0xc4, 0xb4, 0xad, 0x80, + 0x69, 0x7a, 0x95, 0x69, 0xc7, 0xa9, 0xd4, 0x33, + 0x57, 0xf1, 0x74, 0x12, 0xfc, 0xd3, 0x4d, 0x62, + 0x96, 0x94, 0xef, 0x44, 0x81, 0xbd, 0x1b, 0x78, + 0xc0, 0xb9, 0x20, 0xf8, 0x79, 0x07, 0x89, 0xc4, + 0x06, 0x87, 0xc9, 0x32, 0xf1, 0xa6, 0x1b, 0xd4, + 0x81, 0x01, 0x5c, 0x54, 0xad, 0x9f, 0xd0, 0x61, + 0x04, 0x77, 0xf9, 0x32, 0xcd, 0x69, 0xb4, 0xac, + 0x78, 0x72, 0x94, 0x40, 0x4d, 0xee, 0xa9, 0xb3, + 0xc9, 0x98, 0xda, 0xd9, 0x91, 0x8f, 0x2e, 0xa4, + 0x18, 0x07, 0xd9, 0xc8, 0x03, 0xc9, 0x45, 0x38, + 0x38, 0x89, 0xff, 0xb3, 0x57, 0x69, 0x46, 0x37, + 0x37, 0xcd, 0xb5, 0xf5, 0x4c, 0xf7, 0x92, 0xa7, + 0x48, 0xad, 0xa9, 0x57, 0x93, 0x7b, 0xef, 0xae, + 0x59, 0xf6, 0xb6, 0x15, 0xca, 0x22, 0x3e, 0x58, + 0x65, 0x26, 0x4a, 0x39, 0xf0, 0xf4, 0x4a, 0x4a, + 0xd4, 0xff, 0x8a, 0x94, 0x75, 0x9f, 0x29, 0xf5, + 0xdf, 0x36, 0xa3, 0x6e, 0x07, 0xbe, 0xec, 0x2d, + 0xcf, 0xc9, 0xb7, 0xb1, 0x6e, 0xf5, 0xc1, 0x88, + 0x43, 0xf1, 0x7f, 0x81, 0xc0, 0xa4, 0x04, 0x50, + 0x6e, 0x16, 0x7c, 0x3f, 0x05, 0x58, 0x30, 0xe4, + 0x7a, 0x0e, 0x05, 0x58, 0x30, 0x29, 0xc1, 0x8b, + 0x4b, 0x01, 0x4c, 0x0c, 0xa4, 0x18, 0x41, 0x10, + 0x41, 0x10, 0x18, 0x6c, 0xa4, 0x3f, 0x02, 0xe0, + 0xaa, 0x06, 0x0e, 0x41, 0xf0, 0x7f, 0xed, 0x0b, + 0x69, 0x44, 0xb4, 0xe5, 0xcd, 0x5c, 0x1f, 0xb4, + 0x3f, 0xd5, 0x7c, 0x6d, 0xa2, 0xf6, 0x8b, 0xc4, + 0x88, 0x24, 0x2b, 0x4f, 0xac, 0xec, 0xff, 0xc7, + 0x20, 0x64, 0x78, 0xa9, 0x20, 0x32, 0x96, 0x1b, + 0x8a, 0xfc, 0xac, 0xaf, 0xf5, 0xac, 0x6f, 0x14, + 0xe5, 0x6d, 0xa6, 0xcc, 0x45, 0x19, 0x2a, 0xe8, + 0xd0, 0x12, 0x9f, 0xc1, 0xe9, 0xa0, 0x03, 0xe0, + 0x52, 0x9a, 0x82, 0x27, 0xb7, 0x7e, 0x3e, 0xbd, + 0x60, 0xb5, 0xb5, 0x65, 0xcc, 0xf4, 0x42, 0xec, + 0xbb, 0x3f, 0xf4, 0x89, 0x55, 0xef, 0x41, 0x55, + 0x14, 0x03, 0x23, 0x65, 0xb5, 0xae, 0x33, 0xdd, + 0xe1, 0x87, 0x9b, 0xe6, 0xfa, 0x20, 0x27, 0x1f, + 0x27, 0x98, 0xa2, 0x6d, 0x2e, 0x2f, 0x48, 0x3f, + 0x51, 0xde, 0xdc, 0x8d, 0xd4, 0xcd, 0xb6, 0x58, + 0xa5, 0x46, 0xdc, 0x2d, 0xe1, 0x69, 0x67, 0xf8, + 0x36, 0xa7, 0x87, 0x23, 0xf9, 0x41, 0xe0, 0x60, + 0x43, 0x05, 0x14, 0x03, 0x05, 0x9d, 0x08, 0x00, + 0x8a, 0x08, 0xb5, 0x38, 0x2a, 0x80, 0xd6, 0xab, + 0x10, 0xe8, 0x3c, 0x17, 0xfd, 0x34, 0xb8, 0x15, + 0xa0, 0xaa, 0x8a, 0xc0, 0xd4, 0x6d, 0x42, 0xea, + 0x47, 0x0a, 0x03, 0xd0, 0xb1, 0x29, 0xed, 0x06, + 0xe9, 0x7b, 0x6a, 0x9b, 0x06, 0x62, 0x27, 0xf0, + 0x28, 0x84, 0x3c, 0x10, 0x01, 0x84, 0xa0, 0x62, + 0xd5, 0x0d, 0xeb, 0x2c, 0x37, 0x07, 0x9f, 0x57, + 0x73, 0xc0, 0xc2, 0x00, 0x7e, 0xc0, 0xec, 0x71, + 0x55, 0x4c, 0x67, 0xc3, 0xfa, 0xcd, 0x4c, 0x38, + 0xf3, 0x3f, 0x85, 0xd0, 0xc5, 0xba, 0x80, 0xf4, + 0x4d, 0x3f, 0x56, 0x9b, 0x64, 0x40, 0xc2, 0xf1, + 0xd6, 0xab, 0xed, 0xca, 0x93, 0x04, 0xb1, 0xf6, + 0x97, 0xf7, 0x03, 0xbf, 0x52, 0xec, 0x57, 0x53, + 0xcd, 0xf2, 0x8a, 0x5b, 0xea, 0xd2, 0x9c, 0x51, + 0xaa, 0x64, 0xe3, 0xd4, 0x08, 0x25, 0xe5, 0xc2, + 0x56, 0x84, 0x2c, 0x6f, 0xe5, 0xdd, 0x56, 0x24, + 0x97, 0x24, 0x6f, 0x13, 0xa7, 0x9e, 0xd6, 0x07, + 0xca, 0xc3, 0xf1, 0xc8, 0xef, 0x32, 0x2b, 0xf5, + 0x98, 0xab, 0x5a, 0xcc, 0x0f, 0xd9, 0x9f, 0x1f, + 0x78, 0xae, 0x7f, 0x2e, 0xf0, 0x2c, 0x61, 0x08, + 0x1e, 0x06, 0x04, 0x10, 0x53, 0x01, 0xe0, 0xfc, + 0x18, 0xb0, 0x6c, 0x5c, 0xa0, 0x3e, 0x1c, 0xd0, + 0x3b, 0x40, 0xf9, 0x65, 0x53, 0xd0, 0x61, 0x00, + 0x1e, 0x0b, 0xfc, 0xf9, 0x41, 0x56, 0x20, 0x88, + 0x0a, 0x41, 0x80, 0xc7, 0x40, 0xd0, 0xe0, 0x3c, + 0x07, 0xc1, 0x80, 0x54, 0x46, 0x0c, 0xad, 0x30, + 0xf0, 0x1e, 0x0a, 0x02, 0xf4, 0xe3, 0xf6, 0x87, + 0xdc, 0x07, 0x81, 0xff, 0x1c, 0x48, 0x61, 0x5a, + 0xb4, 0xbe, 0x63, 0x80, 0xaa, 0x50, 0x3f, 0xfb, + 0x2d, 0x7d, 0x96, 0x67, 0x01, 0x55, 0xd0, 0xf7, + 0xed, 0x6e, 0x87, 0xd6, 0x95, 0xeb, 0x9e, 0xda, + 0xb2, 0x0e, 0x1a, 0x0c, 0x6c, 0xa7, 0xaa, 0xe1, + 0x79, 0x84, 0xd9, 0x98, 0x23, 0x09, 0x6d, 0xf2, + 0x08, 0xbd, 0x68, 0x70, 0x3c, 0x1f, 0xb2, 0x1e, + 0x71, 0x48, 0x18, 0xef, 0x95, 0x32, 0xc8, 0x79, + 0xc5, 0x25, 0x43, 0x72, 0xa4, 0x6f, 0x7a, 0x3a, + 0xb9, 0x55, 0x27, 0xca, 0x5d, 0x55, 0x5b, 0x2c, + 0x2f, 0x2e, 0xdf, 0x5c, 0xff, 0x92, 0x25, 0x63, + 0x7f, 0x35, 0x4e, 0x76, 0x8d, 0xf2, 0x9b, 0x99, + 0xff, 0x7e, 0xf4, 0xb3, 0xe6, 0x03, 0x10, 0x32, + 0x70, 0x86, 0x0d, 0x85, 0x6a, 0x3a, 0x24, 0xb0, + 0x99, 0x6a, 0x06, 0xb8, 0x21, 0x02, 0x18, 0x32, + 0xe9, 0x18, 0xd0, 0x78, 0x48, 0x0a, 0xd2, 0x83, + 0x15, 0xb0, 0xba, 0x49, 0x67, 0x0b, 0x19, 0x06, + 0x41, 0xa1, 0x70, 0xe9, 0x57, 0x52, 0xe8, 0x85, + 0xf6, 0x1b, 0x55, 0x8a, 0xda, 0x10, 0x68, 0x33, + 0x09, 0x81, 0xe0, 0x7f, 0xb5, 0x04, 0x49, 0xff, + 0x08, 0x40, 0xaa, 0x6f, 0xa3, 0xcf, 0xb6, 0xac, + 0x21, 0x2a, 0x1d, 0xab, 0xf9, 0x6d, 0x2c, 0x6f, + 0xcd, 0xb4, 0x3e, 0xd4, 0x93, 0xfe, 0xf7, 0xd4, + 0xb2, 0x20, 0x99, 0xbb, 0xd3, 0x4a, 0x78, 0x88, + 0x1c, 0x41, 0xa6, 0x83, 0x65, 0xc0, 0x7b, 0xc3, + 0x81, 0xca, 0x41, 0x21, 0x50, 0x82, 0xde, 0x2a, + 0x68, 0xb7, 0xc9, 0xbc, 0x1f, 0xab, 0xfa, 0xde, + 0x55, 0xe2, 0xde, 0x0e, 0x59, 0xff, 0x2a, 0x86, + 0xb3, 0xbf, 0xd5, 0x15, 0x44, 0x59, 0xe6, 0x6d, + 0x06, 0x60, 0xab, 0x07, 0x20, 0xa0, 0x95, 0xb0, + 0x2d, 0x04, 0x11, 0x28, 0xb5, 0x92, 0xbd, 0x68, + 0x0c, 0x42, 0xde, 0xb6, 0x06, 0x73, 0x5a, 0x2a, + 0x5c, 0x73, 0x9b, 0xe0, 0xee, 0x58, 0xe0, 0xb8, + 0x07, 0x40, 0xf8, 0x42, 0x1d, 0xb2, 0x0c, 0x5c, + 0xc0, 0xf8, 0x7a, 0x98, 0xbd, 0xbf, 0x83, 0x2b, + 0x03, 0xc5, 0xf1, 0xa5, 0x5f, 0x9f, 0xdc, 0x63, + 0x2f, 0xfb, 0xac, 0xe6, 0x2e, 0x9b, 0x65, 0x4e, + 0xd0, 0x18, 0x4e, 0x58, 0xdd, 0xa5, 0xb2, 0x67, + 0x5a, 0x6c, 0x05, 0x1e, 0x06, 0x60, 0x1b, 0x00, + 0xf0, 0xec, 0x14, 0x1f, 0x4e, 0x9d, 0x24, 0x56, + 0xc8, 0x43, 0x64, 0x7e, 0x5a, 0xaf, 0x66, 0x6b, + 0x6a, 0xb1, 0x84, 0xec, 0xb1, 0xe0, 0x55, 0x6d, + 0xf5, 0x03, 0x56, 0x70, 0x73, 0x77, 0x3b, 0x7f, + 0xf5, 0x9b, 0x2d, 0x62, 0x40, 0x18, 0x6a, 0xf5, + 0x1f, 0xc5, 0xf7, 0xa3, 0x2e, 0x3f, 0x5c, 0x98, + 0x42, 0x08, 0x21, 0x09, 0x60, 0x78, 0x3f, 0xf8, + 0x47, 0x43, 0xf6, 0xa9, 0x27, 0x0a, 0x1e, 0x33, + 0x03, 0xea, 0xfc, 0x08, 0x61, 0x08, 0x7d, 0xa5, + 0xc9, 0xe6, 0xcd, 0xce, 0x7d, 0x81, 0xfb, 0x43, + 0xd1, 0xf8, 0x90, 0x3c, 0xaa, 0xaf, 0x53, 0x96, + 0x42, 0xfa, 0x98, 0xbc, 0x3c, 0x8c, 0x2f, 0xd2, + 0xc8, 0xa5, 0xaf, 0xa9, 0x93, 0xf9, 0x6b, 0x82, + 0x58, 0x28, 0xc0, 0xf8, 0xfd, 0x85, 0x4a, 0x95, + 0x0e, 0x59, 0xfe, 0xee, 0x16, 0xab, 0x6e, 0x30, + 0xc3, 0x4c, 0x4f, 0xb3, 0xfe, 0x37, 0xfe, 0x4d, + 0xcf, 0x66, 0x4d, 0x6f, 0x79, 0xfb, 0xc9, 0xc8, + 0xbf, 0x21, 0xc3, 0x03, 0xdf, 0x84, 0x0a, 0xc0, + 0xe5, 0x28, 0xf8, 0x0e, 0x8e, 0x83, 0xff, 0xcf, + 0x27, 0x2f, 0x54, 0xb8, 0xe5, 0x52, 0xae, 0xf9, + 0xb9, 0x37, 0x1b, 0x97, 0x62, 0x8f, 0x29, 0x96, + 0xe6, 0xac, 0x6e, 0x1c, 0xb6, 0xde, 0x21, 0xe4, + 0x34, 0xed, 0x71, 0x9b, 0x69, 0xfe, 0xac, 0x4a, + 0x4a, 0x07, 0x55, 0x2b, 0x08, 0x42, 0x1a, 0x46, + 0xe2, 0x51, 0x08, 0x7a, 0x21, 0x7c, 0x0e, 0x68, + 0x34, 0x11, 0x92, 0xd5, 0x6c, 0xf9, 0xa5, 0x4a, + 0x75, 0x52, 0x56, 0x04, 0x11, 0xfb, 0x55, 0x16, + 0xa8, 0xd5, 0x7e, 0xb8, 0x38, 0x93, 0x7f, 0xbb, + 0xa0, 0xb2, 0x28, 0xd0, 0x33, 0x62, 0x58, 0x94, + 0x9c, 0x78, 0x3f, 0x48, 0xa8, 0x4a, 0xa2, 0x1a, + 0x96, 0xb0, 0xb1, 0x52, 0x42, 0xf5, 0x49, 0xfd, + 0x36, 0x66, 0xea, 0xfe, 0x9e, 0x6f, 0xdb, 0x93, + 0x79, 0x6a, 0x25, 0xd7, 0xe3, 0xec, 0x03, 0x5b, + 0x1f, 0x0f, 0x47, 0x63, 0xe1, 0xf4, 0x1d, 0x0f, + 0x00, 0xe8, 0xf9, 0xaf, 0x26, 0x4e, 0xca, 0x7a, + 0x94, 0x7a, 0xc1, 0x77, 0xd5, 0x07, 0xdf, 0xd2, + 0xdf, 0x56, 0x9b, 0xfa, 0x5c, 0x61, 0x99, 0x65, + 0x6b, 0xc0, 0x65, 0x82, 0xbf, 0xa9, 0xa3, 0x89, + 0x02, 0xd4, 0xc2, 0x06, 0x0e, 0x80, 0x31, 0xa0, + 0x78, 0x2f, 0xf9, 0x44, 0x06, 0x18, 0x9b, 0x7e, + 0xac, 0x1e, 0x0b, 0xfd, 0x9f, 0x82, 0x85, 0x91, + 0x28, 0x18, 0x38, 0xf7, 0x04, 0x28, 0x23, 0xe8, + 0x30, 0x18, 0x10, 0x18, 0x51, 0xec, 0xe0, 0x2b, + 0x27, 0xc5, 0x7d, 0x51, 0xde, 0x75, 0x74, 0x27, + 0xb5, 0xc1, 0x66, 0xc0, 0x8e, 0x10, 0xcb, 0xd2, + 0x83, 0x32, 0x21, 0x26, 0x12, 0x07, 0xf1, 0x37, + 0xbe, 0xaf, 0x52, 0x44, 0xcd, 0x40, 0x6c, 0x12, + 0xfb, 0xcc, 0xef, 0x03, 0xfb, 0x90, 0x21, 0xa4, + 0xef, 0x74, 0x18, 0xd2, 0x9b, 0x3c, 0x22, 0x1f, + 0x14, 0x01, 0xe0, 0x51, 0x62, 0x66, 0x52, 0x40, + 0x3b, 0xa2, 0x4e, 0x09, 0x5e, 0x05, 0x3f, 0xc7, + 0xc0, 0xa7, 0xcb, 0x47, 0x20, 0xaa, 0x8c, 0x8e, + 0x14, 0xf0, 0xb7, 0xa3, 0x80, 0x23, 0xc2, 0xc0, + 0xe7, 0x87, 0xcd, 0x24, 0x6c, 0x49, 0x03, 0x82, + 0x18, 0x31, 0x5e, 0x17, 0xc6, 0x9a, 0xbc, 0x60, + 0x1e, 0x0b, 0xfd, 0xb1, 0x28, 0x10, 0xc2, 0x13, + 0x5f, 0xa3, 0x75, 0x05, 0x8d, 0x89, 0x25, 0xc5, + 0x5b, 0xf5, 0x0a, 0x78, 0x05, 0xbe, 0xf2, 0x1a, + 0xca, 0x86, 0x80, 0xc7, 0x9a, 0x55, 0xe9, 0x33, + 0xde, 0x2b, 0xfe, 0xff, 0x74, 0x45, 0xdb, 0x77, + 0x76, 0x95, 0xdf, 0xff, 0x6d, 0xaf, 0x35, 0x8f, + 0x79, 0x01, 0x64, 0x91, 0x10, 0xcc, 0x55, 0xae, + 0x68, 0x14, 0x00, 0xcd, 0x0f, 0x19, 0x56, 0x56, + 0x39, 0xc6, 0x2e, 0x79, 0xa6, 0xb5, 0x70, 0xe6, + 0x90, 0x6a, 0x0c, 0xb2, 0xa9, 0x3d, 0xde, 0x16, + 0xb6, 0xdf, 0xf5, 0x44, 0x59, 0x4d, 0xdb, 0xd7, + 0xc7, 0xd4, 0x06, 0xd0, 0x07, 0x03, 0x97, 0x3f, + 0xa1, 0xa4, 0x48, 0x81, 0xc7, 0x5a, 0x1b, 0x0f, + 0x6d, 0x33, 0xa6, 0x2d, 0xf0, 0xe8, 0xb9, 0x8e, + 0x0e, 0x13, 0x30, 0xd4, 0x35, 0xe6, 0xbd, 0x81, + 0x91, 0x84, 0x0b, 0x32, 0x2c, 0x2f, 0x09, 0x9d, + 0x9d, 0x3f, 0xe5, 0x34, 0x11, 0xce, 0x62, 0x19, + 0xd2, 0x9e, 0x3f, 0x4e, 0x78, 0x0e, 0x25, 0x19, + 0x11, 0xf5, 0x00, 0x3c, 0x94, 0x23, 0xdc, 0x07, + 0x23, 0x39, 0x91, 0xa3, 0xe1, 0xe5, 0x02, 0x43, + 0x4d, 0x3f, 0x51, 0x82, 0xc4, 0x1c, 0x2e, 0xeb, + 0xcf, 0xc1, 0xf3, 0x0d, 0x27, 0xb9, 0x93, 0x74, + 0x73, 0x37, 0x6d, 0xd0, 0x33, 0x9e, 0xea, 0x39, + 0x14, 0xa2, 0xea, 0x22, 0xce, 0x73, 0x88, 0x88, + 0x54, 0xa8, 0xc4, 0xc2, 0xd5, 0x0b, 0x2c, 0x37, + 0xe2, 0xdd, 0x88, 0x44, 0xc6, 0xc1, 0x5d, 0x5c, + 0xae, 0xec, 0xa8, 0xd4, 0x44, 0x1c, 0xaa, 0x3b, + 0xd5, 0x90, 0x20, 0x9d, 0x43, 0xc3, 0x83, 0x71, + 0xea, 0x82, 0xf6, 0xc4, 0x0b, 0x1a, 0xff, 0x40, + 0x87, 0xd8, 0x0f, 0x66, 0xf3, 0xf2, 0x72, 0x6a, + 0xd6, 0x11, 0xad, 0xef, 0xd9, 0xa0, 0xc1, 0xef, + 0xe1, 0x59, 0x56, 0x77, 0x95, 0x44, 0x88, 0x44, + 0x5e, 0xf2, 0x22, 0xea, 0xce, 0x15, 0x26, 0xf6, + 0x24, 0x9b, 0xb9, 0xb7, 0xa8, 0x54, 0xd6, 0x65, + 0xbc, 0xe2, 0xd1, 0x6f, 0x4e, 0x45, 0x90, 0x8c, + 0xce, 0xf6, 0x23, 0x8b, 0xc3, 0x43, 0x5a, 0x9a, + 0xde, 0xe2, 0x82, 0xd0, 0xfb, 0xed, 0xb2, 0x1e, + 0x41, 0xc2, 0x05, 0x08, 0x06, 0xd7, 0x54, 0xf1, + 0x1c, 0x95, 0x71, 0x41, 0x4a, 0xd3, 0x72, 0xc5, + 0xb9, 0x93, 0x6d, 0xd6, 0xb3, 0xa8, 0xaa, 0xc8, + 0xed, 0x8b, 0xc5, 0xd6, 0x97, 0x49, 0xd7, 0x9d, + 0x89, 0xe4, 0x91, 0x69, 0x2c, 0xda, 0xba, 0xd6, + 0x0d, 0x83, 0xde, 0xc5, 0xc6, 0x26, 0xfa, 0x81, + 0xe9, 0x56, 0xea, 0x9b, 0x27, 0x36, 0xa3, 0xe7, + 0x2a, 0xcb, 0x2c, 0x8b, 0xa3, 0x71, 0x99, 0xe5, + 0x9b, 0xc4, 0x10, 0x33, 0xa1, 0x5c, 0x4d, 0x45, + 0x62, 0x02, 0xab, 0x93, 0x9f, 0x51, 0x20, 0x77, + 0xe5, 0x37, 0x72, 0xa0, 0x95, 0x74, 0x5c, 0x5e, + 0xa9, 0x58, 0x6a, 0x33, 0xfa, 0xbf, 0x0f, 0xf9, + 0xa9, 0x8b, 0x75, 0xaf, 0x58, 0x5b, 0xcc, 0xfb, + 0x17, 0x43, 0xd2, 0xae, 0xf9, 0x47, 0xb6, 0x1b, + 0xde, 0xc5, 0xd1, 0xae, 0x8d, 0xeb, 0x37, 0xe5, + 0xf3, 0x3e, 0xc2, 0x9f, 0x69, 0x6e, 0xb7, 0xf0, + 0x21, 0x22, 0x2e, 0x76, 0x49, 0x57, 0x45, 0x56, + 0x40, 0x8d, 0xe2, 0x54, 0x8a, 0x8b, 0x4b, 0x6c, + 0x68, 0x70, 0xc2, 0x2f, 0x7b, 0x99, 0x16, 0xef, + 0x54, 0xc8, 0xa3, 0xa1, 0xea, 0x3e, 0xda, 0xb8, + 0x56, 0xa5, 0xbc, 0x20, 0xab, 0xa2, 0xaf, 0x27, + 0xa2, 0xeb, 0xa1, 0x9b, 0x32, 0x4d, 0xa6, 0xf8, + 0x1c, 0x68, 0x61, 0x45, 0x7a, 0xb3, 0x6b, 0x4d, + 0x0e, 0x3f, 0xfb, 0xb8, 0x8e, 0x7e, 0xf7, 0x85, + 0x8b, 0x55, 0x1c, 0xe6, 0x4e, 0x73, 0xbc, 0x8b, + 0x09, 0x88, 0xfe, 0x37, 0xa5, 0x9d, 0xb6, 0x5b, + 0x67, 0x38, 0x80, 0xd7, 0x7b, 0xc2, 0x53, 0xae, + 0x58, 0xb2, 0xd9, 0xb6, 0xae, 0x4b, 0x0d, 0xaf, + 0x4d, 0x94, 0x3b, 0x5c, 0xfe, 0x9a, 0xb8, 0x90, + 0x15, 0xbf, 0x56, 0xb6, 0xb7, 0x72, 0x2d, 0x7d, + 0x65, 0x96, 0x08, 0x90, 0xab, 0xba, 0xa4, 0xd1, + 0x11, 0x5a, 0x3c, 0xcd, 0x62, 0x59, 0x3e, 0xc4, + 0xe6, 0xf6, 0xac, 0xa4, 0xae, 0x59, 0xb3, 0xba, + 0xa7, 0x88, 0xfb, 0x28, 0xde, 0x72, 0x11, 0xd8, + 0xe3, 0xb2, 0x23, 0x95, 0x05, 0x5a, 0x8c, 0x16, + 0xea, 0xf0, 0xdc, 0x59, 0x01, 0x3c, 0xff, 0x54, + 0xe1, 0x65, 0xf5, 0xe5, 0x0f, 0x2d, 0x58, 0x63, + 0x7b, 0x9c, 0xe3, 0xd9, 0x7a, 0xb1, 0x2f, 0x7b, + 0x28, 0x4b, 0x13, 0x4d, 0x33, 0x03, 0x86, 0x2f, + 0xbc, 0x1e, 0xdc, 0x91, 0x1f, 0x7b, 0x79, 0x00, + 0xae, 0xad, 0xde, 0xf1, 0x18, 0x50, 0x4d, 0x80, + 0x33, 0x9d, 0xb9, 0xca, 0x50, 0x8f, 0x84, 0xab, + 0xf0, 0x99, 0x55, 0x73, 0x73, 0xdc, 0x6b, 0x2e, + 0x7f, 0x9c, 0x9f, 0x11, 0x20, 0x2b, 0xe2, 0x95, + 0xc9, 0xa1, 0xab, 0x24, 0x93, 0xb0, 0xd1, 0x51, + 0x52, 0x05, 0xd6, 0x0c, 0x5f, 0x78, 0x4b, 0x4f, + 0xd4, 0xc4, 0x6a, 0x92, 0xfa, 0x6b, 0x6a, 0x76, + 0xf4, 0x73, 0x62, 0x8e, 0x6a, 0xca, 0x16, 0x43, + 0x06, 0xd3, 0xa8, 0xc2, 0x9b, 0xb0, 0x72, 0xca, + 0xa9, 0xf8, 0xb4, 0x1f, 0xb0, 0xdf, 0xba, 0x49, + 0xb3, 0x96, 0x0d, 0xd1, 0x2e, 0x68, 0x4e, 0x83, + 0x10, 0x41, 0xad, 0xb7, 0x36, 0xde, 0xb7, 0xce, + 0xf0, 0xb7, 0x16, 0x5a, 0xe2, 0xd7, 0x96, 0x0a, + 0xcb, 0xe2, 0xac, 0xeb, 0x05, 0x57, 0x91, 0x99, + 0x78, 0x8f, 0x8b, 0xf7, 0x16, 0x5f, 0x90, 0x28, + 0x5b, 0x6b, 0xa2, 0xee, 0xf7, 0xa0, 0xf5, 0x30, + 0x01, 0x84, 0xbd, 0x05, 0xe0, 0x3a, 0x1b, 0x04, + 0xd5, 0x56, 0xd3, 0x61, 0x8c, 0xa0, 0xe0, 0x1e, + 0x72, 0xa9, 0xf9, 0x10, 0x1f, 0xd3, 0xa3, 0x68, + 0xca, 0x11, 0x1d, 0x2c, 0xa6, 0x9a, 0x88, 0xae, + 0x29, 0xe7, 0xaf, 0xfd, 0x3f, 0xc1, 0xce, 0x7b, + 0xfc, 0x53, 0xec, 0x6f, 0x90, 0x41, 0xcc, 0xb3, + 0x19, 0xe6, 0x0e, 0x66, 0xa8, 0x73, 0x52, 0xb1, + 0xa4, 0x20, 0xe4, 0x47, 0x0c, 0xb4, 0xad, 0x9b, + 0xf6, 0x73, 0xe9, 0xae, 0x7b, 0x2c, 0x2c, 0xf9, + 0x6c, 0x05, 0x6c, 0x0e, 0x54, 0x41, 0xb5, 0xe8, + 0xc5, 0x18, 0xa9, 0x4a, 0x81, 0xc2, 0x8a, 0x98, + 0xaa, 0xf2, 0xce, 0x7f, 0xde, 0xff, 0xaa, 0x36, + 0x99, 0xf7, 0x99, 0x6b, 0x79, 0x7a, 0x56, 0xc3, + 0x33, 0x5a, 0xde, 0x6c, 0x9b, 0x14, 0xe5, 0xe6, + 0xe6, 0x68, 0xdf, 0x23, 0xde, 0xef, 0x57, 0xed, + 0xb6, 0xdb, 0xd4, 0x3d, 0xb4, 0x96, 0xa1, 0xb4, + 0x8d, 0x05, 0x24, 0x80, 0xe2, 0x51, 0xaf, 0xe8, + 0x3f, 0x7c, 0x00, 0x72, 0x13, 0xc6, 0xc2, 0xd0, + 0x2b, 0x26, 0x8e, 0x74, 0x7c, 0x3c, 0xd6, 0x62, + 0x8b, 0x15, 0xfc, 0x74, 0x3c, 0xfa, 0x59, 0x73, + 0x85, 0x97, 0x13, 0xfd, 0x35, 0x57, 0x2b, 0x53, + 0x24, 0x6a, 0x96, 0xf5, 0xa5, 0x12, 0x7a, 0xe2, + 0x88, 0x79, 0x54, 0xe9, 0x07, 0x83, 0xf5, 0x10, + 0x7e, 0x93, 0xc9, 0x7d, 0x2a, 0x9e, 0x37, 0xaa, + 0xfd, 0x4b, 0x78, 0x37, 0x2d, 0x61, 0xb6, 0x1b, + 0x29, 0x0f, 0x54, 0x7d, 0x6b, 0xf9, 0xa5, 0x98, + 0x7a, 0xaf, 0x41, 0x63, 0xd0, 0xc0, 0xeb, 0x19, + 0x83, 0x81, 0x3a, 0xd9, 0x06, 0x24, 0xaf, 0xa3, + 0x44, 0xc4, 0x9b, 0xca, 0x37, 0xcc, 0x2c, 0x51, + 0x22, 0x8a, 0xd6, 0x56, 0x0b, 0x24, 0x92, 0x35, + 0x58, 0xb0, 0x70, 0x20, 0x4c, 0xc9, 0xe8, 0xc1, + 0x60, 0xe0, 0xb2, 0x4f, 0x28, 0x51, 0x0f, 0x29, + 0x31, 0xa9, 0xd8, 0xa9, 0xa4, 0xc9, 0xa6, 0xf3, + 0xb8, 0x3e, 0x1e, 0x24, 0x2e, 0x9b, 0x73, 0xaa, + 0x2b, 0x70, 0xb9, 0x86, 0x87, 0x3b, 0x93, 0x7f, + 0x30, 0xb5, 0x4a, 0x82, 0xdf, 0xa8, 0xe2, 0x9a, + 0x7c, 0xcf, 0x4f, 0x7e, 0x9b, 0x2b, 0x19, 0x05, + 0x5a, 0x8c, 0x24, 0x07, 0x12, 0x91, 0xe9, 0x8b, + 0x44, 0x84, 0x93, 0x47, 0x29, 0xd8, 0x1f, 0x09, + 0x54, 0x77, 0x36, 0x96, 0x27, 0x06, 0x50, 0x3e, + 0xf2, 0x59, 0xff, 0x87, 0x6c, 0xfd, 0x2e, 0x35, + 0x89, 0xef, 0xea, 0x9d, 0x2d, 0xbb, 0xf5, 0x2d, + 0xaf, 0x2d, 0xbd, 0x78, 0x95, 0x38, 0xe1, 0xb4, + 0xda, 0xc7, 0xd3, 0x34, 0x3f, 0x53, 0x24, 0xaa, + 0x93, 0xe3, 0x4c, 0xb1, 0xbf, 0xc1, 0xb5, 0xfb, + 0x5a, 0xa7, 0x0a, 0xbf, 0x26, 0xaf, 0x2f, 0x2a, + 0x24, 0x4e, 0x44, 0x4a, 0x49, 0x93, 0x1a, 0xf9, + 0x6b, 0x79, 0xac, 0xaf, 0xc5, 0x3c, 0xcb, 0xca, + 0x6e, 0x50, 0x60, 0xa5, 0x3d, 0xf3, 0x78, 0xb3, + 0x5c, 0x44, 0xa6, 0xfc, 0xd6, 0x8c, 0xba, 0x8c, + 0x1d, 0x48, 0x06, 0x10, 0x9a, 0x88, 0x10, 0x1e, + 0xd7, 0xb2, 0xe6, 0xf5, 0xa4, 0xe9, 0x15, 0x09, + 0x25, 0xed, 0x35, 0x93, 0x75, 0xb6, 0x5a, 0x92, + 0x22, 0x54, 0xd6, 0x78, 0x93, 0x39, 0xef, 0x01, + 0x49, 0x92, 0x39, 0x3d, 0x4d, 0xe6, 0x8b, 0xa7, + 0x8b, 0x92, 0x5b, 0xb3, 0x1a, 0x48, 0x93, 0xcd, + 0x5e, 0xed, 0xad, 0x7b, 0x22, 0x3d, 0xde, 0xcc, + 0xdb, 0xb7, 0x7b, 0x6f, 0x24, 0x99, 0x88, 0x0f, + 0x6f, 0xe1, 0x66, 0x45, 0x3d, 0x02, 0x74, 0xd2, + 0xc4, 0xa1, 0x57, 0x50, 0x8c, 0x95, 0x11, 0x40, + 0x2c, 0x45, 0x3c, 0x52, 0x85, 0xfa, 0x6a, 0xb4, + 0x21, 0x09, 0x0d, 0x72, 0xaa, 0x10, 0x84, 0x85, + 0x56, 0x7f, 0xcc, 0xe0, 0x80, 0x3a, 0x2e, 0x6a, + 0xc6, 0x58, 0xe8, 0xe1, 0x9c, 0xbe, 0x6b, 0x38, + 0xdb, 0x4a, 0x74, 0x70, 0xdc, 0x0f, 0x5a, 0x2d, + 0xd5, 0x16, 0x29, 0xd3, 0xe5, 0xfc, 0xc3, 0x49, + 0xb2, 0x34, 0xc3, 0x4d, 0x30, 0xd6, 0x5b, 0x71, + 0x86, 0x3d, 0x15, 0x7a, 0x5d, 0xbd, 0xfd, 0x9e, + 0xc9, 0x99, 0x3b, 0x7b, 0xbb, 0x79, 0xdb, 0xb6, + 0xed, 0x5e, 0x9f, 0x2a, 0x63, 0x5a, 0x2f, 0x25, + 0x42, 0x14, 0x42, 0x4a, 0x45, 0x13, 0x74, 0xa3, + 0x87, 0xc4, 0x7b, 0x99, 0xfc, 0xdf, 0x6f, 0xa3, + 0x7e, 0xfc, 0xb1, 0xbf, 0x7f, 0x33, 0xfe, 0xdf, + 0x55, 0xae, 0x7f, 0xdf, 0x53, 0x9b, 0x95, 0x0e, + 0x6f, 0x65, 0x21, 0xba, 0x88, 0x1d, 0xc0, 0x58, + 0x03, 0x9f, 0x81, 0xcb, 0xd4, 0x60, 0xe2, 0x17, + 0x18, 0xbe, 0xa6, 0xa2, 0x41, 0x28, 0x74, 0xd1, + 0x6b, 0x4d, 0x09, 0x43, 0xc5, 0x5e, 0x67, 0x2e, + 0x2b, 0xf2, 0xa1, 0xe2, 0x65, 0x58, 0xaf, 0x39, + 0xb1, 0x43, 0x38, 0xc3, 0x59, 0x8c, 0xe7, 0x3f, + 0xfc, 0xe7, 0xe6, 0xad, 0xfd, 0x82, 0x2b, 0xc5, + 0xad, 0x7b, 0xde, 0x6a, 0x34, 0xd7, 0xa3, 0x5e, + 0xcc, 0x99, 0xef, 0x35, 0x26, 0x67, 0xbd, 0x88, + 0xb3, 0x3d, 0xee, 0x66, 0x64, 0x85, 0x53, 0x24, + 0xe6, 0x49, 0xc8, 0x79, 0x0f, 0x55, 0xc6, 0x43, + 0x20, 0x1f, 0x0a, 0x02, 0xad, 0x88, 0x90, 0x84, + 0x56, 0x94, 0x85, 0x55, 0x1b, 0xe3, 0x0c, 0x7a, + 0xb7, 0xbe, 0x6b, 0x33, 0x59, 0xd2, 0xd6, 0x77, + 0xd9, 0x26, 0xb3, 0xfe, 0x70, 0xb5, 0xbb, 0xc9, + 0x5b, 0xff, 0x39, 0x85, 0xbb, 0xdd, 0x51, 0xc9, + 0xde, 0x3a, 0x38, 0xb0, 0xcc, 0x1d, 0xc0, 0x4e, + 0x4c, 0xe3, 0x5b, 0x62, 0x11, 0xae, 0xbe, 0xa8, + 0x86, 0x2f, 0xce, 0xdd, 0x19, 0x02, 0xc5, 0xee, + 0xc2, 0x9a, 0x0b, 0x96, 0x95, 0x63, 0x9a, 0xfa, + 0x83, 0x88, 0x74, 0x07, 0x1f, 0xd1, 0x02, 0x22, + 0x2a, 0x0c, 0x45, 0xcb, 0x42, 0x64, 0x42, 0x41, + 0xa7, 0x45, 0x21, 0x44, 0x83, 0x86, 0x03, 0x56, + 0x80, 0x31, 0x21, 0x7d, 0x59, 0x10, 0x64, 0x19, + 0x39, 0xd6, 0xe9, 0x1e, 0x9c, 0x5c, 0x44, 0xb1, + 0x28, 0x39, 0x71, 0x5a, 0x62, 0x78, 0x91, 0x60, + 0x7f, 0x2f, 0xff, 0xf0, 0x3d, 0x1c, 0x00, 0x60, + 0xe7, 0x67, 0x74, 0xcb, 0x8c, 0x21, 0x40, 0x2c, + 0x51, 0x0d, 0x75, 0x88, 0x40, 0x70, 0x38, 0x82, + 0x01, 0xc6, 0xba, 0x0e, 0x26, 0x68, 0x56, 0x44, + 0x0e, 0x34, 0xe6, 0x2b, 0x13, 0x69, 0x9a, 0x65, + 0x85, 0x28, 0x79, 0x10, 0xf0, 0x31, 0x91, 0x61, + 0x88, 0x54, 0xa2, 0xaf, 0x41, 0xcf, 0xef, 0x7b, + 0xcb, 0xcb, 0xd9, 0x54, 0xca, 0x22, 0x21, 0x40, + 0xe2, 0xfa, 0x8a, 0xf2, 0x03, 0x81, 0x72, 0x70, + 0x41, 0x9a, 0xd5, 0xdc, 0x8d, 0xf2, 0x76, 0x2e, + 0x55, 0xfb, 0xa8, 0x38, 0x6d, 0x70, 0x74, 0x7a, + 0x10, 0x54, 0xc5, 0xaa, 0x26, 0xa3, 0x44, 0x0b, + 0x00, 0x5f, 0x2c, 0xdc, 0xe0, 0x75, 0x11, 0xde, + 0x44, 0x7c, 0xec, 0x44, 0x75, 0x75, 0x43, 0x9a, + 0xc5, 0x0f, 0xed, 0xde, 0xed, 0x24, 0xd9, 0x10, + 0x62, 0xc8, 0xf8, 0x04, 0x56, 0xec, 0x46, 0x42, + 0x96, 0x15, 0xcb, 0x17, 0x5a, 0xc4, 0x38, 0xb1, + 0x22, 0xe8, 0xa1, 0x48, 0xc8, 0xe1, 0x92, 0xae, + 0x09, 0xd1, 0x34, 0xf3, 0x03, 0x9b, 0xd1, 0xb7, + 0x22, 0x05, 0x89, 0x29, 0x0e, 0xb9, 0x11, 0xf1, + 0x12, 0x14, 0x01, 0x8c, 0x0c, 0xa9, 0x3c, 0xcc, + 0x5e, 0x23, 0xec, 0x28, 0x0a, 0x67, 0x57, 0x36, + 0x0e, 0x28, 0x39, 0x22, 0x11, 0x71, 0xda, 0xbf, + 0x91, 0x7d, 0xd2, 0x85, 0xd7, 0x0c, 0xc6, 0x01, + 0x3d, 0x2b, 0xda, 0xcb, 0x52, 0x23, 0x88, 0x56, + 0xec, 0xe8, 0xc6, 0x20, 0x44, 0x4f, 0x8a, 0x14, + 0x12, 0x50, 0xc5, 0x12, 0xe4, 0x4c, 0xa4, 0xe7, + 0x46, 0x9a, 0x66, 0x72, 0x36, 0xde, 0x8e, 0x7e, + 0xc9, 0x50, 0x14, 0xf4, 0x5a, 0x12, 0x55, 0xa1, + 0x5d, 0x24, 0x22, 0x82, 0xc9, 0x51, 0xcb, 0xde, + 0x02, 0xc0, 0xa7, 0xa2, 0x92, 0x35, 0x44, 0x46, + 0x85, 0x11, 0x28, 0x30, 0x51, 0xa4, 0x43, 0x41, + 0x85, 0xe0, 0xe0, 0xae, 0xf5, 0x09, 0x06, 0x99, + 0x2f, 0x31, 0x99, 0x16, 0xc2, 0xc9, 0xc0, 0xd3, + 0xa3, 0x28, 0x43, 0xda, 0xbf, 0x9b, 0xe8, 0x1d, + 0xdb, 0xf5, 0xd0, 0x16, 0x60, 0x67, 0x49, 0x10, + 0xde, 0x9d, 0x9e, 0x14, 0x8c, 0x51, 0x82, 0xc0, + 0xd0, 0xa9, 0x55, 0x18, 0x5a, 0xd5, 0xb2, 0xd2, + 0xb9, 0xcd, 0x59, 0x65, 0xcd, 0xd4, 0x08, 0x14, + 0x41, 0x83, 0x9c, 0xdd, 0x5d, 0xfa, 0x6b, 0x29, + 0x05, 0xcb, 0x52, 0x32, 0x07, 0x06, 0x24, 0xe6, + 0xaf, 0xe9, 0x48, 0xa5, 0x45, 0x3a, 0x48, 0x0e, + 0x20, 0x5e, 0x70, 0x17, 0xba, 0x75, 0x69, 0x48, + 0x47, 0x1d, 0x36, 0x0e, 0x17, 0x11, 0x6e, 0xea, + 0x34, 0x63, 0x35, 0x86, 0x92, 0x5b, 0xa6, 0xa9, + 0x2c, 0xe8, 0x38, 0x16, 0x02, 0xa5, 0x59, 0xd1, + 0x75, 0x7b, 0xde, 0x70, 0x1f, 0xbe, 0x00, 0x3f, + 0xfa, 0xfa, 0xce, 0x9a, 0x90, 0x51, 0xe4, 0xea, + 0x0c, 0x22, 0x99, 0x57, 0x34, 0x4d, 0x57, 0xa3, + 0x8f, 0x86, 0xca, 0x0f, 0xdb, 0x6d, 0x37, 0x50, + 0x4a, 0xe5, 0x5b, 0x6a, 0xd8, 0xbf, 0x65, 0xec, + 0xd7, 0x2b, 0xb5, 0xff, 0x61, 0xc7, 0xe9, 0x7b, + 0xd3, 0x96, 0xcc, 0x9c, 0x5a, 0xb7, 0xed, 0x41, + 0x38, 0x73, 0x46, 0x53, 0x75, 0x6b, 0xfd, 0x30, + 0xd7, 0x84, 0xaf, 0xd3, 0x32, 0x07, 0x95, 0xfc, + 0x73, 0x5a, 0x1b, 0xf9, 0x42, 0x99, 0x03, 0x8e, + 0x10, 0xcc, 0xa0, 0xe1, 0xa0, 0xc4, 0x10, 0x8b, + 0xf7, 0xe3, 0xdc, 0xf0, 0x7d, 0x71, 0x4e, 0x7e, + 0x5d, 0xb4, 0x36, 0x14, 0x28, 0x83, 0x03, 0x00, + 0x58, 0x82, 0xc0, 0xfa, 0x7f, 0x39, 0x51, 0x9e, + 0x89, 0xbb, 0x20, 0xcd, 0x12, 0x01, 0x3d, 0xaf, + 0x50, 0x83, 0x85, 0xe8, 0x8a, 0x05, 0x29, 0xaf, + 0x4e, 0xe8, 0x84, 0x31, 0x08, 0x8c, 0x3f, 0xa7, + 0x22, 0xf5, 0x88, 0xea, 0x83, 0xba, 0x18, 0x0a, + 0xf4, 0x92, 0xa1, 0x44, 0x0e, 0x44, 0x12, 0x6a, + 0x0e, 0x90, 0x1c, 0x7a, 0xa0, 0x21, 0xa9, 0xb5, + 0xd1, 0x83, 0xba, 0x6d, 0x08, 0x4d, 0xdf, 0x97, + 0x35, 0x22, 0x30, 0x72, 0x03, 0xbf, 0x88, 0xc0, + 0x72, 0xe0, 0x38, 0x29, 0x9d, 0x34, 0xbd, 0x0a, + 0x34, 0xdf, 0x91, 0xf0, 0xa4, 0x53, 0x39, 0x09, + 0x2a, 0x30, 0x73, 0xdf, 0x91, 0xc4, 0x00, 0xe5, + 0xa7, 0x01, 0x39, 0xf9, 0x11, 0xa0, 0x8a, 0xbe, + 0x2f, 0xaa, 0x31, 0x90, 0xcc, 0x31, 0x27, 0xfd, + 0x34, 0xb1, 0xcf, 0x01, 0xfd, 0x7f, 0xff, 0xd2, + 0x74, 0xa0, 0x1d, 0x4a, 0x4e, 0x59, 0x0e, 0xe9, + 0xb4, 0x05, 0x00, 0xe3, 0x44, 0xf8, 0x31, 0x05, + 0xd3, 0x8b, 0x21, 0x7e, 0x5c, 0x1c, 0x03, 0xc1, + 0x3d, 0x51, 0x14, 0x0a, 0xea, 0x78, 0xa0, 0x31, + 0x09, 0x64, 0x1c, 0x12, 0xbe, 0x1b, 0x80, 0xe2, + 0x0c, 0x8b, 0x84, 0x85, 0x20, 0xb0, 0x09, 0x18, + 0x28, 0xd3, 0xe0, 0xe4, 0x20, 0xe0, 0x4d, 0xf6, + 0x9a, 0x07, 0x06, 0x4f, 0x60, 0xe4, 0x46, 0xdf, + 0xc6, 0x22, 0xe0, 0xc0, 0x28, 0xe2, 0x32, 0x0d, + 0x3f, 0xde, 0x00, 0xe0, 0x92, 0x01, 0x79, 0x54, + 0x6e, 0xec, 0xba, 0x02, 0x1a, 0x6c, 0xfc, 0x5f, + 0x8b, 0xc0, 0x77, 0x4f, 0x4a, 0x03, 0x61, 0x1b, + 0x50, 0x83, 0x84, 0x5f, 0xa3, 0x31, 0x45, 0xc5, + 0x81, 0xd4, 0xee, 0x9c, 0xda, 0x48, 0x31, 0xe2, + 0x32, 0x8a, 0xe2, 0xd2, 0x5b, 0xb7, 0x68, 0xcb, + 0x0d, 0x12, 0xa2, 0x42, 0x14, 0x65, 0xcd, 0x03, + 0x83, 0x20, 0x9d, 0x0e, 0x0b, 0x82, 0x96, 0xb4, + 0x64, 0xed, 0x34, 0xf9, 0xb5, 0x0d, 0x80, 0xfd, + 0xb0, 0x01, 0xd6, 0x62, 0x8d, 0x5d, 0x1d, 0x29, + 0xa1, 0x80, 0x66, 0x32, 0x7f, 0xe9, 0xb1, 0x33, + 0x17, 0x1a, 0x87, 0x59, 0x72, 0x0a, 0xba, 0x7a, + 0x88, 0x92, 0xf1, 0xf8, 0x31, 0x07, 0x40, 0x8f, + 0x12, 0xa0, 0x45, 0x3a, 0x88, 0x1c, 0x11, 0x30, + 0x72, 0xe4, 0x5a, 0x83, 0x61, 0x3c, 0x4e, 0xaa, + 0x00, 0xc9, 0x19, 0xf6, 0xb0, 0x38, 0x07, 0x04, + 0x93, 0x46, 0x62, 0x66, 0xb0, 0x2c, 0x08, 0xea, + 0x95, 0xc1, 0x3f, 0x48, 0x99, 0x3a, 0x8e, 0xf4, + 0xd2, 0xc0, 0xe0, 0xc4, 0x69, 0x34, 0x1e, 0x82, + 0x00, 0x30, 0x71, 0x4b, 0xdb, 0x0c, 0x45, 0x29, + 0xda, 0x4d, 0xa7, 0xf9, 0xde, 0x74, 0x5c, 0x0b, + 0xa4, 0xfc, 0xa6, 0xfc, 0x3d, 0x51, 0xc9, 0xf0, + 0xf3, 0x88, 0xcd, 0x4e, 0xd3, 0x60, 0xbb, 0xf3, + 0xaa, 0x17, 0xe4, 0xa2, 0xe0, 0x71, 0xf8, 0x8b, + 0x5c, 0x86, 0xa8, 0x3b, 0xa7, 0x64, 0x1a, 0x69, + 0x8e, 0x01, 0x14, 0x49, 0x41, 0x3c, 0x08, 0xd0, + 0x18, 0x07, 0xb9, 0x1c, 0x4e, 0x25, 0xd4, 0x71, + 0x80, 0x7d, 0x8f, 0xff, 0x52, 0xdd, 0x36, 0x14, + 0xd7, 0x4d, 0x38, 0xba, 0x36, 0x5a, 0x18, 0xa9, + 0xd2, 0x91, 0xda, 0x1f, 0xb5, 0x90, 0xa1, 0x71, + 0x7f, 0x48, 0x28, 0x19, 0x7a, 0x8c, 0xbc, 0x61, + 0xc8, 0x12, 0x7e, 0xae, 0x15, 0x60, 0xc8, 0x4d, + 0xe6, 0xea, 0x20, 0xc0, 0x13, 0x75, 0xe9, 0x52, + 0xaf, 0x74, 0x3d, 0xd6, 0x6d, 0xa2, 0xba, 0x69, + 0x32, 0xa4, 0x77, 0x65, 0x3d, 0x2b, 0x50, 0x75, + 0x05, 0xd5, 0xee, 0x1f, 0x55, 0xca, 0xd1, 0xbf, + 0x5e, 0x59, 0xbe, 0x06, 0x24, 0xc3, 0xe9, 0xff, + 0xeb, 0x20, 0x39, 0x41, 0xda, 0x80, 0x75, 0x07, + 0x0d, 0x56, 0x02, 0xe7, 0xaf, 0xa0, 0xcc, 0x8b, + 0x4e, 0x65, 0x91, 0x12, 0xc3, 0x49, 0x52, 0xe7, + 0x59, 0xa5, 0x01, 0x47, 0x2d, 0x06, 0x14, 0x4e, + 0x6a, 0x3a, 0x76, 0x2e, 0xbf, 0xfe, 0xd7, 0xc1, + 0x8d, 0xfa, 0xd4, 0x44, 0x27, 0x3e, 0x5a, 0x25, + 0xb0, 0xc5, 0x51, 0xd3, 0x54, 0xb2, 0xab, 0xf0, + 0x3c, 0x64, 0x01, 0xad, 0xb7, 0x8b, 0x85, 0x63, + 0x16, 0x67, 0x95, 0xc0, 0x64, 0x3e, 0xd9, 0x62, + 0x14, 0x41, 0x29, 0x6f, 0x5b, 0xc5, 0xba, 0x84, + 0xd0, 0xc4, 0x2b, 0x4d, 0x8a, 0x01, 0xd2, 0xe0, + 0x0f, 0x76, 0x9a, 0x02, 0x40, 0xed, 0xa1, 0x2e, + 0x37, 0x7d, 0x8c, 0xe4, 0xf5, 0x90, 0x15, 0xad, + 0x6b, 0x48, 0x10, 0x29, 0x40, 0xb1, 0x01, 0x1d, + 0xc3, 0x5c, 0x07, 0x1f, 0x24, 0xab, 0x4a, 0x90, + 0x14, 0x82, 0xc0, 0x27, 0x8d, 0x44, 0x18, 0x12, + 0x05, 0x1a, 0x24, 0x1c, 0x34, 0xbf, 0x42, 0xbd, + 0x3b, 0x15, 0x6d, 0x07, 0x12, 0x0b, 0x9e, 0xac, + 0x0c, 0x81, 0xcf, 0xf6, 0x03, 0xd0, 0x40, 0x06, + 0x30, 0x20, 0x61, 0x4e, 0x9d, 0x8c, 0xf8, 0x26, + 0x84, 0x43, 0x33, 0x74, 0x1c, 0x0b, 0xec, 0xb9, + 0x36, 0x41, 0x45, 0x5a, 0x28, 0xb9, 0xcd, 0x3f, + 0x9d, 0x2d, 0x80, 0xe9, 0x01, 0xc2, 0xfa, 0x34, + 0xde, 0x07, 0x1b, 0x73, 0xc1, 0xb8, 0xcf, 0xa5, + 0x23, 0x56, 0xd7, 0x41, 0xc8, 0xf8, 0x14, 0xe7, + 0x2a, 0xf0, 0x52, 0x0e, 0x0a, 0x3c, 0x43, 0x7a, + 0x8c, 0x4f, 0x89, 0x41, 0xd4, 0x13, 0x7d, 0xa0, + 0xe0, 0xc8, 0x89, 0xaa, 0x03, 0xd1, 0x3f, 0x3b, + 0xd2, 0x40, 0x71, 0xd6, 0x37, 0x01, 0xfc, 0x05, + 0xd3, 0x84, 0x39, 0x09, 0x03, 0x23, 0xa1, 0x1e, + 0x9e, 0x19, 0x83, 0x06, 0x41, 0x57, 0x07, 0x0c, + 0x09, 0x4f, 0x63, 0xfc, 0x66, 0xb8, 0x38, 0xf2, + 0xf0, 0x17, 0x71, 0x3c, 0x32, 0x0a, 0xba, 0x28, + 0x81, 0x72, 0x40, 0x5c, 0x35, 0xa9, 0x0b, 0x07, + 0x02, 0x6a, 0x12, 0x11, 0xe9, 0xea, 0x0e, 0x01, + 0xe0, 0xb8, 0xe8, 0x81, 0xc2, 0x8d, 0x46, 0x42, + 0x9c, 0x0f, 0x43, 0xff, 0xff, 0x02, 0x76, 0x22, + 0xa9, 0xcd, 0x07, 0x52, 0x3e, 0x0e, 0x04, 0xea, + 0xa0, 0xf3, 0xd0, 0x01, 0x83, 0x88, 0x9a, 0xe8, + 0xd1, 0x92, 0x03, 0x81, 0x3e, 0xf6, 0x54, 0x5d, + 0x58, 0x4d, 0x17, 0x66, 0xc3, 0x10, 0x5c, 0xf0, + 0xcc, 0x1c, 0x12, 0x3a, 0xe9, 0x05, 0x80, 0x54, + 0xc8, 0xc1, 0xd7, 0xa7, 0xaa, 0xf5, 0xd8, 0x6d, + 0x68, 0x8a, 0xba, 0x39, 0xc4, 0x08, 0xc8, 0x2c, + 0x07, 0x83, 0x84, 0xf5, 0x79, 0xa8, 0x45, 0xcb, + 0x82, 0xc3, 0x83, 0x17, 0xa6, 0x48, 0x48, 0x27, + 0xd3, 0xc2, 0xe1, 0x3f, 0x07, 0x04, 0xcc, 0x65, + 0xd0, 0xc8, 0x28, 0xc0, 0xe2, 0x40, 0x5c, 0x5b, + 0x38, 0x0b, 0xba, 0xbf, 0xa5, 0x72, 0x72, 0xca, + 0x8d, 0x1a, 0x21, 0x75, 0x8b, 0x13, 0xf2, 0x99, + 0x67, 0x10, 0x51, 0x81, 0x07, 0x15, 0x60, 0x75, + 0x58, 0x2a, 0xb6, 0x9e, 0xd3, 0xca, 0x54, 0xc5, + 0x8a, 0x41, 0xce, 0x65, 0x24, 0x4d, 0x15, 0x45, + 0xd0, 0xc0, 0x5c, 0x0b, 0xcc, 0xb1, 0xb1, 0x8f, + 0x20, 0x60, 0x13, 0x34, 0xee, 0x14, 0xbf, 0x5e, + 0x77, 0x4d, 0x03, 0xa0, 0x2c, 0x42, 0x6d, 0x2d, + 0xa7, 0x97, 0x2f, 0x98, 0xdb, 0x5c, 0x2d, 0xd5, + 0xd1, 0x77, 0xa8, 0x2e, 0x5e, 0x73, 0x81, 0x2d, + 0xef, 0xb1, 0xa5, 0x38, 0x38, 0xb9, 0x56, 0xec, + 0xd6, 0xb7, 0x64, 0x24, 0x41, 0x6a, 0x2a, 0x71, + 0x3d, 0x04, 0x5a, 0x28, 0xa9, 0x99, 0xd6, 0x49, + 0x01, 0xc4, 0x16, 0x20, 0xe8, 0xa0, 0xe5, 0x63, + 0xe8, 0x53, 0xe9, 0x2f, 0x14, 0x03, 0xb8, 0x35, + 0xa0, 0x44, 0x82, 0x2f, 0xdb, 0xd8, 0x1b, 0xeb, + 0xd0, 0x3c, 0x58, 0x3d, 0x19, 0x16, 0x1d, 0xd7, + 0xb5, 0x1b, 0x60, 0x54, 0xaf, 0xfd, 0xb4, 0x38, + 0xd7, 0x7a, 0xc2, 0xa0, 0x62, 0x49, 0x2a, 0xf5, + 0x61, 0x33, 0xfa, 0x25, 0xa7, 0xbc, 0x16, 0x27, + 0x7d, 0xd4, 0x3f, 0x76, 0xba, 0xbf, 0xcc, 0xb3, + 0x9d, 0xdc, 0xd9, 0xc3, 0xd5, 0x3e, 0xd2, 0x0b, + 0xfc, 0xb6, 0x58, 0xe8, 0x80, 0x52, 0x06, 0x07, + 0xb5, 0xfd, 0x15, 0xb1, 0x6e, 0x5e, 0xf4, 0xb3, + 0x76, 0x0a, 0xb5, 0xea, 0xfe, 0x4f, 0xd9, 0xe1, + 0xc2, 0x76, 0xbb, 0x02, 0xd9, 0x1e, 0x0f, 0x77, + 0xab, 0x4f, 0x79, 0xb5, 0x8c, 0xd2, 0xdc, 0x42, + 0x27, 0xef, 0xf5, 0x4e, 0x60, 0x31, 0xa9, 0x4d, + 0x54, 0x47, 0xf5, 0xdb, 0x4d, 0x25, 0xec, 0xee, + 0x7d, 0x56, 0x5b, 0x78, 0x2b, 0xd1, 0x25, 0xc4, + 0x75, 0x96, 0xf9, 0xc8, 0x08, 0xce, 0xfb, 0x9f, + 0xe2, 0xf3, 0x1f, 0x6d, 0xb5, 0xb6, 0x21, 0x95, + 0x01, 0xf4, 0xca, 0x8a, 0x87, 0xbb, 0x20, 0x49, + 0x53, 0x2e, 0x5c, 0xa9, 0xa8, 0x5e, 0xc3, 0x74, + 0xb4, 0xa9, 0x96, 0xb4, 0x3b, 0xf8, 0x73, 0x05, + 0x6b, 0x37, 0x79, 0x4a, 0x78, 0x2f, 0x82, 0x75, + 0xd3, 0x2b, 0x03, 0x6a, 0xda, 0x54, 0xc4, 0xfd, + 0xd6, 0xff, 0xef, 0x65, 0xe7, 0x17, 0xba, 0xb5, + 0x5c, 0xc9, 0xa8, 0x9a, 0x8f, 0x9a, 0x61, 0x8a, + 0xce, 0xa7, 0xdc, 0xc0, 0x2f, 0xf4, 0x21, 0x9a, + 0xc6, 0x85, 0x43, 0x2c, 0xe0, 0xca, 0x93, 0x69, + 0xae, 0x5d, 0x7b, 0xe3, 0x6b, 0x82, 0x71, 0x4a, + 0x8a, 0x91, 0xf1, 0x28, 0x3a, 0xbd, 0x05, 0xac, + 0x15, 0x22, 0xea, 0x04, 0x0e, 0xc8, 0xa2, 0xee, + 0xf4, 0x1c, 0x52, 0x0e, 0x40, 0x15, 0x4d, 0x8b, + 0x03, 0xa0, 0x0f, 0xe9, 0x1a, 0x0b, 0x43, 0x61, + 0x85, 0x39, 0xa6, 0x41, 0x78, 0x4b, 0x78, 0x88, + 0xf6, 0x9c, 0xf5, 0x70, 0x77, 0x02, 0x2c, 0x0f, + 0x4f, 0x00, 0x18, 0xd2, 0xc7, 0x08, 0x41, 0xc1, + 0x88, 0x4d, 0x40, 0xc7, 0x99, 0x19, 0x1e, 0x9e, + 0xf2, 0xd6, 0x02, 0xc7, 0x80, 0xe1, 0x93, 0xf7, + 0x91, 0x8c, 0x85, 0x73, 0x1a, 0x5c, 0xfc, 0x22, + 0x74, 0xa7, 0xb4, 0xd8, 0x39, 0x18, 0x4b, 0x97, + 0x01, 0xe8, 0xc1, 0x3f, 0xa2, 0x07, 0xf5, 0x80, + 0x0f, 0xf4, 0x13, 0x35, 0x02, 0xad, 0x7d, 0x20, + 0xc0, 0x1c, 0x14, 0xfa, 0x32, 0xef, 0x41, 0xc3, + 0x56, 0x19, 0x23, 0x21, 0x62, 0xe7, 0xf2, 0x02, + 0xeb, 0x4d, 0x83, 0x8a, 0x41, 0xc3, 0x07, 0x30, + 0x73, 0xf4, 0xea, 0x23, 0x40, 0xe0, 0x9d, 0xae, + 0x4a, 0x32, 0x05, 0xc4, 0xe9, 0x2f, 0x5d, 0xae, + 0xc1, 0xc5, 0x34, 0x51, 0x22, 0xad, 0xc0, 0x75, + 0xbc, 0x07, 0x1e, 0xb3, 0x47, 0xb7, 0x54, 0xf8, + 0x39, 0xcd, 0x08, 0x3a, 0x80, 0xea, 0x13, 0xb5, + 0xc1, 0xcb, 0x84, 0xac, 0x9b, 0x29, 0x0a, 0x34, + 0xfa, 0xe4, 0x83, 0x1a, 0x0e, 0x26, 0x90, 0x72, + 0xeb, 0x03, 0xa0, 0xd7, 0x23, 0xa1, 0x92, 0xc0, + 0xb1, 0x39, 0xd1, 0x03, 0x83, 0x32, 0x78, 0x09, + 0xf5, 0x7f, 0x17, 0x37, 0xd5, 0xa2, 0x31, 0xad, + 0xa2, 0xe8, 0x48, 0xa3, 0x3e, 0x6f, 0xec, 0x75, + 0xb6, 0xb3, 0xf2, 0xcb, 0x9a, 0x0e, 0xe0, 0x48, + 0x36, 0x08, 0x23, 0xe4, 0xa9, 0xd8, 0x5b, 0x6b, + 0x1b, 0x38, 0xdf, 0xbb, 0xc4, 0x7d, 0x86, 0x53, + 0x14, 0x44, 0x47, 0xf5, 0xf5, 0xca, 0x32, 0x17, + 0x86, 0x63, 0x43, 0x09, 0xeb, 0x06, 0x93, 0xfa, + 0xde, 0x08, 0xb1, 0x0c, 0x5a, 0xf4, 0x26, 0x1b, + 0xab, 0x12, 0xd5, 0x6e, 0xd2, 0xcc, 0x56, 0xc3, + 0x1f, 0xa6, 0xcd, 0x10, 0x18, 0x1e, 0x25, 0x65, + 0xb6, 0xf7, 0x7d, 0x1a, 0x56, 0x95, 0x8b, 0x22, + 0xdd, 0x18, 0x74, 0xe1, 0x53, 0xb0, 0x6f, 0xc1, + 0x5e, 0xb9, 0xe1, 0x1e, 0x17, 0x37, 0xe5, 0xbe, + 0x9f, 0x06, 0xf8, 0xb9, 0x49, 0x09, 0x94, 0xf7, + 0xfa, 0x88, 0x40, 0xde, 0x0d, 0xe5, 0xa4, 0xab, + 0x82, 0x4f, 0x48, 0x97, 0x8b, 0x45, 0x17, 0x31, + 0x4c, 0xd2, 0x81, 0x5a, 0x7b, 0x7d, 0x3a, 0xbb, + 0x02, 0x07, 0xfa, 0xf3, 0x1b, 0xcb, 0x56, 0xc5, + 0x0a, 0x62, 0x37, 0x6b, 0xab, 0xff, 0xde, 0x61, + 0x68, 0x1a, 0x6e, 0xf6, 0xc2, 0xb5, 0x91, 0x20, + 0x07, 0x05, 0x6a, 0x6e, 0x6e, 0xd8, 0xa3, 0x9c, + 0x80, 0x3c, 0x4e, 0x8c, 0xc6, 0x96, 0xef, 0x73, + 0x35, 0x08, 0x26, 0x2a, 0xdb, 0x0c, 0x2f, 0xdb, + 0x3d, 0xb3, 0x94, 0xf9, 0x72, 0xe4, 0x25, 0xca, + 0x41, 0xa6, 0x66, 0x83, 0x51, 0xfe, 0xf0, 0xb3, + 0xd7, 0x0a, 0x40, 0x77, 0x02, 0x7a, 0xa2, 0x18, + 0x43, 0x66, 0x22, 0xcb, 0x3a, 0x1c, 0x40, 0x70, + 0x26, 0xa7, 0x02, 0x09, 0x7d, 0x46, 0xd2, 0xab, + 0x41, 0x83, 0x41, 0x79, 0x1a, 0x30, 0x0f, 0xab, + 0x06, 0x0e, 0x18, 0xa0, 0xc0, 0x48, 0x23, 0xf2, + 0x06, 0xd0, 0x64, 0xfd, 0xfe, 0x5c, 0xd7, 0xed, + 0x2b, 0x53, 0xbb, 0x79, 0x0c, 0x49, 0x71, 0x70, + 0x37, 0x34, 0x7b, 0x77, 0xab, 0xa3, 0x80, 0xa6, + 0x89, 0xd7, 0x07, 0x8a, 0x80, 0x24, 0x2d, 0x4f, + 0x3c, 0xba, 0xe7, 0x4a, 0x35, 0x22, 0x4d, 0x4f, + 0x8b, 0xef, 0x10, 0x87, 0xda, 0xdc, 0xe2, 0x00, + 0x21, 0x5f, 0xdb, 0xb4, 0xdc, 0x19, 0xba, 0x11, + 0x26, 0x9d, 0x53, 0x50, 0x41, 0xad, 0x73, 0x50, + 0x85, 0x2f, 0x77, 0x50, 0x65, 0xa3, 0x20, 0x71, + 0x35, 0x71, 0x2e, 0xad, 0x8d, 0x6c, 0x17, 0x06, + 0x67, 0xaa, 0xdc, 0x5d, 0x6a, 0x6d, 0x49, 0xdd, + 0x7f, 0x32, 0xae, 0x8e, 0x04, 0x95, 0xb2, 0x71, + 0x7e, 0x2d, 0x0e, 0xc1, 0x70, 0x7f, 0x35, 0x7f, + 0x60, 0x73, 0x06, 0x11, 0xf0, 0xa8, 0x7d, 0xb2, + 0x87, 0xbf, 0x6d, 0x07, 0xa4, 0x0d, 0x0f, 0x99, + 0xc5, 0x3c, 0xe0, 0x66, 0x0e, 0x9d, 0x3f, 0xa6, + 0xae, 0xa7, 0x6b, 0x16, 0x47, 0x43, 0x87, 0x3e, + 0x17, 0xb6, 0x36, 0x68, 0x71, 0x00, 0x8b, 0x37, + 0x83, 0x08, 0x8c, 0x29, 0x2c, 0xd2, 0x46, 0x98, + 0x1b, 0x2a, 0xe1, 0x2c, 0x46, 0x31, 0xe0, 0x5b, + 0x1c, 0x86, 0xb0, 0x67, 0xd1, 0x7b, 0xe5, 0xe1, + 0xa0, 0xa3, 0x5d, 0x04, 0xc3, 0xe1, 0xeb, 0x50, + 0x15, 0xbf, 0xfc, 0x8b, 0x66, 0x4a, 0x85, 0x47, + 0x69, 0x16, 0x62, 0x2a, 0xff, 0xff, 0x7c, 0xa1, + 0x49, 0x5d, 0xde, 0x44, 0x60, 0xe2, 0x0b, 0xba, + 0x1a, 0xf2, 0x11, 0x56, 0x36, 0x85, 0x03, 0xe2, + 0x9f, 0xe4, 0x24, 0x14, 0xeb, 0xdd, 0xd6, 0x2b, + 0x5c, 0x9b, 0x9c, 0x85, 0x72, 0xae, 0x86, 0x74, + 0x89, 0x74, 0xfb, 0x6a, 0x0b, 0xee, 0xa3, 0x18, + 0xae, 0x47, 0x1c, 0xb0, 0xa6, 0x93, 0x44, 0xcb, + 0xd2, 0x51, 0x33, 0xf5, 0x4a, 0x90, 0x58, 0xba, + 0xa6, 0x50, 0x48, 0x60, 0xb1, 0x95, 0x4a, 0xc7, + 0x3c, 0xd6, 0x99, 0x9f, 0x51, 0xec, 0x61, 0x42, + 0xc8, 0x3b, 0xf6, 0xda, 0xc4, 0x4b, 0x53, 0x4b, + 0x1c, 0x44, 0x3f, 0x69, 0x2e, 0x79, 0xb6, 0xb6, + 0x55, 0xa7, 0x62, 0x9c, 0xd5, 0x14, 0xd5, 0xad, + 0x7f, 0x72, 0x89, 0xa0, 0x0c, 0xa2, 0xea, 0xc2, + 0x80, 0xd8, 0x3e, 0x11, 0xc4, 0x94, 0x9e, 0x1c, + 0x31, 0x18, 0x51, 0xde, 0xf0, 0x70, 0x7e, 0xee, + 0x16, 0x95, 0xa9, 0x2b, 0x0a, 0xa2, 0xeb, 0x25, + 0xa5, 0x55, 0x11, 0xb1, 0x49, 0xa6, 0xba, 0x4a, + 0x48, 0x1c, 0x00, 0xf0, 0xa0, 0x88, 0xf5, 0xbc, + 0xc9, 0x6f, 0x70, 0x3d, 0x93, 0xa7, 0x91, 0xd6, + 0x3d, 0x03, 0x8f, 0xfe, 0x8b, 0xd6, 0x05, 0xc1, + 0x76, 0x96, 0x6e, 0x83, 0xce, 0xff, 0xfb, 0xc3, + 0xda, 0xf0, 0xa1, 0x65, 0x97, 0xa2, 0x8b, 0xbf, + 0xa5, 0x10, 0x89, 0x02, 0xce, 0x23, 0x2d, 0xb2, + 0x55, 0x0e, 0x4f, 0x53, 0x78, 0xdf, 0xf7, 0x3d, + 0xab, 0x14, 0xbf, 0xc8, 0x0a, 0xe8, 0xfd, 0x79, + 0xb0, 0xa4, 0xa4, 0x1c, 0x41, 0x13, 0x64, 0x46, + 0x28, 0x4c, 0xb3, 0x24, 0x02, 0xba, 0x58, 0x50, + 0x14, 0xa7, 0x67, 0x35, 0x7e, 0xf2, 0xa2, 0x7b, + 0xb6, 0x0c, 0x33, 0xa8, 0x4e, 0xeb, 0xee, 0x74, + 0xb6, 0x03, 0xb8, 0x0b, 0x01, 0x71, 0x0d, 0x65, + 0x91, 0x7a, 0x0e, 0x05, 0x8f, 0x68, 0x48, 0x96, + 0x31, 0xb0, 0x39, 0xcc, 0xd4, 0x41, 0x4c, 0xec, + 0xfa, 0x22, 0xbc, 0xb5, 0x09, 0x07, 0x36, 0x77, + 0x8b, 0xe0, 0xaf, 0x5f, 0x58, 0xb1, 0xb9, 0x49, + 0x4d, 0x3b, 0xca, 0x87, 0xb6, 0x70, 0x92, 0x82, + 0xf1, 0xe5, 0xe8, 0xdb, 0x7b, 0x65, 0x2c, 0xd8, + 0xf1, 0x84, 0x08, 0x7f, 0x67, 0xf0, 0x40, 0x69, + 0x24, 0xd4, 0x6b, 0x53, 0x7c, 0x74, 0x9d, 0xe8, + 0x88, 0x2b, 0xab, 0xba, 0x49, 0xc4, 0x34, 0x55, + 0x81, 0x60, 0x0b, 0xb3, 0xc2, 0x30, 0x22, 0xa9, + 0xee, 0x82, 0x2b, 0x3a, 0x0b, 0x00, 0x5c, 0x6c, + 0x95, 0x04, 0xe5, 0xef, 0x46, 0x22, 0x74, 0x98, + 0x52, 0x2a, 0xd7, 0x6f, 0x68, 0x11, 0x85, 0x29, + 0xfd, 0xbd, 0x28, 0xc8, 0x4f, 0xb6, 0xde, 0x41, + 0x13, 0x17, 0x46, 0x46, 0xca, 0x3e, 0x69, 0xd5, + 0x3f, 0xde, 0x02, 0x69, 0x86, 0x47, 0xe3, 0xe6, + 0x03, 0xb6, 0x7d, 0x00, 0x9f, 0x68, 0xc1, 0x1b, + 0xd4, 0xd2, 0xf5, 0x7b, 0x2d, 0x6d, 0xb6, 0x74, + 0x09, 0xff, 0x46, 0x5c, 0x87, 0x15, 0x53, 0xd4, + 0x1a, 0x30, 0xe0, 0x60, 0x31, 0x0a, 0xf5, 0x03, + 0x38, 0x49, 0x0e, 0x6b, 0x9d, 0x12, 0x62, 0xaf, + 0xe1, 0x57, 0xd2, 0xb0, 0xb5, 0x86, 0x0f, 0x36, + 0x3b, 0x4c, 0xda, 0xcd, 0x46, 0x1b, 0xef, 0x0b, + 0x46, 0x07, 0xf6, 0x23, 0x41, 0x42, 0x69, 0xcb, + 0x91, 0x07, 0xaf, 0x78, 0xb9, 0x21, 0x20, 0x9c, + 0xb5, 0x00, 0x4c, 0x13, 0x35, 0xcf, 0x17, 0x08, + 0x62, 0x5e, 0xb6, 0x05, 0xb3, 0xd9, 0x28, 0x78, + 0x0c, 0x2f, 0x21, 0x32, 0x21, 0x30, 0xad, 0x4c, + 0xb6, 0xa5, 0x56, 0xda, 0xdc, 0x46, 0x4d, 0x3a, + 0xa6, 0x2d, 0xcb, 0x94, 0x16, 0x26, 0xc1, 0x75, + 0x0b, 0x8a, 0x6f, 0xf4, 0xaa, 0x0d, 0x9d, 0xae, + 0xb8, 0xf8, 0x78, 0x3c, 0x5d, 0x4f, 0xd5, 0x35, + 0x3a, 0x57, 0xd2, 0x97, 0xce, 0x79, 0x80, 0x24, + 0x0e, 0xed, 0x3e, 0x58, 0x39, 0x90, 0x16, 0x00, + 0x9d, 0x45, 0x74, 0x65, 0xc0, 0x1c, 0x48, 0x43, + 0xc4, 0x7d, 0xe6, 0xf4, 0x9b, 0x5e, 0x61, 0x6a, + 0xeb, 0x74, 0xd2, 0xc0, 0x9a, 0x9b, 0x3b, 0xb3, + 0x0d, 0x5b, 0xc0, 0x5d, 0x65, 0xba, 0x4a, 0x32, + 0x19, 0x02, 0xea, 0x7b, 0x21, 0xbb, 0x1f, 0x8c, + 0xce, 0x77, 0x0a, 0x25, 0x8b, 0x83, 0x81, 0x73, + 0x41, 0xf7, 0xa1, 0xb1, 0x9b, 0xfe, 0x4f, 0xc1, + 0x17, 0x51, 0x9b, 0xe1, 0x28, 0x2d, 0xa2, 0x4a, + 0x4b, 0x4d, 0xbc, 0xad, 0x33, 0x4a, 0x27, 0x10, + 0xd2, 0x50, 0x1c, 0xb1, 0x36, 0x50, 0x48, 0x65, + 0x35, 0xf8, 0x88, 0x28, 0x6b, 0x82, 0xc0, 0x1c, + 0x80, 0xa0, 0xfd, 0x5d, 0x17, 0x78, 0x13, 0xeb, + 0xcb, 0x5d, 0x85, 0x08, 0x51, 0x92, 0xf4, 0x1c, + 0xf4, 0xa4, 0xe2, 0x35, 0x9f, 0x08, 0xa9, 0xa4, + 0x08, 0x05, 0x32, 0x6d, 0x16, 0xf1, 0x7b, 0xc1, + 0x92, 0xc7, 0xd7, 0x8b, 0x2c, 0x27, 0xdf, 0x4e, + 0x9a, 0xe6, 0x54, 0x40, 0xe4, 0x21, 0x5a, 0xf9, + 0xc6, 0x24, 0xef, 0x65, 0x07, 0x2e, 0x2b, 0x4d, + 0x4f, 0x2a, 0x09, 0x6c, 0xe8, 0xc7, 0x88, 0x05, + 0xc7, 0x50, 0xb2, 0xde, 0xa2, 0xa1, 0x80, 0x64, + 0x0b, 0xb3, 0x36, 0xcd, 0x26, 0xde, 0x98, 0x8a, + 0xe4, 0x84, 0x17, 0x54, 0x2c, 0x54, 0x0e, 0x18, + 0x38, 0xa6, 0xb5, 0x0a, 0x46, 0x41, 0x2f, 0x1c, + 0x74, 0x80, 0xee, 0xf1, 0x7e, 0x74, 0x29, 0x8b, + 0xd4, 0xdd, 0xb5, 0x64, 0x74, 0x17, 0xcf, 0xcf, + 0xd8, 0x32, 0x34, 0xf9, 0xfc, 0x58, 0x64, 0xb5, + 0x44, 0x0e, 0x34, 0x41, 0x17, 0x15, 0xeb, 0xe0, + 0xa3, 0x49, 0x08, 0x3f, 0xe8, 0xc8, 0x8d, 0x5e, + 0xde, 0xa2, 0xb5, 0x00, 0x3a, 0x05, 0x78, 0xca, + 0x0a, 0xf5, 0xe5, 0x09, 0xb0, 0x5f, 0xea, 0x33, + 0x73, 0xce, 0x12, 0xde, 0x89, 0xa2, 0x49, 0x17, + 0x5a, 0x70, 0x07, 0xc1, 0x3b, 0xf5, 0x4c, 0x58, + 0xf6, 0xbe, 0x51, 0x49, 0x0f, 0xee, 0x8c, 0x11, + 0x03, 0x85, 0x5a, 0x29, 0x35, 0xd3, 0x44, 0x4c, + 0x63, 0x24, 0x0c, 0xc5, 0x2b, 0x2d, 0x9c, 0x46, + 0x50, 0x28, 0xd3, 0x88, 0xc4, 0x34, 0xbb, 0xb0, + 0x81, 0x41, 0x3d, 0xcf, 0x22, 0x58, 0x63, 0x43, + 0x13, 0xd3, 0x70, 0x64, 0x28, 0xc6, 0xcb, 0x90, + 0x6b, 0x9d, 0xd8, 0x38, 0x74, 0xfe, 0xf8, 0xa5, + 0x18, 0x0f, 0x08, 0xa3, 0x76, 0x8c, 0xa0, 0xbc, + 0x85, 0xc8, 0x2f, 0x0a, 0x16, 0x41, 0xc8, 0x3a, + 0x02, 0xe7, 0x5e, 0x03, 0xd2, 0x49, 0xde, 0x53, + 0x5c, 0x5c, 0x85, 0xf0, 0xa5, 0x69, 0x10, 0xf4, + 0x28, 0x65, 0x48, 0x38, 0x52, 0x11, 0x7b, 0x78, + 0x8b, 0x9d, 0x07, 0x04, 0x53, 0x3b, 0xd4, 0x75, + 0x41, 0xdd, 0x7c, 0xb1, 0xb4, 0x43, 0x21, 0x33, + 0xa0, 0xfd, 0xf0, 0x01, 0xee, 0x5e, 0x23, 0xd0, + 0x1e, 0x4c, 0xef, 0x05, 0xe2, 0xe1, 0x47, 0x8b, + 0x21, 0x84, 0x1a, 0x7b, 0xa8, 0x14, 0x03, 0x8e, + 0xb1, 0x5c, 0xf4, 0x92, 0x42, 0x55, 0x86, 0x92, + 0x69, 0x69, 0x42, 0x5b, 0x6a, 0xf1, 0x01, 0x20, + 0x4b, 0xa7, 0x0b, 0x03, 0x82, 0x36, 0x8b, 0xa8, + 0x0d, 0x10, 0xe1, 0x88, 0x38, 0x62, 0x2e, 0x13, + 0xe0, 0x7a, 0x48, 0x00, 0xc6, 0xb3, 0xbd, 0xe8, + 0x49, 0xaf, 0xb8, 0xed, 0x3b, 0x10, 0xa2, 0x15, + 0x4a, 0xd4, 0x30, 0x7e, 0x9c, 0xe9, 0xb0, 0x58, + 0x92, 0x04, 0x8d, 0x2a, 0xc8, 0xcf, 0xe9, 0xcc, + 0x8b, 0xa3, 0x0c, 0x89, 0xf5, 0x9c, 0xe5, 0xc5, + 0x08, 0xca, 0xd4, 0x95, 0x15, 0x21, 0xe2, 0xc8, + 0xc6, 0x93, 0xc2, 0x40, 0x70, 0x62, 0xf7, 0x20, + 0x39, 0x60, 0xaa, 0x5a, 0x48, 0x2e, 0x22, 0xd3, + 0x47, 0x26, 0x2c, 0xb8, 0xc8, 0x88, 0xaf, 0x11, + 0xf0, 0x32, 0x07, 0x02, 0x6c, 0xf1, 0x0f, 0x38, + 0x84, 0x1d, 0x5d, 0x96, 0x07, 0x70, 0x1c, 0x2b, + 0xb9, 0xc2, 0x50, 0x9b, 0x4e, 0x45, 0xe3, 0x25, + 0x8f, 0xee, 0x14, 0x72, 0x2c, 0x68, 0x29, 0x80, + 0x46, 0x58, 0xa1, 0x11, 0x20, 0x38, 0x9b, 0x70, + 0x90, 0x1c, 0x2e, 0x0c, 0x84, 0xcc, 0x7e, 0x27, + 0x2a, 0x16, 0x07, 0x0a, 0x1a, 0x88, 0x0f, 0x41, + 0xff, 0xf8, 0x61, 0x44, 0xd8, 0x60, 0x18, 0x85, + 0x53, 0x03, 0x20, 0x73, 0xa2, 0x07, 0x6b, 0xee, + 0x92, 0xc7, 0x4f, 0x0d, 0xf6, 0xf0, 0x17, 0x1a, + 0x59, 0xde, 0x9b, 0x28, 0x07, 0x04, 0xda, 0xca, + 0x2b, 0x6a, 0x37, 0x58, 0x6b, 0xaf, 0x83, 0x13, + 0x60, 0xe7, 0x6e, 0xc4, 0x48, 0x21, 0x0e, 0x58, + 0x92, 0x83, 0x82, 0x78, 0x8b, 0x23, 0x58, 0xd9, + 0x0d, 0x24, 0x7d, 0xb9, 0x2c, 0x07, 0x2c, 0x0e, + 0x42, 0x09, 0x98, 0xb0, 0xd8, 0x4d, 0x23, 0x10, + 0x70, 0xa7, 0x73, 0x86, 0xc6, 0x0b, 0x04, 0x9f, + 0xfb, 0x56, 0x29, 0x07, 0x23, 0x8f, 0x98, 0x0e, + 0x8f, 0x63, 0x0a, 0x50, 0x76, 0x29, 0x28, 0x26, + 0x3c, 0x5f, 0x02, 0xfb, 0x51, 0x9b, 0xb0, 0x61, + 0xc0, 0x70, 0xbc, 0x17, 0x29, 0xc0, 0xcc, 0x1d, + 0x08, 0x62, 0xca, 0x72, 0xf0, 0xa4, 0xfd, 0x5d, + 0x2c, 0x58, 0xd5, 0x5c, 0x1c, 0x2a, 0x4e, 0xf7, + 0x0a, 0x01, 0xfa, 0xff, 0xff, 0xd5, 0x09, 0xa8, + 0x8c, 0x1c, 0x30, 0x25, 0x09, 0xd3, 0xd9, 0x30, + 0xd3, 0xdb, 0x94, 0x13, 0x74, 0xc8, 0x71, 0x1a, + 0x21, 0x87, 0x43, 0x10, 0x89, 0x5a, 0x6b, 0x91, + 0xd5, 0x66, 0xa0, 0xb0, 0x1c, 0x30, 0x58, 0x64, + 0x15, 0xfe, 0x36, 0x04, 0x7b, 0x4d, 0x23, 0x07, + 0x3a, 0xf1, 0x0a, 0xc2, 0x7d, 0x3b, 0xa1, 0x91, + 0xa4, 0x62, 0x96, 0xb1, 0xae, 0x83, 0xf6, 0xc0, + 0x07, 0xae, 0x6c, 0x11, 0x45, 0xf4, 0x1c, 0x35, + 0x6a, 0x28, 0x39, 0x60, 0x71, 0x1b, 0xf4, 0x39, + 0x44, 0x41, 0xae, 0xf1, 0x07, 0x01, 0xd4, 0x89, + 0xf6, 0x94, 0x1f, 0x7d, 0xab, 0x1b, 0x20, 0xdb, + 0x22, 0x1e, 0xa2, 0x07, 0x09, 0x8b, 0xe3, 0xf4, + 0xda, 0x82, 0x8c, 0x25, 0x01, 0xc0, 0xe2, 0x36, + 0x59, 0xa0, 0xe2, 0x42, 0x82, 0x64, 0x78, 0xb0, + 0x66, 0x0e, 0x59, 0xdd, 0x63, 0x65, 0x0b, 0x02, + 0x6a, 0x8c, 0xc2, 0xad, 0x7a, 0x90, 0xa3, 0xa0, + 0xbd, 0xda, 0x53, 0xd9, 0xd5, 0x82, 0x4f, 0x2c, + 0x37, 0xd8, 0x50, 0x8c, 0xa0, 0x2a, 0x70, 0x5e, + 0x47, 0x4a, 0xa9, 0x28, 0xaf, 0x4f, 0x58, 0x88, + 0x31, 0x29, 0x19, 0x76, 0x8c, 0xc8, 0xbf, 0x0d, + 0xc1, 0x56, 0xe7, 0x0a, 0x05, 0xe5, 0x20, 0xe8, + 0xe6, 0xb0, 0x3b, 0xb7, 0xa0, 0xe1, 0x80, 0xaa, + 0xa0, 0x23, 0xd7, 0x74, 0xd5, 0x01, 0xfc, 0x19, + 0x85, 0x13, 0x01, 0xc1, 0x91, 0x1b, 0xec, 0x28, + 0x80, 0xb1, 0xe2, 0xc7, 0x6a, 0x74, 0x07, 0x2c, + 0x31, 0x15, 0xd8, 0xbd, 0xb7, 0x82, 0xe2, 0x1d, + 0x3c, 0xa2, 0x83, 0x97, 0x09, 0x3a, 0xc0, 0xb1, + 0x34, 0x50, 0x0b, 0x87, 0x6c, 0xc8, 0xa7, 0x6e, + 0x64, 0x37, 0xb7, 0x91, 0x1f, 0x09, 0x0a, 0x38, + 0x34, 0x8c, 0x97, 0x80, 0xe5, 0x8d, 0x94, 0x0a, + 0xd6, 0xe9, 0x24, 0x18, 0xae, 0x34, 0xd7, 0xd2, + 0x94, 0x20, 0x36, 0x34, 0x7c, 0x29, 0xe9, 0xb0, + 0x71, 0x3e, 0xe2, 0x08, 0x69, 0xde, 0x14, 0x8b, + 0xca, 0x01, 0x32, 0x67, 0x64, 0x43, 0x85, 0x07, + 0xf4, 0xdf, 0x04, 0xdb, 0x88, 0x38, 0xb0, 0xbc, + 0x32, 0x44, 0x14, 0x4f, 0x10, 0xa8, 0x34, 0x89, + 0x10, 0x38, 0x28, 0x7c, 0xe2, 0x0a, 0x0e, 0x17, + 0x04, 0xae, 0xfd, 0x78, 0x5d, 0x12, 0xdc, 0xde, + 0x73, 0x9c, 0x17, 0x85, 0x2f, 0x79, 0xc5, 0xbb, + 0x2c, 0x21, 0x6b, 0x92, 0x14, 0x92, 0x9f, 0x9e, + 0x0c, 0xd6, 0x20, 0x99, 0x28, 0xae, 0x27, 0x22, + 0x6d, 0xd9, 0xc4, 0x41, 0x99, 0xfd, 0x71, 0x42, + 0x25, 0x8a, 0x41, 0xd2, 0x1c, 0x60, 0xe3, 0xfa, + 0x14, 0x70, 0xa4, 0x8a, 0xaf, 0xa5, 0xd1, 0x90, + 0x26, 0x42, 0x2e, 0x53, 0x42, 0xe8, 0x0e, 0x0a, + 0x37, 0x27, 0x69, 0x29, 0x21, 0x41, 0x3c, 0xf6, + 0xf2, 0x21, 0xe5, 0x07, 0x48, 0x7a, 0x49, 0xd0, + 0x5c, 0xe9, 0xc9, 0x25, 0x0c, 0xa7, 0x02, 0xa9, + 0x9d, 0x17, 0x8c, 0x85, 0xdd, 0x05, 0xf6, 0x83, + 0x31, 0x8f, 0x41, 0xc2, 0xa8, 0x46, 0x0e, 0xa0, + 0xe0, 0x5f, 0x3c, 0x19, 0xd1, 0x4e, 0x9e, 0x40, + 0x89, 0x60, 0x5e, 0xcf, 0x60, 0x38, 0x07, 0xd4, + 0x20, 0xba, 0x7c, 0x28, 0xe8, 0x38, 0x62, 0xe9, + 0x25, 0xe1, 0xa1, 0x90, 0x38, 0x9a, 0xac, 0x45, + 0xaf, 0xa5, 0x8b, 0x21, 0xea, 0x23, 0x60, 0xe7, + 0x68, 0x8c, 0xa3, 0x81, 0x4c, 0xc3, 0x74, 0xd7, + 0x03, 0x22, 0x3e, 0xb8, 0xb8, 0x26, 0x64, 0x24, + 0xa4, 0xa7, 0xb4, 0xe6, 0x14, 0x12, 0x05, 0x52, + 0x0f, 0x45, 0x00, 0x19, 0xfc, 0x0e, 0x0a, 0x34, + 0x19, 0x03, 0x81, 0x7f, 0x8d, 0x34, 0xf7, 0x02, + 0x39, 0x8b, 0x8b, 0x90, 0x04, 0x52, 0x14, 0xb8, + 0xb8, 0x2c, 0x42, 0x58, 0x0b, 0x98, 0x9e, 0x51, + 0xc0, 0xc5, 0x68, 0x11, 0xe8, 0x03, 0x81, 0xc0, + 0xbf, 0x66, 0x81, 0xd5, 0xd2, 0xb9, 0x41, 0x27, + 0x02, 0x63, 0x11, 0xa3, 0x3f, 0x57, 0x9e, 0x73, + 0xbc, 0xb1, 0x09, 0x4f, 0x08, 0x37, 0x30, 0x94, + 0xe6, 0x93, 0x8b, 0xa3, 0x36, 0x6e, 0x00, 0xe1, + 0xae, 0xa8, 0x91, 0x83, 0x8d, 0x12, 0x85, 0x4a, + 0x8a, 0x1b, 0x27, 0xd3, 0xd3, 0x88, 0xc3, 0x07, + 0xcc, 0x80, 0xe0, 0x5c, 0xcc, 0xea, 0xc1, 0x90, + 0x2c, 0x5d, 0x3c, 0xa0, 0xe0, 0x9e, 0xad, 0x62, + 0x37, 0xc5, 0xe2, 0xa1, 0x40, 0x84, 0x2b, 0x82, + 0xb0, 0x5d, 0x3e, 0x73, 0xbd, 0x07, 0x0b, 0xc2, + 0x77, 0x16, 0x25, 0x17, 0x70, 0xd8, 0x38, 0x69, + 0x08, 0xb4, 0xcb, 0x0e, 0x05, 0x14, 0x38, 0x27, + 0x48, 0xaa, 0xa1, 0x85, 0x10, 0x07, 0xa3, 0x3d, + 0x54, 0x66, 0x18, 0x03, 0x8f, 0x1b, 0x3a, 0x4a, + 0x27, 0xd7, 0xbb, 0x01, 0xd0, 0xfe, 0xea, 0xf3, + 0xa6, 0xf8, 0x43, 0x86, 0x10, 0x1c, 0x76, 0x86, + 0x34, 0x62, 0x4a, 0x0b, 0xc4, 0xb9, 0xd3, 0x4e, + 0xd7, 0xf9, 0xa0, 0xb1, 0x24, 0x14, 0x50, 0xcf, + 0x86, 0x81, 0x3d, 0xe5, 0x42, 0xb7, 0x68, 0x2e, + 0xf4, 0x92, 0x14, 0x44, 0x63, 0x2e, 0x1d, 0x7e, + 0xaf, 0x42, 0x6d, 0x7f, 0x64, 0x29, 0x0a, 0xb5, + 0xec, 0x40, 0x0e, 0x04, 0xef, 0xbd, 0xe7, 0x56, + 0x40, 0x0b, 0x0a, 0x79, 0x8c, 0x7b, 0xc0, 0xa7, + 0x3d, 0xaf, 0x94, 0xde, 0x21, 0x45, 0xc0, 0xc0, + 0x17, 0x33, 0x31, 0x0a, 0xcb, 0x92, 0x03, 0x8f, + 0xb5, 0xd0, 0xf7, 0x9d, 0x3b, 0x56, 0x61, 0x21, + 0x25, 0x19, 0x82, 0xee, 0xf3, 0x92, 0xa3, 0x76, + 0xbd, 0xe7, 0xf6, 0x76, 0xf6, 0xe4, 0xc0, 0x29, + 0x81, 0xb5, 0xd0, 0x70, 0xad, 0xff, 0x3c, 0xba, + 0xd3, 0x6d, 0x96, 0xf5, 0x10, 0x2f, 0xe3, 0xb3, + 0x05, 0xc4, 0x53, 0xdb, 0x61, 0x20, 0x3a, 0x9f, + 0x9d, 0x35, 0xca, 0x4f, 0xa6, 0xe2, 0x90, 0x72, + 0xdd, 0x09, 0x21, 0x70, 0x7e, 0xe8, 0x00, 0xf2, + 0xe0, 0x3d, 0x60, 0x1d, 0x42, 0x5d, 0x20, 0x6d, + 0x82, 0xb6, 0xea, 0xe8, 0x04, 0xda, 0xfa, 0x48, + 0x8b, 0xb0, 0x96, 0xa0, 0x07, 0x2c, 0x4f, 0xed, + 0xbc, 0x5b, 0xa0, 0xe9, 0x05, 0x0f, 0x3a, 0x4a, + 0x82, 0x0a, 0xfe, 0x62, 0x13, 0xb1, 0x79, 0xde, + 0x8b, 0x88, 0x34, 0xe5, 0x1a, 0x01, 0x70, 0x57, + 0x2b, 0x82, 0xc3, 0x91, 0x72, 0x1a, 0xad, 0x62, + 0x0e, 0x83, 0x89, 0x57, 0x81, 0x27, 0x50, 0x2f, + 0x07, 0x3f, 0x07, 0x23, 0x3f, 0x17, 0xfc, 0xc4, + 0x1d, 0xda, 0x18, 0x11, 0x3b, 0x6f, 0x50, 0x62, + 0xc2, 0xf4, 0x40, 0x9d, 0xbc, 0x52, 0x88, 0x5c, + 0x2b, 0x77, 0x28, 0x6e, 0xb9, 0x20, 0x2e, 0xad, + 0x42, 0x68, 0x9f, 0x5e, 0x64, 0xbd, 0x36, 0x53, + 0x0a, 0x4a, 0x46, 0x8d, 0x64, 0x2b, 0x22, 0x3b, + 0xa6, 0xf5, 0x06, 0x76, 0x12, 0x89, 0xba, 0xc3, + 0x24, 0x23, 0x10, 0xc0, 0x87, 0x92, 0xf0, 0xe6, + 0xbe, 0x2b, 0x88, 0x6d, 0x34, 0x18, 0x1f, 0x95, + 0x89, 0x01, 0x7b, 0xed, 0x07, 0x20, 0x0c, 0x44, + 0xdb, 0x69, 0xae, 0x12, 0x20, 0x20, 0x8b, 0x40, + 0x9e, 0x2c, 0x4f, 0x10, 0x9b, 0x5c, 0x24, 0x79, + 0x78, 0x85, 0x12, 0x31, 0x98, 0x56, 0xf6, 0xde, + 0xa2, 0xb4, 0x66, 0x43, 0x54, 0xa9, 0x76, 0xbc, + 0xf0, 0x1c, 0x45, 0xba, 0x1a, 0x21, 0x28, 0x07, + 0x3f, 0x81, 0x1e, 0x83, 0x06, 0x5d, 0x0c, 0x89, + 0xa7, 0x94, 0x93, 0x80, 0xbd, 0xe9, 0xa0, 0xc3, + 0xa0, 0x3c, 0xee, 0x9c, 0xf2, 0x12, 0x03, 0x85, + 0x4f, 0x80, 0xea, 0x7a, 0xa2, 0xc8, 0x10, 0xae, + 0x8c, 0x82, 0x46, 0x28, 0xc1, 0xc2, 0xf0, 0x77, + 0x48, 0x69, 0xae, 0x48, 0x2b, 0xab, 0xe4, 0x0b, + 0x5e, 0xa3, 0x91, 0x61, 0x5e, 0x5c, 0xda, 0x34, + 0x44, 0xbd, 0xa4, 0x0d, 0x7e, 0x50, 0x73, 0xba, + 0xf4, 0x1f, 0xbf, 0xff, 0xff, 0x6a, 0x20, 0xa6, + 0x27, 0xf9, 0xc0, 0x7a, 0x0f, 0xff, 0xcf, 0xf5, + 0xd1, 0xae, 0x15, 0x65, 0x28, 0x90, 0x84, 0xd3, + 0x0a, 0x2f, 0x06, 0x00, 0xe2, 0x3f, 0x83, 0x4d, + 0x3f, 0x10, 0xac, 0x52, 0x0e, 0x3b, 0x81, 0xd1, + 0x7e, 0x06, 0x01, 0x14, 0x82, 0x3a, 0x04, 0x02, + 0xe4, 0x76, 0x1e, 0xe0, 0xe0, 0x5d, 0x52, 0x95, + 0xdd, 0xa7, 0xb8, 0x0b, 0x14, 0x00, 0xe0, 0xc8, + 0xeb, 0x58, 0xd8, 0xc4, 0x30, 0x21, 0xe0, 0xf4, + 0x30, 0x01, 0x84, 0xf4, 0x31, 0x18, 0x02, 0x7a, + 0x94, 0x2c, 0x15, 0xc4, 0xda, 0xc4, 0x78, 0x62, + 0x32, 0x8b, 0x42, 0x45, 0x81, 0xc5, 0x24, 0x71, + 0x01, 0x74, 0xe0, 0xc8, 0x90, 0x1c, 0x6c, 0x94, + 0x4d, 0x48, 0xb4, 0xf4, 0x37, 0x0d, 0x03, 0x89, + 0x0f, 0x38, 0x67, 0x60, 0x3f, 0xbc, 0x00, 0x6c, + 0x5e, 0x0e, 0x41, 0x4d, 0x85, 0x76, 0x02, 0xef, + 0x5e, 0x41, 0xcb, 0xd0, 0x70, 0x64, 0x85, 0x62, + 0x79, 0xd1, 0x80, 0xb8, 0x1c, 0x27, 0x70, 0x1f, + 0xdf, 0xff, 0xf7, 0x20, 0xa3, 0x25, 0x22, 0xd3, + 0x8b, 0x9e, 0x02, 0x1e, 0x5c, 0x1c, 0x11, 0xae, + 0xa3, 0x3a, 0xb7, 0xb2, 0x8b, 0xab, 0xe0, 0xb1, + 0x12, 0xf0, 0x1c, 0x2e, 0x0a, 0x12, 0xbc, 0x95, + 0x0f, 0x6a, 0x09, 0x2f, 0x45, 0xeb, 0x40, 0x1c, + 0x43, 0xcd, 0x59, 0x0b, 0xe2, 0x6a, 0x5f, 0x43, + 0x4a, 0x09, 0x54, 0xd3, 0x62, 0x9f, 0x65, 0x88, + 0x94, 0x8c, 0xaa, 0xc2, 0xfa, 0xfe, 0x55, 0x2c, + 0xe7, 0x82, 0xad, 0x6d, 0x41, 0xcc, 0x19, 0x22, + 0xe0, 0xa7, 0x31, 0x53, 0x91, 0x03, 0xf5, 0x17, + 0xfe, 0x2e, 0x29, 0x26, 0x4c, 0xb1, 0xb9, 0x2f, + 0x5b, 0x80, 0x8c, 0xb8, 0x61, 0x41, 0x77, 0x41, + 0xef, 0x11, 0xd4, 0x06, 0x86, 0x24, 0x5e, 0x44, + 0x2b, 0x8c, 0xd1, 0x14, 0x93, 0x32, 0xfc, 0x5b, + 0x51, 0x0a, 0xb4, 0xe5, 0x64, 0x3c, 0xb4, 0xd8, + 0x39, 0x18, 0x51, 0x48, 0x41, 0xcb, 0x70, 0x9f, + 0x70, 0x32, 0x40, 0x15, 0x4a, 0x88, 0x0e, 0x46, + 0x19, 0x84, 0x70, 0xd2, 0xe7, 0xf5, 0xe7, 0x81, + 0xaa, 0xe7, 0xdf, 0xe8, 0x69, 0x25, 0x36, 0x48, + 0x0e, 0x42, 0x14, 0x4d, 0xa6, 0xf2, 0x92, 0xac, + 0x49, 0xd2, 0x66, 0x85, 0x01, 0x28, 0xb8, 0x13, + 0x19, 0x6b, 0x78, 0x2e, 0x7e, 0xbf, 0xf8, 0x13, + 0xee, 0x50, 0x71, 0xcf, 0x20, 0x7f, 0x20, 0x30, + 0x2c, 0x34, 0x13, 0x5b, 0xb2, 0x31, 0x8a, 0xe2, + 0xf7, 0x34, 0x83, 0x31, 0xa6, 0xbe, 0x99, 0x56, + 0x1b, 0x6b, 0xb4, 0xa8, 0xf9, 0xca, 0x31, 0x1a, + 0x39, 0x50, 0x2c, 0x0e, 0x90, 0x1c, 0x73, 0xdc, + 0x9d, 0x5d, 0x6e, 0x22, 0xa6, 0x90, 0x9e, 0x5a, + 0xb2, 0x0e, 0x13, 0x45, 0xe7, 0xb3, 0xa0, 0xc4, + 0xcf, 0xbd, 0x43, 0x4d, 0x83, 0x06, 0x50, 0xe5, + 0x81, 0x6e, 0x00, 0xee, 0x00, 0xe8, 0xe9, 0xb8, + 0x52, 0x41, 0xec, 0x1b, 0x51, 0x75, 0x80, 0x99, + 0x57, 0xd1, 0x75, 0xd0, 0x94, 0x12, 0x0b, 0x89, + 0xfc, 0x17, 0x44, 0x25, 0x20, 0xb9, 0x53, 0x79, + 0x67, 0x3b, 0xf5, 0x22, 0x26, 0x69, 0x25, 0x42, + 0xe5, 0x71, 0x9c, 0xa1, 0xd0, 0x31, 0x5f, 0x6c, + 0x9b, 0x56, 0x35, 0x41, 0x71, 0x0b, 0x64, 0xe0, + 0x8a, 0x2b, 0xd3, 0xd7, 0x41, 0x63, 0x00, 0x79, + 0xdd, 0xd9, 0x2a, 0xe8, 0x51, 0x10, 0x40, 0x22, + 0x7d, 0x0b, 0x3b, 0xe2, 0x45, 0xe8, 0xbf, 0x54, + 0xf4, 0x60, 0xb0, 0xa5, 0x29, 0xe5, 0x11, 0x0d, + 0x29, 0xab, 0xde, 0xa2, 0x45, 0x20, 0x2f, 0xea, + 0xc8, 0xfa, 0x2e, 0x7e, 0x9c, 0x95, 0x12, 0x84, + 0xae, 0x23, 0x07, 0x09, 0x93, 0x24, 0x09, 0x38, + 0x3b, 0x86, 0x81, 0x35, 0x84, 0xda, 0xfb, 0x92, + 0x2f, 0x10, 0x83, 0x82, 0x2e, 0xba, 0x10, 0xc8, + 0xa4, 0x22, 0xdd, 0x07, 0x0d, 0x1f, 0x0d, 0xd9, + 0xd0, 0x4d, 0xd7, 0x21, 0xd7, 0x98, 0x03, 0x81, + 0x60, 0x7d, 0xd5, 0xe7, 0x21, 0x42, 0xe7, 0xe6, + 0xa0, 0xab, 0x83, 0x82, 0x7d, 0xc8, 0x32, 0xe5, + 0x07, 0x3e, 0x14, 0x9d, 0xd3, 0xf3, 0xa4, 0xa3, + 0x10, 0xca, 0x83, 0x8e, 0xa6, 0xb1, 0x4a, 0xc4, + 0xed, 0x74, 0x7d, 0x07, 0x02, 0xeb, 0xc3, 0x17, + 0x9c, 0xa8, 0xc2, 0x4a, 0x9f, 0x5c, 0x5c, 0x69, + 0x01, 0x36, 0x9d, 0xa4, 0xa0, 0xf3, 0xff, 0xff, + 0xa0, 0x39, 0x32, 0x52, 0x45, 0x91, 0x2f, 0xc0, + 0x9f, 0x06, 0x60, 0xe2, 0x5a, 0x77, 0x0a, 0x3f, + 0x89, 0x24, 0x28, 0x5c, 0x22, 0xac, 0xc5, 0xf8, + 0xb7, 0x6c, 0x40, 0x33, 0x7d, 0x58, 0x89, 0x72, + 0x69, 0xea, 0xc0, 0xe1, 0x91, 0x1f, 0x57, 0xd9, + 0x99, 0x27, 0x17, 0x47, 0x7a, 0x88, 0x26, 0xdb, + 0xa6, 0xe5, 0xe4, 0x01, 0xe2, 0xa9, 0x0c, 0x05, + 0x3b, 0x90, 0xda, 0x3e, 0x2c, 0x2b, 0x7e, 0x77, + 0xa4, 0x7a, 0x73, 0xc8, 0x1c, 0x59, 0x0a, 0x41, + 0x3f, 0x16, 0x61, 0x47, 0x01, 0xc4, 0xb3, 0x80, + 0xba, 0xd3, 0x4d, 0x86, 0x21, 0x80, 0x52, 0xfa, + 0x48, 0x8d, 0x10, 0xc4, 0x17, 0xd2, 0xf5, 0x14, + 0x0a, 0xe2, 0x7d, 0x46, 0x54, 0x4b, 0x0c, 0x0d, + 0x05, 0x58, 0xb0, 0x95, 0x4f, 0x50, 0x83, 0x91, + 0x05, 0x39, 0x10, 0x39, 0x10, 0x38, 0x8f, 0x1b, + 0xbc, 0x85, 0x01, 0x88, 0xd3, 0xb4, 0x13, 0xb5, + 0xe5, 0x74, 0x4b, 0x03, 0x91, 0x10, 0x31, 0x8c, + 0x0a, 0x25, 0x72, 0x5b, 0x06, 0x70, 0x9e, 0x51, + 0x53, 0x55, 0x19, 0x28, 0x38, 0xa0, 0x8f, 0x83, + 0x64, 0x21, 0x5e, 0xbb, 0x19, 0xcd, 0x18, 0x06, + 0x20, 0xe3, 0xf3, 0x16, 0xe8, 0x38, 0x22, 0xd0, + 0x12, 0x62, 0xac, 0x6c, 0x1d, 0x11, 0x9d, 0xbd, + 0x28, 0x84, 0xfa, 0xfa, 0x95, 0x77, 0xa0, 0x3a, + 0x86, 0x48, 0xa9, 0xa0, 0x8e, 0x2c, 0x50, 0x8f, + 0xbc, 0x01, 0xc0, 0xb0, 0x05, 0xcc, 0xd5, 0x90, + 0x41, 0x70, 0x4e, 0x9a, 0xeb, 0x22, 0x07, 0x14, + 0x82, 0xeb, 0xe0, 0x9f, 0x4e, 0x2c, 0x07, 0xea, + 0x80, 0x0d, 0x12, 0xc2, 0x81, 0x98, 0x38, 0x56, + 0x99, 0x60, 0x38, 0x27, 0xa5, 0x00, 0xf3, 0xff, + 0xff, 0x91, 0x99, 0x54, 0x8c, 0x4d, 0x9f, 0xab, + 0xdd, 0x51, 0x57, 0x5c, 0x90, 0x60, 0xb1, 0xef, + 0xca, 0x2b, 0xc0, 0xe2, 0x2a, 0x58, 0x94, 0xf1, + 0x4a, 0x22, 0xc8, 0x5d, 0xdf, 0x50, 0x49, 0x46, + 0x68, 0xc6, 0x51, 0xd1, 0x7b, 0x03, 0x00, 0x4d, + 0xa5, 0x14, 0x1d, 0x51, 0x05, 0x4f, 0x8b, 0x76, + 0x86, 0x6b, 0x03, 0x81, 0x3b, 0xd3, 0xb5, 0x1a, + 0xa7, 0xb6, 0xce, 0x20, 0x9c, 0x5e, 0x2c, 0x6c, + 0x86, 0x79, 0xc3, 0x64, 0x9d, 0x3f, 0xb8, 0x6c, + 0x1c, 0x42, 0xd6, 0x5a, 0x76, 0x0a, 0x2a, 0x32, + 0x3d, 0x77, 0x79, 0xc4, 0x16, 0x12, 0xd0, 0xa7, + 0x41, 0x80, 0xaf, 0x76, 0x20, 0xec, 0x07, 0x05, + 0x1f, 0x11, 0x85, 0x1c, 0xa8, 0x02, 0x8d, 0x7c, + 0x0e, 0x21, 0x75, 0x4f, 0x60, 0x3a, 0xa2, 0x27, + 0x9d, 0x06, 0x0c, 0x8d, 0x0a, 0xd9, 0x22, 0xf5, + 0x4d, 0x07, 0x50, 0x4c, 0xed, 0xe2, 0x30, 0xcc, + 0x07, 0xbb, 0x4f, 0x0c, 0xd1, 0x14, 0x83, 0x83, + 0x3e, 0x0d, 0x67, 0x94, 0x62, 0x0e, 0x17, 0xf5, + 0x00, 0xd1, 0xf0, 0x1c, 0xfd, 0x62, 0x04, 0x24, + 0x18, 0x51, 0x53, 0xfc, 0x28, 0x07, 0x0d, 0x77, + 0x03, 0x31, 0x5e, 0x51, 0xc8, 0x0e, 0x0a, 0xda, + 0xd5, 0x0f, 0x16, 0x58, 0x1d, 0xc0, 0x71, 0xc6, + 0x8b, 0x22, 0xc4, 0x66, 0xc2, 0x3d, 0x77, 0x6c, + 0xd2, 0x47, 0x65, 0x15, 0x0f, 0x41, 0xc3, 0x31, + 0x3f, 0xec, 0x36, 0x0b, 0xc7, 0x3b, 0x57, 0x44, + 0x52, 0x6e, 0x8a, 0xa7, 0x37, 0x95, 0x6a, 0x09, + 0x95, 0x37, 0xc4, 0x3c, 0x81, 0x98, 0x3a, 0x04, + 0x9f, 0x8b, 0x1a, 0x19, 0x83, 0x83, 0x11, 0x35, + 0x03, 0x90, 0x50, 0x72, 0x12, 0x39, 0xb0, 0xdf, + 0x41, 0xc4, 0x71, 0x4a, 0x12, 0x6d, 0x3e, 0x58, + 0xb8, 0xc9, 0x08, 0x2c, 0x20, 0x38, 0xf7, 0x58, + 0xd7, 0x41, 0xc1, 0x3d, 0x70, 0x33, 0x05, 0xd4, + 0xa8, 0x58, 0x1c, 0x18, 0xc8, 0x14, 0x77, 0xa2, + 0xa8, 0xbf, 0xcb, 0x51, 0x83, 0x8e, 0xc5, 0x29, + 0x5c, 0x17, 0x9e, 0xa0, 0x25, 0x44, 0x28, 0x9a, + 0x2f, 0xa8, 0x43, 0x0a, 0x7a, 0xd8, 0x8f, 0xb6, + 0x82, 0x66, 0x9f, 0x5e, 0x0c, 0x0d, 0x03, 0x97, + 0x42, 0x8c, 0xf4, 0xf0, 0xda, 0x21, 0x3e, 0x47, + 0xc3, 0x64, 0xcc, 0x66, 0x0e, 0x1a, 0x51, 0x5d, + 0x5d, 0x3b, 0x8a, 0x0a, 0x0a, 0x62, 0x3e, 0x72, + 0x3d, 0xdf, 0x83, 0x90, 0xa0, 0x05, 0xf7, 0xde, + 0x45, 0xb8, 0x33, 0xe2, 0xc0, 0xb0, 0x19, 0x91, + 0x3c, 0xef, 0x43, 0x75, 0xa2, 0x33, 0x6b, 0xf0, + 0x33, 0x7e, 0x56, 0x28, 0xd3, 0xab, 0xd4, 0x52, + 0x90, 0xfe, 0x21, 0x40, 0x52, 0xe8, 0x9e, 0xe7, + 0x22, 0x00, 0xd5, 0x4d, 0x06, 0x09, 0xe7, 0x90, + 0x16, 0x3c, 0xe1, 0x42, 0x10, 0xc0, 0x69, 0x10, + 0x71, 0xd1, 0x3d, 0x27, 0x79, 0x08, 0xda, 0x81, + 0x9a, 0x30, 0x72, 0x30, 0x4d, 0x72, 0x2e, 0x83, + 0x9c, 0x07, 0x06, 0x42, 0xbd, 0xcb, 0xd2, 0x2e, + 0x74, 0x51, 0xa7, 0xd4, 0x53, 0x70, 0x63, 0xc0, + 0x70, 0x49, 0xb9, 0x06, 0x66, 0xd0, 0x02, 0xc4, + 0x17, 0x9b, 0x84, 0x88, 0xc3, 0x30, 0x70, 0x55, + 0xb8, 0x0e, 0x5c, 0x1c, 0x32, 0x09, 0x90, 0xe5, + 0x5e, 0x6d, 0x01, 0xc4, 0x7d, 0x0a, 0xfd, 0x46, + 0x48, 0x48, 0xb3, 0xb7, 0x06, 0x4b, 0x8c, 0x10, + 0x03, 0x9f, 0xba, 0x2e, 0x46, 0x19, 0xbe, 0xf5, + 0x1a, 0xc7, 0xb4, 0xe0, 0x65, 0x02, 0x7c, 0x30, + 0x0c, 0x4d, 0x8a, 0x5f, 0x0d, 0x45, 0xca, 0x28, + 0x4b, 0x2b, 0x03, 0xa0, 0x30, 0x2c, 0x42, 0x5c, + 0xe6, 0x9e, 0x28, 0x82, 0xe0, 0x5c, 0xbe, 0xa3, + 0x96, 0x06, 0x61, 0x2c, 0x40, 0x1d, 0xd2, 0x17, + 0xc5, 0xc1, 0xc3, 0x5e, 0xce, 0x1a, 0xe0, 0xaf, + 0x4f, 0x0c, 0xba, 0x19, 0x06, 0x40, 0x3c, 0x6b, + 0xe7, 0x57, 0x58, 0xd4, 0x07, 0x1b, 0x14, 0x27, + 0xce, 0x92, 0xc2, 0x94, 0x60, 0xbe, 0x60, 0xe0, + 0x9f, 0x44, 0x85, 0xfa, 0xf8, 0xd8, 0x64, 0xa3, + 0x80, 0x39, 0x10, 0x55, 0xed, 0x18, 0x9b, 0x0b, + 0x32, 0x20, 0x58, 0x02, 0xe7, 0x1b, 0x21, 0xbd, + 0x9d, 0xe9, 0x50, 0x26, 0xe9, 0xba, 0x1f, 0xa2, + 0xee, 0x14, 0x2e, 0x03, 0xc8, 0xdd, 0x10, 0x4d, + 0x66, 0x8c, 0xe9, 0x48, 0x2e, 0x51, 0xe0, 0x26, + 0xa9, 0xc6, 0x43, 0x9c, 0x92, 0x20, 0x04, 0xd2, + 0xd7, 0x43, 0x27, 0x01, 0x7d, 0xa7, 0x65, 0x7c, + 0x0e, 0xb0, 0x11, 0xc2, 0x5b, 0xbf, 0x51, 0x57, + 0xc0, 0x46, 0xb1, 0x71, 0x97, 0x5d, 0x62, 0x06, + 0x68, 0xdf, 0xba, 0x6c, 0xad, 0x18, 0xc8, 0xe4, + 0x28, 0xcc, 0x1b, 0x7b, 0x85, 0x10, 0x31, 0x3f, + 0x41, 0xc8, 0x88, 0xb4, 0xde, 0x7f, 0x7e, 0x0c, + 0x05, 0x3e, 0xb9, 0xb5, 0x10, 0x6b, 0x2a, 0x1b, + 0xe7, 0x54, 0xe6, 0x12, 0x8d, 0xe8, 0x38, 0x62, + 0x7b, 0xd2, 0x45, 0xe8, 0x51, 0xf8, 0x8d, 0x71, + 0x78, 0x38, 0x62, 0x13, 0xb2, 0xfd, 0x09, 0x62, + 0x6c, 0x0d, 0x60, 0x32, 0x1f, 0xb7, 0xfa, 0x53, + 0xc8, 0x50, 0xb7, 0x06, 0x92, 0xa3, 0x32, 0xad, + 0x38, 0x0e, 0x28, 0x3d, 0x27, 0x9f, 0x20, 0x63, + 0xd7, 0xcb, 0xd4, 0x72, 0xf0, 0x90, 0x83, 0x5f, + 0x5d, 0x18, 0x92, 0xa3, 0x0d, 0xd7, 0x3d, 0xaa, + 0x91, 0x95, 0xe9, 0x48, 0xd1, 0xf4, 0x1f, 0xc2, + 0x00, 0x3f, 0x6c, 0x44, 0xba, 0x00, 0x70, 0x72, + 0x7e, 0x70, 0x57, 0x53, 0x64, 0x92, 0x0c, 0xcd, + 0x92, 0x02, 0xeb, 0xae, 0x50, 0x2a, 0xca, 0x0a, + 0x45, 0xc0, 0x3c, 0x1c, 0xee, 0x18, 0x03, 0x90, + 0x84, 0x54, 0x35, 0xe8, 0x49, 0xa7, 0x35, 0x12, + 0x00, 0x1c, 0x2e, 0x07, 0x3b, 0x49, 0x01, 0xdd, + 0x19, 0x83, 0x90, 0x89, 0xa7, 0x85, 0x05, 0x01, + 0x1b, 0x17, 0x14, 0x03, 0xb8, 0x0b, 0xe6, 0xc2, + 0x9e, 0x94, 0x9c, 0xd3, 0xa0, 0x70, 0x66, 0x43, + 0x3c, 0x07, 0x05, 0x49, 0x74, 0xd5, 0xe0, 0xc0, + 0x07, 0xae, 0xea, 0x5f, 0xa6, 0xc1, 0xc3, 0x05, + 0x85, 0xc2, 0xb8, 0xa4, 0x90, 0x2b, 0x89, 0xb8, + 0x0e, 0x42, 0x12, 0x34, 0x46, 0x81, 0xc4, 0xa2, + 0x96, 0xb8, 0x64, 0x6e, 0x02, 0xe7, 0xa3, 0x40, + 0x32, 0x07, 0x40, 0x5c, 0x3d, 0xed, 0x5f, 0xa1, + 0x55, 0x4b, 0xf9, 0x60, 0x70, 0xa2, 0x11, 0xf4, + 0x32, 0x73, 0xe5, 0x29, 0x0c, 0x01, 0xc5, 0x03, + 0x5b, 0x57, 0x20, 0x89, 0xd8, 0x39, 0x00, 0x39, + 0x71, 0x80, 0xd1, 0x8c, 0x49, 0x3a, 0x09, 0xf0, + 0xa2, 0x23, 0x07, 0x02, 0xfa, 0x54, 0x78, 0x94, + 0x31, 0x13, 0xac, 0x2a, 0x15, 0xd5, 0xe1, 0x17, + 0x51, 0x03, 0xa5, 0x3b, 0xa1, 0x2a, 0x37, 0xed, + 0xd2, 0xa2, 0x52, 0x42, 0x8a, 0xb1, 0xa2, 0x83, + 0xb2, 0xa4, 0xa2, 0x4a, 0x50, 0x8f, 0xa1, 0x80, + 0x55, 0x29, 0xd8, 0x9e, 0x50, 0x87, 0xa7, 0x31, + 0x50, 0x3b, 0x92, 0x0c, 0x0f, 0xf1, 0x99, 0x48, + 0x38, 0x07, 0x22, 0x24, 0x3f, 0xc1, 0xcb, 0x83, + 0x81, 0x60, 0x35, 0xc1, 0x75, 0x13, 0xf1, 0x74, + 0x43, 0x12, 0x51, 0x98, 0x47, 0x84, 0x52, 0x81, + 0x82, 0xc0, 0xe1, 0xac, 0x74, 0x16, 0x04, 0xa1, + 0x81, 0xe6, 0x04, 0x83, 0x20, 0x89, 0xd6, 0x42, + 0x7f, 0x4d, 0xd1, 0x81, 0x48, 0xa1, 0x46, 0x3f, + 0x8c, 0xc5, 0x33, 0x9b, 0xe4, 0x1b, 0x9d, 0x5c, + 0x63, 0x90, 0x1c, 0x83, 0xae, 0xc8, 0x51, 0x06, + 0x50, 0x32, 0xa0, 0xbf, 0x2d, 0xc0, 0x71, 0x20, + 0x38, 0x5c, 0x4a, 0xef, 0xa7, 0xb4, 0xd0, 0xb8, + 0x4b, 0x45, 0xc2, 0xf0, 0x4e, 0x65, 0x21, 0x3f, + 0x34, 0x8c, 0x1c, 0x4a, 0x0e, 0xeb, 0xe4, 0xa0, + 0x1d, 0x46, 0x01, 0x5c, 0xe8, 0x9f, 0x5f, 0x14, + 0xa2, 0x37, 0x49, 0x44, 0xcf, 0x9c, 0x18, 0x92, + 0xa3, 0x07, 0x09, 0xe6, 0x1b, 0x09, 0x2b, 0x83, + 0x10, 0x4c, 0xe2, 0x35, 0x9d, 0x13, 0x92, 0x80, + 0x70, 0x66, 0x35, 0x6b, 0x77, 0x84, 0x6c, 0x64, + 0xb9, 0xa5, 0x96, 0x13, 0xee, 0x0c, 0x41, 0xc8, + 0xfa, 0x13, 0xb5, 0x9d, 0x25, 0x0a, 0x75, 0xde, + 0x50, 0x70, 0x2f, 0xa7, 0x56, 0x37, 0x61, 0xb2, + 0x42, 0x40, 0xae, 0x68, 0xcc, 0xa5, 0x07, 0x42, + 0x4d, 0x0d, 0xad, 0xca, 0x0b, 0xd5, 0xa3, 0x21, + 0x36, 0x9e, 0x8a, 0x22, 0xfd, 0x05, 0x88, 0x38, + 0x82, 0x4a, 0x28, 0xc1, 0x6e, 0x92, 0xad, 0x43, + 0x17, 0x4a, 0x34, 0x60, 0xfe, 0x10, 0x01, 0xe3, + 0x75, 0x6e, 0x03, 0x82, 0x4b, 0xdc, 0xa2, 0xbd, + 0x77, 0x28, 0x3b, 0xab, 0x77, 0x85, 0x21, 0x3c, + 0xc1, 0x9b, 0x9c, 0xb6, 0x76, 0xdb, 0x67, 0x78, + 0xb6, 0x5e, 0x21, 0x92, 0xde, 0x11, 0x4a, 0x20, + 0x74, 0x08, 0xa4, 0xa1, 0xb8, 0xd3, 0x5e, 0x68, + 0xd6, 0x57, 0x85, 0x01, 0x89, 0x0c, 0x5e, 0xa0, + 0x07, 0x1a, 0x07, 0x09, 0xf7, 0x11, 0x02, 0xeb, + 0x07, 0x1e, 0xd3, 0x46, 0xad, 0x11, 0x94, 0x74, + 0x1d, 0xd7, 0x29, 0xc3, 0x62, 0xf7, 0x24, 0x1f, + 0x7c, 0x18, 0x38, 0xf8, 0x30, 0xc2, 0x86, 0x12, + 0x03, 0x9f, 0xea, 0x66, 0xc1, 0x83, 0x86, 0xc6, + 0x5e, 0xa0, 0x39, 0xce, 0x51, 0x44, 0xda, 0xf8, + 0x5f, 0x01, 0xc3, 0x4f, 0x61, 0xb5, 0xe8, 0x62, + 0x8c, 0xa0, 0x17, 0x57, 0x75, 0x0f, 0x36, 0xf1, + 0x65, 0xc8, 0x1c, 0x02, 0x53, 0xab, 0xd0, 0x58, + 0xba, 0xf6, 0x44, 0x00, 0x9d, 0xaf, 0x48, 0x22, + 0x38, 0x85, 0x09, 0x48, 0x45, 0xe5, 0x28, 0x1a, + 0xfb, 0x20, 0x6f, 0x38, 0x32, 0x14, 0x54, 0xb4, + 0x63, 0xd0, 0x70, 0xd6, 0x82, 0xef, 0x5d, 0xd1, + 0x9f, 0x56, 0x3d, 0xc6, 0x1c, 0xe2, 0x11, 0x5b, + 0x46, 0x6a, 0xfd, 0x6e, 0x04, 0xad, 0x62, 0x8c, + 0x07, 0x00, 0xe2, 0x32, 0xf8, 0x1c, 0xf0, 0x51, + 0x57, 0xc0, 0xe0, 0x1c, 0x2a, 0xf1, 0x07, 0x09, + 0xb0, 0xbe, 0x03, 0xb8, 0x09, 0xfd, 0x62, 0x8b, + 0x45, 0xe1, 0x5d, 0x07, 0x2c, 0xb0, 0x4f, 0x17, + 0xf4, 0x95, 0x00, 0x26, 0xc9, 0x4a, 0x18, 0x13, + 0xe2, 0xb4, 0x6b, 0xd0, 0xb1, 0xd4, 0x11, 0x69, + 0x69, 0xc2, 0xc8, 0x75, 0xf2, 0xc0, 0xe4, 0x64, + 0x1d, 0x71, 0x80, 0xb8, 0x4c, 0xc6, 0x36, 0x3b, + 0x64, 0x90, 0x38, 0xb3, 0x56, 0x18, 0x65, 0x08, + 0x8c, 0x46, 0xb9, 0xfa, 0xbf, 0x0c, 0xaa, 0xc1, + 0x26, 0x90, 0x1e, 0x8f, 0xff, 0xf2, 0x36, 0xba, + 0x34, 0x56, 0x54, 0x2b, 0x03, 0x90, 0x9e, 0x9a, + 0x31, 0x44, 0x18, 0x11, 0xfb, 0xc8, 0x13, 0x6b, + 0xe9, 0x61, 0x24, 0xc4, 0x68, 0x85, 0x33, 0x25, + 0x29, 0xa1, 0x15, 0x5d, 0xa4, 0xb2, 0xda, 0x15, + 0x7e, 0x62, 0x35, 0x96, 0x20, 0xf3, 0xa4, 0x51, + 0x79, 0xb0, 0xa5, 0x1f, 0x20, 0xc7, 0x80, 0x9b, + 0xed, 0x24, 0xe2, 0x11, 0xab, 0xe8, 0xcb, 0xa1, + 0x54, 0xcc, 0x44, 0x8b, 0x66, 0x76, 0x3a, 0x62, + 0x20, 0x4f, 0xd7, 0xe2, 0x29, 0xbe, 0x92, 0x93, + 0xb5, 0x90, 0x03, 0xba, 0x27, 0x7d, 0xb0, 0x39, + 0x2b, 0xea, 0x31, 0x9f, 0x02, 0x7f, 0x78, 0x50, + 0x80, 0x30, 0x3f, 0x68, 0x38, 0x90, 0x5e, 0x73, + 0x5f, 0x4e, 0xc5, 0x83, 0x80, 0x58, 0x53, 0x64, + 0x0e, 0xf5, 0x75, 0xea, 0xfd, 0x28, 0x01, 0xc2, + 0x7d, 0x25, 0x24, 0x18, 0x21, 0x26, 0x63, 0x2e, + 0x14, 0x03, 0x89, 0xb0, 0x4b, 0xd7, 0xcb, 0x40, + 0x1c, 0x0e, 0x27, 0xf1, 0x0a, 0x25, 0x08, 0xf8, + 0x0b, 0x00, 0x96, 0x57, 0x24, 0xb4, 0x1c, 0xbb, + 0xf2, 0xc8, 0x90, 0x13, 0xdb, 0xc5, 0xf8, 0x0b, + 0x8d, 0x77, 0x68, 0xc5, 0x12, 0x15, 0xd6, 0x58, + 0x1c, 0x41, 0x0a, 0x24, 0x17, 0x74, 0x99, 0x86, + 0x6e, 0x7b, 0x56, 0x5b, 0x8a, 0x1e, 0xb3, 0xa8, + 0xcf, 0x6b, 0xb5, 0x34, 0x66, 0x18, 0x0c, 0x90, + 0x0c, 0x0f, 0x6e, 0x12, 0x2e, 0x50, 0x30, 0x15, + 0xb8, 0xa5, 0x61, 0xbd, 0xe7, 0x21, 0x0b, 0x51, + 0x94, 0xd4, 0xe7, 0x03, 0x00, 0x75, 0x0a, 0xfb, + 0xce, 0x9c, 0xab, 0xb2, 0x94, 0x48, 0x17, 0x0c, + 0x02, 0x67, 0xc1, 0x91, 0x45, 0xa6, 0xc1, 0x3e, + 0x49, 0x62, 0x34, 0x41, 0x33, 0xb4, 0x67, 0xd1, + 0x5c, 0x9d, 0xe2, 0xe7, 0x62, 0xee, 0x55, 0x08, + 0x81, 0xdc, 0x42, 0x0e, 0x21, 0x85, 0xe4, 0xef, + 0x00, 0x78, 0x39, 0x18, 0x55, 0x2b, 0x92, 0xde, + 0xf4, 0xd1, 0x48, 0x2e, 0x7c, 0x90, 0x91, 0x6e, + 0x83, 0x84, 0xee, 0x4b, 0x16, 0x14, 0x55, 0xf5, + 0x45, 0x10, 0x03, 0x9c, 0xe7, 0x0d, 0xf4, 0x90, + 0x64, 0x0b, 0x17, 0xcd, 0x84, 0x96, 0x4a, 0xbc, + 0x09, 0x37, 0x4a, 0x3a, 0x0f, 0x3d, 0x00, 0x19, + 0x34, 0x74, 0x5f, 0x59, 0x41, 0x18, 0x17, 0x33, + 0x95, 0x75, 0xe7, 0x14, 0x80, 0xee, 0x84, 0xcc, + 0xae, 0x12, 0x80, 0xf2, 0x0d, 0xa4, 0x9d, 0xc9, + 0x00, 0x79, 0x03, 0x3b, 0x5f, 0x5b, 0xc4, 0x3d, + 0x82, 0xf0, 0x71, 0xf9, 0xb3, 0x88, 0xfb, 0xd0, + 0x72, 0x09, 0xd1, 0xa4, 0xe2, 0xc8, 0x33, 0x7a, + 0x8d, 0x00, 0x39, 0x08, 0x2e, 0xb5, 0xc0, 0xd4, + 0xd7, 0x68, 0x38, 0x17, 0x5a, 0x33, 0xfa, 0xf3, + 0x38, 0x83, 0x8b, 0x12, 0x21, 0x39, 0x2b, 0x94, + 0xf5, 0x18, 0x38, 0x33, 0x21, 0x9b, 0x41, 0xf1, + 0xe0, 0x07, 0xd2, 0x52, 0x59, 0x11, 0x92, 0x92, + 0x2f, 0x41, 0xc4, 0x3d, 0x5e, 0x1e, 0xd3, 0x95, + 0xc0, 0x71, 0x0c, 0x7a, 0xc5, 0x38, 0x8c, 0x6e, + 0xed, 0x31, 0xb0, 0xe2, 0x82, 0x35, 0x09, 0x27, + 0x3d, 0xaa, 0x72, 0xdc, 0x43, 0x04, 0x47, 0xc5, + 0xa9, 0xb0, 0x9b, 0x7f +}; diff --git a/contrib/apps/shell/shell.c b/contrib/apps/shell/shell.c new file mode 100644 index 0000000..f4f668d --- /dev/null +++ b/contrib/apps/shell/shell.c @@ -0,0 +1,1277 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "shell.h" + +#include "lwip/opt.h" + +#if LWIP_NETCONN && LWIP_TCP + +#include +#include + +#include "lwip/mem.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/api.h" +#include "lwip/stats.h" + +#if LWIP_SOCKET +#include "lwip/errno.h" +#include "lwip/if_api.h" +#endif + +#ifdef WIN32 +#define NEWLINE "\r\n" +#else /* WIN32 */ +#define NEWLINE "\n" +#endif /* WIN32 */ + +/** Define this to 1 if you want to echo back all received characters + * (e.g. so they are displayed on a remote telnet) + */ +#ifndef SHELL_ECHO +#define SHELL_ECHO 0 +#endif + +#define BUFSIZE 1024 +static unsigned char buffer[BUFSIZE]; + +struct command { + struct netconn *conn; + s8_t (* exec)(struct command *); + u8_t nargs; + char *args[10]; +}; + +#include +#include +#include + +#define ESUCCESS 0 +#define ESYNTAX -1 +#define ETOOFEW -2 +#define ETOOMANY -3 +#define ECLOSED -4 + +#define NCONNS 10 +static struct netconn *conns[NCONNS]; + +/* help_msg is split into 3 strings to prevent exceeding the C89 maximum length of 509 per string */ +static char help_msg1[] = "Available commands:"NEWLINE"\ +open [IP address] [TCP port]: opens a TCP connection to the specified address."NEWLINE"\ +lstn [TCP port]: sets up a server on the specified port."NEWLINE"\ +acpt [connection #]: waits for an incoming connection request."NEWLINE"\ +send [connection #] [message]: sends a message on a TCP connection."NEWLINE"\ +udpc [local UDP port] [IP address] [remote port]: opens a UDP \"connection\"."NEWLINE"\ +udpl [local UDP port] [IP address] [remote port]: opens a UDP-Lite \"connection\"."NEWLINE""; +static char help_msg2[] = "udpn [local UDP port] [IP address] [remote port]: opens a UDP \"connection\" without checksums."NEWLINE"\ +udpb [local port] [remote port]: opens a UDP broadcast \"connection\"."NEWLINE"\ +usnd [connection #] [message]: sends a message on a UDP connection."NEWLINE"\ +recv [connection #]: receives data on a TCP or UDP connection."NEWLINE"\ +clos [connection #]: closes a TCP or UDP connection."NEWLINE"\ +stat: prints out lwIP statistics."NEWLINE"\ +idxtoname [index]: outputs interface name from index."NEWLINE"\ +nametoidx [name]: outputs interface index from name."NEWLINE; +static char help_msg3[] = +"gethostnm [name]: outputs IP address of host."NEWLINE"\ +quit: quits"NEWLINE""; + +#if LWIP_STATS +static char padding_10spaces[] = " "; + +#define PROTOCOL_STATS (LINK_STATS && ETHARP_STATS && IPFRAG_STATS && IP_STATS && ICMP_STATS && UDP_STATS && TCP_STATS) + +#if PROTOCOL_STATS +static const char* shell_stat_proto_names[] = { +#if LINK_STATS + "LINK ", +#endif +#if ETHARP_STATS + "ETHARP ", +#endif +#if IPFRAG_STATS + "IP_FRAG ", +#endif +#if IP_STATS + "IP ", +#endif +#if ICMP_STATS + "ICMP ", +#endif +#if UDP_STATS + "UDP ", +#endif +#if TCP_STATS + "TCP ", +#endif + "last" +}; + +static struct stats_proto* shell_stat_proto_stats[] = { +#if LINK_STATS + &lwip_stats.link, +#endif +#if ETHARP_STATS + &lwip_stats.etharp, +#endif +#if IPFRAG_STATS + &lwip_stats.ip_frag, +#endif +#if IP_STATS + &lwip_stats.ip, +#endif +#if ICMP_STATS + &lwip_stats.icmp, +#endif +#if UDP_STATS + &lwip_stats.udp, +#endif +#if TCP_STATS + &lwip_stats.tcp, +#endif +}; +static const size_t num_protostats = sizeof(shell_stat_proto_stats)/sizeof(struct stats_proto*); + +static const char *stat_msgs_proto[] = { + " * transmitted ", + " * received ", + " forwarded ", + " * dropped ", + " * checksum errors ", + " * length errors ", + " * memory errors ", + " routing errors ", + " protocol errors ", + " option errors ", + " * misc errors ", + " cache hits " +}; +#endif /* PROTOCOL_STATS */ +#endif /* LWIP_STATS */ + +/*-----------------------------------------------------------------------------------*/ +static void +sendstr(const char *str, struct netconn *conn) +{ + netconn_write(conn, (const void *)str, strlen(str), NETCONN_NOCOPY); +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_open(struct command *com) +{ + ip_addr_t ipaddr; + u16_t port; + int i; + err_t err; + long tmp; + + if (ipaddr_aton(com->args[0], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + tmp = strtol(com->args[1], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + port = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Opening connection to ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_TCP); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + err = netconn_connect(conns[i], &ipaddr, port); + if (err != ERR_OK) { + fprintf(stderr, "error %s"NEWLINE, lwip_strerr(err)); + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + netconn_delete(conns[i]); + conns[i] = NULL; + return ESUCCESS; + } + + sendstr("Opened connection, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_lstn(struct command *com) +{ + u16_t port; + int i; + err_t err; + long tmp; + + tmp = strtol(com->args[0], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + port = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Opening a listening connection on port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_TCP); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, port); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_listen(conns[i]); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not listen: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Opened connection, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_clos(struct command *com) +{ + int i; + err_t err; + + i = strtol(com->args[0], NULL, 10); + + if (i > NCONNS) { + sendstr("Connection identifier too high."NEWLINE, com->conn); + return ESUCCESS; + } + if (conns[i] == NULL) { + sendstr("Connection identifier not in use."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_close(conns[i]); + if (err != ERR_OK) { + sendstr("Could not close connection: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Connection closed."NEWLINE, com->conn); + netconn_delete(conns[i]); + conns[i] = NULL; + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_acpt(struct command *com) +{ + int i, j; + err_t err; + + /* Find the first unused connection in conns. */ + for(j = 0; j < NCONNS && conns[j] != NULL; j++); + + if (j == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + i = strtol(com->args[0], NULL, 10); + + if (i > NCONNS) { + sendstr("Connection identifier too high."NEWLINE, com->conn); + return ESUCCESS; + } + if (conns[i] == NULL) { + sendstr("Connection identifier not in use."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_accept(conns[i], &conns[j]); + + if (err != ERR_OK) { + sendstr("Could not accept connection: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Accepted connection, connection identifier for new connection is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, j); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +#if LWIP_STATS +static void +com_stat_write_mem(struct netconn *conn, struct stats_mem *elem, int i) +{ + u16_t len; + char buf[100]; + size_t slen; + +#ifdef LWIP_DEBUG + LWIP_UNUSED_ARG(i); + slen = strlen(elem->name); + netconn_write(conn, elem->name, slen, NETCONN_COPY); +#else /* LWIP_DEBUG */ + len = (u16_t)sprintf(buf, "%d", i); + slen = strlen(buf); + netconn_write(conn, buf, slen, NETCONN_COPY); +#endif /* LWIP_DEBUG */ + if(slen < 10) { + netconn_write(conn, padding_10spaces, 10-slen, NETCONN_COPY); + } + + len = (u16_t)sprintf(buf, " * available %"MEM_SIZE_F NEWLINE, elem->avail); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * used %"MEM_SIZE_F NEWLINE, elem->used); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * high water mark %"MEM_SIZE_F NEWLINE, elem->max); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * errors %"STAT_COUNTER_F NEWLINE, elem->err); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * illegal %"STAT_COUNTER_F NEWLINE, elem->illegal); + netconn_write(conn, buf, len, NETCONN_COPY); +} +static void +com_stat_write_sys(struct netconn *conn, struct stats_syselem *elem, const char *name) +{ + u16_t len; + char buf[100]; + size_t slen = strlen(name); + + netconn_write(conn, name, slen, NETCONN_COPY); + if(slen < 10) { + netconn_write(conn, padding_10spaces, 10-slen, NETCONN_COPY); + } + + len = (u16_t)sprintf(buf, " * used %"STAT_COUNTER_F NEWLINE, elem->used); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * high water mark %"STAT_COUNTER_F NEWLINE, elem->max); + netconn_write(conn, buf, len, NETCONN_COPY); + len = (u16_t)sprintf(buf, " * errors %"STAT_COUNTER_F NEWLINE, elem->err); + netconn_write(conn, buf, len, NETCONN_COPY); +} +static s8_t +com_stat(struct command *com) +{ +#if PROTOCOL_STATS || MEMP_STATS + size_t i; +#endif /* PROTOCOL_STATS || MEMP_STATS */ +#if PROTOCOL_STATS + size_t k; + char buf[100]; + u16_t len; + + /* protocol stats, @todo: add IGMP */ + for(i = 0; i < num_protostats; i++) { + size_t s = sizeof(struct stats_proto)/sizeof(STAT_COUNTER); + STAT_COUNTER *c = &shell_stat_proto_stats[i]->xmit; + LWIP_ASSERT("stats not in sync", s == sizeof(stat_msgs_proto)/sizeof(char*)); + netconn_write(com->conn, shell_stat_proto_names[i], strlen(shell_stat_proto_names[i]), NETCONN_COPY); + for(k = 0; k < s; k++) { + len = (u16_t)sprintf(buf, "%s%"STAT_COUNTER_F NEWLINE, stat_msgs_proto[k], c[k]); + netconn_write(com->conn, buf, len, NETCONN_COPY); + } + } +#endif /* PROTOCOL_STATS */ +#if MEM_STATS + com_stat_write_mem(com->conn, &lwip_stats.mem, -1); +#endif /* MEM_STATS */ +#if MEMP_STATS + for(i = 0; i < MEMP_MAX; i++) { + com_stat_write_mem(com->conn, lwip_stats.memp[i], -1); + } +#endif /* MEMP_STATS */ +#if SYS_STATS + com_stat_write_sys(com->conn, &lwip_stats.sys.sem, "SEM "); + com_stat_write_sys(com->conn, &lwip_stats.sys.mutex, "MUTEX "); + com_stat_write_sys(com->conn, &lwip_stats.sys.mbox, "MBOX "); +#endif /* SYS_STATS */ + + return ESUCCESS; +} +#endif +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_send(struct command *com) +{ + int i; + err_t err; + size_t len; + + i = strtol(com->args[0], NULL, 10); + + if (i > NCONNS) { + sendstr("Connection identifier too high."NEWLINE, com->conn); + return ESUCCESS; + } + + if (conns[i] == NULL) { + sendstr("Connection identifier not in use."NEWLINE, com->conn); + return ESUCCESS; + } + + len = strlen(com->args[1]); + com->args[1][len] = '\r'; + com->args[1][len + 1] = '\n'; + com->args[1][len + 2] = 0; + + err = netconn_write(conns[i], com->args[1], len + 3, NETCONN_COPY); + if (err != ERR_OK) { + sendstr("Could not send data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Data enqueued for sending."NEWLINE, com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_recv(struct command *com) +{ + int i; + err_t err; + struct netbuf *buf; + u16_t len; + + i = strtol(com->args[0], NULL, 10); + + if (i > NCONNS) { + sendstr("Connection identifier too high."NEWLINE, com->conn); + return ESUCCESS; + } + + if (conns[i] == NULL) { + sendstr("Connection identifier not in use."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_recv(conns[i], &buf); + if (err == ERR_OK) { + + netbuf_copy(buf, buffer, BUFSIZE); + len = netbuf_len(buf); + sendstr("Reading from connection:"NEWLINE, com->conn); + netconn_write(com->conn, buffer, len, NETCONN_COPY); + netbuf_delete(buf); + } else { + sendstr("EOF."NEWLINE, com->conn); + } + err = netconn_err(conns[i]); + if (err != ERR_OK) { + sendstr("Could not receive data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpc(struct command *com) +{ + ip_addr_t ipaddr; + u16_t lport, rport; + int i; + err_t err; + long tmp; + + tmp = strtol(com->args[0], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + lport = (u16_t)tmp; + if (ipaddr_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + tmp = strtol(com->args[2], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + rport = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_UDP); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpl(struct command *com) +{ + ip_addr_t ipaddr; + u16_t lport, rport; + int i; + err_t err; + long tmp; + + tmp = strtol(com->args[0], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + lport = (u16_t)tmp; + if (ipaddr_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + tmp = strtol(com->args[2], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + rport = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP-Lite connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_UDPLITE); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpn(struct command *com) +{ + ip_addr_t ipaddr; + u16_t lport, rport; + int i; + err_t err; + long tmp; + + tmp = strtol(com->args[0], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + lport = (u16_t)tmp; + if (ipaddr_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + tmp = strtol(com->args[2], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + rport = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP connection without checksums from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_UDPNOCHKSUM); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpb(struct command *com) +{ + ip_addr_t ipaddr; +#if LWIP_IPV4 + u16_t lport; +#endif /* LWIP_IPV4 */ + u16_t rport; + int i; + err_t err; + long tmp; + + tmp = strtol(com->args[0], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } +#if LWIP_IPV4 + lport = (u16_t)tmp; +#endif /* LWIP_IPV4 */ + if (ipaddr_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + tmp = strtol(com->args[2], NULL, 10); + if((tmp < 0) || (tmp > 0xffff)) { + sendstr("Invalid port number."NEWLINE, com->conn); + return ESUCCESS; + } + rport = (u16_t)tmp; + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if (i == NCONNS) { + sendstr("No more connections available, sorry."NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP broadcast connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + + conns[i] = netconn_new(NETCONN_UDP); + if (conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + +#if LWIP_IPV4 + if (IP_IS_V6_VAL(ipaddr)) { + err = netconn_bind(conns[i], &ip_addr_broadcast, lport); + if (err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + } +#endif /* LWIP_IPV4 */ + + sendstr("Connection set up, connection identifier is ", com->conn); + snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_usnd(struct command *com) +{ + long i; + err_t err; + struct netbuf *buf; + char *mem; + u16_t len; + size_t tmp; + + i = strtol(com->args[0], NULL, 10); + + if (i > NCONNS) { + sendstr("Connection identifier too high."NEWLINE, com->conn); + return ESUCCESS; + } + + if (conns[i] == NULL) { + sendstr("Connection identifier not in use."NEWLINE, com->conn); + return ESUCCESS; + } + tmp = strlen(com->args[1]) + 1; + if (tmp > 0xffff) { + sendstr("Invalid length."NEWLINE, com->conn); + return ESUCCESS; + } + len = (u16_t)tmp; + + buf = netbuf_new(); + mem = (char *)netbuf_alloc(buf, len); + if (mem == NULL) { + sendstr("Could not allocate memory for sending."NEWLINE, com->conn); + return ESUCCESS; + } + strncpy(mem, com->args[1], len); + err = netconn_send(conns[i], buf); + netbuf_delete(buf); + if (err != ERR_OK) { + sendstr("Could not send data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr(NEWLINE, com->conn); + return ESUCCESS; + } + + sendstr("Data sent."NEWLINE, com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +#if LWIP_SOCKET +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_idxtoname(struct command *com) +{ + long i = strtol(com->args[0], NULL, 10); + + if (lwip_if_indextoname((unsigned int)i, (char *)buffer)) { + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + sendstr(NEWLINE, com->conn); + } else { + snprintf((char *)buffer, sizeof(buffer), "if_indextoname() failed: %d"NEWLINE, errno); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + } + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_nametoidx(struct command *com) +{ + unsigned int idx = lwip_if_nametoindex(com->args[0]); + + if (idx) { + snprintf((char *)buffer, sizeof(buffer), "%u"NEWLINE, idx); + netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); + } else { + sendstr("No interface found"NEWLINE, com->conn); + } + return ESUCCESS; +} +#endif /* LWIP_SOCKET */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_DNS +static s8_t +com_gethostbyname(struct command *com) +{ + ip_addr_t addr; + err_t err = netconn_gethostbyname(com->args[0], &addr); + + if (err == ERR_OK) { + if (ipaddr_ntoa_r(&addr, (char *)buffer, sizeof(buffer))) { + sendstr("Host found: ", com->conn); + sendstr((char *)buffer, com->conn); + sendstr(NEWLINE, com->conn); + } else { + sendstr("ipaddr_ntoa_r failed", com->conn); + } + } else { + sendstr("No host found"NEWLINE, com->conn); + } + return ESUCCESS; +} +#endif /* LWIP_DNS */ +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_help(struct command *com) +{ + sendstr(help_msg1, com->conn); + sendstr(help_msg2, com->conn); + sendstr(help_msg3, com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +parse_command(struct command *com, u32_t len) +{ + u16_t i; + u16_t bufp; + + if (strncmp((const char *)buffer, "open", 4) == 0) { + com->exec = com_open; + com->nargs = 2; + } else if (strncmp((const char *)buffer, "lstn", 4) == 0) { + com->exec = com_lstn; + com->nargs = 1; + } else if (strncmp((const char *)buffer, "acpt", 4) == 0) { + com->exec = com_acpt; + com->nargs = 1; + } else if (strncmp((const char *)buffer, "clos", 4) == 0) { + com->exec = com_clos; + com->nargs = 1; +#if LWIP_STATS + } else if (strncmp((const char *)buffer, "stat", 4) == 0) { + com->exec = com_stat; + com->nargs = 0; +#endif + } else if (strncmp((const char *)buffer, "send", 4) == 0) { + com->exec = com_send; + com->nargs = 2; + } else if (strncmp((const char *)buffer, "recv", 4) == 0) { + com->exec = com_recv; + com->nargs = 1; + } else if (strncmp((const char *)buffer, "udpc", 4) == 0) { + com->exec = com_udpc; + com->nargs = 3; + } else if (strncmp((const char *)buffer, "udpb", 4) == 0) { + com->exec = com_udpb; + com->nargs = 2; + } else if (strncmp((const char *)buffer, "udpl", 4) == 0) { + com->exec = com_udpl; + com->nargs = 3; + } else if (strncmp((const char *)buffer, "udpn", 4) == 0) { + com->exec = com_udpn; + com->nargs = 3; + } else if (strncmp((const char *)buffer, "usnd", 4) == 0) { + com->exec = com_usnd; + com->nargs = 2; +#if LWIP_SOCKET + } else if (strncmp((const char *)buffer, "idxtoname", 9) == 0) { + com->exec = com_idxtoname; + com->nargs = 1; + } else if (strncmp((const char *)buffer, "nametoidx", 9) == 0) { + com->exec = com_nametoidx; + com->nargs = 1; +#endif /* LWIP_SOCKET */ +#if LWIP_DNS + } else if (strncmp((const char *)buffer, "gethostnm", 9) == 0) { + com->exec = com_gethostbyname; + com->nargs = 1; +#endif /* LWIP_DNS */ + } else if (strncmp((const char *)buffer, "help", 4) == 0) { + com->exec = com_help; + com->nargs = 0; + } else if (strncmp((const char *)buffer, "quit", 4) == 0) { + printf("quit"NEWLINE); + return ECLOSED; + } else { + return ESYNTAX; + } + + if (com->nargs == 0) { + return ESUCCESS; + } + bufp = 0; + for(; bufp < len && buffer[bufp] != ' '; bufp++); + for(i = 0; i < 10; i++) { + for(; bufp < len && buffer[bufp] == ' '; bufp++); + if (buffer[bufp] == '\r' || + buffer[bufp] == '\n') { + buffer[bufp] = 0; + if (i < com->nargs - 1) { + return ETOOFEW; + } + if (i > com->nargs - 1) { + return ETOOMANY; + } + break; + } + if (bufp > len) { + return ETOOFEW; + } + com->args[i] = (char *)&buffer[bufp]; + for(; bufp < len && buffer[bufp] != ' ' && buffer[bufp] != '\r' && + buffer[bufp] != '\n'; bufp++) { + if (buffer[bufp] == '\\') { + buffer[bufp] = ' '; + } + } + if (bufp > len) { + return ESYNTAX; + } + buffer[bufp] = 0; + bufp++; + if (i == com->nargs - 1) { + break; + } + + } + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static void +shell_error(s8_t err, struct netconn *conn) +{ + switch (err) { + case ESYNTAX: + sendstr("## Syntax error"NEWLINE, conn); + break; + case ETOOFEW: + sendstr("## Too few arguments to command given"NEWLINE, conn); + break; + case ETOOMANY: + sendstr("## Too many arguments to command given"NEWLINE, conn); + break; + case ECLOSED: + sendstr("## Connection closed"NEWLINE, conn); + break; + default: + /* unknown error, don't assert here */ + break; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +prompt(struct netconn *conn) +{ + sendstr("> ", conn); +} +/*-----------------------------------------------------------------------------------*/ +static void +shell_main(struct netconn *conn) +{ + struct pbuf *p; + u16_t len = 0, cur_len; + struct command com; + s8_t err; + int i; + err_t ret; +#if SHELL_ECHO + void *echomem; +#endif /* SHELL_ECHO */ + + do { + ret = netconn_recv_tcp_pbuf(conn, &p); + if (ret == ERR_OK) { + pbuf_copy_partial(p, &buffer[len], (u16_t)(BUFSIZE - len), 0); + cur_len = p->tot_len; + len = (u16_t)(len + cur_len); + if ((len < cur_len) || (len > BUFSIZE)) { + len = BUFSIZE; + } +#if SHELL_ECHO + echomem = mem_malloc(cur_len); + if (echomem != NULL) { + pbuf_copy_partial(p, echomem, cur_len, 0); + netconn_write(conn, echomem, cur_len, NETCONN_COPY); + mem_free(echomem); + } +#endif /* SHELL_ECHO */ + pbuf_free(p); + if (((len > 0) && ((buffer[len-1] == '\r') || (buffer[len-1] == '\n'))) || + (len >= BUFSIZE)) { + if (buffer[0] != 0xff && + buffer[1] != 0xfe) { + err = parse_command(&com, len); + if (err == ESUCCESS) { + com.conn = conn; + err = com.exec(&com); + } + if (err == ECLOSED) { + printf("Closed"NEWLINE); + shell_error(err, conn); + goto close; + } + if (err != ESUCCESS) { + shell_error(err, conn); + } + } else { + sendstr(NEWLINE NEWLINE + "lwIP simple interactive shell."NEWLINE + "(c) Copyright 2001, Swedish Institute of Computer Science."NEWLINE + "Written by Adam Dunkels."NEWLINE + "For help, try the \"help\" command."NEWLINE, conn); + } + if (ret == ERR_OK) { + prompt(conn); + } + len = 0; + } + } + } while (ret == ERR_OK); + printf("err %s"NEWLINE, lwip_strerr(ret)); + +close: + netconn_close(conn); + + for(i = 0; i < NCONNS; i++) { + if (conns[i] != NULL) { + netconn_delete(conns[i]); + } + conns[i] = NULL; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +shell_thread(void *arg) +{ + struct netconn *conn, *newconn; + err_t err; + LWIP_UNUSED_ARG(arg); + +#if LWIP_IPV6 + conn = netconn_new(NETCONN_TCP_IPV6); + LWIP_ERROR("shell: invalid conn", (conn != NULL), return;); + err = netconn_bind(conn, IP6_ADDR_ANY, 23); +#else /* LWIP_IPV6 */ + conn = netconn_new(NETCONN_TCP); + LWIP_ERROR("shell: invalid conn", (conn != NULL), return;); + err = netconn_bind(conn, IP_ADDR_ANY, 23); +#endif /* LWIP_IPV6 */ + LWIP_ERROR("shell: netconn_bind failed", (err == ERR_OK), netconn_delete(conn); return;); + err = netconn_listen(conn); + LWIP_ERROR("shell: netconn_listen failed", (err == ERR_OK), netconn_delete(conn); return;); + + while (1) { + err = netconn_accept(conn, &newconn); + if (err == ERR_OK) { + shell_main(newconn); + netconn_delete(newconn); + } + } +} +/*-----------------------------------------------------------------------------------*/ +void +shell_init(void) +{ + sys_thread_new("shell_thread", shell_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +#endif /* LWIP_NETCONN && LWIP_TCP */ diff --git a/contrib/apps/shell/shell.h b/contrib/apps/shell/shell.h new file mode 100644 index 0000000..1ba9d19 --- /dev/null +++ b/contrib/apps/shell/shell.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_SHELL_H +#define LWIP_SHELL_H + +void shell_init(void); + +#endif /* LWIP_SHELL_H */ diff --git a/contrib/apps/socket_examples/socket_examples.c b/contrib/apps/socket_examples/socket_examples.c new file mode 100644 index 0000000..a60156f --- /dev/null +++ b/contrib/apps/socket_examples/socket_examples.c @@ -0,0 +1,680 @@ + +#include "socket_examples.h" + +#include "lwip/opt.h" + +#if LWIP_SOCKET && (LWIP_IPV4 || LWIP_IPV6) + +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#include +#include + +#ifndef SOCK_TARGET_HOST4 +#define SOCK_TARGET_HOST4 "192.168.0.1" +#endif + +#ifndef SOCK_TARGET_HOST6 +#define SOCK_TARGET_HOST6 "FE80::12:34FF:FE56:78AB" +#endif + +#ifndef SOCK_TARGET_PORT +#define SOCK_TARGET_PORT 80 +#endif + +#ifndef SOCK_TARGET_MAXHTTPPAGESIZE +#define SOCK_TARGET_MAXHTTPPAGESIZE 1024 +#endif + +#ifndef SOCKET_EXAMPLES_RUN_PARALLEL +#define SOCKET_EXAMPLES_RUN_PARALLEL 0 +#endif + +static const u8_t cmpbuf[8] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab}; + +/* a helper struct to ensure memory before/after fd_set is not touched */ +typedef struct _xx +{ + u8_t buf1[8]; + fd_set readset; + u8_t buf2[8]; + fd_set writeset; + u8_t buf3[8]; + fd_set errset; + u8_t buf4[8]; +} fdsets; + +#define INIT_FDSETS(sets) do { \ + memset((sets)->buf1, 0xab, 8); \ + memset((sets)->buf2, 0xab, 8); \ + memset((sets)->buf3, 0xab, 8); \ + memset((sets)->buf4, 0xab, 8); \ +}while(0) + +#define CHECK_FDSETS(sets) do { \ + LWIP_ASSERT("buf1 fail", !memcmp((sets)->buf1, cmpbuf, 8)); \ + LWIP_ASSERT("buf2 fail", !memcmp((sets)->buf2, cmpbuf, 8)); \ + LWIP_ASSERT("buf3 fail", !memcmp((sets)->buf3, cmpbuf, 8)); \ + LWIP_ASSERT("buf4 fail", !memcmp((sets)->buf4, cmpbuf, 8)); \ +}while(0) + +static ip_addr_t dstaddr; + +/** This is an example function that tests + blocking- and nonblocking connect. */ +static void +sockex_nonblocking_connect(void *arg) +{ +#if LWIP_SOCKET_SELECT + int s; + int ret; + int opt; +#if LWIP_IPV6 + struct sockaddr_in6 addr; +#else /* LWIP_IPV6 */ + struct sockaddr_in addr; +#endif /* LWIP_IPV6 */ + fdsets sets; + struct timeval tv; + u32_t ticks_a, ticks_b; + int err; + const ip_addr_t *ipaddr = (const ip_addr_t*)arg; + struct pollfd fds; + INIT_FDSETS(&sets); + + /* set up address to connect to */ + memset(&addr, 0, sizeof(addr)); +#if LWIP_IPV6 + addr.sin6_len = sizeof(addr); + addr.sin6_family = AF_INET6; + addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT); + inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr)); +#else /* LWIP_IPV6 */ + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); + inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr)); +#endif /* LWIP_IPV6 */ + + /* first try blocking: */ + + /* create the socket */ +#if LWIP_IPV6 + s = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s >= 0", s >= 0); + + /* connect */ + ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); + /* should succeed */ + LWIP_ASSERT("ret == 0", ret == 0); + + /* write something */ + ret = lwip_write(s, "test", 4); + LWIP_ASSERT("ret == 4", ret == 4); + + /* close */ + ret = lwip_close(s); + LWIP_ASSERT("ret == 0", ret == 0); + + /* now try nonblocking and close before being connected */ + + /* create the socket */ +#if LWIP_IPV6 + s = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s >= 0", s >= 0); + /* nonblocking */ + opt = lwip_fcntl(s, F_GETFL, 0); + LWIP_ASSERT("ret != -1", ret != -1); + opt |= O_NONBLOCK; + ret = lwip_fcntl(s, F_SETFL, opt); + LWIP_ASSERT("ret != -1", ret != -1); + /* connect */ + ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); + /* should have an error: "inprogress" */ + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); + /* close */ + ret = lwip_close(s); + LWIP_ASSERT("ret == 0", ret == 0); + /* try to close again, should fail with EBADF */ + ret = lwip_close(s); + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EBADF", err == EBADF); + printf("closing socket in nonblocking connect succeeded\n"); + + /* now try nonblocking, connect should succeed: + this test only works if it is fast enough, i.e. no breakpoints, please! */ + + /* create the socket */ +#if LWIP_IPV6 + s = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s >= 0", s >= 0); + + /* nonblocking */ + opt = 1; + ret = lwip_ioctl(s, FIONBIO, &opt); + LWIP_ASSERT("ret == 0", ret == 0); + + /* connect */ + ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); + /* should have an error: "inprogress" */ + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); + + /* write should fail, too */ + ret = lwip_write(s, "test", 4); + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); + + CHECK_FDSETS(&sets); + FD_ZERO(&sets.readset); + CHECK_FDSETS(&sets); + FD_SET(s, &sets.readset); + CHECK_FDSETS(&sets); + FD_ZERO(&sets.writeset); + CHECK_FDSETS(&sets); + FD_SET(s, &sets.writeset); + CHECK_FDSETS(&sets); + FD_ZERO(&sets.errset); + CHECK_FDSETS(&sets); + FD_SET(s, &sets.errset); + CHECK_FDSETS(&sets); + tv.tv_sec = 0; + tv.tv_usec = 0; + /* select without waiting should fail */ + ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv); + CHECK_FDSETS(&sets); + LWIP_ASSERT("ret == 0", ret == 0); + LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset)); + LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); + LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset)); + + fds.fd = s; + fds.events = POLLIN|POLLOUT; + fds.revents = 0; + ret = lwip_poll(&fds, 1, 0); + LWIP_ASSERT("ret == 0", ret == 0); + LWIP_ASSERT("fds.revents == 0", fds.revents == 0); + + FD_ZERO(&sets.readset); + FD_SET(s, &sets.readset); + FD_ZERO(&sets.writeset); + FD_SET(s, &sets.writeset); + FD_ZERO(&sets.errset); + FD_SET(s, &sets.errset); + ticks_a = sys_now(); + /* select with waiting should succeed */ + ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL); + ticks_b = sys_now(); + LWIP_ASSERT("ret == 1", ret == 1); + LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &sets.writeset)); + LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); + LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset)); + + fds.fd = s; + fds.events = POLLIN|POLLOUT; + fds.revents = 0; + ret = lwip_poll(&fds, 1, 0); + LWIP_ASSERT("ret == 1", ret == 1); + LWIP_ASSERT("fds.revents & POLLOUT", fds.revents & POLLOUT); + + /* now write should succeed */ + ret = lwip_write(s, "test", 4); + LWIP_ASSERT("ret == 4", ret == 4); + + /* close */ + ret = lwip_close(s); + LWIP_ASSERT("ret == 0", ret == 0); + + printf("select() needed %d ticks to return writable\n", (int)(ticks_b - ticks_a)); + + + /* now try nonblocking to invalid address: + this test only works if it is fast enough, i.e. no breakpoints, please! */ + + /* create the socket */ +#if LWIP_IPV6 + s = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s >= 0", s >= 0); + + /* nonblocking */ + opt = 1; + ret = lwip_ioctl(s, FIONBIO, &opt); + LWIP_ASSERT("ret == 0", ret == 0); + +#if LWIP_IPV6 + addr.sin6_addr.un.u8_addr[0]++; /* this should result in an invalid address */ +#else /* LWIP_IPV6 */ + addr.sin_addr.s_addr++; /* this should result in an invalid address */ +#endif /* LWIP_IPV6 */ + + /* connect */ + ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); + /* should have an error: "inprogress" */ + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); + + /* write should fail, too */ + ret = lwip_write(s, "test", 4); + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); + LWIP_UNUSED_ARG(err); + + FD_ZERO(&sets.readset); + FD_SET(s, &sets.readset); + FD_ZERO(&sets.writeset); + FD_SET(s, &sets.writeset); + FD_ZERO(&sets.errset); + FD_SET(s, &sets.errset); + tv.tv_sec = 0; + tv.tv_usec = 0; + /* select without waiting should fail */ + ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv); + LWIP_ASSERT("ret == 0", ret == 0); + + FD_ZERO(&sets.readset); + FD_SET(s, &sets.readset); + FD_ZERO(&sets.writeset); + FD_SET(s, &sets.writeset); + FD_ZERO(&sets.errset); + FD_SET(s, &sets.errset); + ticks_a = sys_now(); + /* select with waiting should eventually succeed and return errset! */ + ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL); + ticks_b = sys_now(); + LWIP_ASSERT("ret > 0", ret > 0); + LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &sets.errset)); + /*LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); + LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));*/ + + /* close */ + ret = lwip_close(s); + LWIP_ASSERT("ret == 0", ret == 0); + LWIP_UNUSED_ARG(ret); + + printf("select() needed %d ticks to return error\n", (int)(ticks_b - ticks_a)); + printf("sockex_nonblocking_connect finished successfully\n"); +#else + LWIP_UNUSED_ARG(arg); +#endif +} + +/** This is an example function that tests + the recv function (timeout etc.). */ +static void +sockex_testrecv(void *arg) +{ + int s; + int ret; + int err; +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + int opt, opt2; +#else + struct timeval opt, opt2; +#endif + socklen_t opt2size; +#if LWIP_IPV6 + struct sockaddr_in6 addr; +#else /* LWIP_IPV6 */ + struct sockaddr_in addr; +#endif /* LWIP_IPV6 */ + size_t len; + char rxbuf[SOCK_TARGET_MAXHTTPPAGESIZE]; +#if LWIP_SOCKET_SELECT + fd_set readset; + fd_set errset; + struct timeval tv; +#endif + const ip_addr_t *ipaddr = (const ip_addr_t*)arg; + + /* set up address to connect to */ + memset(&addr, 0, sizeof(addr)); +#if LWIP_IPV6 + addr.sin6_len = sizeof(addr); + addr.sin6_family = AF_INET6; + addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT); + inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr)); +#else /* LWIP_IPV6 */ + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); + inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr)); +#endif /* LWIP_IPV6 */ + + /* first try blocking: */ + + /* create the socket */ +#if LWIP_IPV6 + s = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s >= 0", s >= 0); + + /* connect */ + ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); + /* should succeed */ + LWIP_ASSERT("ret == 0", ret == 0); + + /* set recv timeout (100 ms) */ +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + opt = 100; +#else + opt.tv_sec = 0; + opt.tv_usec = 100 * 1000; +#endif + ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(opt)); + LWIP_ASSERT("ret == 0", ret == 0); +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + opt2 = 0; +#else + opt2.tv_sec = 0; + opt2.tv_usec = 0; +#endif + opt2size = sizeof(opt2); + ret = lwip_getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt2, &opt2size); + LWIP_ASSERT("ret == 0", ret == 0); + LWIP_ASSERT("opt2size == sizeof(opt2)", opt2size == sizeof(opt2)); +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + LWIP_ASSERT("opt == opt2", opt == opt2); +#else + LWIP_ASSERT("opt == opt2", opt.tv_sec == opt2.tv_sec); + LWIP_ASSERT("opt == opt2", opt.tv_usec == opt2.tv_usec); +#endif + + /* write the start of a GET request */ +#define SNDSTR1 "G" + len = strlen(SNDSTR1); + ret = lwip_write(s, SNDSTR1, len); + LWIP_ASSERT("ret == len", ret == (int)len); + + /* should time out if the other side is a good HTTP server */ + ret = lwip_read(s, rxbuf, 1); + LWIP_ASSERT("ret == -1", ret == -1); + err = errno; + LWIP_ASSERT("errno == EAGAIN", err == EAGAIN); + LWIP_UNUSED_ARG(err); + + /* write the rest of a GET request */ +#define SNDSTR2 "ET / HTTP_1.1\r\n\r\n" + len = strlen(SNDSTR2); + ret = lwip_write(s, SNDSTR2, len); + LWIP_ASSERT("ret == len", ret == (int)len); + + /* wait a while: should be enough for the server to send a response */ + sys_msleep(1000); + + /* should not time out but receive a response */ + ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE); + LWIP_ASSERT("ret > 0", ret > 0); + +#if LWIP_SOCKET_SELECT + /* now select should directly return because the socket is readable */ + FD_ZERO(&readset); + FD_ZERO(&errset); + FD_SET(s, &readset); + FD_SET(s, &errset); + tv.tv_sec = 10; + tv.tv_usec = 0; + ret = lwip_select(s + 1, &readset, NULL, &errset, &tv); + LWIP_ASSERT("ret == 1", ret == 1); + LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); + LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset)); +#endif + + /* should not time out but receive a response */ + ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE); + /* might receive a second packet for HTTP/1.1 servers */ + if (ret > 0) { + /* should return 0: closed */ + ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE); + LWIP_ASSERT("ret == 0", ret == 0); + } + + /* close */ + ret = lwip_close(s); + LWIP_ASSERT("ret == 0", ret == 0); + LWIP_UNUSED_ARG(ret); + + printf("sockex_testrecv finished successfully\n"); +} + +#if LWIP_SOCKET_SELECT +/** helper struct for the 2 functions below (multithreaded: thread-argument) */ +struct sockex_select_helper { + int socket; + int wait_read; + int expect_read; + int wait_write; + int expect_write; + int wait_err; + int expect_err; + int wait_ms; + sys_sem_t sem; +}; + +/** helper thread to wait for socket events using select */ +static void +sockex_select_waiter(void *arg) +{ + struct sockex_select_helper *helper = (struct sockex_select_helper *)arg; + int ret; + fd_set readset; + fd_set writeset; + fd_set errset; + struct timeval tv; + + LWIP_ASSERT("helper != NULL", helper != NULL); + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&errset); + if (helper->wait_read) { + FD_SET(helper->socket, &readset); + } + if (helper->wait_write) { + FD_SET(helper->socket, &writeset); + } + if (helper->wait_err) { + FD_SET(helper->socket, &errset); + } + + tv.tv_sec = helper->wait_ms / 1000; + tv.tv_usec = (helper->wait_ms % 1000) * 1000; + + ret = lwip_select(helper->socket, &readset, &writeset, &errset, &tv); + if (helper->expect_read || helper->expect_write || helper->expect_err) { + LWIP_ASSERT("ret > 0", ret > 0); + } else { + LWIP_ASSERT("ret == 0", ret == 0); + } + LWIP_UNUSED_ARG(ret); + if (helper->expect_read) { + LWIP_ASSERT("FD_ISSET(helper->socket, &readset)", FD_ISSET(helper->socket, &readset)); + } else { + LWIP_ASSERT("!FD_ISSET(helper->socket, &readset)", !FD_ISSET(helper->socket, &readset)); + } + if (helper->expect_write) { + LWIP_ASSERT("FD_ISSET(helper->socket, &writeset)", FD_ISSET(helper->socket, &writeset)); + } else { + LWIP_ASSERT("!FD_ISSET(helper->socket, &writeset)", !FD_ISSET(helper->socket, &writeset)); + } + if (helper->expect_err) { + LWIP_ASSERT("FD_ISSET(helper->socket, &errset)", FD_ISSET(helper->socket, &errset)); + } else { + LWIP_ASSERT("!FD_ISSET(helper->socket, &errset)", !FD_ISSET(helper->socket, &errset)); + } + sys_sem_signal(&helper->sem); +} + +/** This is an example function that tests + more than one thread being active in select. */ +static void +sockex_testtwoselects(void *arg) +{ + int s1; + int s2; + int ret; +#if LWIP_IPV6 + struct sockaddr_in6 addr; +#else /* LWIP_IPV6 */ + struct sockaddr_in addr; +#endif /* LWIP_IPV6 */ + size_t len; + err_t lwiperr; + struct sockex_select_helper h1, h2, h3, h4; + const ip_addr_t *ipaddr = (const ip_addr_t*)arg; + + /* set up address to connect to */ + memset(&addr, 0, sizeof(addr)); +#if LWIP_IPV6 + addr.sin6_len = sizeof(addr); + addr.sin6_family = AF_INET6; + addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT); + inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr)); +#else /* LWIP_IPV6 */ + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); + inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr)); +#endif /* LWIP_IPV6 */ + + /* create the sockets */ +#if LWIP_IPV6 + s1 = lwip_socket(AF_INET6, SOCK_STREAM, 0); + s2 = lwip_socket(AF_INET6, SOCK_STREAM, 0); +#else /* LWIP_IPV6 */ + s1 = lwip_socket(AF_INET, SOCK_STREAM, 0); + s2 = lwip_socket(AF_INET, SOCK_STREAM, 0); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("s1 >= 0", s1 >= 0); + LWIP_ASSERT("s2 >= 0", s2 >= 0); + + /* connect, should succeed */ + ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr)); + LWIP_ASSERT("ret == 0", ret == 0); + ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr)); + LWIP_ASSERT("ret == 0", ret == 0); + + /* write the start of a GET request */ +#define SNDSTR1 "G" + len = strlen(SNDSTR1); + ret = lwip_write(s1, SNDSTR1, len); + LWIP_ASSERT("ret == len", ret == (int)len); + ret = lwip_write(s2, SNDSTR1, len); + LWIP_ASSERT("ret == len", ret == (int)len); + LWIP_UNUSED_ARG(ret); + + h1.wait_read = 1; + h1.wait_write = 1; + h1.wait_err = 1; + h1.expect_read = 0; + h1.expect_write = 0; + h1.expect_err = 0; + lwiperr = sys_sem_new(&h1.sem, 0); + LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); + h1.socket = s1; + h1.wait_ms = 500; + + h2 = h1; + lwiperr = sys_sem_new(&h2.sem, 0); + LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); + h2.socket = s2; + h2.wait_ms = 1000; + + h3 = h1; + lwiperr = sys_sem_new(&h3.sem, 0); + LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); + h3.socket = s2; + h3.wait_ms = 1500; + + h4 = h1; + lwiperr = sys_sem_new(&h4.sem, 0); + LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); + LWIP_UNUSED_ARG(lwiperr); + h4.socket = s2; + h4.wait_ms = 2000; + + /* select: all sockets should time out if the other side is a good HTTP server */ + + sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0); + sys_msleep(100); + sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0); + sys_msleep(100); + sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0); + sys_msleep(100); + sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0); + + sys_sem_wait(&h1.sem); + sys_sem_wait(&h2.sem); + sys_sem_wait(&h3.sem); + sys_sem_wait(&h4.sem); + + /* close */ + ret = lwip_close(s1); + LWIP_ASSERT("ret == 0", ret == 0); + ret = lwip_close(s2); + LWIP_ASSERT("ret == 0", ret == 0); + + printf("sockex_testtwoselects finished successfully\n"); +} +#else +static void +sockex_testtwoselects(void *arg) +{ + LWIP_UNUSED_ARG(arg); +} +#endif + +#if !SOCKET_EXAMPLES_RUN_PARALLEL +static void +socket_example_test(void* arg) +{ + sys_msleep(1000); + sockex_nonblocking_connect(arg); + sockex_testrecv(arg); + sockex_testtwoselects(arg); + printf("all tests done, thread ending\n"); +} +#endif + +void socket_examples_init(void) +{ + int addr_ok; +#if LWIP_IPV6 + IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V6); + addr_ok = ip6addr_aton(SOCK_TARGET_HOST6, ip_2_ip6(&dstaddr)); +#else /* LWIP_IPV6 */ + IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V4); + addr_ok = ip4addr_aton(SOCK_TARGET_HOST4, ip_2_ip4(&dstaddr)); +#endif /* LWIP_IPV6 */ + LWIP_ASSERT("invalid address", addr_ok); +#if SOCKET_EXAMPLES_RUN_PARALLEL + sys_thread_new("sockex_nonblocking_connect", sockex_nonblocking_connect, &dstaddr, 0, 0); + sys_thread_new("sockex_testrecv", sockex_testrecv, &dstaddr, 0, 0); + sys_thread_new("sockex_testtwoselects", sockex_testtwoselects, &dstaddr, 0, 0); +#else + sys_thread_new("socket_example_test", socket_example_test, &dstaddr, 0, 0); +#endif +} + +#endif /* LWIP_SOCKET */ diff --git a/contrib/apps/socket_examples/socket_examples.h b/contrib/apps/socket_examples/socket_examples.h new file mode 100644 index 0000000..354d03a --- /dev/null +++ b/contrib/apps/socket_examples/socket_examples.h @@ -0,0 +1,6 @@ +#ifndef LWIP_SOCKET_EXAMPLES_H +#define LWIP_SOCKET_EXAMPLES_H + +void socket_examples_init(void); + +#endif /* LWIP_SOCKET_EXAMPLES_H */ diff --git a/contrib/apps/tcpecho/tcpecho.c b/contrib/apps/tcpecho/tcpecho.c new file mode 100644 index 0000000..8fe1359 --- /dev/null +++ b/contrib/apps/tcpecho/tcpecho.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#include "tcpecho.h" + +#include "lwip/opt.h" + +#if LWIP_NETCONN + +#include "lwip/sys.h" +#include "lwip/api.h" +/*-----------------------------------------------------------------------------------*/ +static void +tcpecho_thread(void *arg) +{ + struct netconn *conn, *newconn; + err_t err; + LWIP_UNUSED_ARG(arg); + + /* Create a new connection identifier. */ + /* Bind connection to well known port number 7. */ +#if LWIP_IPV6 + conn = netconn_new(NETCONN_TCP_IPV6); + netconn_bind(conn, IP6_ADDR_ANY, 7); +#else /* LWIP_IPV6 */ + conn = netconn_new(NETCONN_TCP); + netconn_bind(conn, IP_ADDR_ANY, 7); +#endif /* LWIP_IPV6 */ + LWIP_ERROR("tcpecho: invalid conn", (conn != NULL), return;); + + /* Tell connection to go into listening mode. */ + netconn_listen(conn); + + while (1) { + + /* Grab new connection. */ + err = netconn_accept(conn, &newconn); + /*printf("accepted new connection %p\n", newconn);*/ + /* Process the new connection. */ + if (err == ERR_OK) { + struct netbuf *buf; + void *data; + u16_t len; + + while ((err = netconn_recv(newconn, &buf)) == ERR_OK) { + /*printf("Recved\n");*/ + do { + netbuf_data(buf, &data, &len); + err = netconn_write(newconn, data, len, NETCONN_COPY); +#if 0 + if (err != ERR_OK) { + printf("tcpecho: netconn_write: error \"%s\"\n", lwip_strerr(err)); + } +#endif + } while (netbuf_next(buf) >= 0); + netbuf_delete(buf); + } + /*printf("Got EOF, looping\n");*/ + /* Close connection and discard connection identifier. */ + netconn_close(newconn); + netconn_delete(newconn); + } + } +} +/*-----------------------------------------------------------------------------------*/ +void +tcpecho_init(void) +{ + sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} +/*-----------------------------------------------------------------------------------*/ + +#endif /* LWIP_NETCONN */ diff --git a/contrib/apps/tcpecho/tcpecho.h b/contrib/apps/tcpecho/tcpecho.h new file mode 100644 index 0000000..b27c50f --- /dev/null +++ b/contrib/apps/tcpecho/tcpecho.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_TCPECHO_H +#define LWIP_TCPECHO_H + +void tcpecho_init(void); + +#endif /* LWIP_TCPECHO_H */ diff --git a/contrib/apps/tcpecho_raw/tcpecho_raw.c b/contrib/apps/tcpecho_raw/tcpecho_raw.c new file mode 100644 index 0000000..5a71d84 --- /dev/null +++ b/contrib/apps/tcpecho_raw/tcpecho_raw.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of and a contribution to the lwIP TCP/IP stack. + * + * Credits go to Adam Dunkels (and the current maintainers) of this software. + * + * Christiaan Simons rewrote this file to get a more stable echo example. + */ + +/** + * @file + * TCP echo server example using raw API. + * + * Echos all bytes sent by connecting client, + * and passively closes when client is done. + * + */ + +#include "lwip/opt.h" +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/tcp.h" +#include "tcpecho_raw.h" + +#if LWIP_TCP && LWIP_CALLBACK_API + +static struct tcp_pcb *tcpecho_raw_pcb; + +enum tcpecho_raw_states +{ + ES_NONE = 0, + ES_ACCEPTED, + ES_RECEIVED, + ES_CLOSING +}; + +struct tcpecho_raw_state +{ + u8_t state; + u8_t retries; + struct tcp_pcb *pcb; + /* pbuf (chain) to recycle */ + struct pbuf *p; +}; + +static void +tcpecho_raw_free(struct tcpecho_raw_state *es) +{ + if (es != NULL) { + if (es->p) { + /* free the buffer chain if present */ + pbuf_free(es->p); + } + + mem_free(es); + } +} + +static void +tcpecho_raw_close(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) +{ + tcp_arg(tpcb, NULL); + tcp_sent(tpcb, NULL); + tcp_recv(tpcb, NULL); + tcp_err(tpcb, NULL); + tcp_poll(tpcb, NULL, 0); + + tcpecho_raw_free(es); + + tcp_close(tpcb); +} + +static void +tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) +{ + struct pbuf *ptr; + err_t wr_err = ERR_OK; + + while ((wr_err == ERR_OK) && + (es->p != NULL) && + (es->p->len <= tcp_sndbuf(tpcb))) { + ptr = es->p; + + /* enqueue data for transmission */ + wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1); + if (wr_err == ERR_OK) { + u16_t plen; + + plen = ptr->len; + /* continue with next pbuf in chain (if any) */ + es->p = ptr->next; + if(es->p != NULL) { + /* new reference! */ + pbuf_ref(es->p); + } + /* chop first pbuf from chain */ + pbuf_free(ptr); + /* we can read more data now */ + tcp_recved(tpcb, plen); + } else if(wr_err == ERR_MEM) { + /* we are low on memory, try later / harder, defer to poll */ + es->p = ptr; + } else { + /* other problem ?? */ + } + } +} + +static void +tcpecho_raw_error(void *arg, err_t err) +{ + struct tcpecho_raw_state *es; + + LWIP_UNUSED_ARG(err); + + es = (struct tcpecho_raw_state *)arg; + + tcpecho_raw_free(es); +} + +static err_t +tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb) +{ + err_t ret_err; + struct tcpecho_raw_state *es; + + es = (struct tcpecho_raw_state *)arg; + if (es != NULL) { + if (es->p != NULL) { + /* there is a remaining pbuf (chain) */ + tcpecho_raw_send(tpcb, es); + } else { + /* no remaining pbuf (chain) */ + if(es->state == ES_CLOSING) { + tcpecho_raw_close(tpcb, es); + } + } + ret_err = ERR_OK; + } else { + /* nothing to be done */ + tcp_abort(tpcb); + ret_err = ERR_ABRT; + } + return ret_err; +} + +static err_t +tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + struct tcpecho_raw_state *es; + + LWIP_UNUSED_ARG(len); + + es = (struct tcpecho_raw_state *)arg; + es->retries = 0; + + if(es->p != NULL) { + /* still got pbufs to send */ + tcp_sent(tpcb, tcpecho_raw_sent); + tcpecho_raw_send(tpcb, es); + } else { + /* no more pbufs to send */ + if(es->state == ES_CLOSING) { + tcpecho_raw_close(tpcb, es); + } + } + return ERR_OK; +} + +static err_t +tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + struct tcpecho_raw_state *es; + err_t ret_err; + + LWIP_ASSERT("arg != NULL",arg != NULL); + es = (struct tcpecho_raw_state *)arg; + if (p == NULL) { + /* remote host closed connection */ + es->state = ES_CLOSING; + if(es->p == NULL) { + /* we're done sending, close it */ + tcpecho_raw_close(tpcb, es); + } else { + /* we're not done yet */ + tcpecho_raw_send(tpcb, es); + } + ret_err = ERR_OK; + } else if(err != ERR_OK) { + /* cleanup, for unknown reason */ + LWIP_ASSERT("no pbuf expected here", p == NULL); + ret_err = err; + } + else if(es->state == ES_ACCEPTED) { + /* first data chunk in p->payload */ + es->state = ES_RECEIVED; + /* store reference to incoming pbuf (chain) */ + es->p = p; + tcpecho_raw_send(tpcb, es); + ret_err = ERR_OK; + } else if (es->state == ES_RECEIVED) { + /* read some more data */ + if(es->p == NULL) { + es->p = p; + tcpecho_raw_send(tpcb, es); + } else { + struct pbuf *ptr; + + /* chain pbufs to the end of what we recv'ed previously */ + ptr = es->p; + pbuf_cat(ptr,p); + } + ret_err = ERR_OK; + } else { + /* unknown es->state, trash data */ + tcp_recved(tpcb, p->tot_len); + pbuf_free(p); + ret_err = ERR_OK; + } + return ret_err; +} + +static err_t +tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + err_t ret_err; + struct tcpecho_raw_state *es; + + LWIP_UNUSED_ARG(arg); + if ((err != ERR_OK) || (newpcb == NULL)) { + return ERR_VAL; + } + + /* Unless this pcb should have NORMAL priority, set its priority now. + When running out of pcbs, low priority pcbs can be aborted to create + new pcbs of higher priority. */ + tcp_setprio(newpcb, TCP_PRIO_MIN); + + es = (struct tcpecho_raw_state *)mem_malloc(sizeof(struct tcpecho_raw_state)); + if (es != NULL) { + es->state = ES_ACCEPTED; + es->pcb = newpcb; + es->retries = 0; + es->p = NULL; + /* pass newly allocated es to our callbacks */ + tcp_arg(newpcb, es); + tcp_recv(newpcb, tcpecho_raw_recv); + tcp_err(newpcb, tcpecho_raw_error); + tcp_poll(newpcb, tcpecho_raw_poll, 0); + tcp_sent(newpcb, tcpecho_raw_sent); + ret_err = ERR_OK; + } else { + ret_err = ERR_MEM; + } + return ret_err; +} + +void +tcpecho_raw_init(void) +{ + tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + if (tcpecho_raw_pcb != NULL) { + err_t err; + + err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7); + if (err == ERR_OK) { + tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb); + tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept); + } else { + /* abort? output diagnostic? */ + } + } else { + /* abort? output diagnostic? */ + } +} + +#endif /* LWIP_TCP && LWIP_CALLBACK_API */ diff --git a/contrib/apps/tcpecho_raw/tcpecho_raw.h b/contrib/apps/tcpecho_raw/tcpecho_raw.h new file mode 100644 index 0000000..d1e3b33 --- /dev/null +++ b/contrib/apps/tcpecho_raw/tcpecho_raw.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_TCPECHO_RAW_H +#define LWIP_TCPECHO_RAW_H + +void tcpecho_raw_init(void); + +#endif /* LWIP_TCPECHO_RAW_H */ diff --git a/contrib/apps/udpecho/udpecho.c b/contrib/apps/udpecho/udpecho.c new file mode 100644 index 0000000..b68301e --- /dev/null +++ b/contrib/apps/udpecho/udpecho.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "udpecho.h" + +#include "lwip/opt.h" + +#if LWIP_NETCONN + +#include "lwip/api.h" +#include "lwip/sys.h" + +/*-----------------------------------------------------------------------------------*/ +static void +udpecho_thread(void *arg) +{ + struct netconn *conn; + struct netbuf *buf; + char buffer[4096]; + err_t err; + LWIP_UNUSED_ARG(arg); + +#if LWIP_IPV6 + conn = netconn_new(NETCONN_UDP_IPV6); + LWIP_ERROR("udpecho: invalid conn", (conn != NULL), return;); + netconn_bind(conn, IP6_ADDR_ANY, 7); +#else /* LWIP_IPV6 */ + conn = netconn_new(NETCONN_UDP); + LWIP_ERROR("udpecho: invalid conn", (conn != NULL), return;); + netconn_bind(conn, IP_ADDR_ANY, 7); +#endif /* LWIP_IPV6 */ + + while (1) { + err = netconn_recv(conn, &buf); + if (err == ERR_OK) { + /* no need netconn_connect here, since the netbuf contains the address */ + if(netbuf_copy(buf, buffer, sizeof(buffer)) != buf->p->tot_len) { + LWIP_DEBUGF(LWIP_DBG_ON, ("netbuf_copy failed\n")); + } else { + buffer[buf->p->tot_len] = '\0'; + err = netconn_send(conn, buf); + if(err != ERR_OK) { + LWIP_DEBUGF(LWIP_DBG_ON, ("netconn_send failed: %d\n", (int)err)); + } else { + LWIP_DEBUGF(LWIP_DBG_ON, ("got %s\n", buffer)); + } + } + netbuf_delete(buf); + } + } +} +/*-----------------------------------------------------------------------------------*/ +void +udpecho_init(void) +{ + sys_thread_new("udpecho_thread", udpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +#endif /* LWIP_NETCONN */ diff --git a/contrib/apps/udpecho/udpecho.h b/contrib/apps/udpecho/udpecho.h new file mode 100644 index 0000000..c438911 --- /dev/null +++ b/contrib/apps/udpecho/udpecho.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_UDPECHO_H +#define LWIP_UDPECHO_H + +void udpecho_init(void); + +#endif /* LWIP_UDPECHO_H */ diff --git a/contrib/apps/udpecho_raw/udpecho_raw.c b/contrib/apps/udpecho_raw/udpecho_raw.c new file mode 100644 index 0000000..43c9f0b --- /dev/null +++ b/contrib/apps/udpecho_raw/udpecho_raw.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Stephan Linz , Li-Pro.Net + * All rights reserved. + * + * Based on examples provided by + * Iwan Budi Kusnanto (https://gist.github.com/iwanbk/1399729) + * Juri Haberland (https://lists.gnu.org/archive/html/lwip-users/2007-06/msg00078.html) + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of and a contribution to the lwIP TCP/IP stack. + * + * Credits go to Adam Dunkels (and the current maintainers) of this software. + * + * Stephan Linz rewrote this file to get a basic echo example. + */ + +/** + * @file + * UDP echo server example using raw API. + * + * Echos all bytes sent by connecting client, + * and passively closes when client is done. + * + */ + +#include "lwip/opt.h" +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/udp.h" +#include "udpecho_raw.h" + +#if LWIP_UDP + +static struct udp_pcb *udpecho_raw_pcb; + +static void +udpecho_raw_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port) +{ + LWIP_UNUSED_ARG(arg); + if (p != NULL) { + /* send received packet back to sender */ + udp_sendto(upcb, p, addr, port); + /* free the pbuf */ + pbuf_free(p); + } +} + +void +udpecho_raw_init(void) +{ + udpecho_raw_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (udpecho_raw_pcb != NULL) { + err_t err; + + err = udp_bind(udpecho_raw_pcb, IP_ANY_TYPE, 7); + if (err == ERR_OK) { + udp_recv(udpecho_raw_pcb, udpecho_raw_recv, NULL); + } else { + /* abort? output diagnostic? */ + } + } else { + /* abort? output diagnostic? */ + } +} + +#endif /* LWIP_UDP */ diff --git a/contrib/apps/udpecho_raw/udpecho_raw.h b/contrib/apps/udpecho_raw/udpecho_raw.h new file mode 100644 index 0000000..4a98b74 --- /dev/null +++ b/contrib/apps/udpecho_raw/udpecho_raw.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Stephan Linz , Li-Pro.Net + * All rights reserved. + * + * Based on examples provided by + * Iwan Budi Kusnanto (https://gist.github.com/iwanbk/1399729) + * Juri Haberland (https://lists.gnu.org/archive/html/lwip-users/2007-06/msg00078.html) + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_UDPECHO_RAW_H +#define LWIP_UDPECHO_RAW_H + +void udpecho_raw_init(void); + +#endif /* LWIP_UDPECHO_RAW_H */ diff --git a/contrib/examples/ethernetif/ethernetif.c b/contrib/examples/ethernetif/ethernetif.c new file mode 100644 index 0000000..79763e8 --- /dev/null +++ b/contrib/examples/ethernetif/ethernetif.c @@ -0,0 +1,337 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" + +#if 0 /* don't build, this is only a skeleton, see previous comment */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "lwip/etharp.h" +#include "netif/ppp/pppoe.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +/* Forward declarations. */ +static void ethernetif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = ; + ... + netif->hwaddr[5] = ; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + /* Do whatever else is needed to initialize interface. */ +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + + initiate transfer(); + +#if ETH_PAD_SIZE + pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */ +#endif + + for (q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + send data from(q->payload, q->len); + } + + signal that packet should be sent(); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } else { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + /* increase ifoutdiscards or ifouterrors on error */ + +#if ETH_PAD_SIZE + pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p, *q; + u16_t len; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = ; + +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) { + +#if ETH_PAD_SIZE + pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */ +#endif + + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for (q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + * available data in the pbuf is given by the q->len + * variable. + * This does not necessarily have to be a memcpy, you can also preallocate + * pbufs for a DMA-enabled MAC and after receiving truncate it to the + * actually received size. In this case, ensure the tot_len member of the + * pbuf is the sum of the chained pbuf len members. + */ + read data into(q->payload, q->len); + } + acknowledge that packet has been read(); + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } else { + /* unicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } +#if ETH_PAD_SIZE + pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } else { + drop packet(); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +static void +ethernetif_input(struct netif *netif) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + struct pbuf *p; + + ethernetif = netif->state; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + /* if no packet could be read, silently ignore this */ + if (p != NULL) { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; + } + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]); + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + +#endif /* 0 */ diff --git a/contrib/examples/example_app/default_netif.h b/contrib/examples/example_app/default_netif.h new file mode 100644 index 0000000..1a64f02 --- /dev/null +++ b/contrib/examples/example_app/default_netif.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_DEFAULT_NETIF_H +#define LWIP_DEFAULT_NETIF_H + +#include "lwip/ip_addr.h" + +#if LWIP_IPV4 +void init_default_netif(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw); +#else +void init_default_netif(void); +#endif + +void default_netif_poll(void); +void default_netif_shutdown(void); + +#endif diff --git a/contrib/examples/example_app/lwipcfg.h.ci b/contrib/examples/example_app/lwipcfg.h.ci new file mode 100644 index 0000000..dc8477c --- /dev/null +++ b/contrib/examples/example_app/lwipcfg.h.ci @@ -0,0 +1,73 @@ +/** + * Additional settings for the example app. + * Copy this to lwipcfg.h and make the config changes you need. + */ + +/* configuration for this port */ +#define PPP_USERNAME "Admin" +#define PPP_PASSWORD "pass" + +/** Define this to the index of the windows network adapter to use */ +#define PACKET_LIB_ADAPTER_NR 1 +/** Define this to the GUID of the windows network adapter to use + * or NOT define this if you want PACKET_LIB_ADAPTER_NR to be used */ +/*#define PACKET_LIB_ADAPTER_GUID "00000000-0000-0000-0000-000000000000"*/ +/*#define PACKET_LIB_GET_ADAPTER_NETADDRESS(addr) IP4_ADDR((addr), 192,168,1,0)*/ +/*#define PACKET_LIB_QUIET*/ + +/* #define USE_PCAPIF 1 */ +#define LWIP_PORT_INIT_IPADDR(addr) IP4_ADDR((addr), 192,168,1,200) +#define LWIP_PORT_INIT_GW(addr) IP4_ADDR((addr), 192,168,1,1) +#define LWIP_PORT_INIT_NETMASK(addr) IP4_ADDR((addr), 255,255,255,0) + +/* remember to change this MAC address to suit your needs! + the last octet will be increased by netif->num for each netif */ +#define LWIP_MAC_ADDR_BASE {0x00,0x01,0x02,0x03,0x04,0x05} + +/* #define USE_SLIPIF 0 */ +/* #define SIO_USE_COMPORT 0 */ +#ifdef USE_SLIPIF +#if USE_SLIPIF +#define LWIP_PORT_INIT_SLIP1_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 2) +#define LWIP_PORT_INIT_SLIP1_GW(addr) IP4_ADDR((addr), 192, 168, 2, 1) +#define LWIP_PORT_INIT_SLIP1_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0) +#if USE_SLIPIF > 1 +#define LWIP_PORT_INIT_SLIP2_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 1) +#define LWIP_PORT_INIT_SLIP2_GW(addr) IP4_ADDR((addr), 0, 0, 0, 0) +#define LWIP_PORT_INIT_SLIP2_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0)*/ +#endif /* USE_SLIPIF > 1 */ +#endif /* USE_SLIPIF */ +#endif /* USE_SLIPIF */ + +/* configuration for applications */ + +#define LWIP_CHARGEN_APP 1 +#define LWIP_DNS_APP 1 +#define LWIP_HTTPD_APP LWIP_TCP +/* Set this to 1 to use the netconn http server, + * otherwise the raw api server will be used. */ +/*#define LWIP_HTTPD_APP_NETCONN */ +#define LWIP_NETBIOS_APP LWIP_IPV4 && LWIP_UDP +#define LWIP_NETIO_APP 1 +#define LWIP_MDNS_APP LWIP_UDP +#define LWIP_MQTT_APP LWIP_TCP +#define LWIP_PING_APP 1 +#define LWIP_RTP_APP 1 +#define LWIP_SHELL_APP LWIP_TCP +#define LWIP_SNMP_APP LWIP_UDP +#define LWIP_SNTP_APP LWIP_UDP +#define LWIP_SOCKET_EXAMPLES_APP 1 +#define LWIP_TCPECHO_APP LWIP_TCP +/* Set this to 1 to use the netconn tcpecho server, + * otherwise the raw api server will be used. */ +/*#define LWIP_TCPECHO_APP_NETCONN */ +#define LWIP_TFTP_APP LWIP_UDP +#define LWIP_TFTP_CLIENT_APP LWIP_UDP +#define LWIP_UDPECHO_APP LWIP_UDP +#define LWIP_LWIPERF_APP LWIP_TCP + +#define USE_DHCP LWIP_DHCP +#define USE_AUTOIP LWIP_AUTOIP + +/* define this to your custom application-init function */ +/* #define LWIP_APP_INIT my_app_init() */ diff --git a/contrib/examples/example_app/lwipcfg.h.example b/contrib/examples/example_app/lwipcfg.h.example new file mode 100644 index 0000000..b21e19b --- /dev/null +++ b/contrib/examples/example_app/lwipcfg.h.example @@ -0,0 +1,77 @@ +/** + * Additional settings for the example app. + * Copy this to lwipcfg.h and make the config changes you need. + */ + +/* configuration for this port */ +#define PPP_USERNAME "Admin" +#define PPP_PASSWORD "pass" + +/** Define this to the index of the windows network adapter to use */ +#define PACKET_LIB_ADAPTER_NR 1 +/** Define this to the GUID of the windows network adapter to use + * or NOT define this if you want PACKET_LIB_ADAPTER_NR to be used */ +/*#define PACKET_LIB_ADAPTER_GUID "00000000-0000-0000-0000-000000000000"*/ +/*#define PACKET_LIB_GET_ADAPTER_NETADDRESS(addr) IP4_ADDR((addr), 192,168,1,0)*/ +/*#define PACKET_LIB_QUIET*/ + +/* If these 2 are not defined, the corresponding config setting is used */ +/* #define USE_DHCP 0 */ +/* #define USE_AUTOIP 0 */ + +/* #define USE_PCAPIF 1 */ +#define LWIP_PORT_INIT_IPADDR(addr) IP4_ADDR((addr), 192,168,1,200) +#define LWIP_PORT_INIT_GW(addr) IP4_ADDR((addr), 192,168,1,1) +#define LWIP_PORT_INIT_NETMASK(addr) IP4_ADDR((addr), 255,255,255,0) + +/* remember to change this MAC address to suit your needs! + the last octet will be increased by netif->num for each netif */ +#define LWIP_MAC_ADDR_BASE {0x00,0x01,0x02,0x03,0x04,0x05} + +/* #define USE_SLIPIF 0 */ +/* #define SIO_USE_COMPORT 0 */ +#ifdef USE_SLIPIF +#if USE_SLIPIF +#define LWIP_PORT_INIT_SLIP1_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 2) +#define LWIP_PORT_INIT_SLIP1_GW(addr) IP4_ADDR((addr), 192, 168, 2, 1) +#define LWIP_PORT_INIT_SLIP1_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0) +#if USE_SLIPIF > 1 +#define LWIP_PORT_INIT_SLIP2_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 1) +#define LWIP_PORT_INIT_SLIP2_GW(addr) IP4_ADDR((addr), 0, 0, 0, 0) +#define LWIP_PORT_INIT_SLIP2_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0)*/ +#endif /* USE_SLIPIF > 1 */ +#endif /* USE_SLIPIF */ +#endif /* USE_SLIPIF */ + +/* configuration for applications */ + +#define LWIP_CHARGEN_APP 0 +#define LWIP_DNS_APP 0 +#define LWIP_HTTPD_APP 0 +/* Set this to 1 to use the netconn http server, + * otherwise the raw api server will be used. */ +/*#define LWIP_HTTPD_APP_NETCONN */ +#define LWIP_NETBIOS_APP 0 +#define LWIP_NETIO_APP 0 +#define LWIP_MDNS_APP 0 +#define LWIP_MQTT_APP 0 +#define LWIP_PING_APP 0 +#define LWIP_RTP_APP 0 +#define LWIP_SHELL_APP 0 +#define LWIP_SNMP_APP 0 +#define LWIP_SNTP_APP 0 +#define LWIP_SOCKET_EXAMPLES_APP 0 +#define LWIP_TCPECHO_APP 0 +/* Set this to 1 to use the netconn tcpecho server, + * otherwise the raw api server will be used. */ +/*#define LWIP_TCPECHO_APP_NETCONN */ +#define LWIP_TFTP_APP 0 +#define LWIP_TFTP_CLIENT_APP 0 +#define LWIP_UDPECHO_APP 0 +#define LWIP_LWIPERF_APP 0 + +/*#define USE_DHCP 1*/ +/*#define USE_AUTOIP 1*/ + +/* define this to your custom application-init function */ +/* #define LWIP_APP_INIT my_app_init() */ diff --git a/contrib/examples/example_app/lwipopts.h b/contrib/examples/example_app/lwipopts.h new file mode 100644 index 0000000..410b922 --- /dev/null +++ b/contrib/examples/example_app/lwipopts.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +#ifdef LWIP_OPTTEST_FILE +#include "lwipopts_test.h" +#else /* LWIP_OPTTEST_FILE */ + +#define LWIP_IPV4 1 +#define LWIP_IPV6 1 + +#define NO_SYS 0 +#define LWIP_SOCKET (NO_SYS==0) +#define LWIP_NETCONN (NO_SYS==0) +#define LWIP_NETIF_API (NO_SYS==0) + +#define LWIP_IGMP LWIP_IPV4 +#define LWIP_ICMP LWIP_IPV4 + +#define LWIP_SNMP LWIP_UDP +#define MIB2_STATS LWIP_SNMP +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_SNMP_V3 (LWIP_SNMP) +#endif + +#define LWIP_DNS LWIP_UDP +#define LWIP_MDNS_RESPONDER LWIP_UDP + +#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER) + +#define LWIP_HAVE_LOOPIF 1 +#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_LOOPBACK_MAX_PBUFS 10 + +#define TCP_LISTEN_BACKLOG 1 + +#define LWIP_COMPAT_SOCKETS 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_RCVBUF 1 + +#define LWIP_TCPIP_CORE_LOCKING 1 + +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 + +#ifdef LWIP_DEBUG + +#define LWIP_DBG_MIN_LEVEL 0 +#define PPP_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) + + +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ +/* MSVC port: intel processors don't need 4-byte alignment, + but are faster that way! */ +#define MEM_ALIGNMENT 4U + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#define MEM_SIZE 10240 + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#define MEMP_NUM_PBUF 16 +/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One + per active RAW "connection". */ +#define MEMP_NUM_RAW_PCB 3 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 8 +/* MEMP_NUM_TCP_PCB: the number of simultaneously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 5 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 16 +/* MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 17 + +/* The following four are used only with the sequential API and can be + set to 0 if the application only will use the raw API. */ +/* MEMP_NUM_NETBUF: the number of struct netbufs. */ +#define MEMP_NUM_NETBUF 2 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 12 +/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used + for sequential API communication and incoming packets. Used in + src/api/tcpip.c. */ +#define MEMP_NUM_TCPIP_MSG_API 16 +#define MEMP_NUM_TCPIP_MSG_INPKT 16 + + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 120 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 256 + +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT (NO_SYS==0) + + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +#define LWIP_ALTCP (LWIP_TCP) +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_ALTCP_TLS (LWIP_TCP) +#define LWIP_ALTCP_TLS_MBEDTLS (LWIP_TCP) +#endif + + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 1 + +/* TCP Maximum segment size. */ +#define TCP_MSS 1024 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF 2048 + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) + +/* TCP writable space (bytes). This must be less than or equal + to TCP_SND_BUF. It is the amount of space which must be + available in the tcp snd_buf for select to return writable */ +#define TCP_SNDLOWAT (TCP_SND_BUF/2) + +/* TCP receive window. */ +#define TCP_WND (20 * 1024) + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + + +/* ---------- ARP options ---------- */ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_QUEUEING 1 + + +/* ---------- IP options ---------- */ +/* Define IP_FORWARD to 1 if you wish to have the ability to forward + IP packets across network interfaces. If you are going to run lwIP + on a device with only one network interface, define this to 0. */ +#define IP_FORWARD 1 + +/* IP reassembly and segmentation.These are orthogonal even + * if they both deal with IP fragments */ +#define IP_REASSEMBLY 1 +#define IP_REASS_MAX_PBUFS (10 * ((1500 + PBUF_POOL_BUFSIZE - 1) / PBUF_POOL_BUFSIZE)) +#define MEMP_NUM_REASSDATA IP_REASS_MAX_PBUFS +#define IP_FRAG 1 +#define IPV6_FRAG_COPYHEADER 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. */ +#define LWIP_DHCP LWIP_UDP + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK (LWIP_DHCP) + + +/* ---------- AUTOIP options ------- */ +#define LWIP_AUTOIP (LWIP_DHCP) +#define LWIP_DHCP_AUTOIP_COOP (LWIP_DHCP && LWIP_AUTOIP) + + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define LWIP_UDPLITE LWIP_UDP +#define UDP_TTL 255 + + +/* ---------- RAW options ---------- */ +#define LWIP_RAW 1 + + +/* ---------- Statistics options ---------- */ + +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 + +#if LWIP_STATS +#define LINK_STATS 1 +#define IP_STATS 1 +#define ICMP_STATS 1 +#define IGMP_STATS 1 +#define IPFRAG_STATS 1 +#define UDP_STATS 1 +#define TCP_STATS 1 +#define MEM_STATS 1 +#define MEMP_STATS 1 +#define PBUF_STATS 1 +#define SYS_STATS 1 +#endif /* LWIP_STATS */ + +/* ---------- NETBIOS options ---------- */ +#define LWIP_NETBIOS_RESPOND_NAME_QUERY 1 + +/* ---------- PPP options ---------- */ + +#define PPP_SUPPORT 1 /* Set > 0 for PPP */ + +#if PPP_SUPPORT + +#define NUM_PPP 1 /* Max PPP sessions. */ + + +/* Select modules to enable. Ideally these would be set in the makefile but + * we're limited by the command line length so you need to modify the settings + * in this file. + */ +#define PPPOE_SUPPORT 1 +#define PPPOS_SUPPORT 1 + +#define PAP_SUPPORT 1 /* Set > 0 for PAP. */ +#define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */ +#define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP */ +#define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */ +#define CCP_SUPPORT 0 /* Set > 0 for CCP */ +#define VJ_SUPPORT 0 /* Set > 0 for VJ header compression. */ +#define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */ + +#endif /* PPP_SUPPORT */ + +#endif /* LWIP_OPTTEST_FILE */ + +/* The following defines must be done even in OPTTEST mode: */ + +#if !defined(NO_SYS) || !NO_SYS /* default is 0 */ +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() +#endif + +#ifndef LWIP_PLATFORM_ASSERT +/* Define LWIP_PLATFORM_ASSERT to something to catch missing stdio.h includes */ +void lwip_example_app_platform_assert(const char *msg, int line, const char *file); +#define LWIP_PLATFORM_ASSERT(x) lwip_example_app_platform_assert(x, __LINE__, __FILE__) +#endif + +#endif /* LWIP_LWIPOPTS_H */ diff --git a/contrib/examples/example_app/lwippools.h b/contrib/examples/example_app/lwippools.h new file mode 100644 index 0000000..f58aa59 --- /dev/null +++ b/contrib/examples/example_app/lwippools.h @@ -0,0 +1,20 @@ +/* OPTIONAL: Pools to replace heap allocation + * Optional: Pools can be used instead of the heap for mem_malloc. If + * so, these should be defined here, in increasing order according to + * the pool element size. + * + * LWIP_MALLOC_MEMPOOL(number_elements, element_size) + */ +#if MEM_USE_POOLS +LWIP_MALLOC_MEMPOOL_START +LWIP_MALLOC_MEMPOOL(100, 256) +LWIP_MALLOC_MEMPOOL(50, 512) +LWIP_MALLOC_MEMPOOL(20, 1024) +LWIP_MALLOC_MEMPOOL(20, 1536) +LWIP_MALLOC_MEMPOOL_END +#endif /* MEM_USE_POOLS */ + +/* Optional: Your custom pools can go here if you would like to use + * lwIP's memory pools for anything else. + */ +LWIP_MEMPOOL(SYS_MBOX, 22, 100, "SYS_MBOX") diff --git a/contrib/examples/example_app/ppp_settings.h b/contrib/examples/example_app/ppp_settings.h new file mode 100644 index 0000000..7b3ee1a --- /dev/null +++ b/contrib/examples/example_app/ppp_settings.h @@ -0,0 +1,6 @@ +#ifdef _MSC_VER +#pragma warning (disable: 4242) /* PPP only: conversion from 'x' to 'y', possible loss of data */ +#pragma warning (disable: 4244) /* PPP only: conversion from 'x' to 'y', possible loss of data (again?) */ +#pragma warning (disable: 4310) /* PPP only: cast truncates constant value */ +#pragma warning (disable: 4706) /* PPP only: assignment within conditional expression */ +#endif /* MSC_VER */ diff --git a/contrib/examples/example_app/test.c b/contrib/examples/example_app/test.c new file mode 100644 index 0000000..4f4b5d7 --- /dev/null +++ b/contrib/examples/example_app/test.c @@ -0,0 +1,773 @@ +/* + * Copyright (c) 2001,2002 Florian Schulze. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the authors nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * test.c - This file is part of lwIP test + * + */ + +/* C runtime includes */ +#include +#include +#include +#include +#include + +/* lwIP core includes */ +#include "lwip/opt.h" + +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/init.h" +#include "lwip/tcpip.h" +#include "lwip/netif.h" +#include "lwip/api.h" + +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +/* lwIP netif includes */ +#include "lwip/etharp.h" +#include "netif/ethernet.h" + +/* applications includes */ +#include "lwip/apps/netbiosns.h" +#include "lwip/apps/httpd.h" +#include "apps/httpserver/httpserver-netconn.h" +#include "apps/netio/netio.h" +#include "apps/ping/ping.h" +#include "apps/rtp/rtp.h" +#include "apps/chargen/chargen.h" +#include "apps/shell/shell.h" +#include "apps/tcpecho/tcpecho.h" +#include "apps/udpecho/udpecho.h" +#include "apps/tcpecho_raw/tcpecho_raw.h" +#include "apps/socket_examples/socket_examples.h" + +#include "examples/lwiperf/lwiperf_example.h" +#include "examples/mdns/mdns_example.h" +#include "examples/snmp/snmp_example.h" +#include "examples/tftp/tftp_example.h" +#include "examples/sntp/sntp_example.h" +#include "examples/mqtt/mqtt_example.h" + +#include "examples/httpd/cgi_example/cgi_example.h" +#include "examples/httpd/fs_example/fs_example.h" +#include "examples/httpd/https_example/https_example.h" +#include "examples/httpd/ssi_example/ssi_example.h" + +#include "default_netif.h" + +#if NO_SYS +/* ... then we need information about the timer intervals: */ +#include "lwip/ip4_frag.h" +#include "lwip/igmp.h" +#endif /* NO_SYS */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT +/* PPP includes */ +#include "lwip/sio.h" +#include "netif/ppp/pppapi.h" +#include "netif/ppp/pppos.h" +#include "netif/ppp/pppoe.h" +#if !NO_SYS && !LWIP_PPP_API +#error With NO_SYS==0, LWIP_PPP_API==1 is required. +#endif +#endif /* PPP_SUPPORT */ + +/* include the port-dependent configuration */ +#include "lwipcfg.h" + +#ifndef LWIP_EXAMPLE_APP_ABORT +#define LWIP_EXAMPLE_APP_ABORT() 0 +#endif + +/** Define this to 1 to enable a port-specific ethernet interface as default interface. */ +#ifndef USE_DEFAULT_ETH_NETIF +#define USE_DEFAULT_ETH_NETIF 1 +#endif + +/** Define this to 1 to enable a PPP interface. */ +#ifndef USE_PPP +#define USE_PPP 0 +#endif + +/** Define this to 1 or 2 to support 1 or 2 SLIP interfaces. */ +#ifndef USE_SLIPIF +#define USE_SLIPIF 0 +#endif + +/** Use an ethernet adapter? Default to enabled if port-specific ethernet netif or PPPoE are used. */ +#ifndef USE_ETHERNET +#define USE_ETHERNET (USE_DEFAULT_ETH_NETIF || PPPOE_SUPPORT) +#endif + +/** Use an ethernet adapter for TCP/IP? By default only if port-specific ethernet netif is used. */ +#ifndef USE_ETHERNET_TCPIP +#define USE_ETHERNET_TCPIP (USE_DEFAULT_ETH_NETIF) +#endif + +#if USE_SLIPIF +#include +#endif /* USE_SLIPIF */ + +#ifndef USE_DHCP +#define USE_DHCP LWIP_DHCP +#endif +#ifndef USE_AUTOIP +#define USE_AUTOIP LWIP_AUTOIP +#endif + +/* global variables for netifs */ +#if USE_ETHERNET +#if LWIP_DHCP +/* dhcp struct for the ethernet netif */ +static struct dhcp netif_dhcp; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP +/* autoip struct for the ethernet netif */ +static struct autoip netif_autoip; +#endif /* LWIP_AUTOIP */ +#endif /* USE_ETHERNET */ +#if USE_PPP +/* THE PPP PCB */ +static ppp_pcb *ppp; +/* THE PPP interface */ +static struct netif ppp_netif; +/* THE PPP descriptor */ +static u8_t sio_idx = 0; +static sio_fd_t ppp_sio; +#endif /* USE_PPP */ +#if USE_SLIPIF +static struct netif slipif1; +#if USE_SLIPIF > 1 +static struct netif slipif2; +#endif /* USE_SLIPIF > 1 */ +#endif /* USE_SLIPIF */ + + +#if USE_PPP +static void +pppLinkStatusCallback(ppp_pcb *pcb, int errCode, void *ctx) +{ + struct netif *pppif = ppp_netif(pcb); + LWIP_UNUSED_ARG(ctx); + + switch(errCode) { + case PPPERR_NONE: { /* No error. */ + printf("pppLinkStatusCallback: PPPERR_NONE\n"); +#if LWIP_IPV4 + printf(" our_ipaddr = %s\n", ip4addr_ntoa(netif_ip4_addr(pppif))); + printf(" his_ipaddr = %s\n", ip4addr_ntoa(netif_ip4_gw(pppif))); + printf(" netmask = %s\n", ip4addr_ntoa(netif_ip4_netmask(pppif))); +#endif /* LWIP_IPV4 */ +#if LWIP_DNS + printf(" dns1 = %s\n", ipaddr_ntoa(dns_getserver(0))); + printf(" dns2 = %s\n", ipaddr_ntoa(dns_getserver(1))); +#endif /* LWIP_DNS */ +#if PPP_IPV6_SUPPORT + printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); +#endif /* PPP_IPV6_SUPPORT */ + break; + } + case PPPERR_PARAM: { /* Invalid parameter. */ + printf("pppLinkStatusCallback: PPPERR_PARAM\n"); + break; + } + case PPPERR_OPEN: { /* Unable to open PPP session. */ + printf("pppLinkStatusCallback: PPPERR_OPEN\n"); + break; + } + case PPPERR_DEVICE: { /* Invalid I/O device for PPP. */ + printf("pppLinkStatusCallback: PPPERR_DEVICE\n"); + break; + } + case PPPERR_ALLOC: { /* Unable to allocate resources. */ + printf("pppLinkStatusCallback: PPPERR_ALLOC\n"); + break; + } + case PPPERR_USER: { /* User interrupt. */ + printf("pppLinkStatusCallback: PPPERR_USER\n"); + break; + } + case PPPERR_CONNECT: { /* Connection lost. */ + printf("pppLinkStatusCallback: PPPERR_CONNECT\n"); + break; + } + case PPPERR_AUTHFAIL: { /* Failed authentication challenge. */ + printf("pppLinkStatusCallback: PPPERR_AUTHFAIL\n"); + break; + } + case PPPERR_PROTOCOL: { /* Failed to meet protocol. */ + printf("pppLinkStatusCallback: PPPERR_PROTOCOL\n"); + break; + } + case PPPERR_PEERDEAD: { /* Connection timeout */ + printf("pppLinkStatusCallback: PPPERR_PEERDEAD\n"); + break; + } + case PPPERR_IDLETIMEOUT: { /* Idle Timeout */ + printf("pppLinkStatusCallback: PPPERR_IDLETIMEOUT\n"); + break; + } + case PPPERR_CONNECTTIME: { /* Max connect time reached */ + printf("pppLinkStatusCallback: PPPERR_CONNECTTIME\n"); + break; + } + case PPPERR_LOOPBACK: { /* Loopback detected */ + printf("pppLinkStatusCallback: PPPERR_LOOPBACK\n"); + break; + } + default: { + printf("pppLinkStatusCallback: unknown errCode %d\n", errCode); + break; + } + } +} + +#if PPPOS_SUPPORT +static u32_t +ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(ctx); + return sio_write(ppp_sio, (const u8_t*)data, len); +} +#endif /* PPPOS_SUPPORT */ +#endif /* USE_PPP */ + +#if LWIP_NETIF_STATUS_CALLBACK +static void +status_callback(struct netif *state_netif) +{ + if (netif_is_up(state_netif)) { +#if LWIP_IPV4 + printf("status_callback==UP, local interface IP is %s\n", ip4addr_ntoa(netif_ip4_addr(state_netif))); +#else + printf("status_callback==UP\n"); +#endif + } else { + printf("status_callback==DOWN\n"); + } +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +static void +link_callback(struct netif *state_netif) +{ + if (netif_is_link_up(state_netif)) { + printf("link_callback==UP\n"); + } else { + printf("link_callback==DOWN\n"); + } +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +/* This function initializes all network interfaces */ +static void +test_netif_init(void) +{ +#if LWIP_IPV4 && USE_ETHERNET + ip4_addr_t ipaddr, netmask, gw; +#endif /* LWIP_IPV4 && USE_ETHERNET */ +#if USE_SLIPIF + u8_t num_slip1 = 0; +#if LWIP_IPV4 + ip4_addr_t ipaddr_slip1, netmask_slip1, gw_slip1; +#endif +#if USE_SLIPIF > 1 + u8_t num_slip2 = 1; +#if LWIP_IPV4 + ip4_addr_t ipaddr_slip2, netmask_slip2, gw_slip2; +#endif +#endif /* USE_SLIPIF > 1 */ +#endif /* USE_SLIPIF */ +#if USE_DHCP || USE_AUTOIP + err_t err; +#endif + +#if USE_PPP + const char *username = NULL, *password = NULL; +#ifdef PPP_USERNAME + username = PPP_USERNAME; +#endif +#ifdef PPP_PASSWORD + password = PPP_PASSWORD; +#endif + printf("ppp_connect: COM%d\n", (int)sio_idx); +#if PPPOS_SUPPORT + ppp_sio = sio_open(sio_idx); + if (ppp_sio == NULL) { + printf("sio_open error\n"); + } else { + ppp = pppos_create(&ppp_netif, ppp_output_cb, pppLinkStatusCallback, NULL); + if (ppp == NULL) { + printf("pppos_create error\n"); + } else { + ppp_set_auth(ppp, PPPAUTHTYPE_ANY, username, password); + ppp_connect(ppp, 0); + } + } +#endif /* PPPOS_SUPPORT */ +#endif /* USE_PPP */ + +#if USE_ETHERNET +#if LWIP_IPV4 + ip4_addr_set_zero(&gw); + ip4_addr_set_zero(&ipaddr); + ip4_addr_set_zero(&netmask); +#if USE_ETHERNET_TCPIP +#if USE_DHCP + printf("Starting lwIP, local interface IP is dhcp-enabled\n"); +#elif USE_AUTOIP + printf("Starting lwIP, local interface IP is autoip-enabled\n"); +#else /* USE_DHCP */ + LWIP_PORT_INIT_GW(&gw); + LWIP_PORT_INIT_IPADDR(&ipaddr); + LWIP_PORT_INIT_NETMASK(&netmask); + printf("Starting lwIP, local interface IP is %s\n", ip4addr_ntoa(&ipaddr)); +#endif /* USE_DHCP */ +#endif /* USE_ETHERNET_TCPIP */ +#else /* LWIP_IPV4 */ + printf("Starting lwIP, IPv4 disable\n"); +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV4 + init_default_netif(&ipaddr, &netmask, &gw); +#else + init_default_netif(); +#endif +#if LWIP_IPV6 + netif_create_ip6_linklocal_address(netif_default, 1); + printf("ip6 linklocal address: %s\n", ip6addr_ntoa(netif_ip6_addr(netif_default, 0))); +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + netif_set_status_callback(netif_default, status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif_set_link_callback(netif_default, link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if USE_ETHERNET_TCPIP +#if LWIP_AUTOIP + autoip_set_struct(netif_default, &netif_autoip); +#endif /* LWIP_AUTOIP */ +#if LWIP_DHCP + dhcp_set_struct(netif_default, &netif_dhcp); +#endif /* LWIP_DHCP */ + netif_set_up(netif_default); +#if USE_DHCP + err = dhcp_start(netif_default); + LWIP_ASSERT("dhcp_start failed", err == ERR_OK); +#elif USE_AUTOIP + err = autoip_start(netif_default); + LWIP_ASSERT("autoip_start failed", err == ERR_OK); +#endif /* USE_DHCP */ +#else /* USE_ETHERNET_TCPIP */ + /* Use ethernet for PPPoE only */ + netif.flags &= ~(NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP); /* no ARP */ + netif.flags |= NETIF_FLAG_ETHERNET; /* but pure ethernet */ +#endif /* USE_ETHERNET_TCPIP */ + +#if USE_PPP && PPPOE_SUPPORT + /* start PPPoE after ethernet netif is added! */ + ppp = pppoe_create(&ppp_netif, netif_default, NULL, NULL, pppLinkStatusCallback, NULL); + if (ppp == NULL) { + printf("pppoe_create error\n"); + } else { + ppp_set_auth(ppp, PPPAUTHTYPE_ANY, username, password); + ppp_connect(ppp, 0); + } +#endif /* USE_PPP && PPPOE_SUPPORT */ + +#endif /* USE_ETHERNET */ +#if USE_SLIPIF +#if LWIP_IPV4 +#define SLIP1_ADDRS &ipaddr_slip1, &netmask_slip1, &gw_slip1, + LWIP_PORT_INIT_SLIP1_IPADDR(&ipaddr_slip1); + LWIP_PORT_INIT_SLIP1_GW(&gw_slip1); + LWIP_PORT_INIT_SLIP1_NETMASK(&netmask_slip1); + printf("Starting lwIP slipif, local interface IP is %s\n", ip4addr_ntoa(&ipaddr_slip1)); +#else +#define SLIP1_ADDRS + printf("Starting lwIP slipif\n"); +#endif +#if defined(SIO_USE_COMPORT) && SIO_USE_COMPORT + num_slip1++; /* COM ports cannot be 0-based */ +#endif + netif_add(&slipif1, SLIP1_ADDRS &num_slip1, slipif_init, ip_input); +#if !USE_ETHERNET + netif_set_default(&slipif1); +#endif /* !USE_ETHERNET */ +#if LWIP_IPV6 + netif_create_ip6_linklocal_address(&slipif1, 1); + printf("SLIP ip6 linklocal address: %s\n", ip6addr_ntoa(netif_ip6_addr(&slipif1, 0))); +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + netif_set_status_callback(&slipif1, status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif_set_link_callback(&slipif1, link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + netif_set_up(&slipif1); + +#if USE_SLIPIF > 1 +#if LWIP_IPV4 +#define SLIP2_ADDRS &ipaddr_slip2, &netmask_slip2, &gw_slip2, + LWIP_PORT_INIT_SLIP2_IPADDR(&ipaddr_slip2); + LWIP_PORT_INIT_SLIP2_GW(&gw_slip2); + LWIP_PORT_INIT_SLIP2_NETMASK(&netmask_slip2); + printf("Starting lwIP SLIP if #2, local interface IP is %s\n", ip4addr_ntoa(&ipaddr_slip2)); +#else +#define SLIP2_ADDRS + printf("Starting lwIP SLIP if #2\n"); +#endif +#if defined(SIO_USE_COMPORT) && SIO_USE_COMPORT + num_slip2++; /* COM ports cannot be 0-based */ +#endif + netif_add(&slipif2, SLIP2_ADDRS &num_slip2, slipif_init, ip_input); +#if LWIP_IPV6 + netif_create_ip6_linklocal_address(&slipif1, 1); + printf("SLIP2 ip6 linklocal address: "); + ip6_addr_debug_print(0xFFFFFFFF & ~LWIP_DBG_HALT, netif_ip6_addr(&slipif2, 0)); + printf("\n"); +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + netif_set_status_callback(&slipif2, status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif_set_link_callback(&slipif2, link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + netif_set_up(&slipif2); +#endif /* USE_SLIPIF > 1*/ +#endif /* USE_SLIPIF */ +} + +#if LWIP_DNS_APP && LWIP_DNS +static void +dns_found(const char *name, const ip_addr_t *addr, void *arg) +{ + LWIP_UNUSED_ARG(arg); + printf("%s: %s\n", name, addr ? ipaddr_ntoa(addr) : ""); +} + +static void +dns_dorequest(void *arg) +{ + const char* dnsname = "3com.com"; + ip_addr_t dnsresp; + LWIP_UNUSED_ARG(arg); + + if (dns_gethostbyname(dnsname, &dnsresp, dns_found, NULL) == ERR_OK) { + dns_found(dnsname, &dnsresp, NULL); + } +} +#endif /* LWIP_DNS_APP && LWIP_DNS */ + +/* This function initializes applications */ +static void +apps_init(void) +{ +#if LWIP_DNS_APP && LWIP_DNS + /* wait until the netif is up (for dhcp, autoip or ppp) */ + sys_timeout(5000, dns_dorequest, NULL); +#endif /* LWIP_DNS_APP && LWIP_DNS */ + +#if LWIP_CHARGEN_APP && LWIP_SOCKET + chargen_init(); +#endif /* LWIP_CHARGEN_APP && LWIP_SOCKET */ + +#if LWIP_PING_APP && LWIP_RAW && LWIP_ICMP + ping_init(&netif_default->gw); +#endif /* LWIP_PING_APP && LWIP_RAW && LWIP_ICMP */ + +#if LWIP_NETBIOS_APP && LWIP_UDP + netbiosns_init(); +#ifndef NETBIOS_LWIP_NAME +#if LWIP_NETIF_HOSTNAME + netbiosns_set_name(netif_default->hostname); +#else + netbiosns_set_name("NETBIOSLWIPDEV"); +#endif +#endif +#endif /* LWIP_NETBIOS_APP && LWIP_UDP */ + +#if LWIP_HTTPD_APP && LWIP_TCP +#ifdef LWIP_HTTPD_APP_NETCONN + http_server_netconn_init(); +#else /* LWIP_HTTPD_APP_NETCONN */ +#if defined(LWIP_HTTPD_EXAMPLE_CUSTOMFILES) && LWIP_HTTPD_EXAMPLE_CUSTOMFILES && defined(LWIP_HTTPD_EXAMPLE_CUSTOMFILES_ROOTDIR) + fs_ex_init(LWIP_HTTPD_EXAMPLE_CUSTOMFILES_ROOTDIR); +#endif + httpd_init(); +#if defined(LWIP_HTTPD_EXAMPLE_SSI_SIMPLE) && LWIP_HTTPD_EXAMPLE_SSI_SIMPLE + ssi_ex_init(); +#endif +#if defined(LWIP_HTTPD_EXAMPLE_CGI_SIMPLE) && LWIP_HTTPD_EXAMPLE_CGI_SIMPLE + cgi_ex_init(); +#endif +#if defined(LWIP_HTTPD_EXAMPLE_HTTPS) && LWIP_HTTPD_EXAMPLE_HTTPS + https_ex_init(); +#endif +#endif /* LWIP_HTTPD_APP_NETCONN */ +#endif /* LWIP_HTTPD_APP && LWIP_TCP */ + +#if LWIP_NETIO_APP && LWIP_TCP + netio_init(); +#endif /* LWIP_NETIO_APP && LWIP_TCP */ + +#if LWIP_RTP_APP && LWIP_SOCKET && LWIP_IGMP + rtp_init(); +#endif /* LWIP_RTP_APP && LWIP_SOCKET && LWIP_IGMP */ + +#if LWIP_SHELL_APP && LWIP_NETCONN + shell_init(); +#endif /* LWIP_SHELL_APP && LWIP_NETCONN */ +#if LWIP_TCPECHO_APP +#if LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN) + tcpecho_init(); +#else /* LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN) */ + tcpecho_raw_init(); +#endif +#endif /* LWIP_TCPECHO_APP && LWIP_NETCONN */ +#if LWIP_UDPECHO_APP && LWIP_NETCONN + udpecho_init(); +#endif /* LWIP_UDPECHO_APP && LWIP_NETCONN */ +#if LWIP_SOCKET_EXAMPLES_APP && LWIP_SOCKET + socket_examples_init(); +#endif /* LWIP_SOCKET_EXAMPLES_APP && LWIP_SOCKET */ +#if LWIP_MDNS_APP + mdns_example_init(); +#endif +#if LWIP_SNMP_APP + snmp_example_init(); +#endif +#if LWIP_SNTP_APP + sntp_example_init(); +#endif +#if LWIP_TFTP_APP + tftp_example_init_server(); +#endif +#if LWIP_TFTP_CLIENT_APP + tftp_example_init_client(); +#endif +#if LWIP_LWIPERF_APP + lwiperf_example_init(); +#endif +#if LWIP_MQTT_APP + mqtt_example_init(); +#endif + +#ifdef LWIP_APP_INIT + LWIP_APP_INIT(); +#endif +} + +/* This function initializes this lwIP test. When NO_SYS=1, this is done in + * the main_loop context (there is no other one), when NO_SYS=0, this is done + * in the tcpip_thread context */ +static void +test_init(void * arg) +{ /* remove compiler warning */ +#if NO_SYS + LWIP_UNUSED_ARG(arg); +#else /* NO_SYS */ + sys_sem_t *init_sem; + LWIP_ASSERT("arg != NULL", arg != NULL); + init_sem = (sys_sem_t*)arg; +#endif /* NO_SYS */ + + /* init randomizer again (seed per thread) */ + srand((unsigned int)time(NULL)); + + /* init network interfaces */ + test_netif_init(); + + /* init apps */ + apps_init(); + +#if !NO_SYS + sys_sem_signal(init_sem); +#endif /* !NO_SYS */ +} + +/* This is somewhat different to other ports: we have a main loop here: + * a dedicated task that waits for packets to arrive. This would normally be + * done from interrupt context with embedded hardware, but we don't get an + * interrupt in windows for that :-) */ +static void +main_loop(void) +{ +#if !NO_SYS + err_t err; + sys_sem_t init_sem; +#endif /* NO_SYS */ +#if USE_PPP +#if !USE_ETHERNET + int count; + u8_t rxbuf[1024]; +#endif + volatile int callClosePpp = 0; +#endif /* USE_PPP */ + + /* initialize lwIP stack, network interfaces and applications */ +#if NO_SYS + lwip_init(); + test_init(NULL); +#else /* NO_SYS */ + err = sys_sem_new(&init_sem, 0); + LWIP_ASSERT("failed to create init_sem", err == ERR_OK); + LWIP_UNUSED_ARG(err); + tcpip_init(test_init, &init_sem); + /* we have to wait for initialization to finish before + * calling update_adapter()! */ + sys_sem_wait(&init_sem); + sys_sem_free(&init_sem); +#endif /* NO_SYS */ + +#if (LWIP_SOCKET || LWIP_NETCONN) && LWIP_NETCONN_SEM_PER_THREAD + netconn_thread_init(); +#endif + + /* MAIN LOOP for driver update (and timers if NO_SYS) */ + while (!LWIP_EXAMPLE_APP_ABORT()) { +#if NO_SYS + /* handle timers (already done in tcpip.c when NO_SYS=0) */ + sys_check_timeouts(); +#endif /* NO_SYS */ + +#if USE_ETHERNET + default_netif_poll(); +#else /* USE_ETHERNET */ + /* try to read characters from serial line and pass them to PPPoS */ + count = sio_read(ppp_sio, (u8_t*)rxbuf, 1024); + if(count > 0) { + pppos_input(ppp, rxbuf, count); + } else { + /* nothing received, give other tasks a chance to run */ + sys_msleep(1); + } + +#endif /* USE_ETHERNET */ +#if USE_SLIPIF + slipif_poll(&slipif1); +#if USE_SLIPIF > 1 + slipif_poll(&slipif2); +#endif /* USE_SLIPIF > 1 */ +#endif /* USE_SLIPIF */ +#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING + /* check for loopback packets on all netifs */ + netif_poll_all(); +#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#if USE_PPP + { + int do_hup = 0; + if(do_hup) { + ppp_close(ppp, 1); + do_hup = 0; + } + } + if(callClosePpp && ppp) { + /* make sure to disconnect PPP before stopping the program... */ + callClosePpp = 0; +#if NO_SYS + ppp_close(ppp, 0); +#else + pppapi_close(ppp, 0); +#endif + ppp = NULL; + } +#endif /* USE_PPP */ + } + +#if USE_PPP + if(ppp) { + u32_t started; + printf("Closing PPP connection...\n"); + /* make sure to disconnect PPP before stopping the program... */ +#if NO_SYS + ppp_close(ppp, 0); +#else + pppapi_close(ppp, 0); +#endif + ppp = NULL; + /* Wait for some time to let PPP finish... */ + started = sys_now(); + do + { +#if USE_ETHERNET + default_netif_poll(); +#endif + /* @todo: need a better check here: only wait until PPP is down */ + } while(sys_now() - started < 5000); + } +#endif /* USE_PPP */ +#if (LWIP_SOCKET || LWIP_NETCONN) && LWIP_NETCONN_SEM_PER_THREAD + netconn_thread_cleanup(); +#endif +#if USE_ETHERNET + default_netif_shutdown(); +#endif /* USE_ETHERNET */ +} + +#if USE_PPP && PPPOS_SUPPORT +int main(int argc, char **argv) +#else /* USE_PPP && PPPOS_SUPPORT */ +int main(void) +#endif /* USE_PPP && PPPOS_SUPPORT */ +{ +#if USE_PPP && PPPOS_SUPPORT + if(argc > 1) { + sio_idx = (u8_t)atoi(argv[1]); + } + printf("Using serial port %d for PPP\n", sio_idx); +#endif /* USE_PPP && PPPOS_SUPPORT */ + /* no stdio-buffering, please! */ + setvbuf(stdout, NULL,_IONBF, 0); + + main_loop(); + + return 0; +} + +/* This function is only required to prevent arch.h including stdio.h + * (which it does if LWIP_PLATFORM_ASSERT is undefined) + */ +void lwip_example_app_platform_assert(const char *msg, int line, const char *file) +{ + printf("Assertion \"%s\" failed at line %d in %s\n", msg, line, file); + fflush(NULL); + abort(); +} diff --git a/contrib/examples/example_app/test_configs/opt_default.h b/contrib/examples/example_app/test_configs/opt_default.h new file mode 100644 index 0000000..67b69d2 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_default.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 1 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 1 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 1 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 0 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_dualstack.h b/contrib/examples/example_app/test_configs/opt_dualstack.h new file mode 100644 index 0000000..4caf490 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_dualstack.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 1 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP LWIP_UDP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 1 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 1 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 1 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_ipv4only.h b/contrib/examples/example_app/test_configs/opt_ipv4only.h new file mode 100644 index 0000000..82ba467 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_ipv4only.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 1 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP LWIP_UDP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 1 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 1 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 0 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_ipv6only.h b/contrib/examples/example_app/test_configs/opt_ipv6only.h new file mode 100644 index 0000000..b3cb1e0 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_ipv6only.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 0 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP 0 +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 1 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 1 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 1 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_tcp_dualstack.h b/contrib/examples/example_app/test_configs/opt_no_tcp_dualstack.h new file mode 100644 index 0000000..9d70ace --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_tcp_dualstack.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_dualstack.h" + +#undef LWIP_TCP +#define LWIP_TCP 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_tcp_ipv4only.h b/contrib/examples/example_app/test_configs/opt_no_tcp_ipv4only.h new file mode 100644 index 0000000..bd22831 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_tcp_ipv4only.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_ipv4only.h" + +#undef LWIP_TCP +#define LWIP_TCP 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_tcp_ipv6only.h b/contrib/examples/example_app/test_configs/opt_no_tcp_ipv6only.h new file mode 100644 index 0000000..9f956e3 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_tcp_ipv6only.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_ipv6only.h" + +#undef LWIP_TCP +#define LWIP_TCP 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_udp_dualstack.h b/contrib/examples/example_app/test_configs/opt_no_udp_dualstack.h new file mode 100644 index 0000000..c9b9e9a --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_udp_dualstack.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_dualstack.h" + +#undef LWIP_UDP +#define LWIP_UDP 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_udp_ipv4only.h b/contrib/examples/example_app/test_configs/opt_no_udp_ipv4only.h new file mode 100644 index 0000000..7aa3ace --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_udp_ipv4only.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_ipv4only.h" + +#undef LWIP_UDP +#define LWIP_UDP 0 diff --git a/contrib/examples/example_app/test_configs/opt_no_udp_ipv6only.h b/contrib/examples/example_app/test_configs/opt_no_udp_ipv6only.h new file mode 100644 index 0000000..0572798 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_no_udp_ipv6only.h @@ -0,0 +1,4 @@ +#include "test_configs/opt_ipv6only.h" + +#undef LWIP_UDP +#define LWIP_UDP 0 diff --git a/contrib/examples/example_app/test_configs/opt_none.h b/contrib/examples/example_app/test_configs/opt_none.h new file mode 100644 index 0000000..3c39321 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_none.h @@ -0,0 +1,2 @@ +/* test and empty lwipopts.h file */ + diff --git a/contrib/examples/example_app/test_configs/opt_nosys_dual.h b/contrib/examples/example_app/test_configs/opt_nosys_dual.h new file mode 100644 index 0000000..17ee97f --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_nosys_dual.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 1 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 0 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 0 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 1 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_nosys_ipv4.h b/contrib/examples/example_app/test_configs/opt_nosys_ipv4.h new file mode 100644 index 0000000..024d79b --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_nosys_ipv4.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 1 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 0 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 0 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 0 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/example_app/test_configs/opt_nosys_ipv6.h b/contrib/examples/example_app/test_configs/opt_nosys_ipv6.h new file mode 100644 index 0000000..d027352 --- /dev/null +++ b/contrib/examples/example_app/test_configs/opt_nosys_ipv6.h @@ -0,0 +1,295 @@ +/* test an lwipopts.h file with default contents */ +#define NO_SYS 0 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_TIMERS_CUSTOM 0 +#define LWIP_MPU_COMPATIBLE 0 +#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_MEM_INIT 0 +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 +#define MEMP_OVERFLOW_CHECK 0 +#define MEMP_SANITY_CHECK 0 +#define MEM_OVERFLOW_CHECK 0 +#define MEM_SANITY_CHECK 0 +#define MEM_USE_POOLS 0 +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#define MEMP_USE_CUSTOM_POOLS 0 +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +/*#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 5 +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#define MEMP_NUM_REASSDATA 5 +#define MEMP_NUM_FRAG_PBUF 15 +#define MEMP_NUM_ARP_QUEUE 30 +#define MEMP_NUM_IGMP_GROUP 8 +#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 2) +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_SELECT_CB 4 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETDB 1 +#define MEMP_NUM_LOCALHOSTLIST 1 +#define PBUF_POOL_SIZE 16 +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API*/ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_MAXAGE 300 +#define ARP_QUEUEING 0 +#define ARP_QUEUE_LEN 3 +#define ETHARP_SUPPORT_VLAN 0 +#define LWIP_ETHERNET LWIP_ARP +#define ETH_PAD_SIZE 0 +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#define LWIP_IPV4 0 +#define IP_FORWARD 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASS_MAXAGE 15 +#define IP_REASS_MAX_PBUFS 10 +#define IP_DEFAULT_TTL 255 +#define IP_SOF_BROADCAST 0 +#define IP_SOF_BROADCAST_RECV 0 +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#define LWIP_ICMP 1 +#define ICMP_TTL (IP_DEFAULT_TTL) +#define LWIP_BROADCAST_PING 0 +#define LWIP_MULTICAST_PING 0 +#define LWIP_RAW 0 +#define RAW_TTL (IP_DEFAULT_TTL) +#define LWIP_DHCP 0 +#define LWIP_DHCP_CHECK_LINK_UP 0 +#define LWIP_DHCP_BOOTP_FILE 0 +#define LWIP_DHCP_GET_NTP_SRV 0 +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#define LWIP_AUTOIP 0 +#define LWIP_DHCP_AUTOIP_COOP 0 +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#define LWIP_MIB2_CALLBACKS 0 +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#define LWIP_IGMP 0 +#define LWIP_DNS 0 +#define DNS_TABLE_SIZE 4 +#define DNS_MAX_NAME_LENGTH 256 +#define DNS_MAX_SERVERS 2 +#define DNS_MAX_RETRIES 4 +#define DNS_DOES_NAME_CHECK 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#define DNS_LOCAL_HOSTLIST 0 +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 0 +#define UDP_TTL (IP_DEFAULT_TTL) +#define LWIP_NETBUF_RECVINFO 0 +#define LWIP_TCP 1 +#define TCP_TTL (IP_DEFAULT_TTL) +#define TCP_WND (4 * TCP_MSS) +#define TCP_MAXRTX 12 +#define TCP_SYNMAXRTX 6 +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_MAX_SACK_NUM 4 +#define TCP_MSS 536 +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_OOSEQ_MAX_BYTES 0 +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_PBUFS 0 +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#define TCP_LISTEN_BACKLOG 0 +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#define TCP_OVERSIZE TCP_MSS +#define LWIP_TCP_TIMESTAMPS 0 +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#define LWIP_ALTCP 0 +#define LWIP_ALTCP_TLS 0 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#define LWIP_PBUF_REF_T u8_t +#define LWIP_SINGLE_NETIF 0 +#define LWIP_NETIF_HOSTNAME 0 +#define LWIP_NETIF_API 0 +#define LWIP_NETIF_STATUS_CALLBACK 0 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#define LWIP_NETIF_LINK_CALLBACK 0 +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#define LWIP_NETIF_HWADDRHINT 0 +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#define LWIP_LOOPIF_MULTICAST 0 +#define LWIP_NETIF_LOOPBACK 0 +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +/*#define TCPIP_THREAD_NAME "tcpip_thread" +#define TCPIP_THREAD_STACKSIZE 0 +#define TCPIP_THREAD_PRIO 1 +#define TCPIP_MBOX_SIZE 0 +#define LWIP_TCPIP_THREAD_ALIVE() +#define SLIPIF_THREAD_NAME "slipif_loop" +#define SLIPIF_THREAD_STACKSIZE 0 +#define SLIPIF_THREAD_PRIO 1 +#define DEFAULT_THREAD_NAME "lwIP" +#define DEFAULT_THREAD_STACKSIZE 0 +#define DEFAULT_THREAD_PRIO 1 +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#define DEFAULT_ACCEPTMBOX_SIZE 0*/ +#define LWIP_NETCONN 0 +#define LWIP_TCPIP_TIMEOUT 0 +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#define LWIP_NETCONN_FULLDUPLEX 0 +#define LWIP_SOCKET 0 +#define LWIP_COMPAT_SOCKETS 1 /* 0..2 */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#define LWIP_SOCKET_OFFSET 0 +#define LWIP_TCP_KEEPALIVE 0 +#define LWIP_SO_SNDTIMEO 0 +#define LWIP_SO_RCVTIMEO 0 +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#define LWIP_SO_RCVBUF 0 +#define LWIP_SO_LINGER 0 +#define RECV_BUFSIZE_DEFAULT INT_MAX +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#define SO_REUSE 0 +#define SO_REUSE_RXTOALL 0 +#define LWIP_FIONREAD_LINUXMODE 0 +#define LWIP_SOCKET_SELECT 1 +#define LWIP_SOCKET_POLL 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 0 +#define LINK_STATS 1 +#define ETHARP_STATS (LWIP_ARP) +#define IP_STATS 1 +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#define ICMP_STATS 1 +#define IGMP_STATS (LWIP_IGMP) +#define UDP_STATS (LWIP_UDP) +#define TCP_STATS (LWIP_TCP) +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#define SYS_STATS (NO_SYS == 0) +#define IP6_STATS (LWIP_IPV6) +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#define ND6_STATS (LWIP_IPV6) +#define MIB2_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 +#define CHECKSUM_CHECK_ICMP6 1 +#define LWIP_CHECKSUM_ON_COPY 0 +#define LWIP_IPV6 1 +#define IPV6_REASS_MAXAGE 60 +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#define LWIP_IPV6_SCOPES_DEBUG 0 +#define LWIP_IPV6_NUM_ADDRESSES 3 +#define LWIP_IPV6_FORWARD 0 +#define LWIP_IPV6_FRAG 1 +#define LWIP_IPV6_REASS (LWIP_IPV6) +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_ICMP6 (LWIP_IPV6) +#define LWIP_ICMP6_DATASIZE 8 +#define LWIP_ICMP6_HL 255 +#define LWIP_IPV6_MLD (LWIP_IPV6) +#define MEMP_NUM_MLD6_GROUP 4 +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#define MEMP_NUM_ND6_QUEUE 20 +#define LWIP_ND6_NUM_NEIGHBORS 10 +#define LWIP_ND6_NUM_DESTINATIONS 10 +#define LWIP_ND6_NUM_PREFIXES 5 +#define LWIP_ND6_NUM_ROUTERS 3 +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#define LWIP_ND6_REACHABLE_TIME 30000 +#define LWIP_ND6_RETRANS_TIMER 1000 +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#define LWIP_IPV6_DHCP6 0 +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#define LWIP_DHCP6_GET_NTP_SRV 0 +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS + +/* TODO: check hooks */ + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#define LWIP_PERF 0 diff --git a/contrib/examples/httpd/cgi_example/cgi_example.c b/contrib/examples/httpd/cgi_example/cgi_example.c new file mode 100644 index 0000000..c9c7476 --- /dev/null +++ b/contrib/examples/httpd/cgi_example/cgi_example.c @@ -0,0 +1,107 @@ +/** + * @file + * HTTPD simple CGI example + * + * This file demonstrates how to add support for basic CGI. + */ + + /* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "cgi_example.h" + +#include "lwip/apps/httpd.h" + +#include "lwip/def.h" +#include "lwip/mem.h" + +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_CGI_SIMPLE to 1 to enable this cgi example */ +#ifndef LWIP_HTTPD_EXAMPLE_CGI_SIMPLE +#define LWIP_HTTPD_EXAMPLE_CGI_SIMPLE 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_CGI_SIMPLE + +#if !LWIP_HTTPD_CGI +#error LWIP_HTTPD_EXAMPLE_CGI_SIMPLE needs LWIP_HTTPD_CGI +#endif + +static const char *cgi_handler_basic(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); + +static const tCGI cgi_handlers[] = { + { + "/basic_cgi", + cgi_handler_basic + }, + { + "/basic_cgi_2", + cgi_handler_basic + } +}; + +void +cgi_ex_init(void) +{ + http_set_cgi_handlers(cgi_handlers, LWIP_ARRAYSIZE(cgi_handlers)); +} + +/** This basic CGI function can parse param/value pairs and return an url that + * is sent as a response by httpd. + * + * This example function just checks that the input url has two key value + * parameter pairs: "foo=bar" and "test=123" + * If not, it returns 404 + */ +static const char * +cgi_handler_basic(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + LWIP_ASSERT("check index", iIndex < LWIP_ARRAYSIZE(cgi_handlers)); + + if (iNumParams == 2) { + if (!strcmp(pcParam[0], "foo")) { + if (!strcmp(pcValue[0], "bar")) { + if (!strcmp(pcParam[1], "test")) { + if (!strcmp(pcValue[1], "123")) { + return "/index.html"; + } + } + } + } + } + return "/404.html"; +} + +#endif /* LWIP_HTTPD_EXAMPLE_CGI_SIMPLE */ diff --git a/contrib/examples/httpd/cgi_example/cgi_example.h b/contrib/examples/httpd/cgi_example/cgi_example.h new file mode 100644 index 0000000..b655661 --- /dev/null +++ b/contrib/examples/httpd/cgi_example/cgi_example.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_HTTP_EXAMPLES_CGI_EXAMPLE +#define LWIP_HDR_HTTP_EXAMPLES_CGI_EXAMPLE + +void cgi_ex_init(void); + +#endif /* LWIP_HDR_HTTP_EXAMPLES_CGI_EXAMPLE */ diff --git a/contrib/examples/httpd/examples_fs/404.html b/contrib/examples/httpd/examples_fs/404.html new file mode 100644 index 0000000..40b343a --- /dev/null +++ b/contrib/examples/httpd/examples_fs/404.html @@ -0,0 +1,21 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + +
+ SICS logo + +

lwIP - A Lightweight TCP/IP Stack

+

404 - Page not found

+

+ Sorry, the page you are requesting was not found on this + server. +

+
+   +
+ + diff --git a/contrib/examples/httpd/examples_fs/img/sics.gif b/contrib/examples/httpd/examples_fs/img/sics.gif new file mode 100644 index 0000000000000000000000000000000000000000..0a4fc7bb07050eec9226ca93bc9ad237f35502c8 GIT binary patch literal 724 zcmZ?wbhEHbbYoCrSjxa~Q`<5tD{KG${gWq8=I7_%uwlcpWy=~G8p_Jb4zT=SA;^3z!7uBu>UZ()&> z+r1;Oh0mFly?klC)5cAV$sD}98F{LBUHERS_hGGKac5`W-mvIltqUt73*&`X?UVf< z%Uqmm^}K~z9MaFS-jwgVGIUF9Z77P_s7Vc}y?@_XT+GT)AcZF$6%$qQsA+Q0bF z!Mss%ktc&>+n*qp2aIzy6-8A8zNf3ovHkU%wPnH@(O;*7g5`QX{a~M@%VFg!JaWkVUk6yFE1wL^V{({yi?^s!by^W;pXIz%mY}~L;uBR^JK|)kW|Avap zVzxyL+2N;b1q1f77^T<4c)gUoN8c;6;F^+^0^VN o#HPS7gPr3^SVM!%(d|c@c+6frXclnOc-SHmma$O4k%7S)08~d;ZvX%Q literal 0 HcmV?d00001 diff --git a/contrib/examples/httpd/examples_fs/index.html b/contrib/examples/httpd/examples_fs/index.html new file mode 100644 index 0000000..ab575ef --- /dev/null +++ b/contrib/examples/httpd/examples_fs/index.html @@ -0,0 +1,47 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + +
+ SICS logo + +

lwIP - A Lightweight TCP/IP Stack

+

+ The web page you are watching was served by a simple web + server running on top of the lightweight TCP/IP stack lwIP. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ The focus of the lwIP TCP/IP implementation is to reduce + the RAM usage while still having a full scale TCP. This + makes lwIP suitable for use in embedded systems with tens + of kilobytes of free RAM and room for around 40 kilobytes + of code ROM. +

+

+ More information about lwIP can be found at the lwIP + homepage at http://savannah.nongnu.org/projects/lwip/ + or at the lwIP wiki at http://lwip.wikia.com/. +

+
+   +
+ + + diff --git a/contrib/examples/httpd/examples_fs/login.html b/contrib/examples/httpd/examples_fs/login.html new file mode 100644 index 0000000..71c535b --- /dev/null +++ b/contrib/examples/httpd/examples_fs/login.html @@ -0,0 +1,28 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + + + + + +
+ SICS logo + +

Login

+
+
+ + + + + +
+
+
+   +
+ + diff --git a/contrib/examples/httpd/examples_fs/loginfail.html b/contrib/examples/httpd/examples_fs/loginfail.html new file mode 100644 index 0000000..6d5c742 --- /dev/null +++ b/contrib/examples/httpd/examples_fs/loginfail.html @@ -0,0 +1,25 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + + + + + +
+ SICS logo + +

lwIP - A Lightweight TCP/IP Stack

+

+ Login failed. +

+

+ Click here to retry login. +

+
+   +
+ + diff --git a/contrib/examples/httpd/examples_fs/session.html b/contrib/examples/httpd/examples_fs/session.html new file mode 100644 index 0000000..72d3bff --- /dev/null +++ b/contrib/examples/httpd/examples_fs/session.html @@ -0,0 +1,25 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + + + + + +
+ SICS logo + +

lwIP - A Lightweight TCP/IP Stack

+

+ Login succeeded, session active. +

+

+ Click here to retry login. +

+
+   +
+ + diff --git a/contrib/examples/httpd/examples_fs/ssi.shtml b/contrib/examples/httpd/examples_fs/ssi.shtml new file mode 100644 index 0000000..153d016 --- /dev/null +++ b/contrib/examples/httpd/examples_fs/ssi.shtml @@ -0,0 +1,315 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + +
+ SICS logo + +

lwIP - A Lightweight TCP/IP Stack

+

+

+ The web page you are watching was served by a simple web + server running on top of the lightweight TCP/IP stack lwIP. +

+

+ This page is here to test SSI, so here is a counter as + an example of content changing for every request: + "" +

+

+ And here is an example of a tag result buffer return in + multiple parts: "" +

+

+ To test LWIP_HTTPD_CGI_SSI, here are the CGI parameters: + +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ lwIP is an open source implementation of the TCP/IP + protocol suite that was originally written by Adam Dunkels + of the Swedish Institute of Computer Science but now is + being actively developed by a team of developers + distributed world-wide. Since it's release, lwIP has + spurred a lot of interest and has been ported to several + platforms and operating systems. lwIP can be used either + with or without an underlying OS. +

+

+ The focus of the lwIP TCP/IP implementation is to reduce + the RAM usage while still having a full scale TCP. This + makes lwIP suitable for use in embedded systems with tens + of kilobytes of free RAM and room for around 40 kilobytes + of code ROM. +

+

+ More information about lwIP can be found at the lwIP + homepage at http://savannah.nongnu.org/projects/lwip/ + or at the lwIP wiki at http://lwip.wikia.com/. +

+
+   +
+ + + diff --git a/contrib/examples/httpd/examples_fsdata.c b/contrib/examples/httpd/examples_fsdata.c new file mode 100644 index 0000000..7eed926 --- /dev/null +++ b/contrib/examples/httpd/examples_fsdata.c @@ -0,0 +1,1543 @@ +#include "lwip/apps/fs.h" +#include "lwip/def.h" + + +#define file_NULL (struct fsdata_file *) NULL + + +#ifndef FS_FILE_FLAGS_HEADER_INCLUDED +#define FS_FILE_FLAGS_HEADER_INCLUDED 1 +#endif +#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT +#define FS_FILE_FLAGS_HEADER_PERSISTENT 0 +#endif +/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */ +#ifndef FSDATA_FILE_ALIGNMENT +#define FSDATA_FILE_ALIGNMENT 0 +#endif +#ifndef FSDATA_ALIGN_PRE +#define FSDATA_ALIGN_PRE +#endif +#ifndef FSDATA_ALIGN_POST +#define FSDATA_ALIGN_POST +#endif +#if FSDATA_FILE_ALIGNMENT==2 +#include "fsdata_alignment.h" +#endif +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__img_sics_gif = 0; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__img_sics_gif[] FSDATA_ALIGN_POST = { +/* /img/sics.gif (14 chars) */ +0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00, + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 724 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x37,0x32,0x34,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: image/gif + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d, +0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a, +/* raw file data (724 bytes) */ +0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39, +0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6, +0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e, +0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99, +0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5, +0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b, +0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00, +0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f, +0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac, +0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31, +0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9, +0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51, +0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78, +0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0, +0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07, +0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42, +0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c, +0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01, +0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10, +0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8, +0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4, +0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86, +0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06, +0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07, +0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29, +0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a, +0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97, +0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9, +0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70, +0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c, +0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01, +0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24, +0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29, +0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73, +0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab, +0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45, +0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8, +0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5, +0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10, +0x41,0x00,0x00,0x3b,}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__404_html = 1; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__404_html[] FSDATA_ALIGN_POST = { +/* /404.html (10 chars) */ +0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00, + +/* HTTP header */ +/* "HTTP/1.1 404 File not found +" (29 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c, +0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 565 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x35,0x36,0x35,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: text/html + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, +/* raw file data (565 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, +0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, +0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, +0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, +0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, +0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, +0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, +0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, +0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, +0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, +0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, +0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20, +0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72, +0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75, +0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20, +0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e, +0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76, +0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, +0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, +0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, +0x6d,0x6c,0x3e,0x0d,0x0a,}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__index_html = 2; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__index_html[] FSDATA_ALIGN_POST = { +/* /index.html (12 chars) */ +0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00, + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 1751 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x31,0x37,0x35,0x31,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: text/html + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, +/* raw file data (1751 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, +0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, +0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, +0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, +0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, +0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, +0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, +0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, +0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, +0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, +0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, +0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77, +0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20, +0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72, +0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20, +0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72, +0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20, +0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67, +0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20, +0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c, +0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70, +0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20, +0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, +0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50, +0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63, +0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61, +0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69, +0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77, +0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f, +0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b, +0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65, +0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75, +0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53, +0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e, +0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e, +0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c, +0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f, +0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77, +0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65, +0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c, +0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70, +0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69, +0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20, +0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73, +0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61, +0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61, +0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77, +0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65, +0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68, +0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75, +0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f, +0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49, +0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e, +0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67, +0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61, +0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c, +0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69, +0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e, +0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d, +0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f, +0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72, +0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34, +0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72, +0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49, +0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61, +0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67, +0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f, +0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61, +0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72, +0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f, +0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74, +0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61, +0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d, +0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b, +0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, +0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c, +0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, +0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, +0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, +0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__login_html = 3; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__login_html[] FSDATA_ALIGN_POST = { +/* /login.html (12 chars) */ +0x2f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x68,0x74,0x6d,0x6c,0x00, + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 768 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x37,0x36,0x38,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: text/html + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, +/* raw file data (768 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x3c,0x74, +0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x31,0x30,0x30,0x25, +0x22,0x3e,0x0d,0x0a,0x20,0x3c,0x74,0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d, +0x22,0x74,0x6f,0x70,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x61, +0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77, +0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67, +0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e, +0x67,0x69,0x66,0x22,0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20, +0x61,0x6c,0x74,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20, +0x74,0x69,0x74,0x6c,0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f, +0x22,0x2f,0x3e,0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e, +0x0d,0x0a,0x20,0x20,0x3c,0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x35, +0x30,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x68,0x31,0x3e,0x4c,0x6f,0x67, +0x69,0x6e,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x66,0x6f,0x72, +0x6d,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x6c,0x6f,0x67,0x69,0x6e,0x22,0x20,0x61, +0x63,0x74,0x69,0x6f,0x6e,0x3d,0x22,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x63,0x67,0x69, +0x22,0x20,0x6d,0x65,0x74,0x68,0x6f,0x64,0x3d,0x22,0x70,0x6f,0x73,0x74,0x22,0x3e, +0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x64,0x69,0x76,0x3e,0x0d,0x0a,0x20,0x20,0x20, +0x20,0x20,0x3c,0x6c,0x61,0x62,0x65,0x6c,0x3e,0x3c,0x62,0x3e,0x55,0x73,0x65,0x72, +0x6e,0x61,0x6d,0x65,0x3c,0x2f,0x62,0x3e,0x3c,0x2f,0x6c,0x61,0x62,0x65,0x6c,0x3e, +0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x3c,0x69,0x6e,0x70,0x75,0x74,0x20,0x74,0x79, +0x70,0x65,0x3d,0x22,0x74,0x65,0x78,0x74,0x22,0x20,0x70,0x6c,0x61,0x63,0x65,0x68, +0x6f,0x6c,0x64,0x65,0x72,0x3d,0x22,0x45,0x6e,0x74,0x65,0x72,0x20,0x55,0x73,0x65, +0x72,0x6e,0x61,0x6d,0x65,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x75,0x73,0x65, +0x72,0x22,0x20,0x72,0x65,0x71,0x75,0x69,0x72,0x65,0x64,0x3e,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x20,0x3c,0x6c,0x61,0x62,0x65,0x6c,0x3e,0x3c,0x62,0x3e,0x50,0x61,0x73, +0x73,0x77,0x6f,0x72,0x64,0x3c,0x2f,0x62,0x3e,0x3c,0x2f,0x6c,0x61,0x62,0x65,0x6c, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x3c,0x69,0x6e,0x70,0x75,0x74,0x20,0x74, +0x79,0x70,0x65,0x3d,0x22,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64,0x22,0x20,0x70, +0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x3d,0x22,0x45,0x6e,0x74,0x65, +0x72,0x20,0x50,0x61,0x73,0x73,0x77,0x6f,0x72,0x64,0x22,0x20,0x6e,0x61,0x6d,0x65, +0x3d,0x22,0x70,0x61,0x73,0x73,0x22,0x20,0x72,0x65,0x71,0x75,0x69,0x72,0x65,0x64, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x3c,0x62,0x75,0x74,0x74,0x6f,0x6e,0x20, +0x74,0x79,0x70,0x65,0x3d,0x22,0x73,0x75,0x62,0x6d,0x69,0x74,0x22,0x3e,0x4c,0x6f, +0x67,0x69,0x6e,0x3c,0x2f,0x62,0x75,0x74,0x74,0x6f,0x6e,0x3e,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x2f,0x64,0x69,0x76,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x2f,0x66, +0x6f,0x72,0x6d,0x3e,0x20,0x0d,0x0a,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a, +0x20,0x20,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x26,0x6e,0x62,0x73,0x70, +0x3b,0x0d,0x0a,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x3c,0x2f,0x74, +0x72,0x3e,0x0d,0x0a,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,0x3e,0x0d,0x0a,0x3c,0x2f, +0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a, +}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__loginfail_html = 4; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__loginfail_html[] FSDATA_ALIGN_POST = { +/* /loginfail.html (16 chars) */ +0x2f,0x6c,0x6f,0x67,0x69,0x6e,0x66,0x61,0x69,0x6c,0x2e,0x68,0x74,0x6d,0x6c,0x00, + + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 559 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x35,0x35,0x39,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: text/html + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, +/* raw file data (559 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x3c, +0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x31,0x30,0x30, +0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x74,0x72,0x20,0x76,0x61,0x6c,0x69,0x67, +0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x74,0x64, +0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x22,0x3e, +0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,0x6d,0x67,0x2f,0x73, +0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d, +0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f, +0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20, +0x6c,0x6f,0x67,0x6f,0x22,0x2f,0x3e,0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x20,0x20,0x20, +0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,0x67, +0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20, +0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x3c,0x70,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x67,0x69,0x6e,0x20, +0x66,0x61,0x69,0x6c,0x65,0x64,0x2e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x2f,0x70, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x20,0x43,0x6c,0x69,0x63,0x6b,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22, +0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x68,0x74,0x6d,0x6c,0x22,0x3e,0x68,0x65,0x72,0x65, +0x3c,0x2f,0x61,0x3e,0x20,0x74,0x6f,0x20,0x72,0x65,0x74,0x72,0x79,0x20,0x6c,0x6f, +0x67,0x69,0x6e,0x2e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a, +0x20,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x74,0x64, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x26,0x6e,0x62,0x73,0x70,0x3b,0x0d,0x0a,0x20, +0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x2f,0x74,0x72,0x3e, +0x0d,0x0a,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,0x3e,0x0d,0x0a,0x3c,0x2f,0x62, +0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__session_html = 5; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__session_html[] FSDATA_ALIGN_POST = { +/* /session.html (14 chars) */ +0x2f,0x73,0x65,0x73,0x73,0x69,0x6f,0x6e,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00, + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 578 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x35,0x37,0x38,0x0d,0x0a, +/* "Connection: keep-alive +" (24 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70, +0x2d,0x61,0x6c,0x69,0x76,0x65,0x0d,0x0a, +/* "Content-Type: text/html + +" (27 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, +/* raw file data (578 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x3c, +0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x31,0x30,0x30, +0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x74,0x72,0x20,0x76,0x61,0x6c,0x69,0x67, +0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x74,0x64, +0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x22,0x3e, +0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,0x6d,0x67,0x2f,0x73, +0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d, +0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f, +0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20, +0x6c,0x6f,0x67,0x6f,0x22,0x2f,0x3e,0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x20,0x20,0x20, +0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,0x67, +0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20, +0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x3c,0x70,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x67,0x69,0x6e,0x20, +0x73,0x75,0x63,0x63,0x65,0x65,0x64,0x65,0x64,0x2c,0x20,0x73,0x65,0x73,0x73,0x69, +0x6f,0x6e,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x2e,0x0d,0x0a,0x20,0x20,0x20,0x20, +0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x20, +0x20,0x20,0x20,0x20,0x43,0x6c,0x69,0x63,0x6b,0x20,0x3c,0x61,0x20,0x68,0x72,0x65, +0x66,0x3d,0x22,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x68,0x74,0x6d,0x6c,0x22,0x3e,0x68, +0x65,0x72,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x74,0x6f,0x20,0x72,0x65,0x74,0x72,0x79, +0x20,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x3c,0x2f,0x70, +0x3e,0x0d,0x0a,0x20,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20, +0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x26,0x6e,0x62,0x73,0x70,0x3b, +0x0d,0x0a,0x20,0x20,0x20,0x3c,0x2f,0x74,0x64,0x3e,0x0d,0x0a,0x20,0x20,0x3c,0x2f, +0x74,0x72,0x3e,0x0d,0x0a,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,0x3e,0x0d,0x0a, +0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,0x6d,0x6c,0x3e, +0x0d,0x0a,}; + +#if FSDATA_FILE_ALIGNMENT==1 +static const unsigned int dummy_align__ssi_shtml = 6; +#endif +static const unsigned char FSDATA_ALIGN_PRE data__ssi_shtml[] FSDATA_ALIGN_POST = { +/* /ssi.shtml (11 chars) */ +0x2f,0x73,0x73,0x69,0x2e,0x73,0x68,0x74,0x6d,0x6c,0x00,0x00, + +/* HTTP header */ +/* "HTTP/1.1 200 OK +" (17 bytes) */ +0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, +0x0a, +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Connection: Close +" (19 bytes) */ +0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x43,0x6c,0x6f,0x73, +0x65,0x0d,0x0a, +/* "Content-Type: text/html +Expires: Fri, 10 Apr 2008 14:00:00 GMT +Pragma: no-cache + +" (85 bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x45,0x78,0x70,0x69,0x72,0x65,0x73, +0x3a,0x20,0x46,0x72,0x69,0x2c,0x20,0x31,0x30,0x20,0x41,0x70,0x72,0x20,0x32,0x30, +0x30,0x38,0x20,0x31,0x34,0x3a,0x30,0x30,0x3a,0x30,0x30,0x20,0x47,0x4d,0x54,0x0d, +0x0a,0x50,0x72,0x61,0x67,0x6d,0x61,0x3a,0x20,0x6e,0x6f,0x2d,0x63,0x61,0x63,0x68, +0x65,0x0d,0x0a,0x0d,0x0a, +/* raw file data (14429 bytes) */ +0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, +0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, +0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, +0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, +0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, +0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, +0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, +0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, +0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, +0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, +0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, +0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, +0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, +0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, +0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, +0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, +0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, +0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, +0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x68,0x31,0x3e,0x3c,0x21,0x2d,0x2d,0x23,0x48,0x65,0x6c,0x6c,0x57,0x6f, +0x72,0x6c,0x2d,0x2d,0x3e,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c, +0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,0x65,0x62, +0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,0x77,0x61, +0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,0x76,0x65, +0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,0x77,0x65, +0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,0x20,0x72, +0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,0x6f,0x66, +0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74, +0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,0x3c,0x61, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f, +0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,0x77,0x49, +0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68, +0x69,0x73,0x20,0x70,0x61,0x67,0x65,0x20,0x69,0x73,0x20,0x68,0x65,0x72,0x65,0x20, +0x74,0x6f,0x20,0x74,0x65,0x73,0x74,0x20,0x53,0x53,0x49,0x2c,0x20,0x73,0x6f,0x20, +0x68,0x65,0x72,0x65,0x20,0x69,0x73,0x20,0x61,0x20,0x63,0x6f,0x75,0x6e,0x74,0x65, +0x72,0x20,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x61,0x6e,0x20,0x65,0x78, +0x61,0x6d,0x70,0x6c,0x65,0x20,0x6f,0x66,0x20,0x63,0x6f,0x6e,0x74,0x65,0x6e,0x74, +0x20,0x63,0x68,0x61,0x6e,0x67,0x69,0x6e,0x67,0x20,0x66,0x6f,0x72,0x20,0x65,0x76, +0x65,0x72,0x79,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x3a,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x22,0x3c,0x21,0x2d,0x2d,0x23,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72, +0x2d,0x2d,0x3e,0x22,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x41,0x6e,0x64,0x20, +0x68,0x65,0x72,0x65,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x65,0x78,0x61,0x6d,0x70, +0x6c,0x65,0x20,0x6f,0x66,0x20,0x61,0x20,0x74,0x61,0x67,0x20,0x72,0x65,0x73,0x75, +0x6c,0x74,0x20,0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x72,0x65,0x74,0x75,0x72,0x6e, +0x20,0x69,0x6e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6d,0x75,0x6c,0x74,0x69,0x70, +0x6c,0x65,0x20,0x70,0x61,0x72,0x74,0x73,0x3a,0x20,0x22,0x3c,0x21,0x2d,0x2d,0x23, +0x4d,0x75,0x6c,0x74,0x50,0x61,0x72,0x74,0x2d,0x2d,0x3e,0x22,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x54,0x6f,0x20,0x74,0x65,0x73,0x74,0x20,0x4c,0x57,0x49,0x50, +0x5f,0x48,0x54,0x54,0x50,0x44,0x5f,0x43,0x47,0x49,0x5f,0x53,0x53,0x49,0x2c,0x20, +0x68,0x65,0x72,0x65,0x20,0x61,0x72,0x65,0x20,0x74,0x68,0x65,0x20,0x43,0x47,0x49, +0x20,0x70,0x61,0x72,0x61,0x6d,0x65,0x74,0x65,0x72,0x73,0x3a,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x3c,0x21,0x2d,0x2d,0x23,0x43,0x67,0x69,0x50,0x61,0x72,0x61,0x6d, +0x2d,0x2d,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20, +0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63, +0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e, +0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75, +0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69, +0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20, +0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66, +0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63, +0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f, +0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64, +0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66, +0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63, +0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74, +0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20, +0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76, +0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69, +0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d, +0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73, +0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68, +0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64, +0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65, +0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20, +0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61, +0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d, +0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20, +0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61, +0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77, +0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c, +0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70, +0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70, +0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20, +0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69, +0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66, +0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65, +0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e, +0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20, +0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41, +0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68, +0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f, +0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f, +0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65, +0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20, +0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f, +0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72, +0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64, +0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65, +0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20, +0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20, +0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72, +0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61, +0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73, +0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62, +0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68, +0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e, +0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49, +0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75, +0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20, +0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f, +0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65, +0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72, +0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73, +0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69, +0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77, +0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20, +0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65, +0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20, +0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61, +0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65, +0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64, +0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c, +0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74, +0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50, +0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72, +0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65, +0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65, +0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65, +0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f, +0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e, +0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20, +0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68, +0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72, +0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65, +0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c, +0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65, +0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65, +0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54, +0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74, +0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20, +0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77, +0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, +0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61, +0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75, +0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74, +0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69, +0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72, +0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74, +0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65, +0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76, +0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d, +0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64, +0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e, +0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c, +0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66, +0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61, +0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f, +0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70, +0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65, +0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20, +0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64, +0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69, +0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e, +0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d, +0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61, +0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d, +0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20, +0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20, +0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61, +0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c, +0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74, +0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65, +0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64, +0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20, +0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d, +0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61, +0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c, +0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61, +0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70, +0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69, +0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65, +0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c, +0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c, +0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61, +0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74, +0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e, +0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74, +0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65, +0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f, +0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67, +0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50, +0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72, +0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f, +0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73, +0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72, +0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e, +0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65, +0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69, +0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70, +0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65, +0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f, +0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e, +0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63, +0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64, +0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65, +0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64, +0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64, +0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27, +0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20, +0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65, +0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72, +0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e, +0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72, +0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72, +0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67, +0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63, +0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65, +0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20, +0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72, +0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f, +0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e, +0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43, +0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f, +0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77, +0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72, +0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77, +0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d, +0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e, +0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68, +0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74, +0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20, +0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20, +0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69, +0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65, +0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20, +0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20, +0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63, +0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20, +0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73, +0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20, +0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73, +0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20, +0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c, +0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72, +0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c, +0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20, +0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74, +0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20, +0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e, +0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74, +0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74, +0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c, +0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f, +0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61, +0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49, +0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70, +0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e, +0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79, +0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20, +0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65, +0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62, +0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e, +0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65, +0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f, +0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e, +0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65, +0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64, +0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65, +0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20, +0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75, +0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20, +0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20, +0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63, +0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e, +0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75, +0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69, +0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20, +0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66, +0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63, +0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f, +0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64, +0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66, +0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63, +0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74, +0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20, +0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76, +0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69, +0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d, +0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73, +0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68, +0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64, +0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65, +0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20, +0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61, +0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d, +0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20, +0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61, +0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77, +0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c, +0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70, +0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20, +0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, +0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50, +0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63, +0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61, +0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69, +0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77, +0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f, +0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b, +0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65, +0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75, +0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53, +0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e, +0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e, +0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c, +0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f, +0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77, +0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65, +0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c, +0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70, +0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69, +0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20, +0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73, +0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61, +0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61, +0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77, +0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65, +0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68, +0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75, +0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20, +0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c, +0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68, +0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70, +0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68, +0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c, +0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e, +0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d, +0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f, +0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e, +0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75, +0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20, +0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20, +0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74, +0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75, +0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20, +0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61, +0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74, +0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64, +0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64, +0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20, +0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d, +0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75, +0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74, +0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f, +0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20, +0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69, +0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65, +0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20, +0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69, +0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67, +0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62, +0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d, +0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73, +0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22, +0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69, +0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20, +0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65, +0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69, +0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62, +0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65, +0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73, +0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77, +0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20, +0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20, +0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73, +0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70, +0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73, +0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73, +0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e, +0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69, +0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79, +0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e, +0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c, +0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73, +0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61, +0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f, +0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f, +0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73, +0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74, +0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77, +0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c, +0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65, +0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20, +0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74, +0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63, +0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f, +0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67, +0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f, +0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66, +0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f, +0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20, +0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77, +0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75, +0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e, +0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62, +0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65, +0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74, +0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74, +0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49, +0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69, +0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20, +0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e, +0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f, +0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65, +0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65, +0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72, +0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61, +0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79, +0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61, +0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20, +0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66, +0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73, +0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74, +0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62, +0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64, +0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65, +0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74, +0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53, +0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73, +0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20, +0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20, +0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20, +0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f, +0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73, +0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73, +0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20, +0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53, +0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c, +0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73, +0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20, +0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f, +0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74, +0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69, +0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79, +0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22, +0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e, +0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e, +0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73, +0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43, +0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c, +0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76, +0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79, +0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c, +0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74, +0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69, +0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72, +0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61, +0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74, +0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f, +0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20, +0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79, +0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20, +0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74, +0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69, +0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77, +0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f, +0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74, +0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49, +0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c, +0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20, +0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74, +0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68, +0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e, +0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77, +0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53, +0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65, +0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69, +0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77, +0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20, +0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70, +0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20, +0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72, +0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69, +0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49, +0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72, +0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74, +0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65, +0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76, +0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66, +0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69, +0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50, +0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74, +0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f, +0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64, +0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20, +0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70, +0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20, +0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f, +0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74, +0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20, +0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f, +0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64, +0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44, +0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20, +0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74, +0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65, +0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75, +0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62, +0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65, +0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61, +0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65, +0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69, +0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65, +0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f, +0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68, +0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74, +0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70, +0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e, +0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65, +0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77, +0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61, +0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e, +0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70, +0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20, +0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69, +0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66, +0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65, +0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e, +0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20, +0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, +0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41, +0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68, +0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f, +0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f, +0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65, +0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20, +0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f, +0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72, +0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64, +0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65, +0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20, +0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20, +0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72, +0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61, +0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73, +0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62, +0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68, +0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e, +0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49, +0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75, +0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20, +0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f, +0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65, +0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72, +0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73, +0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69, +0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77, +0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20, +0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65, +0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20, +0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61, +0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65, +0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64, +0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c, +0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74, +0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50, +0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72, +0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65, +0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65, +0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65, +0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f, +0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e, +0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20, +0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68, +0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72, +0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65, +0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c, +0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65, +0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65, +0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54, +0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74, +0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20, +0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77, +0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, +0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61, +0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75, +0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74, +0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69, +0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72, +0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74, +0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65, +0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76, +0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d, +0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64, +0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e, +0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c, +0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66, +0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61, +0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f, +0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70, +0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65, +0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20, +0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64, +0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69, +0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e, +0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d, +0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61, +0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d, +0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20, +0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20, +0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61, +0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c, +0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74, +0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65, +0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64, +0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20, +0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d, +0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61, +0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c, +0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61, +0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70, +0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69, +0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65, +0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c, +0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a, +0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c, +0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61, +0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74, +0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e, +0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74, +0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65, +0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f, +0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67, +0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50, +0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72, +0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f, +0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73, +0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72, +0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e, +0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65, +0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69, +0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70, +0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65, +0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f, +0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e, +0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63, +0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64, +0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65, +0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64, +0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64, +0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27, +0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20, +0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65, +0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72, +0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e, +0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72, +0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72, +0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67, +0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63, +0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65, +0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20, +0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72, +0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f, +0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e, +0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43, +0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f, +0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77, +0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72, +0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77, +0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d, +0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e, +0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68, +0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74, +0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20, +0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20, +0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69, +0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65, +0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20, +0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20, +0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63, +0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20, +0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73, +0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20, +0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73, +0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20, +0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c, +0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72, +0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c, +0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20, +0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74, +0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20, +0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a, +0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x20,0x20,0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e, +0x20,0x6f,0x70,0x65,0x6e,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74, +0x68,0x65,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x70,0x72,0x6f,0x74,0x6f,0x63,0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74, +0x68,0x61,0x74,0x20,0x77,0x61,0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c, +0x6c,0x79,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f, +0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61, +0x6d,0x20,0x44,0x75,0x6e,0x6b,0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, +0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49, +0x6e,0x73,0x74,0x69,0x74,0x75,0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70, +0x75,0x74,0x65,0x72,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e, +0x20,0x62,0x75,0x74,0x20,0x6e,0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79, +0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20, +0x74,0x65,0x61,0x6d,0x20,0x6f,0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65, +0x72,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62, +0x75,0x74,0x65,0x64,0x20,0x77,0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e, +0x20,0x53,0x69,0x6e,0x63,0x65,0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65, +0x61,0x73,0x65,0x2c,0x20,0x6c,0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09, +0x20,0x20,0x20,0x20,0x73,0x70,0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f, +0x74,0x20,0x6f,0x66,0x20,0x69,0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e, +0x64,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65, +0x64,0x20,0x74,0x6f,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20, +0x20,0x20,0x20,0x70,0x6c,0x61,0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64, +0x20,0x6f,0x70,0x65,0x72,0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65, +0x6d,0x73,0x2e,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20, +0x75,0x73,0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20, +0x20,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75, +0x74,0x20,0x61,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20, +0x4f,0x53,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20, +0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66, +0x6f,0x63,0x75,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50, +0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64, +0x75,0x63,0x65,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41, +0x4d,0x20,0x75,0x73,0x61,0x67,0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74, +0x69,0x6c,0x6c,0x20,0x68,0x61,0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c, +0x6c,0x20,0x73,0x63,0x61,0x6c,0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77, +0x49,0x50,0x20,0x73,0x75,0x69,0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20, +0x75,0x73,0x65,0x20,0x69,0x6e,0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20, +0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62, +0x79,0x74,0x65,0x73,0x20,0x6f,0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d, +0x20,0x61,0x6e,0x64,0x20,0x72,0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72, +0x6f,0x75,0x6e,0x64,0x20,0x34,0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65, +0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20, +0x52,0x4f,0x4d,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, +0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65, +0x20,0x69,0x6e,0x66,0x6f,0x72,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f, +0x75,0x74,0x20,0x6c,0x77,0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66, +0x6f,0x75,0x6e,0x64,0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50, +0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20, +0x61,0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66, +0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61, +0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f, +0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e, +0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73, +0x2f,0x6c,0x77,0x69,0x70,0x2f,0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x6f,0x72,0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20, +0x77,0x69,0x6b,0x69,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20, +0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77, +0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61, +0x2e,0x63,0x6f,0x6d,0x2f,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c, +0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d, +0x0a,0x09,0x20,0x20,0x26,0x6e,0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74, +0x64,0x3e,0x3c,0x2f,0x74,0x72,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c, +0x2f,0x74,0x61,0x62,0x6c,0x65,0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e, +0x0d,0x0a,0x3c,0x2f,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,}; + + + +const struct fsdata_file file__img_sics_gif[] = { { +file_NULL, +data__img_sics_gif, +data__img_sics_gif + 16, +sizeof(data__img_sics_gif) - 16, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__404_html[] = { { +file__img_sics_gif, +data__404_html, +data__404_html + 12, +sizeof(data__404_html) - 12, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__index_html[] = { { +file__404_html, +data__index_html, +data__index_html + 12, +sizeof(data__index_html) - 12, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__login_html[] = { { +file__index_html, +data__login_html, +data__login_html + 12, +sizeof(data__login_html) - 12, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__loginfail_html[] = { { +file__login_html, +data__loginfail_html, +data__loginfail_html + 16, +sizeof(data__loginfail_html) - 16, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__session_html[] = { { +file__loginfail_html, +data__session_html, +data__session_html + 16, +sizeof(data__session_html) - 16, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT | FS_FILE_FLAGS_HEADER_HTTPVER_1_1, +}}; + +const struct fsdata_file file__ssi_shtml[] = { { +file__session_html, +data__ssi_shtml, +data__ssi_shtml + 12, +sizeof(data__ssi_shtml) - 12, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_SSI, +}}; + +#define FS_ROOT file__ssi_shtml +#define FS_NUMFILES 7 + diff --git a/contrib/examples/httpd/fs_example/fs_example.c b/contrib/examples/httpd/fs_example/fs_example.c new file mode 100644 index 0000000..e3552b1 --- /dev/null +++ b/contrib/examples/httpd/fs_example/fs_example.c @@ -0,0 +1,324 @@ +/** + * @file + * HTTPD custom file system example + * + * This file demonstrates how to add support for an external file system to httpd. + * It provides access to the specified root directory and uses stdio.h file functions + * to read files. + * + * ATTENTION: This implementation is *not* secure: no checks are added to ensure + * files are only read below the specified root directory! + */ + + /* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "fs_example.h" + +#include "lwip/apps/fs.h" +#include "lwip/def.h" +#include "lwip/mem.h" + +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_CUSTOMFILES to 1 to enable this file system */ +#ifndef LWIP_HTTPD_EXAMPLE_CUSTOMFILES +#define LWIP_HTTPD_EXAMPLE_CUSTOMFILES 0 +#endif + +/** define LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED to 1 to delay open and read + * as if e.g. reading from external SPI flash */ +#ifndef LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED +#define LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED 1 +#endif + +/** define LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ to the number of bytes + * to read to emulate limited transfer buffers and don't read whole files in + * one chunk. + * WARNING: lowering this slows down the connection! + */ +#ifndef LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ +#define LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES + +#if !LWIP_HTTPD_CUSTOM_FILES +#error This needs LWIP_HTTPD_CUSTOM_FILES +#endif +#if !LWIP_HTTPD_DYNAMIC_HEADERS +#error This needs LWIP_HTTPD_DYNAMIC_HEADERS +#endif +#if !LWIP_HTTPD_DYNAMIC_FILE_READ +#error This wants to demonstrate read-after-open, so LWIP_HTTPD_DYNAMIC_FILE_READ is required! +#endif +#if !LWIP_HTTPD_FS_ASYNC_READ +#error This needs LWIP_HTTPD_FS_ASYNC_READ +#endif +#if !LWIP_HTTPD_FILE_EXTENSION +#error This needs LWIP_HTTPD_FILE_EXTENSION +#endif + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED +#include "lwip/tcpip.h" +#endif + +struct fs_custom_data { + FILE *f; +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED + int delay_read; + fs_wait_cb callback_fn; + void *callback_arg; +#endif +}; + +const char* fs_ex_root_dir; + +void +fs_ex_init(const char *httpd_root_dir) +{ + fs_ex_root_dir = strdup(httpd_root_dir); +} + +#if LWIP_HTTPD_CUSTOM_FILES +int +fs_open_custom(struct fs_file *file, const char *name) +{ + char full_filename[256]; + FILE *f; + + snprintf(full_filename, 255, "%s%s", fs_ex_root_dir, name); + full_filename[255] = 0; + + f = fopen(full_filename, "rb"); + if (f != NULL) { + if (!fseek(f, 0, SEEK_END)) { + int len = (int)ftell(f); + if(!fseek(f, 0, SEEK_SET)) { + struct fs_custom_data *data = (struct fs_custom_data *)mem_malloc(sizeof(struct fs_custom_data)); + LWIP_ASSERT("out of memory?", data != NULL); + memset(file, 0, sizeof(struct fs_file)); +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED + file->len = 0; /* read size delayed */ + data->delay_read = 3; + LWIP_UNUSED_ARG(len); +#else + file->len = len; +#endif + file->flags = FS_FILE_FLAGS_HEADER_PERSISTENT; + data->f = f; + file->pextension = data; + return 1; + } + } + fclose(f); + } + return 0; +} + +void +fs_close_custom(struct fs_file *file) +{ + if (file && file->pextension) { + struct fs_custom_data *data = (struct fs_custom_data *)file->pextension; + if (data->f != NULL) { + fclose(data->f); + data->f = NULL; + } + mem_free(data); + } +} + +#if LWIP_HTTPD_FS_ASYNC_READ +u8_t +fs_canread_custom(struct fs_file *file) +{ + /* This function is only necessary for asynchronous I/O: + If reading would block, return 0 and implement fs_wait_read_custom() to call the + supplied callback if reading works. */ +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED + struct fs_custom_data *data; + LWIP_ASSERT("file != NULL", file != NULL); + data = (struct fs_custom_data *)file->pextension; + if (data == NULL) { + /* file transfer has been completed already */ + LWIP_ASSERT("transfer complete", file->index == file->len); + return 1; + } + LWIP_ASSERT("data != NULL", data != NULL); + /* This just simulates a simple delay. This delay would normally come e.g. from SPI transfer */ + if (data->delay_read == 3) { + /* delayed file size mode */ + data->delay_read = 1; + LWIP_ASSERT("", file->len == 0); + if (!fseek(data->f, 0, SEEK_END)) { + int len = (int)ftell(data->f); + if(!fseek(data->f, 0, SEEK_SET)) { + file->len = len; /* read size delayed */ + data->delay_read = 1; + return 0; + } + } + /* if we come here, something is wrong with the file */ + LWIP_ASSERT("file error", 0); + } + if (data->delay_read == 1) { + /* tell read function to delay further */ + } +#endif + LWIP_UNUSED_ARG(file); + return 1; +} + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED +static void +fs_example_read_cb(void *arg) +{ + struct fs_custom_data *data = (struct fs_custom_data *)arg; + fs_wait_cb callback_fn = data->callback_fn; + void *callback_arg = data->callback_arg; + data->callback_fn = NULL; + data->callback_arg = NULL; + + LWIP_ASSERT("no callback_fn", callback_fn != NULL); + + callback_fn(callback_arg); +} +#endif + +u8_t +fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg) +{ +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED + err_t err; + struct fs_custom_data *data = (struct fs_custom_data *)file->pextension; + LWIP_ASSERT("data not set", data != NULL); + data->callback_fn = callback_fn; + data->callback_arg = callback_arg; + err = tcpip_try_callback(fs_example_read_cb, data); + LWIP_ASSERT("out of queue elements?", err == ERR_OK); + LWIP_UNUSED_ARG(err); +#else + LWIP_ASSERT("not implemented in this example configuration", 0); +#endif + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); + /* Return + - 0 if ready to read (at least one byte) + - 1 if reading should be delayed (call 'tcpip_callback(callback_fn, callback_arg)' when ready) */ + return 1; +} + +int +fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg) +{ + struct fs_custom_data *data = (struct fs_custom_data *)file->pextension; + FILE *f; + int len; + int read_count = count; + LWIP_ASSERT("data not set", data != NULL); + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_DELAYED + /* This just simulates a delay. This delay would normally come e.g. from SPI transfer */ + LWIP_ASSERT("invalid state", data->delay_read >= 0 && data->delay_read <= 2); + if (data->delay_read == 2) { + /* no delay next time */ + data->delay_read = 0; + return FS_READ_DELAYED; + } else if (data->delay_read == 1) { + err_t err; + /* execute requested delay */ + data->delay_read = 2; + LWIP_ASSERT("duplicate callback request", data->callback_fn == NULL); + data->callback_fn = callback_fn; + data->callback_arg = callback_arg; + err = tcpip_try_callback(fs_example_read_cb, data); + LWIP_ASSERT("out of queue elements?", err == ERR_OK); + LWIP_UNUSED_ARG(err); + return FS_READ_DELAYED; + } + /* execute this read but delay the next one */ + data->delay_read = 1; +#endif + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ + read_count = LWIP_MIN(read_count, LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ); +#endif + + f = data->f; + len = (int)fread(buffer, 1, read_count, f); + + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); + + file->index += len; + + /* Return + - FS_READ_EOF if all bytes have been read + - FS_READ_DELAYED if reading is delayed (call 'tcpip_callback(callback_fn, callback_arg)' when done) */ + if (len == 0) { + /* all bytes read already */ + return FS_READ_EOF; + } + return len; +} + +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int +fs_read_custom(struct fs_file *file, char *buffer, int count) +{ + struct fs_custom_data *data = (struct fs_custom_data *)file->pextension; + FILE *f; + int len; + int read_count = count; + LWIP_ASSERT("data not set", data != NULL); + +#if LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ + read_count = LWIP_MIN(read_count, LWIP_HTTPD_EXAMPLE_CUSTOMFILES_LIMIT_READ); +#endif + + f = data->f; + len = (int)fread(buffer, 1, read_count, f); + + file->index += len; + + /* Return FS_READ_EOF if all bytes have been read */ + return len; +} + +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_CUSTOM_FILES */ + +#endif /* LWIP_HTTPD_EXAMPLE_CUSTOMFILES */ diff --git a/contrib/examples/httpd/fs_example/fs_example.h b/contrib/examples/httpd/fs_example/fs_example.h new file mode 100644 index 0000000..b399e4d --- /dev/null +++ b/contrib/examples/httpd/fs_example/fs_example.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_HTTP_EXAMPLES_FS_EXAMPLE +#define LWIP_HDR_HTTP_EXAMPLES_FS_EXAMPLE + +void fs_ex_init(const char *httpd_root_dir); + +#endif /* LWIP_HDR_HTTP_EXAMPLES_FS_EXAMPLE */ diff --git a/contrib/examples/httpd/genfiles_example/genfiles_example.c b/contrib/examples/httpd/genfiles_example/genfiles_example.c new file mode 100644 index 0000000..b96df2a --- /dev/null +++ b/contrib/examples/httpd/genfiles_example/genfiles_example.c @@ -0,0 +1,186 @@ +/** + * @file + * HTTPD custom file system example for runtime generated files + * + * This file demonstrates how to add support for generated files to httpd. + */ + + /* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "genfiles_example.h" + +#include "lwip/apps/fs.h" +#include "lwip/def.h" +#include "lwip/mem.h" + +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_GENERATEDFILES to 1 to enable this file system */ +#ifndef LWIP_HTTPD_EXAMPLE_GENERATEDFILES +#define LWIP_HTTPD_EXAMPLE_GENERATEDFILES 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_GENERATEDFILES + +#if !LWIP_HTTPD_CUSTOM_FILES +#error This needs LWIP_HTTPD_CUSTOM_FILES +#endif +#if !LWIP_HTTPD_FILE_EXTENSION +#error This needs LWIP_HTTPD_FILE_EXTENSION +#endif +#if !LWIP_HTTPD_DYNAMIC_HEADERS +#error This needs LWIP_HTTPD_DYNAMIC_HEADERS +#endif + +/* This is the page we send. It's not generated, as you see. + * Generating custom things instead of memcpy is left to your imagination :-) + */ +const char generated_html[] = +"\n" +"lwIP - A Lightweight TCP/IP Stack\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"SICS\n" +" \n" +"

lwIP - A Lightweight TCP/IP Stack

\n" +"

Generated page

\n" +"

This page might be generated in-memory at runtime

\n" +"
\n" +"  \n" +"
\n" +" \n" +""; + + +void +genfiles_ex_init(void) +{ + /* nothing to do here yet */ +} + +int +fs_open_custom(struct fs_file *file, const char *name) +{ + /* this example only provides one file */ + if (!strcmp(name, "/generated.html")) { + /* initialize fs_file correctly */ + memset(file, 0, sizeof(struct fs_file)); + file->pextension = mem_malloc(sizeof(generated_html)); + if (file->pextension != NULL) { + /* instead of doing memcpy, you would generate e.g. a JSON here */ + memcpy(file->pextension, generated_html, sizeof(generated_html)); + file->data = (const char *)file->pextension; + file->len = sizeof(generated_html) - 1; /* don't send the trailing 0 */ + file->index = file->len; + /* allow persisteng connections */ + file->flags = FS_FILE_FLAGS_HEADER_PERSISTENT; + return 1; + } + } + return 0; +} + +void +fs_close_custom(struct fs_file *file) +{ + if (file && file->pextension) { + mem_free(file->pextension); + file->pextension = NULL; + } +} + +#if LWIP_HTTPD_FS_ASYNC_READ +u8_t +fs_canread_custom(struct fs_file *file) +{ + LWIP_UNUSED_ARG(file); + /* This example does not use delayed/async reading */ + return 1; +} + +u8_t +fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg) +{ + LWIP_ASSERT("not implemented in this example configuration", 0); + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); + /* Return + - 1 if ready to read (at least one byte) + - 0 if reading should be delayed (call 'tcpip_callback(callback_fn, callback_arg)' when ready) */ + return 1; +} + +int +fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg) +{ + LWIP_ASSERT("not implemented in this example configuration", 0); + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(buffer); + LWIP_UNUSED_ARG(count); + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); + /* Return + - FS_READ_EOF if all bytes have been read + - FS_READ_DELAYED if reading is delayed (call 'tcpip_callback(callback_fn, callback_arg)' when done) */ + /* all bytes read already */ + return FS_READ_EOF; +} + +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int +fs_read_custom(struct fs_file *file, char *buffer, int count) +{ + LWIP_ASSERT("not implemented in this example configuration", 0); + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(buffer); + LWIP_UNUSED_ARG(count); + /* Return + - FS_READ_EOF if all bytes have been read + - FS_READ_DELAYED if reading is delayed (call 'tcpip_callback(callback_fn, callback_arg)' when done) */ + /* all bytes read already */ + return FS_READ_EOF; +} + +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + +#endif /* LWIP_HTTPD_EXAMPLE_GENERATEDFILES */ diff --git a/contrib/examples/httpd/genfiles_example/genfiles_example.h b/contrib/examples/httpd/genfiles_example/genfiles_example.h new file mode 100644 index 0000000..dd9731e --- /dev/null +++ b/contrib/examples/httpd/genfiles_example/genfiles_example.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_HTTP_EXAMPLES_GENFILES_EXAMPLE +#define LWIP_HDR_HTTP_EXAMPLES_GENFILES_EXAMPLE + +void genfiles_ex_init(void); + +#endif /* LWIP_HDR_HTTP_EXAMPLES_GENFILES_EXAMPLE */ diff --git a/contrib/examples/httpd/https_example/https_example.c b/contrib/examples/httpd/https_example/https_example.c new file mode 100644 index 0000000..7619896 --- /dev/null +++ b/contrib/examples/httpd/https_example/https_example.c @@ -0,0 +1,144 @@ +/** + * @file + * HTTPD https example + * + * This file demonstrates how to initialize httpd for https. + * To do this, it needs 2 files: + * - server certificate + * - server private key + * + * In addition to that, watch out for resource shortage. You'll need plenty of + * heap (start with MEM_SIZE >= 200 KByte or monitor its err counters) and be + * sure to at least set the following settings high enough (monitor + * lwip_stats for an idea of what's needed): + * - MEMP_NUM_TCP_PCB/MEMP_NUM_ALTCP_PCB + * - MEMP_NUM_TCPIP_MSG_INPKT + * - MEMP_NUM_TCP_SEG + */ + + /* + * Copyright (c) 2017-2019 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "https_example.h" + +#include "lwip/altcp_tls.h" +#include "lwip/apps/httpd.h" + +#include +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_HTTPS to 1 to enable this file system */ +#ifndef LWIP_HTTPD_EXAMPLE_HTTPS +#define LWIP_HTTPD_EXAMPLE_HTTPS 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_HTTPS && LWIP_ALTCP_TLS + +#ifndef LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE +#error "define LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE to the created server private key" +#endif + +/* If the key file is password-protected, define LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS */ +#ifdef LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS +#ifndef LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS_LEN +#define LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS_LEN strlen(LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS) +#endif +#else +#define LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS NULL +#define LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS_LEN 0 +#endif + +#ifndef LWIP_HTTPD_EXAMPLE_HTTPS_CERT_FILE +#error "define LWIP_HTTPD_EXAMPLE_HTTPS_CERT_FILE to the created server certificate" +#endif + +static u8_t *read_file(const char *filename, size_t *file_size) +{ + u8_t *buf; + long fsize; + FILE *f = fopen(filename, "rb"); + if (!f) { + return NULL; + } + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = (u8_t *)malloc(fsize + 1); + if (!buf) { + fclose(f); + return NULL; + } + fread(buf, 1, fsize, f); + fclose(f); + + buf[fsize] = 0; + if (file_size) { + /* Note: the '+ 1' is required for mbedTLS to correctly parse the buffer */ + *file_size = (size_t)(fsize + 1); + } + return buf; +} + +/** This function loads a server certificate and private key as x509 from disk. + * For information how to create such files, see mbedTLS tutorial ("How to + * generate a self-signed certificate") or OpenSSL documentation ("How to + * generate a self-signed certificate and private key using OpenSSL"), e.g. + * 'openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt' + * Copy the resulting files and define the path to them + */ +void +https_ex_init(void) +{ + struct altcp_tls_config *conf; + u8_t *privkey, *cert; + size_t privkey_size, cert_size; + + privkey = read_file(LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE, &privkey_size); + LWIP_ASSERT("Failed to open https server private key", privkey != NULL); + cert = read_file(LWIP_HTTPD_EXAMPLE_HTTPS_CERT_FILE, &cert_size); + LWIP_ASSERT("Failed to open https server certificate", cert != NULL); + + conf = altcp_tls_create_config_server_privkey_cert(privkey, privkey_size, + LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS, LWIP_HTTPD_EXAMPLE_HTTPS_KEY_FILE_PASS_LEN, cert, cert_size); + LWIP_ASSERT("Failed to create https server config", conf != NULL); + + httpd_inits(conf); + + /* secure erase should be done in production environment */ + free(privkey); + free(cert); +} + +#endif /* LWIP_HTTPD_EXAMPLE_HTTPS */ diff --git a/contrib/examples/httpd/https_example/https_example.h b/contrib/examples/httpd/https_example/https_example.h new file mode 100644 index 0000000..c1525e6 --- /dev/null +++ b/contrib/examples/httpd/https_example/https_example.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_HTTP_EXAMPLES_HTTPS_EXAMPLE +#define LWIP_HDR_HTTP_EXAMPLES_HTTPS_EXAMPLE + +void https_ex_init(void); + +#endif /* LWIP_HDR_HTTP_EXAMPLES_HTTPS_EXAMPLE */ diff --git a/contrib/examples/httpd/post_example/post_example.c b/contrib/examples/httpd/post_example/post_example.c new file mode 100644 index 0000000..f4e4369 --- /dev/null +++ b/contrib/examples/httpd/post_example/post_example.c @@ -0,0 +1,167 @@ +/** + * @file + * HTTPD example for simple POST + */ + + /* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#include "lwip/apps/httpd.h" +#include "lwip/def.h" +#include "lwip/mem.h" + +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_GENERATEDFILES to 1 to enable this file system */ +#ifndef LWIP_HTTPD_EXAMPLE_SIMPLEPOST +#define LWIP_HTTPD_EXAMPLE_SIMPLEPOST 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_SIMPLEPOST + +#if !LWIP_HTTPD_SUPPORT_POST +#error This needs LWIP_HTTPD_SUPPORT_POST +#endif + +#define USER_PASS_BUFSIZE 16 + +static void *current_connection; +static void *valid_connection; +static char last_user[USER_PASS_BUFSIZE]; + +err_t +httpd_post_begin(void *connection, const char *uri, const char *http_request, + u16_t http_request_len, int content_len, char *response_uri, + u16_t response_uri_len, u8_t *post_auto_wnd) +{ + LWIP_UNUSED_ARG(connection); + LWIP_UNUSED_ARG(http_request); + LWIP_UNUSED_ARG(http_request_len); + LWIP_UNUSED_ARG(content_len); + LWIP_UNUSED_ARG(post_auto_wnd); + if (!memcmp(uri, "/login.cgi", 11)) { + if (current_connection != connection) { + current_connection = connection; + valid_connection = NULL; + /* default page is "login failed" */ + snprintf(response_uri, response_uri_len, "/loginfail.html"); + /* e.g. for large uploads to slow flash over a fast connection, you should + manually update the rx window. That way, a sender can only send a full + tcp window at a time. If this is required, set 'post_aut_wnd' to 0. + We do not need to throttle upload speed here, so: */ + *post_auto_wnd = 1; + return ERR_OK; + } + } + return ERR_VAL; +} + +err_t +httpd_post_receive_data(void *connection, struct pbuf *p) +{ + err_t ret; + + LWIP_ASSERT("NULL pbuf", p != NULL); + + if (current_connection == connection) { + u16_t token_user = pbuf_memfind(p, "user=", 5, 0); + u16_t token_pass = pbuf_memfind(p, "pass=", 5, 0); + if ((token_user != 0xFFFF) && (token_pass != 0xFFFF)) { + u16_t value_user = token_user + 5; + u16_t value_pass = token_pass + 5; + u16_t len_user = 0; + u16_t len_pass = 0; + u16_t tmp; + /* find user len */ + tmp = pbuf_memfind(p, "&", 1, value_user); + if (tmp != 0xFFFF) { + len_user = tmp - value_user; + } else { + len_user = p->tot_len - value_user; + } + /* find pass len */ + tmp = pbuf_memfind(p, "&", 1, value_pass); + if (tmp != 0xFFFF) { + len_pass = tmp - value_pass; + } else { + len_pass = p->tot_len - value_pass; + } + if ((len_user > 0) && (len_user < USER_PASS_BUFSIZE) && + (len_pass > 0) && (len_pass < USER_PASS_BUFSIZE)) { + /* provide contiguous storage if p is a chained pbuf */ + char buf_user[USER_PASS_BUFSIZE]; + char buf_pass[USER_PASS_BUFSIZE]; + char *user = (char *)pbuf_get_contiguous(p, buf_user, sizeof(buf_user), len_user, value_user); + char *pass = (char *)pbuf_get_contiguous(p, buf_pass, sizeof(buf_pass), len_pass, value_pass); + if (user && pass) { + user[len_user] = 0; + pass[len_pass] = 0; + if (!strcmp(user, "lwip") && !strcmp(pass, "post")) { + /* user and password are correct, create a "session" */ + valid_connection = connection; + memcpy(last_user, user, sizeof(last_user)); + } + } + } + } + /* not returning ERR_OK aborts the connection, so return ERR_OK unless the + connection is unknown */ + ret = ERR_OK; + } else { + ret = ERR_VAL; + } + + /* this function must ALWAYS free the pbuf it is passed or it will leak memory */ + pbuf_free(p); + + return ret; +} + +void +httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len) +{ + /* default page is "login failed" */ + snprintf(response_uri, response_uri_len, "/loginfail.html"); + if (current_connection == connection) { + if (valid_connection == connection) { + /* login succeeded */ + snprintf(response_uri, response_uri_len, "/session.html"); + } + current_connection = NULL; + valid_connection = NULL; + } +} + +#endif /* LWIP_HTTPD_EXAMPLE_SIMPLEPOST*/ diff --git a/contrib/examples/httpd/ssi_example/ssi_example.c b/contrib/examples/httpd/ssi_example/ssi_example.c new file mode 100644 index 0000000..2024e2e --- /dev/null +++ b/contrib/examples/httpd/ssi_example/ssi_example.c @@ -0,0 +1,264 @@ +/** + * @file + * HTTPD simple SSI example + * + * This file demonstrates how to add support for SSI. + * It does this in a very simple way by providing the three tags 'HelloWorld' + * 'counter', and 'MultiPart'. + * + * This file also demonstrates how to integrate CGI with SSI. + */ + + /* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "ssi_example.h" + +#include "lwip/apps/httpd.h" + +#include "lwip/def.h" +#include "lwip/mem.h" + +#include +#include + +/** define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE to 1 to enable this ssi example*/ +#ifndef LWIP_HTTPD_EXAMPLE_SSI_SIMPLE +#define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE 0 +#endif + +/** define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION to 1 to show how to + * integrate CGI into SSI (LWIP_HTTPD_CGI_SSI) */ +#ifndef LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION +#define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION 0 +#endif + +#if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE + +#if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION +#if !LWIP_HTTPD_FILE_STATE +#error LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION needs LWIP_HTTPD_FILE_STATE +#endif +#if !LWIP_HTTPD_CGI_SSI +#error LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION needs LWIP_HTTPD_CGI_SSI +#endif + +#define MAX_CGI_LEN 16 +#endif + +const char * ssi_example_tags[] = { + "HellWorl", + "counter", + "MultPart" +#if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION + ,"CgiParam" +#endif +}; + +u16_t ssi_example_ssi_handler( +#if LWIP_HTTPD_SSI_RAW + const char* ssi_tag_name, +#else /* LWIP_HTTPD_SSI_RAW */ + int iIndex, +#endif /* LWIP_HTTPD_SSI_RAW */ + char *pcInsert, int iInsertLen +#if LWIP_HTTPD_SSI_MULTIPART + , u16_t current_tag_part, u16_t *next_tag_part +#endif /* LWIP_HTTPD_SSI_MULTIPART */ +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ) +{ + size_t printed; +#if LWIP_HTTPD_SSI_RAW + /* a real application could use if(!strcmp) blocks here, but we want to keep + the differences between configurations small, so translate string to index here */ + int iIndex; + for (iIndex = 0; iIndex < LWIP_ARRAYSIZE(ssi_example_tags); iIndex++) { + if(!strcmp(ssi_tag_name, ssi_example_tags[iIndex])) { + break; + } + } +#endif +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + LWIP_UNUSED_ARG(connection_state); +#endif + + switch (iIndex) { + case 0: /* "HelloWorld" */ + printed = snprintf(pcInsert, iInsertLen, "Hello World!"); + break; + case 1: /* "counter" */ + { + static int counter; + counter++; + printed = snprintf(pcInsert, iInsertLen, "%d", counter); + } + break; + case 2: /* "MultPart" */ +#if LWIP_HTTPD_SSI_MULTIPART + switch (current_tag_part) { + case 0: + printed = snprintf(pcInsert, iInsertLen, "part0"); + *next_tag_part = 1; + break; + case 1: + printed = snprintf(pcInsert, iInsertLen, "part1"); + *next_tag_part = 2; + break; + case 2: + printed = snprintf(pcInsert, iInsertLen, "part2"); + break; + default: + printed = snprintf(pcInsert, iInsertLen, "unhandled part: %d", (int)current_tag_part); + break; + } +#else + printed = snprintf(pcInsert, iInsertLen, "LWIP_HTTPD_SSI_MULTIPART disabled"); +#endif + break; +#if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION + case 3: + if (connection_state) { + char *params = (char *)connection_state; + if (*params) { + printed = snprintf(pcInsert, iInsertLen, "%s", (char *)params); + } else { + printed = snprintf(pcInsert, iInsertLen, "none"); + } + } else { + printed = snprintf(pcInsert, iInsertLen, "NULL"); + } + break; +#endif + default: /* unknown tag */ + printed = 0; + break; + } + LWIP_ASSERT("sane length", printed <= 0xFFFF); + return (u16_t)printed; +} + +void +ssi_ex_init(void) +{ + int i; + for (i = 0; i < LWIP_ARRAYSIZE(ssi_example_tags); i++) { + LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN", + strlen(ssi_example_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN); + } + + http_set_ssi_handler(ssi_example_ssi_handler, +#if LWIP_HTTPD_SSI_RAW + NULL, 0 +#else + ssi_example_tags, LWIP_ARRAYSIZE(ssi_example_tags) +#endif + ); +} + +#if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION +void * +fs_state_init(struct fs_file *file, const char *name) +{ + char *ret; + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(name); + ret = (char *)mem_malloc(MAX_CGI_LEN); + if (ret) { + *ret = 0; + } + return ret; +} + +void +fs_state_free(struct fs_file *file, void *state) +{ + LWIP_UNUSED_ARG(file); + if (state != NULL) { + mem_free(state); + } +} + +void +httpd_cgi_handler(struct fs_file *file, const char* uri, int iNumParams, + char **pcParam, char **pcValue +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ) +{ + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(uri); + if (connection_state != NULL) { + char *start = (char *)connection_state; + char *end = start + MAX_CGI_LEN; + int i; + memset(start, 0, MAX_CGI_LEN); + /* print a string of the arguments: */ + for (i = 0; i < iNumParams; i++) { + size_t len; + len = end - start; + if (len) { + size_t inlen = strlen(pcParam[i]); + size_t copylen = LWIP_MIN(inlen, len); + memcpy(start, pcParam[i], copylen); + start += copylen; + len -= copylen; + } + if (len) { + *start = '='; + start++; + len--; + } + if (len) { + size_t inlen = strlen(pcValue[i]); + size_t copylen = LWIP_MIN(inlen, len); + memcpy(start, pcValue[i], copylen); + start += copylen; + len -= copylen; + } + if (len) { + *start = ';'; + len--; + } + /* ensure NULL termination */ + end--; + *end = 0; + } + } +} +#endif /* LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION */ + +#endif /* LWIP_HTTPD_EXAMPLE_SSI_SIMPLE */ diff --git a/contrib/examples/httpd/ssi_example/ssi_example.h b/contrib/examples/httpd/ssi_example/ssi_example.h new file mode 100644 index 0000000..b7ec298 --- /dev/null +++ b/contrib/examples/httpd/ssi_example/ssi_example.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_HTTP_EXAMPLES_SSI_EXAMPLE +#define LWIP_HDR_HTTP_EXAMPLES_SSI_EXAMPLE + +void ssi_ex_init(void); + +#endif /* LWIP_HDR_HTTP_EXAMPLES_SSI_EXAMPLE */ diff --git a/contrib/examples/lwiperf/lwiperf_example.c b/contrib/examples/lwiperf/lwiperf_example.c new file mode 100644 index 0000000..a33bc6f --- /dev/null +++ b/contrib/examples/lwiperf/lwiperf_example.c @@ -0,0 +1,50 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include "lwip/apps/lwiperf.h" +#include "lwiperf_example.h" + +static void +lwiperf_report(void *arg, enum lwiperf_report_type report_type, + const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, + u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(local_addr); + LWIP_UNUSED_ARG(local_port); + + LWIP_PLATFORM_DIAG(("IPERF report: type=%d, remote: %s:%d, total bytes: %"U32_F", duration in ms: %"U32_F", kbits/s: %"U32_F"\n", + (int)report_type, ipaddr_ntoa(remote_addr), (int)remote_port, bytes_transferred, ms_duration, bandwidth_kbitpsec)); +} + +void +lwiperf_example_init(void) +{ + lwiperf_start_tcp_server_default(lwiperf_report, NULL); +} diff --git a/contrib/examples/lwiperf/lwiperf_example.h b/contrib/examples/lwiperf/lwiperf_example.h new file mode 100644 index 0000000..d7b35c8 --- /dev/null +++ b/contrib/examples/lwiperf/lwiperf_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIPERF_EXAMPLE_H +#define LWIPERF_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void lwiperf_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIPERF_EXAMPLE_H */ diff --git a/contrib/examples/mdns/mdns_example.c b/contrib/examples/mdns/mdns_example.c new file mode 100644 index 0000000..49625ef --- /dev/null +++ b/contrib/examples/mdns/mdns_example.c @@ -0,0 +1,63 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include "lwip/apps/mdns.h" +#include "mdns_example.h" + +#if LWIP_MDNS_RESPONDER +static void +srv_txt(struct mdns_service *service, void *txt_userdata) +{ + err_t res; + LWIP_UNUSED_ARG(txt_userdata); + + res = mdns_resp_add_service_txtitem(service, "path=/", 6); + LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return); +} +#endif + +#if LWIP_MDNS_RESPONDER +static void +mdns_example_report(struct netif* netif, u8_t result, s8_t service) +{ + LWIP_PLATFORM_DIAG(("mdns status[netif %d][service %d]: %d\n", netif->num, service, result)); +} +#endif + +void +mdns_example_init(void) +{ +#if LWIP_MDNS_RESPONDER + mdns_resp_register_name_result_cb(mdns_example_report); + mdns_resp_init(); + mdns_resp_add_netif(netif_default, "lwip"); + mdns_resp_add_service(netif_default, "myweb", "_http", DNSSD_PROTO_TCP, 80, srv_txt, NULL); + mdns_resp_announce(netif_default); +#endif +} diff --git a/contrib/examples/mdns/mdns_example.h b/contrib/examples/mdns/mdns_example.h new file mode 100644 index 0000000..ab51ade --- /dev/null +++ b/contrib/examples/mdns/mdns_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef MDNS_EXAMPLE_H +#define MDNS_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void mdns_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* MDNS_EXAMPLE_H */ diff --git a/contrib/examples/mqtt/mqtt_example.c b/contrib/examples/mqtt/mqtt_example.c new file mode 100644 index 0000000..9cf188d --- /dev/null +++ b/contrib/examples/mqtt/mqtt_example.c @@ -0,0 +1,129 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include "lwip/apps/mqtt.h" +#include "mqtt_example.h" + +#if LWIP_TCP + +/** Define this to a compile-time IP address initialization + * to connect anything else than IPv4 loopback + */ +#ifndef LWIP_MQTT_EXAMPLE_IPADDR_INIT +#if LWIP_IPV4 +#define LWIP_MQTT_EXAMPLE_IPADDR_INIT = IPADDR4_INIT(PP_HTONL(IPADDR_LOOPBACK)) +#else +#define LWIP_MQTT_EXAMPLE_IPADDR_INIT +#endif +#endif + +static ip_addr_t mqtt_ip LWIP_MQTT_EXAMPLE_IPADDR_INIT; +static mqtt_client_t* mqtt_client; + +static const struct mqtt_connect_client_info_t mqtt_client_info = +{ + "test", + NULL, /* user */ + NULL, /* pass */ + 100, /* keep alive */ + NULL, /* will_topic */ + NULL, /* will_msg */ + 0, /* will_msg_len */ + 0, /* will_qos */ + 0 /* will_retain */ +#if LWIP_ALTCP && LWIP_ALTCP_TLS + , NULL +#endif +}; + +static void +mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) +{ + const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg; + LWIP_UNUSED_ARG(data); + + LWIP_PLATFORM_DIAG(("MQTT client \"%s\" data cb: len %d, flags %d\n", client_info->client_id, + (int)len, (int)flags)); +} + +static void +mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) +{ + const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg; + + LWIP_PLATFORM_DIAG(("MQTT client \"%s\" publish cb: topic %s, len %d\n", client_info->client_id, + topic, (int)tot_len)); +} + +static void +mqtt_request_cb(void *arg, err_t err) +{ + const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg; + + LWIP_PLATFORM_DIAG(("MQTT client \"%s\" request cb: err %d\n", client_info->client_id, (int)err)); +} + +static void +mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) +{ + const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg; + LWIP_UNUSED_ARG(client); + + LWIP_PLATFORM_DIAG(("MQTT client \"%s\" connection cb: status %d\n", client_info->client_id, (int)status)); + + if (status == MQTT_CONNECT_ACCEPTED) { + mqtt_sub_unsub(client, + "topic_qos1", 1, + mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), + 1); + mqtt_sub_unsub(client, + "topic_qos0", 0, + mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), + 1); + } +} +#endif /* LWIP_TCP */ + +void +mqtt_example_init(void) +{ +#if LWIP_TCP + mqtt_client = mqtt_client_new(); + + mqtt_set_inpub_callback(mqtt_client, + mqtt_incoming_publish_cb, + mqtt_incoming_data_cb, + LWIP_CONST_CAST(void*, &mqtt_client_info)); + + mqtt_client_connect(mqtt_client, + &mqtt_ip, MQTT_PORT, + mqtt_connection_cb, LWIP_CONST_CAST(void*, &mqtt_client_info), + &mqtt_client_info); +#endif /* LWIP_TCP */ +} diff --git a/contrib/examples/mqtt/mqtt_example.h b/contrib/examples/mqtt/mqtt_example.h new file mode 100644 index 0000000..797678b --- /dev/null +++ b/contrib/examples/mqtt/mqtt_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef MQTT_EXAMPLE_H +#define MQTT_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void mqtt_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* MQTT_EXAMPLE_H */ diff --git a/contrib/examples/ppp/pppos_example.c b/contrib/examples/ppp/pppos_example.c new file mode 100644 index 0000000..0d18ce5 --- /dev/null +++ b/contrib/examples/ppp/pppos_example.c @@ -0,0 +1,221 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include "lwip/dns.h" + +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT 0 +#endif /* PPPOS_SUPPORT */ + +#if PPPOS_SUPPORT +#include "netif/ppp/pppos.h" +#include "lwip/sio.h" +#define PPP_PTY_TEST 1 +#endif /* PPPOS_SUPPORT */ + +#include "pppos_example.h" + +#include + +#if PPPOS_SUPPORT +static sio_fd_t ppp_sio; +static ppp_pcb *ppp; +static struct netif pppos_netif; + +static void +pppos_rx_thread(void *arg) +{ + u32_t len; + u8_t buffer[128]; + LWIP_UNUSED_ARG(arg); + + /* Please read the "PPPoS input path" chapter in the PPP documentation. */ + while (1) { + len = sio_read(ppp_sio, buffer, sizeof(buffer)); + if (len > 0) { + /* Pass received raw characters from PPPoS to be decoded through lwIP + * TCPIP thread using the TCPIP API. This is thread safe in all cases + * but you should avoid passing data byte after byte. */ + pppos_input_tcpip(ppp, buffer, len); + } + } +} + +static void +ppp_link_status_cb(ppp_pcb *pcb, int err_code, void *ctx) +{ + struct netif *pppif = ppp_netif(pcb); + LWIP_UNUSED_ARG(ctx); + + switch(err_code) { + case PPPERR_NONE: /* No error. */ + { +#if LWIP_DNS + const ip_addr_t *ns; +#endif /* LWIP_DNS */ + fprintf(stderr, "ppp_link_status_cb: PPPERR_NONE\n\r"); +#if LWIP_IPV4 + fprintf(stderr, " our_ip4addr = %s\n\r", ip4addr_ntoa(netif_ip4_addr(pppif))); + fprintf(stderr, " his_ipaddr = %s\n\r", ip4addr_ntoa(netif_ip4_gw(pppif))); + fprintf(stderr, " netmask = %s\n\r", ip4addr_ntoa(netif_ip4_netmask(pppif))); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + fprintf(stderr, " our_ip6addr = %s\n\r", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); +#endif /* LWIP_IPV6 */ + +#if LWIP_DNS + ns = dns_getserver(0); + fprintf(stderr, " dns1 = %s\n\r", ipaddr_ntoa(ns)); + ns = dns_getserver(1); + fprintf(stderr, " dns2 = %s\n\r", ipaddr_ntoa(ns)); +#endif /* LWIP_DNS */ +#if PPP_IPV6_SUPPORT + fprintf(stderr, " our6_ipaddr = %s\n\r", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); +#endif /* PPP_IPV6_SUPPORT */ + } + break; + + case PPPERR_PARAM: /* Invalid parameter. */ + printf("ppp_link_status_cb: PPPERR_PARAM\n"); + break; + + case PPPERR_OPEN: /* Unable to open PPP session. */ + printf("ppp_link_status_cb: PPPERR_OPEN\n"); + break; + + case PPPERR_DEVICE: /* Invalid I/O device for PPP. */ + printf("ppp_link_status_cb: PPPERR_DEVICE\n"); + break; + + case PPPERR_ALLOC: /* Unable to allocate resources. */ + printf("ppp_link_status_cb: PPPERR_ALLOC\n"); + break; + + case PPPERR_USER: /* User interrupt. */ + printf("ppp_link_status_cb: PPPERR_USER\n"); + break; + + case PPPERR_CONNECT: /* Connection lost. */ + printf("ppp_link_status_cb: PPPERR_CONNECT\n"); + break; + + case PPPERR_AUTHFAIL: /* Failed authentication challenge. */ + printf("ppp_link_status_cb: PPPERR_AUTHFAIL\n"); + break; + + case PPPERR_PROTOCOL: /* Failed to meet protocol. */ + printf("ppp_link_status_cb: PPPERR_PROTOCOL\n"); + break; + + case PPPERR_PEERDEAD: /* Connection timeout. */ + printf("ppp_link_status_cb: PPPERR_PEERDEAD\n"); + break; + + case PPPERR_IDLETIMEOUT: /* Idle Timeout. */ + printf("ppp_link_status_cb: PPPERR_IDLETIMEOUT\n"); + break; + + case PPPERR_CONNECTTIME: /* PPPERR_CONNECTTIME. */ + printf("ppp_link_status_cb: PPPERR_CONNECTTIME\n"); + break; + + case PPPERR_LOOPBACK: /* Connection timeout. */ + printf("ppp_link_status_cb: PPPERR_LOOPBACK\n"); + break; + + default: + printf("ppp_link_status_cb: unknown errCode %d\n", err_code); + break; + } +} + +static u32_t +ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(ctx); + return sio_write(ppp_sio, (const u8_t*)data, len); +} + +#if LWIP_NETIF_STATUS_CALLBACK +static void +netif_status_callback(struct netif *nif) +{ + printf("PPPNETIF: %c%c%d is %s\n", nif->name[0], nif->name[1], nif->num, + netif_is_up(nif) ? "UP" : "DOWN"); +#if LWIP_IPV4 + printf("IPV4: Host at %s ", ip4addr_ntoa(netif_ip4_addr(nif))); + printf("mask %s ", ip4addr_ntoa(netif_ip4_netmask(nif))); + printf("gateway %s\n", ip4addr_ntoa(netif_ip4_gw(nif))); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + printf("IPV6: Host at %s\n", ip6addr_ntoa(netif_ip6_addr(nif, 0))); +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_HOSTNAME + printf("FQDN: %s\n", netif_get_hostname(nif)); +#endif /* LWIP_NETIF_HOSTNAME */ +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#endif + +void +pppos_example_init(void) +{ +#if PPPOS_SUPPORT +#if PPP_PTY_TEST + ppp_sio = sio_open(2); +#else + ppp_sio = sio_open(0); +#endif + if(!ppp_sio) + { + perror("PPPOS example: Error opening device"); + return; + } + + ppp = pppos_create(&pppos_netif, ppp_output_cb, ppp_link_status_cb, NULL); + if (!ppp) + { + printf("PPPOS example: Could not create PPP control interface"); + return; + } + +#ifdef LWIP_PPP_CHAP_TEST + ppp_set_auth(ppp, PPPAUTHTYPE_CHAP, "lwip", "mysecret"); +#endif + + ppp_connect(ppp, 0); + +#if LWIP_NETIF_STATUS_CALLBACK + netif_set_status_callback(&pppos_netif, netif_status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + + sys_thread_new("pppos_rx_thread", pppos_rx_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +#endif /* PPPOS_SUPPORT */ +} diff --git a/contrib/examples/ppp/pppos_example.h b/contrib/examples/ppp/pppos_example.h new file mode 100644 index 0000000..726961c --- /dev/null +++ b/contrib/examples/ppp/pppos_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef PPPOS_EXAMPLE_H +#define PPPOS_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void pppos_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PPPOS_EXAMPLE_H */ diff --git a/contrib/examples/snmp/snmp_example.c b/contrib/examples/snmp/snmp_example.c new file mode 100644 index 0000000..5952474 --- /dev/null +++ b/contrib/examples/snmp/snmp_example.c @@ -0,0 +1,80 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include "lwip/netif.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmpv3.h" +#include "lwip/apps/snmp_snmpv2_framework.h" +#include "lwip/apps/snmp_snmpv2_usm.h" +#include "examples/snmp/snmp_v3/snmpv3_dummy.h" +#include "examples/snmp/snmp_private_mib/private_mib.h" +#include "snmp_example.h" + +#if LWIP_SNMP +static const struct snmp_mib *mibs[] = { + &mib2, + &mib_private +#if LWIP_SNMP_V3 + , &snmpframeworkmib + , &snmpusmmib +#endif +}; +#endif /* LWIP_SNMP */ + +void +snmp_example_init(void) +{ +#if LWIP_SNMP + s32_t req_nr; + lwip_privmib_init(); +#if SNMP_LWIP_MIB2 +#if SNMP_USE_NETCONN + snmp_threadsync_init(&snmp_mib2_lwip_locks, snmp_mib2_lwip_synchronizer); +#endif /* SNMP_USE_NETCONN */ + snmp_mib2_set_syscontact_readonly((const u8_t*)"root", NULL); + snmp_mib2_set_syslocation_readonly((const u8_t*)"lwIP development PC", NULL); + snmp_mib2_set_sysdescr((const u8_t*)"lwIP example", NULL); +#endif /* SNMP_LWIP_MIB2 */ + +#if LWIP_SNMP_V3 + snmpv3_dummy_init(); +#endif + + snmp_set_mibs(mibs, LWIP_ARRAYSIZE(mibs)); + snmp_init(); + + snmp_trap_dst_ip_set(0, &netif_default->gw); + snmp_trap_dst_enable(0, 1); + + snmp_send_inform_generic(SNMP_GENTRAP_COLDSTART, NULL, &req_nr); + snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART); + +#endif /* LWIP_SNMP */ +} diff --git a/contrib/examples/snmp/snmp_example.h b/contrib/examples/snmp/snmp_example.h new file mode 100644 index 0000000..fafcd68 --- /dev/null +++ b/contrib/examples/snmp/snmp_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef SNMP_EXAMPLE_H +#define SNMP_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void snmp_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SNMP_EXAMPLE_H */ diff --git a/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c b/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c new file mode 100644 index 0000000..51a49fe --- /dev/null +++ b/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c @@ -0,0 +1,401 @@ +/** + * @file + * lwip Private MIB + * + * @todo create MIB file for this example + * @note the lwip enterprise tree root (26381) is owned by the lwIP project. + * It is NOT allowed to allocate new objects under this ID (26381) without our, + * the lwip developers, permission! + * + * Please apply for your own ID with IANA: http://www.iana.org/numbers.html + * + * lwip OBJECT IDENTIFIER ::= { enterprises 26381 } + * example OBJECT IDENTIFIER ::= { lwip 1 } + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#include "private_mib.h" + +#if LWIP_SNMP + +/** Directory where the sensor files are */ +#define SENSORS_DIR "w:\\sensors" +/** Set to 1 to read sensor values from files (in directory defined by SENSORS_DIR) */ +#define SENSORS_USE_FILES 0 +/** Set to 1 to search sensor files at startup (in directory defined by SENSORS_DIR) */ +#define SENSORS_SEARCH_FILES 0 + +#if SENSORS_SEARCH_FILES +#include +#include +#include +#include +#include +#endif /* SENSORS_SEARCH_FILES */ + +#include +#include + +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" + +#if !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES +/** When not using & searching files, defines the number of sensors */ +#define SENSOR_COUNT 4 +#endif /* !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES */ + +/* + This example presents a table for a few (at most 10) sensors. + Sensor detection takes place at initialization (once only). + Sensors may and can not be added or removed after agent + has started. Note this is only a limitation of this crude example, + the agent does support dynamic object insertions and removals. + + You'll need to manually create a directory called "sensors" and + a few single line text files with an integer temperature value. + The files must be called [0..9].txt. + + ./sensors/0.txt [content: 20] + ./sensors/3.txt [content: 75] + + The sensor values may be changed in runtime by editing the + text files in the "sensors" directory. +*/ + +#define SENSOR_MAX 10 +#define SENSOR_NAME_LEN 20 + +struct sensor_inf +{ + u8_t num; + + char file[SENSOR_NAME_LEN + 1]; + +#if !SENSORS_USE_FILES + /** When not using files, contains the value of the sensor */ + s32_t value; +#endif /* !SENSORS_USE_FILES */ +}; + +static struct sensor_inf sensors[SENSOR_MAX]; + +static s16_t sensor_count_get_value(struct snmp_node_instance* instance, void* value); +static snmp_err_t sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); +static snmp_err_t sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); +static s16_t sensor_table_get_value(struct snmp_node_instance* instance, void* value); +static snmp_err_t sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value); + +/* sensorentry .1.3.6.1.4.1.26381.1.1.1 (.level0.level1) + where level 0 is the table column (temperature/file name) + and level 1 the table row (sensor index) */ +static const struct snmp_table_col_def sensor_table_columns[] = { + { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, + { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY } +}; + +/* sensortable .1.3.6.1.4.1.26381.1.1 */ +static const struct snmp_table_node sensor_table = SNMP_TABLE_CREATE( + 1, sensor_table_columns, + sensor_table_get_cell_instance, sensor_table_get_next_cell_instance, + sensor_table_get_value, snmp_set_test_ok, sensor_table_set_value); + +/* sensorcount .1.3.6.1.4.1.26381.1.2 */ +static const struct snmp_scalar_node sensor_count = SNMP_SCALAR_CREATE_NODE_READONLY( + 2, SNMP_ASN1_TYPE_INTEGER, sensor_count_get_value); + +/* example .1.3.6.1.4.1.26381.1 */ +static const struct snmp_node* const example_nodes[] = { + &sensor_table.node.node, + &sensor_count.node.node +}; +static const struct snmp_tree_node example_node = SNMP_CREATE_TREE_NODE(1, example_nodes); + +static const u32_t prvmib_base_oid[] = { 1,3,6,1,4,1,26381,1 }; +const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &example_node.node); + +#if 0 +/* for reference: we could also have expressed it like this: */ + +/* lwip .1.3.6.1.4.1.26381 */ +static const struct snmp_node* const lwip_nodes[] = { + &example_node.node +}; +static const struct snmp_tree_node lwip_node = SNMP_CREATE_TREE_NODE(26381, lwip_nodes); + +/* enterprises .1.3.6.1.4.1 */ +static const struct snmp_node* const enterprises_nodes[] = { + &lwip_node.node +}; +static const struct snmp_tree_node enterprises_node = SNMP_CREATE_TREE_NODE(1, enterprises_nodes); + +/* private .1.3.6.1.4 */ +static const struct snmp_node* const private_nodes[] = { + &enterprises_node.node +}; +static const struct snmp_tree_node private_root = SNMP_CREATE_TREE_NODE(4, private_nodes); + +static const u32_t prvmib_base_oid[] = { 1,3,6,1,4 }; +const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &private_root.node); +#endif + +/** + * Initialises this private MIB before use. + * @see main.c + */ +void +lwip_privmib_init(void) +{ +#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES + char *buf, *ebuf, *cp; + size_t bufsize; + int nbytes; + struct stat sb; + struct dirent *dp; + int fd; +#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + u8_t i; +#endif /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + + memset(sensors, 0, sizeof(sensors)); + + printf("SNMP private MIB start, detecting sensors.\n"); + +#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES + /* look for sensors in sensors directory */ + fd = open(SENSORS_DIR, O_RDONLY); + if (fd > -1) + { + fstat(fd, &sb); + bufsize = sb.st_size; + if (bufsize < (size_t)sb.st_blksize) + { + bufsize = sb.st_blksize; + } + buf = (char*)malloc(bufsize); + if (buf != NULL) + { + do + { + long base; + + nbytes = getdirentries(fd, buf, bufsize, &base); + if (nbytes > 0) + { + ebuf = buf + nbytes; + cp = buf; + while (cp < ebuf) + { + dp = (struct dirent *)cp; + if (lwip_isdigit(dp->d_name[0])) + { + unsigned char idx = dp->d_name[0] - '0'; + + sensors[idx].num = idx+1; + strncpy(&sensors[idx].file[0], dp->d_name, SENSOR_NAME_LEN); + printf("%s\n", sensors[idx].file); + } + cp += dp->d_reclen; + } + } + } + while (nbytes > 0); + + free(buf); + } + close(fd); + } +#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + for (i = 0; i < SENSOR_COUNT; i++) { + sensors[i].num = (u8_t)(i + 1); + snprintf(sensors[i].file, sizeof(sensors[i].file), "%d.txt", i); + +#if !SENSORS_USE_FILES + /* initialize sensor value to != zero */ + sensors[i].value = 11 * (i+1); +#endif /* !SENSORS_USE_FILES */ + } +#endif /* SENSORS_USE_FILE && SENSORS_SEARCH_FILES */ +} + +/* sensorcount .1.3.6.1.4.1.26381.1.2 */ +static s16_t +sensor_count_get_value(struct snmp_node_instance* instance, void* value) +{ + size_t count = 0; + u32_t *uint_ptr = (u32_t*)value; + + LWIP_UNUSED_ARG(instance); + + for(count=0; countreference.u32 = (u32_t)i; + return SNMP_ERR_NOERROR; + } + } + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance) +{ + size_t i; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(sensor_table_oid_ranges)]; + + LWIP_UNUSED_ARG(column); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(sensor_table_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + for(i=0; ireference.u32 = LWIP_CONST_CAST(u32_t, state.reference); + return SNMP_ERR_NOERROR; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static s16_t +sensor_table_get_value(struct snmp_node_instance* instance, void* value) +{ + u32_t i = instance->reference.u32; + s32_t *temperature = (s32_t *)value; + + switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) + { + case 1: /* sensor value */ +#if SENSORS_USE_FILES + FILE* sensf; + char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; + + strncpy(&senspath[sizeof(SENSORS_DIR)], + sensors[i].file, + SENSOR_NAME_LEN); + sensf = fopen(senspath,"r"); + if (sensf != NULL) + { + fscanf(sensf,"%"S32_F,temperature); + fclose(sensf); + } +#else /* SENSORS_USE_FILES */ + *temperature = sensors[i].value; +#endif /* SENSORS_USE_FILES */ + return sizeof(s32_t); + case 2: /* file name */ + MEMCPY(value, sensors[i].file, strlen(sensors[i].file)); + return (s16_t)strlen(sensors[i].file); + default: + return 0; + } +} + +static snmp_err_t +sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value) +{ + u32_t i = instance->reference.u32; + s32_t *temperature = (s32_t *)value; +#if SENSORS_USE_FILES + FILE* sensf; + char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; + + strncpy(&senspath[sizeof(SENSORS_DIR)], + sensors[i].file, + SENSOR_NAME_LEN); + sensf = fopen(senspath, "w"); + if (sensf != NULL) + { + fprintf(sensf, "%"S32_F, *temperature); + fclose(sensf); + } +#else /* SENSORS_USE_FILES */ + sensors[i].value = *temperature; +#endif /* SENSORS_USE_FILES */ + + LWIP_UNUSED_ARG(len); + + return SNMP_ERR_NOERROR; +} + +#endif /* LWIP_SNMP */ diff --git a/contrib/examples/snmp/snmp_private_mib/private_mib.h b/contrib/examples/snmp/snmp_private_mib/private_mib.h new file mode 100644 index 0000000..69be8a4 --- /dev/null +++ b/contrib/examples/snmp/snmp_private_mib/private_mib.h @@ -0,0 +1,26 @@ +/** + * @file + * Exports Private lwIP MIB + */ + +#ifndef LWIP_HDR_PRIVATE_MIB_H +#define LWIP_HDR_PRIVATE_MIB_H + +#include "lwip/apps/snmp_opts.h" + +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* export MIB */ +extern const struct snmp_mib mib_private; + +void lwip_privmib_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c new file mode 100644 index 0000000..a7c53ed --- /dev/null +++ b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c @@ -0,0 +1,395 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + * Dirk Ziegelmeier + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_dummy.h" +#include +#include "lwip/err.h" +#include "lwip/def.h" +#include "lwip/timeouts.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +struct user_table_entry { + char username[32]; + snmpv3_auth_algo_t auth_algo; + u8_t auth_key[20]; + snmpv3_priv_algo_t priv_algo; + u8_t priv_key[20]; +}; + +static struct user_table_entry user_table[] = { + { "lwip", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" }, + { "piwl", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" }, + { "test", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" } +}; + +static char snmpv3_engineid[32]; +static u8_t snmpv3_engineid_len; + +static u32_t enginetime = 0; + +/* In this implementation engineboots is volatile. In a real world application this value should be stored in non-volatile memory.*/ +static u32_t engineboots = 0; + +/** + * @brief Get the user table entry for the given username. + * + * @param[in] username pointer to the username + * + * @return pointer to the user table entry or NULL if not found. + */ +static struct user_table_entry* +get_user(const char *username) +{ + size_t i; + + for (i = 0; i < LWIP_ARRAYSIZE(user_table); i++) { + if (strnlen(username, 32) != strnlen(user_table[i].username, 32)) { + continue; + } + + if (memcmp(username, user_table[i].username, strnlen(username, 32)) == 0) { + return &user_table[i]; + } + } + + return NULL; +} + +u8_t +snmpv3_get_amount_of_users(void) +{ + return LWIP_ARRAYSIZE(user_table); +} + +/** + * @brief Get the username of a user number (index) + * @param username is a pointer to a string. + * @param index is the user index. + * @return ERR_OK if user is found, ERR_VAL is user is not found. + */ +err_t +snmpv3_get_username(char *username, u8_t index) +{ + if (index < LWIP_ARRAYSIZE(user_table)) { + MEMCPY(username, user_table[index].username, sizeof(user_table[0].username)); + return ERR_OK; + } + + return ERR_VAL; +} + +/** + * Timer callback function that increments enginetime and reschedules itself. + * + * @param arg unused argument + */ +static void +snmpv3_enginetime_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + enginetime++; + + /* This handles the engine time reset */ + snmpv3_get_engine_time_internal(); + + /* restart timer */ + sys_timeout(1000, snmpv3_enginetime_timer, NULL); +} + +err_t +snmpv3_set_user_auth_algo(const char *username, snmpv3_auth_algo_t algo) +{ + struct user_table_entry *p = get_user(username); + + if (p) { + switch (algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + if (p->priv_algo != SNMP_V3_PRIV_ALGO_INVAL) { + /* Privacy MUST be disabled before configuring authentication */ + break; + } else { + p->auth_algo = algo; + return ERR_OK; + } +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + case SNMP_V3_AUTH_ALGO_SHA: +#endif + p->auth_algo = algo; + return ERR_OK; + default: + break; + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_priv_algo(const char *username, snmpv3_priv_algo_t algo) +{ + struct user_table_entry *p = get_user(username); + + if (p) { + switch (algo) { +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_PRIV_ALGO_AES: + case SNMP_V3_PRIV_ALGO_DES: + if (p->auth_algo == SNMP_V3_AUTH_ALGO_INVAL) { + /* Authentication MUST be enabled before configuring privacy */ + break; + } else { + p->priv_algo = algo; + return ERR_OK; + } +#endif + case SNMP_V3_PRIV_ALGO_INVAL: + p->priv_algo = algo; + return ERR_OK; + default: + break; + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_auth_key(const char *username, const char *password) +{ + struct user_table_entry *p = get_user(username); + const char *engineid; + u8_t engineid_len; + + if (p) { + /* password should be at least 8 characters long */ + if (strlen(password) >= 8) { + memset(p->auth_key, 0, sizeof(p->auth_key)); + snmpv3_get_engine_id(&engineid, &engineid_len); + switch (p->auth_algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + return ERR_OK; +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + snmpv3_password_to_key_md5((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->auth_key); + return ERR_OK; + case SNMP_V3_AUTH_ALGO_SHA: + snmpv3_password_to_key_sha((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->auth_key); + return ERR_OK; +#endif + default: + return ERR_VAL; + } + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_priv_key(const char *username, const char *password) +{ + struct user_table_entry *p = get_user(username); + const char *engineid; + u8_t engineid_len; + + if (p) { + /* password should be at least 8 characters long */ + if (strlen(password) >= 8) { + memset(p->priv_key, 0, sizeof(p->priv_key)); + snmpv3_get_engine_id(&engineid, &engineid_len); + switch (p->auth_algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + return ERR_OK; +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + snmpv3_password_to_key_md5((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->priv_key); + return ERR_OK; + case SNMP_V3_AUTH_ALGO_SHA: + snmpv3_password_to_key_sha((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->priv_key); + return ERR_OK; +#endif + default: + return ERR_VAL; + } + } + } + + return ERR_VAL; +} + +/** + * @brief Get the storage type of the given username. + * + * @param[in] username pointer to the username + * @param[out] type the storage type + * + * @return ERR_OK if the user was found, ERR_VAL if not. + */ +err_t +snmpv3_get_user_storagetype(const char *username, snmpv3_user_storagetype_t *type) +{ + if (get_user(username) != NULL) { + /* Found user in user table + * In this dummy implementation, storage is permanent because no user can be deleted. + * All changes to users are lost after a reboot.*/ + *type = SNMP_V3_USER_STORAGETYPE_PERMANENT; + return ERR_OK; + } + + return ERR_VAL; +} + +/** + * @param username is a pointer to a string. + * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + */ +err_t +snmpv3_get_user(const char* username, snmpv3_auth_algo_t *auth_algo, u8_t *auth_key, snmpv3_priv_algo_t *priv_algo, u8_t *priv_key) +{ + const struct user_table_entry *p; + + /* The msgUserName specifies the user (principal) on whose behalf the + message is being exchanged. Note that a zero-length userName will + not match any user, but it can be used for snmpEngineID discovery. */ + if(strlen(username) == 0) { + return ERR_OK; + } + + p = get_user(username); + + if (!p) { + return ERR_VAL; + } + + if (auth_algo != NULL) { + *auth_algo = p->auth_algo; + } + if(auth_key != NULL) { + MEMCPY(auth_key, p->auth_key, sizeof(p->auth_key)); + } + if (priv_algo != NULL) { + *priv_algo = p->priv_algo; + } + if(priv_key != NULL) { + MEMCPY(priv_key, p->priv_key, sizeof(p->priv_key)); + } + return ERR_OK; +} + +/** + * Get engine ID from persistence + */ +void +snmpv3_get_engine_id(const char **id, u8_t *len) +{ + *id = snmpv3_engineid; + *len = snmpv3_engineid_len; +} + +/** + * Store engine ID in persistence + */ +err_t +snmpv3_set_engine_id(const char *id, u8_t len) +{ + MEMCPY(snmpv3_engineid, id, len); + snmpv3_engineid_len = len; + return ERR_OK; +} + +/** + * Get engine boots from persistence. Must be increased on each boot. + */ +u32_t +snmpv3_get_engine_boots(void) +{ + return engineboots; +} + +/** + * Store engine boots in persistence + */ +void +snmpv3_set_engine_boots(u32_t boots) +{ + engineboots = boots; +} + +/** + * RFC3414 2.2.2. + * Once the timer reaches 2147483647 it gets reset to zero and the + * engine boot ups get incremented. + */ +u32_t +snmpv3_get_engine_time(void) +{ + return enginetime; +} + +/** + * Reset current engine time to 0 + */ +void +snmpv3_reset_engine_time(void) +{ + enginetime = 0; +} + +/** + * Initialize dummy SNMPv3 implementation + */ +void +snmpv3_dummy_init(void) +{ + snmpv3_set_engine_id("FOO", 3); + + snmpv3_set_user_auth_algo("lwip", SNMP_V3_AUTH_ALGO_SHA); + snmpv3_set_user_auth_key("lwip", "maplesyrup"); + + snmpv3_set_user_priv_algo("lwip", SNMP_V3_PRIV_ALGO_DES); + snmpv3_set_user_priv_key("lwip", "maplesyrup"); + + /* Start the engine time timer */ + snmpv3_enginetime_timer(NULL); +} + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ diff --git a/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h new file mode 100644 index 0000000..ba25b6d --- /dev/null +++ b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h @@ -0,0 +1,53 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2017 Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_DUMMY_H +#define LWIP_HDR_APPS_SNMP_V3_DUMMY_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" +#include "lwip/apps/snmpv3.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +err_t snmpv3_set_user_auth_algo(const char *username, snmpv3_auth_algo_t algo); +err_t snmpv3_set_user_priv_algo(const char *username, snmpv3_priv_algo_t algo); +err_t snmpv3_set_user_auth_key(const char *username, const char *password); +err_t snmpv3_set_user_priv_key(const char *username, const char *password); + +void snmpv3_dummy_init(void); + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ + +#endif /* LWIP_HDR_APPS_SNMP_V3_DUMMY_H */ diff --git a/contrib/examples/sntp/sntp_example.c b/contrib/examples/sntp/sntp_example.c new file mode 100644 index 0000000..e9f6ac8 --- /dev/null +++ b/contrib/examples/sntp/sntp_example.c @@ -0,0 +1,66 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include + +#include "lwip/opt.h" +#include "lwip/apps/sntp.h" +#include "sntp_example.h" +#include "lwip/netif.h" + +void +sntp_set_system_time(u32_t sec) +{ + char buf[32]; + struct tm current_time_val; + time_t current_time = (time_t)sec; + +#if defined(_WIN32) || defined(WIN32) + localtime_s(¤t_time_val, ¤t_time); +#else + localtime_r(¤t_time, ¤t_time_val); +#endif + + strftime(buf, sizeof(buf), "%d.%m.%Y %H:%M:%S", ¤t_time_val); + LWIP_PLATFORM_DIAG(("SNTP time: %s\n", buf)); +} + +void +sntp_example_init(void) +{ + sntp_setoperatingmode(SNTP_OPMODE_POLL); +#if LWIP_DHCP + sntp_servermode_dhcp(1); /* get SNTP server via DHCP */ +#else /* LWIP_DHCP */ +#if LWIP_IPV4 + sntp_setserver(0, netif_ip_gw4(netif_default)); +#endif /* LWIP_IPV4 */ +#endif /* LWIP_DHCP */ + sntp_init(); +} diff --git a/contrib/examples/sntp/sntp_example.h b/contrib/examples/sntp/sntp_example.h new file mode 100644 index 0000000..94fc10d --- /dev/null +++ b/contrib/examples/sntp/sntp_example.h @@ -0,0 +1,45 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef SNTP_EXAMPLE_H +#define SNTP_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void sntp_example_init(void); + +void sntp_set_system_time(u32_t sec); + +#ifdef __cplusplus +} +#endif + +#endif /* SNTP_EXAMPLE_H */ diff --git a/contrib/examples/tftp/tftp_example.c b/contrib/examples/tftp/tftp_example.c new file mode 100644 index 0000000..f6a28b4 --- /dev/null +++ b/contrib/examples/tftp/tftp_example.c @@ -0,0 +1,156 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#include + +#include "lwip/apps/tftp_client.h" +#include "lwip/apps/tftp_server.h" +#include "tftp_example.h" + +#include + +#if LWIP_UDP + +/* Define a base directory for TFTP access + * ATTENTION: This code does NOT check for sandboxing, + * i.e. '..' in paths is not checked! */ +#ifndef LWIP_TFTP_EXAMPLE_BASE_DIR +#define LWIP_TFTP_EXAMPLE_BASE_DIR "" +#endif + +/* Define this to a file to get via tftp client */ +#ifndef LWIP_TFTP_EXAMPLE_CLIENT_FILENAME +#define LWIP_TFTP_EXAMPLE_CLIENT_FILENAME "test.bin" +#endif + +/* Define this to a server IP string */ +#ifndef LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP +#define LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP "192.168.0.1" +#endif + +static char full_filename[256]; + +static void * +tftp_open_file(const char* fname, u8_t is_write) +{ + snprintf(full_filename, sizeof(full_filename), "%s%s", LWIP_TFTP_EXAMPLE_BASE_DIR, fname); + full_filename[sizeof(full_filename)-1] = 0; + + if (is_write) { + return (void*)fopen(full_filename, "wb"); + } else { + return (void*)fopen(full_filename, "rb"); + } +} + +static void* +tftp_open(const char* fname, const char* mode, u8_t is_write) +{ + LWIP_UNUSED_ARG(mode); + return tftp_open_file(fname, is_write); +} + +static void +tftp_close(void* handle) +{ + fclose((FILE*)handle); +} + +static int +tftp_read(void* handle, void* buf, int bytes) +{ + int ret = fread(buf, 1, bytes, (FILE*)handle); + if (ret <= 0) { + return -1; + } + return ret; +} + +static int +tftp_write(void* handle, struct pbuf* p) +{ + while (p != NULL) { + if (fwrite(p->payload, 1, p->len, (FILE*)handle) != (size_t)p->len) { + return -1; + } + p = p->next; + } + + return 0; +} + +/* For TFTP client only */ +static void +tftp_error(void* handle, int err, const char* msg, int size) +{ + char message[100]; + + LWIP_UNUSED_ARG(handle); + + memset(message, 0, sizeof(message)); + MEMCPY(message, msg, LWIP_MIN(sizeof(message)-1, (size_t)size)); + + printf("TFTP error: %d (%s)", err, message); +} + +static const struct tftp_context tftp = { + tftp_open, + tftp_close, + tftp_read, + tftp_write, + tftp_error +}; + +void +tftp_example_init_server(void) +{ + tftp_init_server(&tftp); +} + +void +tftp_example_init_client(void) +{ + void *f; + err_t err; + ip_addr_t srv; + int ret = ipaddr_aton(LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP, &srv); + LWIP_ASSERT("ipaddr_aton failed", ret == 1); + LWIP_UNUSED_ARG(ret); + + err = tftp_init_client(&tftp); + LWIP_ASSERT("tftp_init_client failed", err == ERR_OK); + + f = tftp_open_file(LWIP_TFTP_EXAMPLE_CLIENT_FILENAME, 1); + LWIP_ASSERT("failed to create file", f != NULL); + + err = tftp_get(f, &srv, TFTP_PORT, LWIP_TFTP_EXAMPLE_CLIENT_FILENAME, TFTP_MODE_OCTET); + LWIP_ASSERT("tftp_get failed", err == ERR_OK); +} + +#endif /* LWIP_UDP */ diff --git a/contrib/examples/tftp/tftp_example.h b/contrib/examples/tftp/tftp_example.h new file mode 100644 index 0000000..7340700 --- /dev/null +++ b/contrib/examples/tftp/tftp_example.h @@ -0,0 +1,29 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: tftp_example.h + * Author: dziegel + * + * Created on February 17, 2018, 3:43 PM + */ + +#ifndef TFTP_EXAMPLE_H +#define TFTP_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void tftp_example_init_server(void); +void tftp_example_init_client(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TFTP_EXAMPLE_H */ + diff --git a/contrib/ports/CMakeCommon.cmake b/contrib/ports/CMakeCommon.cmake new file mode 100644 index 0000000..a56b59c --- /dev/null +++ b/contrib/ports/CMakeCommon.cmake @@ -0,0 +1,128 @@ +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "CMAKE_BUILD_TYPE not set - defaulting to Debug build.") + set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}." FORCE) +endif() +message (STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +set(LWIP_CONTRIB_DIR ${LWIP_DIR}/contrib) + +# ARM mbedtls support https://tls.mbed.org/ +if(NOT DEFINED LWIP_MBEDTLSDIR) + set(LWIP_MBEDTLSDIR ${LWIP_DIR}/../mbedtls) + message(STATUS "LWIP_MBEDTLSDIR not set - using default location ${LWIP_MBEDTLSDIR}") +endif() +if(EXISTS ${LWIP_MBEDTLSDIR}/CMakeLists.txt) + set(LWIP_HAVE_MBEDTLS ON BOOL) + + # Prevent building MBEDTLS programs and tests + set(ENABLE_PROGRAMS OFF CACHE BOOL "") + set(ENABLE_TESTING OFF CACHE BOOL "") + + # mbedtls uses cmake. Sweet! + add_subdirectory(${LWIP_MBEDTLSDIR} mbedtls) + + set (LWIP_MBEDTLS_DEFINITIONS + LWIP_HAVE_MBEDTLS=1 + ) + set (LWIP_MBEDTLS_INCLUDE_DIRS + ${LWIP_MBEDTLSDIR}/include + ) + set (LWIP_MBEDTLS_LINK_LIBRARIES + mbedtls + mbedcrypto + mbedx509 + ) +endif() + +set(LWIP_COMPILER_FLAGS_GNU_CLANG + $<$:-Og> + $<$:-g> + $<$:-O3> + -Wall + -pedantic + -Werror + -Wparentheses + -Wsequence-point + -Wswitch-default + -Wextra + -Wundef + -Wshadow + -Wpointer-arith + -Wcast-qual + -Wwrite-strings + $<$:-Wold-style-definition> + -Wcast-align + $<$:-Wmissing-prototypes> + $<$:-Wnested-externs> + -Wunreachable-code + -Wuninitialized + -Wmissing-prototypes + -Waggregate-return + -Wlogical-not-parentheses +) + +if (NOT LWIP_HAVE_MBEDTLS) + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -Wredundant-decls + $<$:-Wc++-compat> + ) +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -Wlogical-op + -Wtrampolines + ) + + if (NOT LWIP_HAVE_MBEDTLS) + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + $<$:-Wc90-c99-compat> + ) + endif() + + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) + if(LWIP_USE_SANITIZERS) + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -fsanitize=address + -fsanitize=undefined + -fno-sanitize=alignment + -fstack-protector + -fstack-check + ) + set(LWIP_SANITIZER_LIBS asan ubsan) + endif() + endif() + + set(LWIP_COMPILER_FLAGS ${LWIP_COMPILER_FLAGS_GNU_CLANG}) +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -Wdocumentation + -Wno-documentation-deprecated-sync + ) + + if(LWIP_USE_SANITIZERS) + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -fsanitize=address + -fsanitize=undefined + -fno-sanitize=alignment + ) + set(LWIP_SANITIZER_LIBS asan ubsan) + endif() + + set(LWIP_COMPILER_FLAGS ${LWIP_COMPILER_FLAGS_GNU_CLANG}) +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set(LWIP_COMPILER_FLAGS + $<$:/Od> + $<$:/Ox> + /W4 + /WX + ) +endif() diff --git a/contrib/ports/Common.allports.mk b/contrib/ports/Common.allports.mk new file mode 100644 index 0000000..049ba6a --- /dev/null +++ b/contrib/ports/Common.allports.mk @@ -0,0 +1,91 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +#CC=gcc +#CC=clang +CCDEP?=$(CC) + +CFLAGS+=-g -DLWIP_DEBUG -Wall -pedantic -Werror \ + -Wparentheses -Wsequence-point -Wswitch-default \ + -Wextra -Wundef -Wshadow -Wpointer-arith -Wcast-qual \ + -Wc++-compat -Wwrite-strings -Wold-style-definition -Wcast-align \ + -Wmissing-prototypes -Wnested-externs \ + -Wunreachable-code -Wuninitialized -Wmissing-prototypes \ + -Wredundant-decls -Waggregate-return -Wlogical-not-parentheses +# -Wconversion -Wsign-compare -Wmissing-include-dirs + +ifeq (,$(findstring clang,$(CC))) +CFLAGS+= -Wlogical-op -Wc90-c99-compat -Wtrampolines +# if GCC is newer than 4.8/4.9 you may use: +#CFLAGS:=$(CFLAGS) -fsanitize=address -fstack-protector -fstack-check -fsanitize=undefined -fno-sanitize=alignment +else +# we cannot sanitize alignment on x86-64 targets because clang wants 64 bit alignment +CFLAGS+= -fsanitize=address -fsanitize=undefined -fno-sanitize=alignment -Wdocumentation -Wno-documentation-deprecated-sync +endif + +CONTRIBDIR?=../../.. +ARFLAGS?=rs + +#Set this to where you have the lwip core module checked out from git +#default assumes it's a dir above the contrib module +LWIPDIR?=$(CONTRIBDIR)/.. + +CFLAGS+=-I. \ + -I$(CONTRIBDIR) \ + -I$(LWIPDIR)/include \ + -I$(LWIPARCH)/include + +# Add include path and link to mbedTLS lib if available +MBEDTLSDIR?=$(LWIPDIR)/../mbedtls +ifneq (,$(wildcard $(MBEDTLSDIR)/include/mbedtls/*.h)) +LDFLAGS+=-L$(MBEDTLSDIR)/library -lmbedtls -lmbedcrypto -lmbedx509 +CFLAGS+=-I$(MBEDTLSDIR)/include -Wno-redundant-decls -DLWIP_HAVE_MBEDTLS=1 -Wno-c90-c99-compat +endif + +include $(CONTRIBDIR)/Filelists.mk +include $(LWIPDIR)/Filelists.mk + +# LWIPFILES: All the above. +LWIPFILES=$(LWIPNOAPPSFILES) $(ARCHFILES) +LWIPOBJS=$(notdir $(LWIPFILES:.c=.o)) + +LWIPLIBCOMMON=liblwipcommon.a +$(LWIPLIBCOMMON): $(LWIPOBJS) + $(AR) $(ARFLAGS) $(LWIPLIBCOMMON) $? + +APPFILES=$(CONTRIBAPPFILES) $(LWIPAPPFILES) +APPLIB=liblwipapps.a +APPOBJS=$(notdir $(APPFILES:.c=.o)) +$(APPLIB): $(APPOBJS) + $(AR) $(ARFLAGS) $(APPLIB) $? + +%.o: + $(CC) $(CFLAGS) -c $< diff --git a/contrib/ports/freertos/include/arch/sys_arch.h b/contrib/ports/freertos/include/arch/sys_arch.h new file mode 100644 index 0000000..0cfc889 --- /dev/null +++ b/contrib/ports/freertos/include/arch/sys_arch.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmdit + * + */ +#ifndef LWIP_ARCH_SYS_ARCH_H +#define LWIP_ARCH_SYS_ARCH_H + +#include "lwip/opt.h" +#include "lwip/arch.h" + +/** This is returned by _fromisr() sys functions to tell the outermost function + * that a higher priority task was woken and the scheduler needs to be invoked. + */ +#define ERR_NEED_SCHED 123 + +/* This port includes FreeRTOS headers in sys_arch.c only. + * FreeRTOS uses pointers as object types. We use wrapper structs instead of + * void pointers directly to get a tiny bit of type safety. + */ + +void sys_arch_msleep(u32_t delay_ms); +#define sys_msleep(ms) sys_arch_msleep(ms) + +#if SYS_LIGHTWEIGHT_PROT +typedef u32_t sys_prot_t; +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#if !LWIP_COMPAT_MUTEX +struct _sys_mut { + void *mut; +}; +typedef struct _sys_mut sys_mutex_t; +#define sys_mutex_valid_val(mutex) ((mutex).mut != NULL) +#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex))) +#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL) +#endif /* !LWIP_COMPAT_MUTEX */ + +struct _sys_sem { + void *sem; +}; +typedef struct _sys_sem sys_sem_t; +#define sys_sem_valid_val(sema) ((sema).sem != NULL) +#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema))) +#define sys_sem_set_invalid(sema) ((sema)->sem = NULL) + +struct _sys_mbox { + void *mbx; +}; +typedef struct _sys_mbox sys_mbox_t; +#define sys_mbox_valid_val(mbox) ((mbox).mbx != NULL) +#define sys_mbox_valid(mbox) (((mbox) != NULL) && sys_mbox_valid_val(*(mbox))) +#define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL) + +struct _sys_thread { + void *thread_handle; +}; +typedef struct _sys_thread sys_thread_t; + +#if LWIP_NETCONN_SEM_PER_THREAD +sys_sem_t* sys_arch_netconn_sem_get(void); +void sys_arch_netconn_sem_alloc(void); +void sys_arch_netconn_sem_free(void); +#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get() +#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc() +#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free() +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#endif /* LWIP_ARCH_SYS_ARCH_H */ diff --git a/contrib/ports/freertos/sys_arch.c b/contrib/ports/freertos/sys_arch.c new file mode 100644 index 0000000..8568353 --- /dev/null +++ b/contrib/ports/freertos/sys_arch.c @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +/* lwIP includes. */ +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/stats.h" +#include "lwip/tcpip.h" +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" + +/** Set this to 1 if you want the stack size passed to sys_thread_new() to be + * interpreted as number of stack words (FreeRTOS-like). + * Default is that they are interpreted as byte count (lwIP-like). + */ +#ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS +#define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 0 +#endif + +/** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions. + * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT(). + */ +#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX +#define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0 +#endif + +/** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and + * SYS_ARCH_UNPROTECT() are called matching. + */ +#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK +#define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0 +#endif + +/** Set this to 1 to let sys_mbox_free check that queues are empty when freed */ +#ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE +#define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0 +#endif + +/** Set this to 1 to enable core locking check functions in this port. + * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED() + * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */ +#ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING +#define LWIP_FREERTOS_CHECK_CORE_LOCKING 0 +#endif + +/** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer. + * Default is 1, where FreeRTOS ticks are used to calculate back to ms. + */ +#ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS +#define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1 +#endif + +#if !configSUPPORT_DYNAMIC_ALLOCATION +# error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION" +#endif +#if !INCLUDE_vTaskDelay +# error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay" +#endif +#if !INCLUDE_vTaskSuspend +# error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend" +#endif +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX +#if !configUSE_MUTEXES +# error "lwIP FreeRTOS port requires configUSE_MUTEXES" +#endif +#endif + +#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX +static SemaphoreHandle_t sys_arch_protect_mutex; +#endif +#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK +static sys_prot_t sys_arch_protect_nesting; +#endif + +/* Initialize this module (see description in sys.h) */ +void +sys_init(void) +{ +#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX + /* initialize sys_arch_protect global mutex */ + sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex(); + LWIP_ASSERT("failed to create sys_arch_protect mutex", + sys_arch_protect_mutex != NULL); +#endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ +} + +#if configUSE_16_BIT_TICKS == 1 +#error This port requires 32 bit ticks or timer overflow will fail +#endif + +#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS +u32_t +sys_now(void) +{ + return xTaskGetTickCount() * portTICK_PERIOD_MS; +} +#endif + +u32_t +sys_jiffies(void) +{ + return xTaskGetTickCount(); +} + +#if SYS_LIGHTWEIGHT_PROT + +sys_prot_t +sys_arch_protect(void) +{ +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX + BaseType_t ret; + LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL); + + ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY); + LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE); +#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ + taskENTER_CRITICAL(); +#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK + { + /* every nested call to sys_arch_protect() returns an increased number */ + sys_prot_t ret = sys_arch_protect_nesting; + sys_arch_protect_nesting++; + LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret); + return ret; + } +#else + return 1; +#endif +} + +void +sys_arch_unprotect(sys_prot_t pval) +{ +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX + BaseType_t ret; +#endif +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK + LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0); + sys_arch_protect_nesting--; + LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval); +#endif + +#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX + LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL); + + ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex); + LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE); +#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ + taskEXIT_CRITICAL(); +#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ + LWIP_UNUSED_ARG(pval); +} + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +void +sys_arch_msleep(u32_t delay_ms) +{ + TickType_t delay_ticks = delay_ms / portTICK_RATE_MS; + vTaskDelay(delay_ticks); +} + +#if !LWIP_COMPAT_MUTEX + +/* Create a new mutex*/ +err_t +sys_mutex_new(sys_mutex_t *mutex) +{ + LWIP_ASSERT("mutex != NULL", mutex != NULL); + + mutex->mut = xSemaphoreCreateRecursiveMutex(); + if(mutex->mut == NULL) { + SYS_STATS_INC(mutex.err); + return ERR_MEM; + } + SYS_STATS_INC_USED(mutex); + return ERR_OK; +} + +void +sys_mutex_lock(sys_mutex_t *mutex) +{ + BaseType_t ret; + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + + ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY); + LWIP_ASSERT("failed to take the mutex", ret == pdTRUE); +} + +void +sys_mutex_unlock(sys_mutex_t *mutex) +{ + BaseType_t ret; + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + + ret = xSemaphoreGiveRecursive(mutex->mut); + LWIP_ASSERT("failed to give the mutex", ret == pdTRUE); +} + +void +sys_mutex_free(sys_mutex_t *mutex) +{ + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + + SYS_STATS_DEC(mutex.used); + vSemaphoreDelete(mutex->mut); + mutex->mut = NULL; +} + +#endif /* !LWIP_COMPAT_MUTEX */ + +err_t +sys_sem_new(sys_sem_t *sem, u8_t initial_count) +{ + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("initial_count invalid (not 0 or 1)", + (initial_count == 0) || (initial_count == 1)); + + sem->sem = xSemaphoreCreateBinary(); + if(sem->sem == NULL) { + SYS_STATS_INC(sem.err); + return ERR_MEM; + } + SYS_STATS_INC_USED(sem); + + if(initial_count == 1) { + BaseType_t ret = xSemaphoreGive(sem->sem); + LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); + } + return ERR_OK; +} + +void +sys_sem_signal(sys_sem_t *sem) +{ + BaseType_t ret; + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + + ret = xSemaphoreGive(sem->sem); + /* queue full is OK, this is a signal only... */ + LWIP_ASSERT("sys_sem_signal: sane return value", + (ret == pdTRUE) || (ret == errQUEUE_FULL)); +} + +u32_t +sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms) +{ + BaseType_t ret; + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + + if(!timeout_ms) { + /* wait infinite */ + ret = xSemaphoreTake(sem->sem, portMAX_DELAY); + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); + } else { + TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; + ret = xSemaphoreTake(sem->sem, timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + return SYS_ARCH_TIMEOUT; + } + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); + } + + /* Old versions of lwIP required us to return the time waited. + This is not the case any more. Just returning != SYS_ARCH_TIMEOUT + here is enough. */ + return 1; +} + +void +sys_sem_free(sys_sem_t *sem) +{ + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + + SYS_STATS_DEC(sem.used); + vSemaphoreDelete(sem->sem); + sem->sem = NULL; +} + +err_t +sys_mbox_new(sys_mbox_t *mbox, int size) +{ + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("size > 0", size > 0); + + mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *)); + if(mbox->mbx == NULL) { + SYS_STATS_INC(mbox.err); + return ERR_MEM; + } + SYS_STATS_INC_USED(mbox); + return ERR_OK; +} + +void +sys_mbox_post(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret; + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + + ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY); + LWIP_ASSERT("mbox post failed", ret == pdTRUE); +} + +err_t +sys_mbox_trypost(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret; + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + + ret = xQueueSendToBack(mbox->mbx, &msg, 0); + if (ret == pdTRUE) { + return ERR_OK; + } else { + LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); + SYS_STATS_INC(mbox.err); + return ERR_MEM; + } +} + +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + + ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken); + if (ret == pdTRUE) { + if (xHigherPriorityTaskWoken == pdTRUE) { + return ERR_NEED_SCHED; + } + return ERR_OK; + } else { + LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); + SYS_STATS_INC(mbox.err); + return ERR_MEM; + } +} + +u32_t +sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms) +{ + BaseType_t ret; + void *msg_dummy; + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + + if (!msg) { + msg = &msg_dummy; + } + + if (!timeout_ms) { + /* wait infinite */ + ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + } else { + TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; + ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + *msg = NULL; + return SYS_ARCH_TIMEOUT; + } + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + } + + /* Old versions of lwIP required us to return the time waited. + This is not the case any more. Just returning != SYS_ARCH_TIMEOUT + here is enough. */ + return 1; +} + +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) +{ + BaseType_t ret; + void *msg_dummy; + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + + if (!msg) { + msg = &msg_dummy; + } + + ret = xQueueReceive(mbox->mbx, &(*msg), 0); + if (ret == errQUEUE_EMPTY) { + *msg = NULL; + return SYS_MBOX_EMPTY; + } + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + + return 0; +} + +void +sys_mbox_free(sys_mbox_t *mbox) +{ + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); + +#if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE + { + UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx); + LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0); + + if (msgs_waiting != 0) { + SYS_STATS_INC(mbox.err); + } + } +#endif + + vQueueDelete(mbox->mbx); + + SYS_STATS_DEC(mbox.used); +} + +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) +{ + TaskHandle_t rtos_task; + BaseType_t ret; + sys_thread_t lwip_thread; + size_t rtos_stacksize; + + LWIP_ASSERT("invalid stacksize", stacksize > 0); +#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS + rtos_stacksize = (size_t)stacksize; +#else + rtos_stacksize = (size_t)stacksize / sizeof(StackType_t); +#endif + + /* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the + thread function without adaption here. */ + ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task); + LWIP_ASSERT("task creation failed", ret == pdTRUE); + + lwip_thread.thread_handle = rtos_task; + return lwip_thread; +} + +#if LWIP_NETCONN_SEM_PER_THREAD +#if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 + +sys_sem_t * +sys_arch_netconn_sem_get(void) +{ + void* ret; + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + LWIP_ASSERT("task != NULL", task != NULL); + + ret = pvTaskGetThreadLocalStoragePointer(task, 0); + return ret; +} + +void +sys_arch_netconn_sem_alloc(void) +{ + void *ret; + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + LWIP_ASSERT("task != NULL", task != NULL); + + ret = pvTaskGetThreadLocalStoragePointer(task, 0); + if(ret == NULL) { + sys_sem_t *sem; + err_t err; + /* need to allocate the memory for this semaphore */ + sem = mem_malloc(sizeof(sys_sem_t)); + LWIP_ASSERT("sem != NULL", sem != NULL); + err = sys_sem_new(sem, 0); + LWIP_ASSERT("err == ERR_OK", err == ERR_OK); + LWIP_ASSERT("sem invalid", sys_sem_valid(sem)); + vTaskSetThreadLocalStoragePointer(task, 0, sem); + } +} + +void sys_arch_netconn_sem_free(void) +{ + void* ret; + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + LWIP_ASSERT("task != NULL", task != NULL); + + ret = pvTaskGetThreadLocalStoragePointer(task, 0); + if(ret != NULL) { + sys_sem_t *sem = ret; + sys_sem_free(sem); + mem_free(sem); + vTaskSetThreadLocalStoragePointer(task, 0, NULL); + } +} + +#else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */ +#error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */ + +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#if LWIP_FREERTOS_CHECK_CORE_LOCKING +#if LWIP_TCPIP_CORE_LOCKING + +/** Flag the core lock held. A counter for recursive locks. */ +static u8_t lwip_core_lock_count; +static TaskHandle_t lwip_core_lock_holder_thread; + +void +sys_lock_tcpip_core(void) +{ + sys_mutex_lock(&lock_tcpip_core); + if (lwip_core_lock_count == 0) { + lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle(); + } + lwip_core_lock_count++; +} + +void +sys_unlock_tcpip_core(void) +{ + lwip_core_lock_count--; + if (lwip_core_lock_count == 0) { + lwip_core_lock_holder_thread = 0; + } + sys_mutex_unlock(&lock_tcpip_core); +} + +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#if !NO_SYS +static TaskHandle_t lwip_tcpip_thread; +#endif + +void +sys_mark_tcpip_thread(void) +{ +#if !NO_SYS + lwip_tcpip_thread = xTaskGetCurrentTaskHandle(); +#endif +} + +void +sys_check_core_locking(void) +{ + /* Embedded systems should check we are NOT in an interrupt context here */ + /* E.g. core Cortex-M3/M4 ports: + configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); + + Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */ + taskENTER_CRITICAL(); + taskEXIT_CRITICAL(); + +#if !NO_SYS + if (lwip_tcpip_thread != 0) { + TaskHandle_t current_thread = xTaskGetCurrentTaskHandle(); + +#if LWIP_TCPIP_CORE_LOCKING + LWIP_ASSERT("Function called without core lock", + current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0); +#else /* LWIP_TCPIP_CORE_LOCKING */ + LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + } +#endif /* !NO_SYS */ +} + +#endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/ diff --git a/contrib/ports/unix/Common.mk b/contrib/ports/unix/Common.mk new file mode 100644 index 0000000..f80a980 --- /dev/null +++ b/contrib/ports/unix/Common.mk @@ -0,0 +1,51 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +# Architecture specific files. +LWIPARCH?=$(CONTRIBDIR)/ports/unix/port +SYSARCH?=$(LWIPARCH)/sys_arch.c +ARCHFILES=$(LWIPARCH)/perf.c \ + $(SYSARCH) \ + $(LWIPARCH)/netif/tapif.c \ + $(LWIPARCH)/netif/list.c \ + $(LWIPARCH)/netif/sio.c \ + $(LWIPARCH)/netif/fifo.c + +UNIX_COMMON_MK_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +include $(UNIX_COMMON_MK_DIR)../Common.allports.mk + +LDFLAGS+=-lutil + +UNAME_S:= $(shell uname -s) +ifneq ($(UNAME_S),Darwin) +# Darwin doesn't have pthreads or POSIX real-time extensions libs +LDFLAGS+=-pthread -lrt +endif diff --git a/contrib/ports/unix/Filelists.cmake b/contrib/ports/unix/Filelists.cmake new file mode 100644 index 0000000..84bfded --- /dev/null +++ b/contrib/ports/unix/Filelists.cmake @@ -0,0 +1,44 @@ +# This file is indended to be included in end-user CMakeLists.txt +# include(/path/to/Filelists.cmake) +# It assumes the variable LWIP_CONTRIB_DIR is defined pointing to the +# root path of lwIP/contrib sources. +# +# This file is NOT designed (on purpose) to be used as cmake +# subdir via add_subdirectory() +# The intention is to provide greater flexibility to users to +# create their own targets using the *_SRCS variables. + +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + +set(lwipcontribportunix_SRCS + ${LWIP_CONTRIB_DIR}/ports/unix/port/sys_arch.c + ${LWIP_CONTRIB_DIR}/ports/unix/port/perf.c +) + +set(lwipcontribportunixnetifs_SRCS + ${LWIP_CONTRIB_DIR}/ports/unix/port/netif/tapif.c + ${LWIP_CONTRIB_DIR}/ports/unix/port/netif/list.c + ${LWIP_CONTRIB_DIR}/ports/unix/port/netif/sio.c + ${LWIP_CONTRIB_DIR}/ports/unix/port/netif/fifo.c +) + +add_library(lwipcontribportunix EXCLUDE_FROM_ALL ${lwipcontribportunix_SRCS} ${lwipcontribportunixnetifs_SRCS}) +target_include_directories(lwipcontribportunix PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) +target_compile_options(lwipcontribportunix PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipcontribportunix PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_link_libraries(lwipcontribportunix PUBLIC ${LWIP_MBEDTLS_LINK_LIBRARIES}) + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_library(LIBUTIL util) + find_library(LIBPTHREAD pthread) + find_library(LIBRT rt) + target_link_libraries(lwipcontribportunix PUBLIC ${LIBUTIL} ${LIBPTHREAD} ${LIBRT}) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Darwin doesn't have pthreads or POSIX real-time extensions libs + find_library(LIBUTIL util) + target_link_libraries(lwipcontribportunix PUBLIC ${LIBUTIL}) +endif() diff --git a/contrib/ports/unix/README b/contrib/ports/unix/README new file mode 100644 index 0000000..3b8f995 --- /dev/null +++ b/contrib/ports/unix/README @@ -0,0 +1,25 @@ +This port contains infrastructure and examples for running lwIP on Unix-like +operating systems (Linux, OpenBSD, cygwin). Much of this is targeted towards +testing lwIP applications. + +* port/sys_arch.c, port/perf.c, port/include/arch/: Generic platform porting, + for both states of NO_SYS. (Mapping debugging to printf, providing + sys_now & co from the system time etc.) + +* check: Runs the unit tests shipped with main lwIP on the Unix port. + +* port/netif, port/include/netif: Various network interface implementations and + their helpers, some explicitly for Unix infrastructure, some generic (but most + useful on an easy to debug system): + + * fifo: Helper for sio + + * list: Helper for unixif + + * pcapif: Network interface that replays packages from a PCAP dump file, and + discards packages sent out from it + + * sio: Mapping Unix character devices to lwIP's sio mechanisms + + * tapif: Network interface that is mapped to a tap interface (Unix user + space layer 2 network device). Uses lwIP threads. diff --git a/contrib/ports/unix/check/CMakeLists.txt b/contrib/ports/unix/check/CMakeLists.txt new file mode 100644 index 0000000..9cf8d05 --- /dev/null +++ b/contrib/ports/unix/check/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.8) + +set (CMAKE_CONFIGURATION_TYPES "Debug;Release") + +project(lwipunittests C) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_SYSTEM_NAME STREQUAL "GNU") + message(FATAL_ERROR "Unit test are currently only working on Linux, Darwin or Hurd") +endif() + +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) +if (NOT CMAKE_SYSTEM_NAME STREQUAL "GNU") + set(LWIP_USE_SANITIZERS true) +endif() +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + # check.h causes 'error: token pasting of ',' and __VA_ARGS__ is a GNU extension' with clang 9.0.0 + list(LWIP_COMPILER_FLAGS APPEND -Wno-gnu-zero-variadic-macro-arguments) +endif() + +set (LWIP_DEFINITIONS -DLWIP_DEBUG -DLWIP_NOASSERT_ON_ERROR) +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/test/unit" + "${LWIP_DIR}/src/include" + "${LWIP_CONTRIB_DIR}/" + "${LWIP_CONTRIB_DIR}/ports/unix/port/include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +include(${LWIP_CONTRIB_DIR}/ports/unix/Filelists.cmake) +include(${LWIP_DIR}/src/Filelists.cmake) +include(${LWIP_DIR}/test/unit/Filelists.cmake) + +add_executable(lwip_unittests ${LWIP_TESTFILES}) +target_include_directories(lwip_unittests PRIVATE ${LWIP_INCLUDE_DIRS}) +target_compile_options(lwip_unittests PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwip_unittests PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) + +find_library(LIBCHECK check) +find_library(LIBM m) +target_link_libraries(lwip_unittests ${LWIP_SANITIZER_LIBS} lwipallapps lwipcore ${LIBCHECK} ${LIBM}) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # check installed via brew on Darwin doesn't have a separate subunit library (must be statically linked) + find_library(LIBSUBUNIT subunit) + target_link_libraries(lwip_unittests ${LIBSUBUNIT}) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "GNU") + find_library(LIBUTIL util) + find_library(LIBPTHREAD pthread) + find_library(LIBRT rt) + target_link_libraries(lwip_unittests ${LIBUTIL} ${LIBPTHREAD} ${LIBRT}) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Darwin doesn't have pthreads or POSIX real-time extensions libs + find_library(LIBUTIL util) + target_link_libraries(lwip_unittests ${LIBUTIL}) +endif() diff --git a/contrib/ports/unix/check/Makefile b/contrib/ports/unix/check/Makefile new file mode 100644 index 0000000..81e22e5 --- /dev/null +++ b/contrib/ports/unix/check/Makefile @@ -0,0 +1,94 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +all compile: lwip_unittests +.PHONY: all clean check + +LWIPDIR=../../../../src + +# The include path to sys_arch.h and lwipopts.h must be first, so this must be before Common.mk +CFLAGS=-DLWIP_NOASSERT_ON_ERROR -I/usr/include/check -I$(LWIPDIR)/../test/unit + +# Ignore 'too many arguments for format' warnings which happen with GCCs +# from check 0.15.2 on fail_if/fail_unless macros with text. +# See https://github.com/libcheck/check/pull/298/commits/82540c5428d3818b64d +CFLAGS+=-Wno-error=format-extra-args + +ifeq (clang,$(findstring clang,$(CC))) +# check.h causes 'error: token pasting of ',' and __VA_ARGS__ is a GNU extension' with clang 9.0.0 +CFLAGS+=-Wno-gnu-zero-variadic-macro-arguments +endif + +# Prevent compiling sys_arch.c of unix port because unit test provide their own port +SYSARCH?= +include ../Common.mk + +LDFLAGS:=-lcheck -lm $(LDFLAGS) + +ifneq ($(UNAME_S),Darwin) +# check installed via brew on Darwin doesn't have a separate subunit library (must be statically linked) +LDFLAGS+=-lsubunit +endif + +TESTDIR=$(LWIPDIR)/../test/unit +include $(TESTDIR)/Filelists.mk +TESTOBJS=$(notdir $(TESTFILES:.c=.o)) + +DEPFILES=.depend_test .depend_lwip .depend_app + +clean: + @rm -f *.o $(LWIPLIBCOMMON) $(APPLIB) lwip_unittests *.s $(DEPFILES) *.core core lwip_unittests.xml + +depend dep: $(DEPFILES) + @true + +ifneq ($(MAKECMDGOALS),clean) +include $(DEPFILES) +endif + +.depend_test: $(TESTFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend_test || rm -f .depend_test +.depend_lwip: $(LWIPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend_lwip || rm -f .depend_lwip +.depend_app: $(APPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend_app || rm -f .depend_app + +ifneq ($(UNAME_S),Darwin) +# clang on Darwin doesn't support --start-group +lwip_unittests: $(DEPFILES) $(TESTOBJS) $(LWIPLIBCOMMON) $(APPLIB) + $(CC) $(CFLAGS) -o lwip_unittests $(TESTOBJS) -Wl,--start-group $(LWIPLIBCOMMON) $(APPLIB) $(LDFLAGS) -Wl,--end-group +else +lwip_unittests: $(DEPFILES) $(TESTOBJS) $(LWIPLIBCOMMON) $(APPLIB) + $(CC) $(CFLAGS) -o lwip_unittests $(TESTOBJS) $(LWIPLIBCOMMON) $(APPLIB) $(LDFLAGS) +endif + +check: lwip_unittests + @./lwip_unittests diff --git a/contrib/ports/unix/check/README b/contrib/ports/unix/check/README new file mode 100644 index 0000000..8b32672 --- /dev/null +++ b/contrib/ports/unix/check/README @@ -0,0 +1,8 @@ + +Helper files to run lwIP unit tests on unix-like systems. + +1. Install the check library, through a package manager or from https://libcheck.github.io/check/ +2. Put the lwip code in a directory called 'lwip' +3. Run `make check` +4. Make sure all tests pass + diff --git a/contrib/ports/unix/check/config.h b/contrib/ports/unix/check/config.h new file mode 100644 index 0000000..0d84b36 --- /dev/null +++ b/contrib/ports/unix/check/config.h @@ -0,0 +1,2 @@ +/* Enable this to simplify debugging */ +/* #define LWIP_UNITTESTS_NOFORK */ diff --git a/contrib/ports/unix/example_app/CMakeLists.txt b/contrib/ports/unix/example_app/CMakeLists.txt new file mode 100644 index 0000000..961be1b --- /dev/null +++ b/contrib/ports/unix/example_app/CMakeLists.txt @@ -0,0 +1,27 @@ +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/src/include" + "${LWIP_DIR}/contrib/" + "${LWIP_DIR}/contrib/ports/unix/port/include" + "${LWIP_DIR}/contrib/examples/example_app" +) + +include(${LWIP_DIR}/src/Filelists.cmake) +include(${LWIP_DIR}/contrib/Filelists.cmake) +include(${LWIP_DIR}/contrib/ports/unix/Filelists.cmake) + +if(NOT EXISTS ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h) + message(WARNING "${LWIP_DIR}/contrib/examples/example_app is missing lwipcfg.h +Copy ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h.example to ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h and edit appropriately") +endif() +add_executable(example_app ${LWIP_DIR}/contrib/examples/example_app/test.c default_netif.c) +target_include_directories(example_app PRIVATE ${LWIP_INCLUDE_DIRS}) +target_compile_options(example_app PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(example_app PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_link_libraries(example_app ${LWIP_SANITIZER_LIBS} lwipcontribexamples lwipcontribapps lwipcontribaddons lwipallapps lwipcontribportunix lwipcore lwipmbedtls) + +add_executable(makefsdata ${lwipmakefsdata_SRCS}) +target_compile_options(makefsdata PRIVATE ${LWIP_COMPILER_FLAGS}) +target_include_directories(makefsdata PRIVATE ${LWIP_INCLUDE_DIRS}) +target_link_libraries(makefsdata ${LWIP_SANITIZER_LIBS}) diff --git a/contrib/ports/unix/example_app/Makefile b/contrib/ports/unix/example_app/Makefile new file mode 100644 index 0000000..38aaba1 --- /dev/null +++ b/contrib/ports/unix/example_app/Makefile @@ -0,0 +1,60 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +all compile: example_app makefsdata +.PHONY: all + +LWIPDIR=../../../../src + +include ../Common.mk + +CFLAGS+=-I$(CONTRIBDIR)/examples/example_app + +TESTFLAGS?= +CFLAGS+=$(TESTFLAGS) + +MAKEFSDATAOBJS=$(notdir $(MAKEFSDATAFILES:.c=.o)) + +clean: + rm -f *.o $(LWIPLIBCOMMON) $(APPLIB) example_app makefsdata *.s .depend* *.core core + +depend dep: .depend + +include .depend + +.depend: $(CONTRIBDIR)/examples/example_app/test.c default_netif.c $(LWIPFILES) $(APPFILES) $(MAKEFSDATAFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend + +example_app: .depend $(LWIPLIBCOMMON) $(APPLIB) default_netif.o test.o + $(CC) $(CFLAGS) -o example_app test.o default_netif.o -Wl,--start-group $(APPLIB) $(LWIPLIBCOMMON) -Wl,--end-group $(LDFLAGS) + +makefsdata: .depend $(MAKEFSDATAOBJS) + $(CC) $(CFLAGS) -o makefsdata $(MAKEFSDATAOBJS) diff --git a/contrib/ports/unix/example_app/default_netif.c b/contrib/ports/unix/example_app/default_netif.c new file mode 100644 index 0000000..4c7eb6a --- /dev/null +++ b/contrib/ports/unix/example_app/default_netif.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/tcpip.h" +#include "netif/tapif.h" +#include "examples/example_app/default_netif.h" + +static struct netif netif; + +#if LWIP_IPV4 +#define NETIF_ADDRS ipaddr, netmask, gw, +void init_default_netif(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw) +#else +#define NETIF_ADDRS +void init_default_netif(void) +#endif +{ +#if NO_SYS +netif_add(&netif, NETIF_ADDRS NULL, tapif_init, netif_input); +#else + netif_add(&netif, NETIF_ADDRS NULL, tapif_init, tcpip_input); +#endif + netif_set_default(&netif); +} + +void +default_netif_poll(void) +{ + tapif_poll(&netif); +} + +void +default_netif_shutdown(void) +{ +} diff --git a/contrib/ports/unix/example_app/iteropts.sh b/contrib/ports/unix/example_app/iteropts.sh new file mode 100755 index 0000000..3856141 --- /dev/null +++ b/contrib/ports/unix/example_app/iteropts.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +LOGFILE=iteropts.log +EXAPPDIR=../../../examples/example_app +RETVAL=0 + +pushd `dirname "$0"` +pwd +echo Starting Iteropts run >> $LOGFILE +for f in $EXAPPDIR/test_configs/*.h +do + echo Cleaning... + make clean > /dev/null + BUILDLOG=$(basename "$f" ".h").log + echo testing $f + echo testing $f >> $LOGFILE + rm -f $EXAPPDIR/lwipopts_test.h + # cat the file to update its timestamp + cat $f > $EXAPPDIR/lwipopts_test.h + make TESTFLAGS="-DLWIP_OPTTEST_FILE -Wno-documentation" -j 4 1> $BUILDLOG 2>&1 + ERR=$? + if [ $ERR != 0 ]; then + cat $BUILDLOG + echo file $f failed with $ERR >> $LOGFILE + echo ++++++++ $f FAILED +++++++ + RETVAL=1 + fi + echo test $f done >> $LOGFILE +done +echo done, cleaning +make clean > /dev/null +popd +echo Exit value: $RETVAL +exit $RETVAL diff --git a/contrib/ports/unix/lib/CMakeLists.txt b/contrib/ports/unix/lib/CMakeLists.txt new file mode 100644 index 0000000..40229c4 --- /dev/null +++ b/contrib/ports/unix/lib/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.8) + +project(lwip C) + +set (BUILD_SHARED_LIBS ON) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_SYSTEM_NAME STREQUAL "GNU") + message(FATAL_ERROR "Lwip shared library is only working on Linux or the Hurd") +endif() + +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_DEFINITIONS -DLWIP_DEBUG) +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/src/include" + "${LWIP_CONTRIB_DIR}/" + "${LWIP_CONTRIB_DIR}/ports/unix/port/include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +set (LWIP_EXCLUDE_SLIPIF TRUE) +include(${LWIP_CONTRIB_DIR}/ports/unix/Filelists.cmake) +include(${LWIP_DIR}/src/Filelists.cmake) + +add_library(lwip ${lwipnoapps_SRCS} ${lwipcontribportunix_SRCS} ${lwipcontribportunixnetifs_SRCS}) +target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) +target_link_libraries(lwip ${LWIP_SANITIZER_LIBS}) + +find_library(LIBPTHREAD pthread) +target_link_libraries(lwip ${LIBPTHREAD}) diff --git a/contrib/ports/unix/lib/README b/contrib/ports/unix/lib/README new file mode 100644 index 0000000..3e6d0b1 --- /dev/null +++ b/contrib/ports/unix/lib/README @@ -0,0 +1,28 @@ +This directory contains an example of how to compile lwIP as a shared library +on Linux. + +Some brief instructions: + +* Compile the code: + + > mkdir build + > cd build + > cmake .. + > make clean all + + This should produce liblwip.so. This is the shared library. + +* Link an application against the shared library + + If you're using gcc you can do this by including -llwip in your link command. + +* Run your application + + Ensure that LD_LIBRARY_PATH includes the directory that contains liblwip.so + (ie. this directory) + + +If you are unsure about shared libraries and libraries on linux in +general, you might find this HOWTO useful: + + diff --git a/contrib/ports/unix/lib/lwipopts.h b/contrib/ports/unix/lib/lwipopts.h new file mode 100644 index 0000000..79319a1 --- /dev/null +++ b/contrib/ports/unix/lib/lwipopts.h @@ -0,0 +1,435 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 0 + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#define NO_SYS 0 + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT 1U + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#define MEM_SIZE 1600 + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#define MEMP_NUM_PBUF 16 + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#define MEMP_NUM_RAW_PCB 4 + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB 4 + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB 4 + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB_LISTEN 4 + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_SEG 16 + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#define MEMP_NUM_REASSDATA 1 + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#define MEMP_NUM_ARP_QUEUE 2 + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * (requires NO_SYS==0) + */ +#define MEMP_NUM_SYS_TIMEOUT 8 + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETBUF 2 + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETCONN 32 + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#define MEMP_NUM_TCPIP_MSG_API 8 + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#define MEMP_NUM_TCPIP_MSG_INPKT 8 + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#define PBUF_POOL_SIZE 8 + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#define LWIP_ARP 1 + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#define IP_FORWARD 0 + +/** + * IP_OPTIONS: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#define IP_OPTIONS_ALLOWED 1 + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY 1 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG 1 + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#define IP_REASS_MAXAGE 3 + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#define IP_REASS_MAX_PBUFS 4 + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented. +*/ +#define IP_FRAG_USES_STATIC_BUF 0 + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#define IP_DEFAULT_TTL 255 + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#define LWIP_ICMP 1 + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#define LWIP_RAW 1 + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP 0 + + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#define LWIP_AUTOIP 0 + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#define LWIP_SNMP 0 + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#define LWIP_IGMP 0 + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#define LWIP_DNS 0 + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#define LWIP_UDP 1 + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#define LWIP_TCP 1 + +#define TCP_LISTEN_BACKLOG 0 + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#define PBUF_LINK_HLEN 16 + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#define LWIP_HAVE_LOOPIF 0 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 1 + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 1 + +/** + * SO_REUSE==1: Enable SO_REUSEADDR + */ +#define SO_REUSE 1 + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#define LWIP_STATS 0 +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#define PPP_SUPPORT 0 + + + +/* + --------------------------------------- + ---------- Threading options ---------- + --------------------------------------- +*/ + +#define LWIP_TCPIP_CORE_LOCKING 1 + +#if !NO_SYS +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() +#endif + +#endif /* LWIP_LWIPOPTS_H */ diff --git a/contrib/ports/unix/port/include/arch/cc.h b/contrib/ports/unix/port/include/arch/cc.h new file mode 100644 index 0000000..a072f60 --- /dev/null +++ b/contrib/ports/unix/port/include/arch/cc.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ +#if defined __ANDROID__ +#define LWIP_UNIX_ANDROID +#elif defined __linux__ +#define LWIP_UNIX_LINUX +#elif defined __APPLE__ +#define LWIP_UNIX_MACH +#elif defined __OpenBSD__ +#define LWIP_UNIX_OPENBSD +#elif defined __FreeBSD__ +#define LWIP_UNIX_FREEBSD +#elif defined __FreeBSD_kernel__ && __GLIBC__ +#define LWIP_UNIX_KFREEBSD +#elif defined __CYGWIN__ +#define LWIP_UNIX_CYGWIN +#elif defined __GNU__ +#define LWIP_UNIX_HURD +#endif + +#define LWIP_TIMEVAL_PRIVATE 0 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_ERRNO_INCLUDE + +#if defined(LWIP_UNIX_LINUX) || defined(LWIP_UNIX_HURD) || defined(LWIP_UNIX_KFREEBSD) +#define LWIP_ERRNO_STDINCLUDE 1 +#endif + +extern unsigned int lwip_port_rand(void); +#define LWIP_RAND() (lwip_port_rand()) + +/* different handling for unit test, normally not needed */ +#ifdef LWIP_NOASSERT_ON_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;}} while(0) +#endif + +#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET) +typedef __kernel_fd_set fd_set; +#endif + +#if defined(LWIP_UNIX_MACH) +/* sys/types.h and signal.h bring in Darwin byte order macros. pull the + header here and disable LwIP's version so that apps still can get + the macros via LwIP headers and use system headers */ +#include +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#endif + +struct sio_status_s; +typedef struct sio_status_s sio_status_t; +#define sio_fd_t sio_status_t* +#define __sio_fd_t_defined + +typedef unsigned int sys_prot_t; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARCH_CC_H */ diff --git a/contrib/ports/unix/port/include/arch/perf.h b/contrib/ports/unix/port/include/arch/perf.h new file mode 100644 index 0000000..112a347 --- /dev/null +++ b/contrib/ports/unix/port/include/arch/perf.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_PERF_H +#define LWIP_ARCH_PERF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PERF +#define PERF_START { \ + unsigned long __c1l, __c1h, __c2l, __c2h; \ + __asm__(".byte 0x0f, 0x31" : "=a" (__c1l), "=d" (__c1h)) +#define PERF_STOP(x) __asm__(".byte 0x0f, 0x31" : "=a" (__c2l), "=d" (__c2h)); \ + perf_print(__c1l, __c1h, __c2l, __c2h, x);} + +/*#define PERF_START do { \ + struct tms __perf_start, __perf_end; \ + times(&__perf_start) +#define PERF_STOP(x) times(&__perf_end); \ + perf_print_times(&__perf_start, &__perf_end, x);\ + } while(0)*/ +#else /* PERF */ +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ +#endif /* PERF */ + +void perf_print(unsigned long c1l, unsigned long c1h, + unsigned long c2l, unsigned long c2h, + char *key); + +void perf_print_times(struct tms *start, struct tms *end, char *key); + +void perf_init(char *fname); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARCH_PERF_H */ diff --git a/contrib/ports/unix/port/include/arch/sys_arch.h b/contrib/ports/unix/port/include/arch/sys_arch.h new file mode 100644 index 0000000..eb6d1d3 --- /dev/null +++ b/contrib/ports/unix/port/include/arch/sys_arch.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_SYS_ARCH_H +#define LWIP_ARCH_SYS_ARCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SYS_MBOX_NULL NULL +#define SYS_SEM_NULL NULL + +/*typedef u32_t sys_prot_t;*/ + +struct sys_sem; +typedef struct sys_sem * sys_sem_t; +#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL)) +#define sys_sem_valid_val(sem) ((sem) != NULL) +#define sys_sem_set_invalid(sem) do { if((sem) != NULL) { *(sem) = NULL; }}while(0) +#define sys_sem_set_invalid_val(sem) do { (sem) = NULL; }while(0) + +struct sys_mutex; +typedef struct sys_mutex * sys_mutex_t; +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +struct sys_mbox; +typedef struct sys_mbox * sys_mbox_t; +#define sys_mbox_valid(mbox) sys_sem_valid(mbox) +#define sys_mbox_valid_val(mbox) sys_sem_valid_val(mbox) +#define sys_mbox_set_invalid(mbox) sys_sem_set_invalid(mbox) +#define sys_mbox_set_invalid_val(mbox) sys_sem_set_invalid_val(mbox) + +struct sys_thread; +typedef struct sys_thread * sys_thread_t; + +#if LWIP_NETCONN_SEM_PER_THREAD +sys_sem_t* sys_arch_netconn_sem_get(void); +void sys_arch_netconn_sem_alloc(void); +void sys_arch_netconn_sem_free(void); +#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get() +#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc() +#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free() +#endif /* #if LWIP_NETCONN_SEM_PER_THREAD */ + +#define LWIP_EXAMPLE_APP_ABORT() lwip_unix_keypressed() +int lwip_unix_keypressed(void); + +/* + --------------------------------------- + ---------- Threading options ---------- + --------------------------------------- +*/ + +void sys_mark_tcpip_thread(void); +#define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread() + +#if LWIP_TCPIP_CORE_LOCKING +void sys_lock_tcpip_core(void); +#define LOCK_TCPIP_CORE() sys_lock_tcpip_core() +void sys_unlock_tcpip_core(void); +#define UNLOCK_TCPIP_CORE() sys_unlock_tcpip_core() +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARCH_SYS_ARCH_H */ diff --git a/contrib/ports/unix/port/include/netif/fifo.h b/contrib/ports/unix/port/include/netif/fifo.h new file mode 100644 index 0000000..7c87c82 --- /dev/null +++ b/contrib/ports/unix/port/include/netif/fifo.h @@ -0,0 +1,62 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "lwip/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** How many bytes in fifo */ +#define FIFOSIZE 2048 + +/** fifo data structure, this one is passed to all fifo functions */ +typedef struct fifo_t { + u8_t data[FIFOSIZE+10]; /* data segment, +10 is a hack probably not needed.. FIXME! */ + int dataslot; /* index to next char to be read */ + int emptyslot; /* index to next empty slot */ + int len; /* len probably not needed, may be calculated from dataslot and emptyslot in conjunction with FIFOSIZE */ + + sys_sem_t sem; /* semaphore protecting simultaneous data manipulation */ + sys_sem_t getSem; /* sepaphore used to signal new data if getWaiting is set */ + u8_t getWaiting; /* flag used to indicate that fifoget is waiting for data. fifoput is supposed to clear */ + /* this flag prior to signaling the getSem semaphore */ +} fifo_t; + + +/** +* Get a character from fifo +* Blocking call. +* @param fifo pointer to fifo data structure +* @return character read from fifo +*/ +u8_t fifoGet(fifo_t * fifo); + +/** +* Get a character from fifo +* Non blocking call. +* @param fifo pointer to fifo data structure +* @return character read from fifo, or < zero if non was available +*/ +s16_t fifoGetNonBlock(fifo_t * fifo); + +/** +* fifoput is called by the signalhandler when new data has arrived (or some other event is indicated) +* fifoput reads directly from the serialport and is thus highly dependent on unix arch at this moment +* @param fifo pointer to fifo data structure +* @param fd unix file descriptor +*/ +void fifoPut(fifo_t * fifo, int fd); + +/** +* fifoinit initiate fifo +* @param fifo pointer to fifo data structure, allocated by the user +*/ +void fifoInit(fifo_t * fifo); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/ports/unix/port/include/netif/list.h b/contrib/ports/unix/port/include/netif/list.h new file mode 100644 index 0000000..8c0fe25 --- /dev/null +++ b/contrib/ports/unix/port/include/netif/list.h @@ -0,0 +1,34 @@ + +#ifndef LWIP_LIST_H +#define LWIP_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct elem; + +struct list { + struct elem *first, *last; + int size, elems; +}; + +struct elem { + struct elem *next; + void *data; +}; + +struct list *list_new(int size); +int list_push(struct list *list, void *data); +void *list_pop(struct list *list); +void *list_first(struct list *list); +int list_elems(struct list *list); +void list_delete(struct list *list); +int list_remove(struct list *list, void *elem); +void list_map(struct list *list, void (* func)(void *arg)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ports/unix/port/include/netif/pcapif.h b/contrib/ports/unix/port/include/netif/pcapif.h new file mode 100644 index 0000000..a9e1972 --- /dev/null +++ b/contrib/ports/unix/port/include/netif/pcapif.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_PCAPIF_H +#define LWIP_PCAPIF_H + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t pcapif_init(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PCAPIF_H */ diff --git a/contrib/ports/unix/port/include/netif/sio.h b/contrib/ports/unix/port/include/netif/sio.h new file mode 100644 index 0000000..cb992f8 --- /dev/null +++ b/contrib/ports/unix/port/include/netif/sio.h @@ -0,0 +1,68 @@ +#ifndef SIO_UNIX_H +#define SIO_UNIX_H + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "netif/fifo.h" +/*#include "netif/pppif.h"*/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct sio_status_s { + int fd; + fifo_t myfifo; +}; + +/* BAUDRATE is defined in sio.c as it is implementation specific */ +/** Baudrates */ +typedef enum sioBaudrates { + SIO_BAUD_9600, + SIO_BAUD_19200, + SIO_BAUD_38400, + SIO_BAUD_57600, + SIO_BAUD_115200 +} sioBaudrates; + +/** +* Poll for a new character from incoming data stream +* @param siostat siostatus struct, contains sio instance data, given by sio_open +* @return char read from input stream, or < 0 if no char was available +*/ +s16_t sio_poll(sio_status_t * siostat); + +/** +* Parse incoming characters until a string str is received, blocking call +* @param str zero terminated string to expect +* @param siostat siostatus struct, contains sio instance data, given by sio_open +*/ +void sio_expect_string(u8_t *str, sio_status_t * siostat); + +/** +* Write a char to output data stream +* @param str pointer to a zero terminated string +* @param siostat siostatus struct, contains sio instance data, given by sio_open +*/ +void sio_send_string(u8_t *str, sio_status_t * siostat); + +/** +* Flush outbuffer (send everything in buffer now), useful if some layer below is +* holding on to data, waitng to fill a buffer +* @param siostat siostatus struct, contains sio instance data, given by sio_open +*/ +void sio_flush( sio_status_t * siostat ); + +/** +* Change baudrate of port, may close and reopen port +* @param baud new baudrate +* @param siostat siostatus struct, contains sio instance data, given by sio_open +*/ +void sio_change_baud( sioBaudrates baud, sio_status_t * siostat ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/ports/unix/port/include/netif/tapif.h b/contrib/ports/unix/port/include/netif/tapif.h new file mode 100644 index 0000000..c156e1d --- /dev/null +++ b/contrib/ports/unix/port/include/netif/tapif.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_TAPIF_H +#define LWIP_TAPIF_H + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t tapif_init(struct netif *netif); +void tapif_poll(struct netif *netif); +#if NO_SYS +int tapif_select(struct netif *netif); +#endif /* NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TAPIF_H */ diff --git a/contrib/ports/unix/port/include/netif/vdeif.h b/contrib/ports/unix/port/include/netif/vdeif.h new file mode 100644 index 0000000..e318392 --- /dev/null +++ b/contrib/ports/unix/port/include/netif/vdeif.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_VDEIF_H +#define LWIP_VDEIF_H + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t vdeif_init(struct netif *netif); +void vdeif_poll(struct netif *netif); +#if NO_SYS +int vdeif_select(struct netif *netif); +#endif /* NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_VDEIF_H */ diff --git a/contrib/ports/unix/port/netif/fifo.c b/contrib/ports/unix/port/netif/fifo.c new file mode 100644 index 0000000..350d3ea --- /dev/null +++ b/contrib/ports/unix/port/netif/fifo.c @@ -0,0 +1,139 @@ +/* Author: Magnus Ivarsson */ + +/* ---------------------------------------------- */ +/* --- fifo 4 unix ------------------------------ */ +/* ---------------------------------------------- */ +#include "lwip/err.h" +#include "netif/fifo.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/arch.h" +#include + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef SIO_FIFO_DEBUG +#define SIO_FIFO_DEBUG LWIP_DBG_OFF +#endif + +u8_t fifoGet(fifo_t * fifo) +{ + u8_t c; + + sys_sem_wait(&fifo->sem); /* enter critical section */ + + if (fifo->dataslot == fifo->emptyslot) + { + fifo->getWaiting = TRUE; /* tell putFifo to signal us when data is available */ + sys_sem_signal(&fifo->sem); /* leave critical section (allow input from serial port..) */ + sys_sem_wait(&fifo->getSem); /* wait 4 data */ + sys_sem_wait(&fifo->sem); /* reenter critical section */ + } + + c = fifo->data[fifo->dataslot++]; + fifo->len--; + + if (fifo->dataslot == FIFOSIZE) + { + fifo->dataslot = 0; + } + sys_sem_signal(&fifo->sem); /* leave critical section */ + return c; +} + + +s16_t fifoGetNonBlock(fifo_t * fifo) +{ + u16_t c; + + sys_sem_wait(&fifo->sem); /* enter critical section */ + + if (fifo->dataslot == fifo->emptyslot) + { + /* empty fifo */ + c = -1; + } + else + { + c = fifo->data[fifo->dataslot++]; + fifo->len--; + + if (fifo->dataslot == FIFOSIZE) + { + fifo->dataslot = 0; + } + } + sys_sem_signal(&fifo->sem); /* leave critical section */ + return c; +} + + +void fifoPut(fifo_t * fifo, int fd) +{ + /* FIXME: mutex around struct data.. */ + int cnt=0; + + sys_sem_wait(&fifo->sem ); /* enter critical */ + + LWIP_DEBUGF( SIO_FIFO_DEBUG,("fifoput: len%d dat%d empt%d --> ", fifo->len, fifo->dataslot, fifo->emptyslot ) ); + + if ( fifo->emptyslot < fifo->dataslot ) + { + cnt = read( fd, &fifo->data[fifo->emptyslot], fifo->dataslot - fifo->emptyslot ); + } + else + { + cnt = read( fd, &fifo->data[fifo->emptyslot], FIFOSIZE-fifo->emptyslot ); + } + fifo->emptyslot += cnt; + fifo->len += cnt; + + LWIP_DEBUGF( SIO_FIFO_DEBUG,("len%d dat%d empt%d\n", fifo->len, fifo->dataslot, fifo->emptyslot ) ); + + if ( fifo->len > FIFOSIZE ) + { + printf( "ERROR: fifo overrun detected len=%d, flushing\n", fifo->len ); + fifo->dataslot = 0; + fifo->emptyslot = 0; + fifo->len = 0; + } + + if ( fifo->emptyslot == FIFOSIZE ) + { + fifo->emptyslot = 0; + LWIP_DEBUGF( SIO_FIFO_DEBUG, ("(WRAP) ") ); + + sys_sem_signal(&fifo->sem ); /* leave critical */ + fifoPut( fifo, fd ); + return; + } + if ( fifo->getWaiting ) + { + fifo->getWaiting = FALSE; + sys_sem_signal(&fifo->getSem ); + } + + sys_sem_signal(&fifo->sem ); /* leave critical */ + return; +} + + +void fifoInit(fifo_t * fifo) +{ + fifo->dataslot = 0; + fifo->emptyslot = 0; + fifo->len = 0; + if(sys_sem_new(&fifo->sem, 1) != ERR_OK) { /* critical section 1=free to enter */ + LWIP_ASSERT("Failed to create semaphore", 0); + } + if(sys_sem_new(&fifo->getSem, 0) != ERR_OK) { /* 0 = no one waiting */ + LWIP_ASSERT("Failed to create semaphore", 0); + } + fifo->getWaiting = FALSE; +} diff --git a/contrib/ports/unix/port/netif/list.c b/contrib/ports/unix/port/netif/list.c new file mode 100644 index 0000000..77faab5 --- /dev/null +++ b/contrib/ports/unix/port/netif/list.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + + +#include +#include + + +/*-----------------------------------------------------------------------------------*/ +struct list * +list_new(int size) +{ + struct list *list; + list = (struct list *)malloc(sizeof(struct list)); + list->first = list->last = NULL; + list->size = size; + list->elems = 0; + return list; +} +/*-----------------------------------------------------------------------------------*/ +int +list_push(struct list *list, void *data) +{ + struct elem *elem; + + if (list->elems < list->size) { + elem = (struct elem *)malloc(sizeof(struct elem)); + elem->data = data; + elem->next = NULL; + if (list->last != NULL) { + list->last->next = elem; + } + list->last = elem; + if (list->first == NULL) { + list->first = elem; + } + list->elems++; + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void * +list_pop(struct list *list) +{ + struct elem *elem; + void *data; + + if (list->elems > 0) { + elem = list->first; + if (elem == list->last) { + list->last = elem->next; + } + list->first = elem->next; + + list->elems--; + + data = elem->data; + free(elem); + + return data; + } + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +void * +list_first(struct list *list) +{ + return list->first; +} +/*-----------------------------------------------------------------------------------*/ +int +list_elems(struct list *list) +{ + return list->elems; +} +/*-----------------------------------------------------------------------------------*/ +void +list_delete(struct list *list) +{ + while (list_pop(list) != NULL); + free(list); +} +/*-----------------------------------------------------------------------------------*/ +int +list_remove(struct list *list, void *elem) +{ + struct elem *e, *p; + + p = NULL; + for(e = list->first; e != NULL; e = e->next) { + if (e->data == elem) { + if (p != NULL) { + p->next = e->next; + } else { + list->first = e->next; + } + if (list->last == e) { + list->last = p; + if (p != NULL) { + p->next = NULL; + } + } + free(e); + list->elems--; + return 1; + } + p = e; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void +list_map(struct list *list, void (* func)(void *arg)) +{ + struct elem *e; + + for(e = list->first; e != NULL; e = e->next) { + func(e->data); + } +} +/*-----------------------------------------------------------------------------------*/ diff --git a/contrib/ports/unix/port/netif/pcapif.c b/contrib/ports/unix/port/netif/pcapif.c new file mode 100644 index 0000000..2851c82 --- /dev/null +++ b/contrib/ports/unix/port/netif/pcapif.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef linux /* Apparently, this doesn't work under Linux. */ + +#include "lwip/debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "netif/etharp.h" + +#include "lwip/stats.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "lwip/ip.h" + + +struct pcapif { + pcap_t *pd; + sys_sem_t sem; + u8_t pkt[2048]; + u32_t len; + u32_t lasttime; + struct pbuf *p; + struct eth_addr *ethaddr; +}; + +static char errbuf[PCAP_ERRBUF_SIZE]; + +/*-----------------------------------------------------------------------------------*/ +static err_t +pcapif_output(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr) +{ + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static void +timeout(void *arg) +{ + struct netif *netif; + struct pcapif *pcapif; + struct pbuf *p; + struct eth_hdr *ethhdr; + + netif = (struct netif *)arg; + pcapif = netif->state; + ethhdr = (struct eth_hdr *)pcapif->pkt; + + + if (lwip_htons(ethhdr->type) != ETHTYPE_IP || + ip_lookup(pcapif->pkt + 14, netif)) { + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, pcapif->len, PBUF_POOL); + + if (p != NULL) { + pbuf_take(p, pcapif->pkt, pcapif->len); + + ethhdr = p->payload; + switch (lwip_htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_IP: + case ETHTYPE_ARP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + break; + default: + pbuf_free(p); + break; + } + } + } else { + printf("ip_lookup dropped\n"); + } + + sys_sem_signal(&pcapif->sem); +} +/*-----------------------------------------------------------------------------------*/ +static void +callback(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *pkt) +{ + struct netif *netif; + struct pcapif *pcapif; + u32_t time, lasttime; + + netif = (struct netif *)arg; + pcapif = netif->state; + + pcapif->len = hdr->len; + + bcopy(pkt, pcapif->pkt, hdr->len); + + time = hdr->ts.tv_sec * 1000 + hdr->ts.tv_usec / 1000; + + lasttime = pcapif->lasttime; + pcapif->lasttime = time; + + + if (lasttime == 0) { + sys_timeout(1000, timeout, netif); + } else { + sys_timeout(time - lasttime, timeout, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +pcapif_thread(void *arg) +{ + struct netif *netif; + struct pcapif *pcapif; + netif = arg; + pcapif = netif->state; + + while (1) { + pcap_loop(pcapif->pd, 1, callback, (u_char *)netif); + sys_sem_wait(&pcapif->sem); + if (pcapif->p != NULL) { + netif->input(pcapif->p, netif); + } + } +} +/*-----------------------------------------------------------------------------------*/ +err_t +pcapif_init(struct netif *netif) +{ + struct pcapif *p; + + p = malloc(sizeof(struct pcapif)); + if (p == NULL) + return ERR_MEM; + netif->state = p; + netif->name[0] = 'p'; + netif->name[1] = 'c'; + netif->output = pcapif_output; + + p->pd = pcap_open_offline("pcapdump", errbuf); + if (p->pd == NULL) { + printf("pcapif_init: failed %s\n", errbuf); + return ERR_IF; + } + + if(sys_sem_new(&p->sem, 0) != ERR_OK) { + LWIP_ASSERT("Failed to create semaphore", 0); + } + p->p = NULL; + p->lasttime = 0; + + sys_thread_new("pcapif_thread", pcapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +#endif /* linux */ diff --git a/contrib/ports/unix/port/netif/sio.c b/contrib/ports/unix/port/netif/sio.c new file mode 100644 index 0000000..41bbba5 --- /dev/null +++ b/contrib/ports/unix/port/netif/sio.c @@ -0,0 +1,490 @@ +/* Author: Magnus Ivarsson */ + +/* to get rid of implicit function declarations */ +#ifndef __FreeBSD__ +/* defining this on FreeBSD hides non-standard defines that sio.c depends on */ +#define _XOPEN_SOURCE 600 +#endif +#define _GNU_SOURCE + +/* build with Darwin C extensions not part of POSIX, i.e. FASYNC, SIGIO. + we can't use LWIP_UNIX_MACH because extensions need to be turned + on before any system headers (which are pulled in through cc.h) + are included */ +#if defined(__APPLE__) +#define _DARWIN_C_SOURCE +#endif + +#include "netif/sio.h" +#include "netif/fifo.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/arch.h" +#include "lwip/sio.h" +#include "netif/ppp/ppp_opts.h" + +/* Following #undefs are here to keep compiler from issuing warnings + about them being double defined. (They are defined in lwip/inet.h + as well as the Unix #includes below.) */ +#undef htonl +#undef ntohl +#undef htons +#undef ntohs +#undef HTONL +#undef NTOHL +#undef HTONS +#undef NTOHS + +#include +#include +#if defined(LWIP_UNIX_OPENBSD) || defined(LWIP_UNIX_MACH) +#include +#elif defined(LWIP_UNIX_FREEBSD) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +#if (PPP_SUPPORT || LWIP_HAVE_SLIPIF) && defined(LWIP_UNIX_LINUX) +#include +#endif + +/*#define BAUDRATE B19200 */ +/*#define BAUDRATE B57600 */ +#define BAUDRATE B115200 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* for all of you who don't define SIO_DEBUG in debug.h */ +#ifndef SIO_DEBUG +#define SIO_DEBUG 0 +#endif + + +/* typedef struct siostruct_t */ +/* { */ +/* sio_status_t *sio; */ +/* } siostruct_t; */ + +/** array of ((siostruct*)netif->state)->sio structs */ +static sio_status_t statusar[4]; + +#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) +/* --private-functions----------------------------------------------------------------- */ +/** + * Signal handler for ttyXX0 to indicate bytes received + * one per interface is needed since we cannot send a instance number / pointer as callback argument (?) + */ +static void signal_handler_IO_0( int status ) +{ + LWIP_UNUSED_ARG(status); + LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 0\n")); + fifoPut( &statusar[0].myfifo, statusar[0].fd ); +} + +/** + * Signal handler for ttyXX1 to indicate bytes received + * one per interface is needed since we cannot send a instance number / pointer as callback argument (?) + */ +static void signal_handler_IO_1( int status ) +{ + LWIP_UNUSED_ARG(status); + LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 1\n")); + fifoPut( &statusar[1].myfifo, statusar[1].fd ); +} +#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */ + +/** +* Initiation of serial device +* @param device string with the device name and path, eg. "/dev/ttyS0" +* @param devnum device number +* @param siostat status +* @return file handle to serial dev. +*/ +static int sio_init( char * device, int devnum, sio_status_t * siostat ) +{ + struct termios oldtio,newtio; +#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) + struct sigaction saio; /* definition of signal action */ +#endif + int fd; + LWIP_UNUSED_ARG(siostat); + LWIP_UNUSED_ARG(devnum); + + /* open the device to be non-blocking (read will return immediately) */ + fd = open( device, O_RDWR | O_NOCTTY | O_NONBLOCK ); + if ( fd < 0 ) + { + perror( device ); + exit( -1 ); + } + +#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) + memset(&saio, 0, sizeof(struct sigaction)); + /* install the signal handler before making the device asynchronous */ + switch ( devnum ) + { + case 0: + LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_0\n") ); + saio.sa_handler = signal_handler_IO_0; + break; + case 1: + LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_1\n") ); + saio.sa_handler = signal_handler_IO_1; + break; + default: + LWIP_DEBUGF( SIO_DEBUG,("sioinit, devnum not allowed\n") ); + break; + } + + sigaction( SIGIO,&saio,NULL ); + + /* allow the process to receive SIGIO */ + if ( fcntl( fd, F_SETOWN, getpid( ) ) != 0) + { + perror( device ); + exit( -1 ); + } + /* Make the file descriptor asynchronous (the manual page says only + O_APPEND and O_NONBLOCK, will work with F_SETFL...) */ + if ( fcntl( fd, F_SETFL, FASYNC ) != 0) + { + perror( device ); + exit( -1 ); + } +#else + if ( fcntl( fd, F_SETFL, 0 ) != 0) + { + perror( device ); + exit( -1 ); + } + +#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */ + + tcgetattr( fd,&oldtio ); /* save current port settings */ + /* set new port settings */ + /* see 'man termios' for further settings */ + memset(&newtio, 0, sizeof(newtio)); + newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS; + newtio.c_iflag = 0; + newtio.c_oflag = 0; + newtio.c_lflag = 0; /*ECHO; */ + newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */ + newtio.c_cc[VTIME] = 0; + + tcsetattr( fd,TCSANOW,&newtio ); + tcflush( fd, TCIOFLUSH ); + + return fd; +} + +/** +* +*/ +static void sio_speed( int fd, int speed ) +{ + struct termios oldtio,newtio; + /* int fd; */ + + LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: baudcode:%d enter\n", fd, speed)); + + if ( fd < 0 ) + { + LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: fd ERROR\n", fd)); + exit( -1 ); + } + + tcgetattr( fd,&oldtio ); /* get current port settings */ + + /* set new port settings + * see 'man termios' for further settings */ + memset(&newtio, 0, sizeof(newtio)); + newtio.c_cflag = speed | CS8 | CLOCAL | CREAD; /* | CRTSCTS; */ + newtio.c_iflag = 0; + newtio.c_oflag = 0; + newtio.c_lflag = 0; /*ECHO; */ + newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */ + newtio.c_cc[VTIME] = 0; + + tcsetattr( fd,TCSANOW,&newtio ); + tcflush( fd, TCIOFLUSH ); + + LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: leave\n", fd)); +} + +/* --public-functions----------------------------------------------------------------------------- */ +void sio_send( u8_t c, sio_status_t * siostat ) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ + + if ( write( siostat->fd, &c, 1 ) <= 0 ) + { + LWIP_DEBUGF(SIO_DEBUG, ("sio_send[%d]: write refused\n", siostat->fd)); + } +} + +void sio_send_string( u8_t *str, sio_status_t * siostat ) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ + int len = strlen( (const char *)str ); + + if ( write( siostat->fd, str, len ) <= 0 ) + { + LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: write refused\n", siostat->fd)); + } + LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: sent: %s\n", siostat->fd, str)); +} + + +void sio_flush( sio_status_t * siostat ) +{ + LWIP_UNUSED_ARG(siostat); + /* not implemented in unix as it is not needed */ + /*sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ +} + + +#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) +/*u8_t sio_recv( struct netif * netif )*/ +u8_t sio_recv( sio_status_t * siostat ) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ + return fifoGet( &(siostat->myfifo) ); +} + +s16_t sio_poll(sio_status_t * siostat) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ + return fifoGetNonBlock( &(siostat->myfifo) ); +} + + +void sio_expect_string( u8_t *str, sio_status_t * siostat ) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ + u8_t c; + int finger=0; + + LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: %s\n", siostat->fd, str)); + while ( 1 ) + { + c=fifoGet( &(siostat->myfifo) ); + LWIP_DEBUGF(SIO_DEBUG, ("_%c", c)); + if ( c==str[finger] ) + { + finger++; + } else if ( finger > 0 ) + { + /*it might fit in the beginning? */ + if ( str[0] == c ) + { + finger = 1; + } + } + if ( 0 == str[finger] ) + break; /* done, we have a match */ + } + LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: [match]\n", siostat->fd)); +} +#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */ + +#if (PPP_SUPPORT || LWIP_HAVE_SLIPIF) +u32_t sio_write(sio_status_t * siostat, const u8_t *buf, u32_t size) +{ + ssize_t wsz = write( siostat->fd, buf, size ); + return wsz < 0 ? 0 : wsz; +} + +u32_t sio_read(sio_status_t * siostat, u8_t *buf, u32_t size) +{ + ssize_t rsz = read( siostat->fd, buf, size ); + return rsz < 0 ? 0 : rsz; +} + +void sio_read_abort(sio_status_t * siostat) +{ + LWIP_UNUSED_ARG(siostat); + printf("sio_read_abort[%d]: not yet implemented for unix\n", siostat->fd); +} +#endif /* (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */ + +sio_fd_t sio_open(u8_t devnum) +{ + char dev[20]; + + /* would be nice with dynamic memory alloc */ + sio_status_t * siostate = &statusar[ devnum ]; +/* siostruct_t * tmp; */ + + +/* tmp = (siostruct_t*)(netif->state); */ +/* tmp->sio = siostate; */ + +/* tmp = (siostruct_t*)(netif->state); */ + +/* ((sio_status_t*)(tmp->sio))->fd = 0; */ + + LWIP_DEBUGF(SIO_DEBUG, ("sio_open: for devnum %d\n", devnum)); + +#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) + fifoInit( &siostate->myfifo ); +#endif /* ! PPP_SUPPORT */ + + snprintf( dev, sizeof(dev), "/dev/ttyS%d", devnum ); + + if ( (devnum == 1) || (devnum == 0) ) + { + if ( ( siostate->fd = sio_init( dev, devnum, siostate ) ) == 0 ) + { + LWIP_DEBUGF(SIO_DEBUG, ("sio_open: ERROR opening serial device dev=%s\n", dev)); + abort( ); + return NULL; + } + LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: dev=%s open.\n", siostate->fd, dev)); + } +#if PPP_SUPPORT + else if (devnum == 2) { + pid_t childpid; + char name[256]; + childpid = forkpty(&siostate->fd, name, NULL, NULL); + if(childpid < 0) { + perror("forkpty"); + exit (1); + } + if(childpid == 0) { + execl("/usr/sbin/pppd", "pppd", + "ms-dns", "198.168.100.7", + "local", "crtscts", + "debug", +#ifdef LWIP_PPP_CHAP_TEST + "auth", + "require-chap", + "remotename", "lwip", +#else + "noauth", +#endif +#if LWIP_IPV6 + "+ipv6", +#endif + "192.168.1.1:192.168.1.2", + NULL); + perror("execl pppd"); + exit (1); + } else { + LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned pppd pid %d on %s\n", + siostate->fd, childpid, name)); + } + + } +#endif +#if LWIP_HAVE_SLIPIF + else if (devnum == 3) { + pid_t childpid; + /* create PTY pair */ + siostate->fd = posix_openpt(O_RDWR | O_NOCTTY); + if (siostate->fd < 0) { + perror("open pty master"); + exit (1); + } + if (grantpt(siostate->fd) != 0) { + perror("grant pty master"); + exit (1); + } + if (unlockpt(siostate->fd) != 0) { + perror("unlock pty master"); + exit (1); + } + LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: for %s\n", + siostate->fd, ptsname(siostate->fd))); + /* fork for slattach */ + childpid = fork(); + if(childpid < 0) { + perror("fork"); + exit (1); + } + if(childpid == 0) { + /* esteblish SLIP interface on host side connected to PTY slave */ + execl("/sbin/slattach", "slattach", + "-d", "-v", "-L", "-p", "slip", + ptsname(siostate->fd), + NULL); + perror("execl slattach"); + exit (1); + } else { + int ret; + char buf[1024]; + LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned slattach pid %d on %s\n", + siostate->fd, childpid, ptsname(siostate->fd))); + /* wait a moment for slattach startup */ + sleep(1); + /* configure SLIP interface on host side as P2P interface */ + snprintf(buf, sizeof(buf), + "/sbin/ifconfig sl0 mtu %d %s pointopoint %s up", + SLIP_MAX_SIZE, "192.168.2.1", "192.168.2.2"); + LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: system(\"%s\");\n", siostate->fd, buf)); + ret = system(buf); + if (ret < 0) { + perror("ifconfig failed"); + exit(1); + } + } + } +#endif /* LWIP_HAVE_SLIPIF */ + else + { + LWIP_DEBUGF(SIO_DEBUG, ("sio_open: device %s (%d) is not supported\n", dev, devnum)); + return NULL; + } + + return siostate; +} + +/** +* +*/ +void sio_change_baud( sioBaudrates baud, sio_status_t * siostat ) +{ + /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ + + LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]\n", siostat->fd)); + + switch ( baud ) + { + case SIO_BAUD_9600: + sio_speed( siostat->fd, B9600 ); + break; + case SIO_BAUD_19200: + sio_speed( siostat->fd, B19200 ); + break; + case SIO_BAUD_38400: + sio_speed( siostat->fd, B38400 ); + break; + case SIO_BAUD_57600: + sio_speed( siostat->fd, B57600 ); + break; + case SIO_BAUD_115200: + sio_speed( siostat->fd, B115200 ); + break; + + default: + LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]: Unknown baudrate, code:%d\n", + siostat->fd, baud)); + break; + } +} diff --git a/contrib/ports/unix/port/netif/tapif.c b/contrib/ports/unix/port/netif/tapif.c new file mode 100644 index 0000000..cff0783 --- /dev/null +++ b/contrib/ports/unix/port/netif/tapif.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lwip/opt.h" + +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/mem.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "netif/etharp.h" +#include "lwip/ethip6.h" + +#include "netif/tapif.h" + +#define IFCONFIG_BIN "/sbin/ifconfig " + +#if defined(LWIP_UNIX_LINUX) +#include +#include +#include +/* + * Creating a tap interface requires special privileges. If the interfaces + * is created in advance with `tunctl -u ` it can be opened as a regular + * user. The network must already be configured. If DEVTAP_IF is defined it + * will be opened instead of creating a new tap device. + * + * You can also use PRECONFIGURED_TAPIF environment variable to do so. + */ +#ifndef DEVTAP_DEFAULT_IF +#define DEVTAP_DEFAULT_IF "tap0" +#endif +#ifndef DEVTAP +#define DEVTAP "/dev/net/tun" +#endif +#define NETMASK_ARGS "netmask %d.%d.%d.%d" +#define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d " NETMASK_ARGS +#elif defined(LWIP_UNIX_OPENBSD) +#define DEVTAP "/dev/tun0" +#define NETMASK_ARGS "netmask %d.%d.%d.%d" +#define IFCONFIG_ARGS "tun0 inet %d.%d.%d.%d " NETMASK_ARGS " link0" +#else /* others */ +#define DEVTAP "/dev/tap0" +#define NETMASK_ARGS "netmask %d.%d.%d.%d" +#define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d " NETMASK_ARGS +#endif + +/* Define those to better describe your network interface. */ +#define IFNAME0 't' +#define IFNAME1 'p' + +#ifndef TAPIF_DEBUG +#define TAPIF_DEBUG LWIP_DBG_OFF +#endif + +struct tapif { + /* Add whatever per-interface state that is needed here. */ + int fd; +}; + +/* Forward declarations. */ +static void tapif_input(struct netif *netif); +#if !NO_SYS +static void tapif_thread(void *arg); +#endif /* !NO_SYS */ + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif) +{ + struct tapif *tapif; +#if LWIP_IPV4 + int ret; + char buf[1024]; +#endif /* LWIP_IPV4 */ + char *preconfigured_tapif = getenv("PRECONFIGURED_TAPIF"); + + tapif = (struct tapif *)netif->state; + + /* Obtain MAC address from network interface. */ + + /* (We just fake an address...) */ + netif->hwaddr[0] = 0x02; + netif->hwaddr[1] = 0x12; + netif->hwaddr[2] = 0x34; + netif->hwaddr[3] = 0x56; + netif->hwaddr[4] = 0x78; + netif->hwaddr[5] = 0xab; + netif->hwaddr_len = 6; + + /* device capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; + + tapif->fd = open(DEVTAP, O_RDWR); + LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: fd %d\n", tapif->fd)); + if (tapif->fd == -1) { +#ifdef LWIP_UNIX_LINUX + perror("tapif_init: try running \"modprobe tun\" or rebuilding your kernel with CONFIG_TUN; cannot open "DEVTAP); +#else /* LWIP_UNIX_LINUX */ + perror("tapif_init: cannot open "DEVTAP); +#endif /* LWIP_UNIX_LINUX */ + exit(1); + } + +#ifdef LWIP_UNIX_LINUX + { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + + if (preconfigured_tapif) { + strncpy(ifr.ifr_name, preconfigured_tapif, sizeof(ifr.ifr_name) - 1); + } else { + strncpy(ifr.ifr_name, DEVTAP_DEFAULT_IF, sizeof(ifr.ifr_name) - 1); + } + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; /* ensure \0 termination */ + + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0) { + perror("tapif_init: "DEVTAP" ioctl TUNSETIFF"); + exit(1); + } + } +#endif /* LWIP_UNIX_LINUX */ + + netif_set_link_up(netif); + + if (preconfigured_tapif == NULL) { +#if LWIP_IPV4 + snprintf(buf, 1024, IFCONFIG_BIN IFCONFIG_ARGS, + ip4_addr1(netif_ip4_gw(netif)), + ip4_addr2(netif_ip4_gw(netif)), + ip4_addr3(netif_ip4_gw(netif)), + ip4_addr4(netif_ip4_gw(netif)) +#ifdef NETMASK_ARGS + , + ip4_addr1(netif_ip4_netmask(netif)), + ip4_addr2(netif_ip4_netmask(netif)), + ip4_addr3(netif_ip4_netmask(netif)), + ip4_addr4(netif_ip4_netmask(netif)) +#endif /* NETMASK_ARGS */ + ); + + LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: system(\"%s\");\n", buf)); + ret = system(buf); + if (ret < 0) { + perror("ifconfig failed"); + exit(1); + } + if (ret != 0) { + printf("ifconfig returned %d\n", ret); + } +#else /* LWIP_IPV4 */ + perror("todo: support IPv6 support for non-preconfigured tapif"); + exit(1); +#endif /* LWIP_IPV4 */ + } + +#if !NO_SYS + sys_thread_new("tapif_thread", tapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +#endif /* !NO_SYS */ +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_output(): + * + * Should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + */ +/*-----------------------------------------------------------------------------------*/ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct tapif *tapif = (struct tapif *)netif->state; + char buf[1518]; /* max packet size including VLAN excluding CRC */ + ssize_t written; + +#if 0 + if (((double)rand()/(double)RAND_MAX) < 0.2) { + printf("drop output\n"); + return ERR_OK; /* ERR_OK because we simulate packet loss on cable */ + } +#endif + + if (p->tot_len > sizeof(buf)) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + perror("tapif: packet too large"); + return ERR_IF; + } + + /* initiate transfer(); */ + pbuf_copy_partial(p, buf, p->tot_len, 0); + + /* signal that packet should be sent(); */ + written = write(tapif->fd, buf, p->tot_len); + if (written < p->tot_len) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + perror("tapif: write"); + return ERR_IF; + } else { + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, (u32_t)written); + return ERR_OK; + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct pbuf *p; + u16_t len; + ssize_t readlen; + char buf[1518]; /* max packet size including VLAN excluding CRC */ + struct tapif *tapif = (struct tapif *)netif->state; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + readlen = read(tapif->fd, buf, sizeof(buf)); + if (readlen < 0) { + perror("read returned -1"); + exit(1); + } + len = (u16_t)readlen; + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, len); + +#if 0 + if (((double)rand()/(double)RAND_MAX) < 0.2) { + printf("drop\n"); + return NULL; + } +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, buf, len); + /* acknowledge that packet has been read(); */ + } else { + /* drop packet(); */ + MIB2_STATS_NETIF_INC(netif, ifindiscards); + LWIP_DEBUGF(NETIF_DEBUG, ("tapif_input: could not allocate pbuf\n")); + } + + return p; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * tapif_input(): + * + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. + * + */ +/*-----------------------------------------------------------------------------------*/ +static void +tapif_input(struct netif *netif) +{ + struct pbuf *p = low_level_input(netif); + + if (p == NULL) { +#if LINK_STATS + LINK_STATS_INC(link.recv); +#endif /* LINK_STATS */ + LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_input: low_level_input returned NULL\n")); + return; + } + + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("tapif_input: netif input error\n")); + pbuf_free(p); + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tapif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t +tapif_init(struct netif *netif) +{ + struct tapif *tapif = (struct tapif *)mem_malloc(sizeof(struct tapif)); + + if (tapif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("tapif_init: out of memory for tapif\n")); + return ERR_MEM; + } + netif->state = tapif; + MIB2_INIT_NETIF(netif, snmp_ifType_other, 100000000); + + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + netif->mtu = 1500; + + low_level_init(netif); + + return ERR_OK; +} + + +/*-----------------------------------------------------------------------------------*/ +void +tapif_poll(struct netif *netif) +{ + tapif_input(netif); +} + +#if NO_SYS + +int +tapif_select(struct netif *netif) +{ + fd_set fdset; + int ret; + struct timeval tv; + struct tapif *tapif; + u32_t msecs = sys_timeouts_sleeptime(); + + tapif = (struct tapif *)netif->state; + + tv.tv_sec = msecs / 1000; + tv.tv_usec = (msecs % 1000) * 1000; + + FD_ZERO(&fdset); + FD_SET(tapif->fd, &fdset); + + ret = select(tapif->fd + 1, &fdset, NULL, NULL, &tv); + if (ret > 0) { + tapif_input(netif); + } + return ret; +} + +#else /* NO_SYS */ + +static void +tapif_thread(void *arg) +{ + struct netif *netif; + struct tapif *tapif; + fd_set fdset; + int ret; + + netif = (struct netif *)arg; + tapif = (struct tapif *)netif->state; + + while(1) { + FD_ZERO(&fdset); + FD_SET(tapif->fd, &fdset); + + /* Wait for a packet to arrive. */ + ret = select(tapif->fd + 1, &fdset, NULL, NULL, NULL); + + if(ret == 1) { + /* Handle incoming packet. */ + tapif_input(netif); + } else if(ret == -1) { + perror("tapif_thread: select"); + } + } +} + +#endif /* NO_SYS */ diff --git a/contrib/ports/unix/port/netif/vdeif.c b/contrib/ports/unix/port/netif/vdeif.c new file mode 100644 index 0000000..9b6b50e --- /dev/null +++ b/contrib/ports/unix/port/netif/vdeif.c @@ -0,0 +1,344 @@ +/* + * VDE (virtual distributed ethernet) interface for ale4net + * (based on tapif interface Adam Dunkels ) + * 2005,2010,2011,2023 Renzo Davoli University of Bologna - Italy + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lwip/opt.h" + +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/mem.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "netif/etharp.h" +#include "lwip/ethip6.h" +#include + +#include "netif/vdeif.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'v' +#define IFNAME1 'd' + +#ifndef VDEIF_DEBUG +#define VDEIF_DEBUG LWIP_DBG_OFF +#endif + +static char vdedescr[] = "lwip"; + +struct vdeif { + VDECONN *vdeconn; +}; + +/* Forward declarations. */ +static void vdeif_input(struct netif *netif); +#if !NO_SYS +static void vdeif_thread(void *arg); +#endif /* !NO_SYS */ + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif, char *vderl) +{ + struct vdeif *vdeif; + int randaddr; + struct timeval now; + + vdeif = (struct vdeif *)netif->state; + gettimeofday(&now, NULL); + srand(now.tv_sec + now.tv_usec); + randaddr = rand(); + + /* Obtain MAC address from network interface. */ + + /* (We just fake an address...) */ + netif->hwaddr[0] = 0x02; + netif->hwaddr[1] = 0x2; + netif->hwaddr[2] = randaddr >> 24; + netif->hwaddr[3] = randaddr >> 16; + netif->hwaddr[4] = randaddr >> 8; + netif->hwaddr[5] = randaddr; + netif->hwaddr_len = 6; + + /* device capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; + + vdeif->vdeconn = vde_open(vderl, vdedescr, NULL); + LWIP_DEBUGF(VDEIF_DEBUG, ("vdeif_init: ok = %d\n", !!vdeif->vdeconn)); + if (vdeif->vdeconn == NULL) { + perror("vdeif_init: cannot open vde net"); + exit(1); + } + + netif_set_link_up(netif); + +#if !NO_SYS + sys_thread_new("vdeif_thread", vdeif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +#endif /* !NO_SYS */ +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_output(): + * + * Should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + */ +/*-----------------------------------------------------------------------------------*/ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct vdeif *vdeif = (struct vdeif *)netif->state; + char buf[1518]; /* max packet size including VLAN excluding CRC */ + ssize_t written; + + if (p->tot_len > sizeof(buf)) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + perror("vdeif: packet too large"); + return ERR_IF; + } + + /* initiate transfer(); */ + pbuf_copy_partial(p, buf, p->tot_len, 0); + + /* signal that packet should be sent(); */ + written = vde_send(vdeif->vdeconn, buf, p->tot_len, 0); + if (written < p->tot_len) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + perror("vdeif: write"); + return ERR_IF; + } else { + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, (u32_t)written); + return ERR_OK; + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct pbuf *p; + u16_t len; + ssize_t readlen; + char buf[1518]; /* max packet size including VLAN excluding CRC */ + struct vdeif *vdeif = (struct vdeif *)netif->state; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + readlen = vde_recv(vdeif->vdeconn, buf, sizeof(buf), 0); + if (readlen < 0) { + perror("read returned -1"); + exit(1); + } + len = (u16_t)readlen; + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, len); + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, buf, len); + /* acknowledge that packet has been read(); */ + } else { + /* drop packet(); */ + MIB2_STATS_NETIF_INC(netif, ifindiscards); + LWIP_DEBUGF(NETIF_DEBUG, ("vdeif_input: could not allocate pbuf\n")); + } + + return p; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * vdeif_input(): + * + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. + * + */ +/*-----------------------------------------------------------------------------------*/ +static void +vdeif_input(struct netif *netif) +{ + struct pbuf *p = low_level_input(netif); + + if (p == NULL) { +#if LINK_STATS + LINK_STATS_INC(link.recv); +#endif /* LINK_STATS */ + LWIP_DEBUGF(VDEIF_DEBUG, ("vdeif_input: low_level_input returned NULL\n")); + return; + } + + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("vdeif_input: netif input error\n")); + pbuf_free(p); + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * vdeif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t +vdeif_init(struct netif *netif) +{ + char *vderl = (char *) netif->state; + struct vdeif *vdeif = (struct vdeif *)mem_malloc(sizeof(struct vdeif)); + + if (vdeif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("vdeif_init: out of memory for vdeif\n")); + return ERR_MEM; + } + netif->state = vdeif; + MIB2_INIT_NETIF(netif, snmp_ifType_other, 100000000); + + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + netif->mtu = 1500; + + low_level_init(netif, vderl); + + return ERR_OK; +} + + +/*-----------------------------------------------------------------------------------*/ +void +vdeif_poll(struct netif *netif) +{ + vdeif_input(netif); +} + +#if NO_SYS + +int +vdeif_select(struct netif *netif) +{ + fd_set fdset; + int ret; + struct timeval tv; + struct vdeif *vdeif; + u32_t msecs = sys_timeouts_sleeptime(); + int datafd; + + vdeif = (struct vdeif *)netif->state; + datafd = vde_datafd(vdeif->vdeconn); + + tv.tv_sec = msecs / 1000; + tv.tv_usec = (msecs % 1000) * 1000; + + FD_ZERO(&fdset); + FD_SET(datafd, &fdset); + + ret = select(datafd + 1, &fdset, NULL, NULL, &tv); + if (ret > 0) { + vdeif_input(netif); + } + return ret; +} + +#else /* NO_SYS */ + +static void +vdeif_thread(void *arg) +{ + struct netif *netif; + struct vdeif *vdeif; + fd_set fdset; + int ret; + int datafd; + + netif = (struct netif *)arg; + vdeif = (struct vdeif *)netif->state; + datafd = vde_datafd(vdeif->vdeconn); + + while(1) { + FD_ZERO(&fdset); + FD_SET(datafd, &fdset); + + /* Wait for a packet to arrive. */ + ret = select(datafd + 1, &fdset, NULL, NULL, NULL); + + if(ret == 1) { + /* Handle incoming packet. */ + vdeif_input(netif); + } else if(ret == -1) { + perror("vdeif_thread: select"); + } + } +} + +#endif /* NO_SYS */ diff --git a/contrib/ports/unix/port/perf.c b/contrib/ports/unix/port/perf.c new file mode 100644 index 0000000..bed4614 --- /dev/null +++ b/contrib/ports/unix/port/perf.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "arch/perf.h" + +#include + +static FILE *f; + +void +perf_print(unsigned long c1l, unsigned long c1h, + unsigned long c2l, unsigned long c2h, + char *key) +{ + unsigned long sub_ms, sub_ls; + + sub_ms = c2h - c1h; + sub_ls = c2l - c1l; + if (c2l < c1l) sub_ms--; + fprintf(f, "%s: %.8lu%.8lu\n", key, sub_ms, sub_ls); + fflush(NULL); +} + +void +perf_print_times(struct tms *start, struct tms *end, char *key) +{ + fprintf(f, "%s: %lu\n", key, end->tms_stime - start->tms_stime); + fflush(NULL); +} + +void +perf_init(char *fname) +{ + f = fopen(fname, "w"); +} + diff --git a/contrib/ports/unix/port/sys_arch.c b/contrib/ports/unix/port/sys_arch.c new file mode 100644 index 0000000..1e094e8 --- /dev/null +++ b/contrib/ports/unix/port/sys_arch.c @@ -0,0 +1,840 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * Wed Apr 17 16:05:29 EDT 2002 (James Roth) + * + * - Fixed an unlikely sys_thread_new() race condition. + * + * - Made current_thread() work with threads which where + * not created with sys_thread_new(). This includes + * the main thread and threads made with pthread_create(). + * + * - Catch overflows where more than SYS_MBOX_SIZE messages + * are waiting to be read. The sys_mbox_post() routine + * will block until there is more room instead of just + * leaking messages. + */ +#define _GNU_SOURCE /* pull in pthread_setname_np() on Linux */ + +#include "lwip/debug.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "lwip/def.h" + +#ifdef LWIP_UNIX_MACH +#include +#include +#endif + +#include "lwip/sys.h" +#include "lwip/opt.h" +#include "lwip/stats.h" +#include "lwip/tcpip.h" + +#if LWIP_NETCONN_SEM_PER_THREAD +/* pthread key to *our* thread local storage entry */ +static pthread_key_t sys_thread_sem_key; +#endif + +/* Return code for an interrupted timed wait */ +#define SYS_ARCH_INTR 0xfffffffeUL + +u32_t +lwip_port_rand(void) +{ + return (u32_t)rand(); +} + +static void +get_monotonic_time(struct timespec *ts) +{ +#ifdef LWIP_UNIX_MACH + /* darwin impl (no CLOCK_MONOTONIC) */ + u64_t t = mach_absolute_time(); + mach_timebase_info_data_t timebase_info = {0, 0}; + mach_timebase_info(&timebase_info); + u64_t nano = (t * timebase_info.numer) / (timebase_info.denom); + u64_t sec = nano/1000000000L; + nano -= sec * 1000000000L; + ts->tv_sec = sec; + ts->tv_nsec = nano; +#else + clock_gettime(CLOCK_MONOTONIC, ts); +#endif +} + +#if SYS_LIGHTWEIGHT_PROT +static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t lwprot_thread = (pthread_t)0xDEAD; +static int lwprot_count = 0; +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#if !NO_SYS + +static struct sys_thread *threads = NULL; +static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct sys_mbox_msg { + struct sys_mbox_msg *next; + void *msg; +}; + +#define SYS_MBOX_SIZE 128 + +struct sys_mbox { + int first, last; + void *msgs[SYS_MBOX_SIZE]; + struct sys_sem *not_empty; + struct sys_sem *not_full; + struct sys_sem *mutex; + int wait_send; +}; + +struct sys_sem { + unsigned int c; + pthread_condattr_t condattr; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +struct sys_mutex { + pthread_mutex_t mutex; +}; + +struct sys_thread { + struct sys_thread *next; + pthread_t pthread; +}; + +static struct sys_sem *sys_sem_new_internal(u8_t count); +static void sys_sem_free_internal(struct sys_sem *sem); + +static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, + u32_t timeout); + +/*-----------------------------------------------------------------------------------*/ +/* Threads */ +static struct sys_thread * +introduce_thread(pthread_t id) +{ + struct sys_thread *thread; + + thread = (struct sys_thread *)malloc(sizeof(struct sys_thread)); + + if (thread != NULL) { + pthread_mutex_lock(&threads_mutex); + thread->next = threads; + thread->pthread = id; + threads = thread; + pthread_mutex_unlock(&threads_mutex); + } + + return thread; +} + +struct thread_wrapper_data +{ + lwip_thread_fn function; + void *arg; +}; + +static void * +thread_wrapper(void *arg) +{ + struct thread_wrapper_data *thread_data = (struct thread_wrapper_data *)arg; + + thread_data->function(thread_data->arg); + + /* we should never get here */ + free(arg); + return NULL; +} + +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) +{ + int code; + pthread_t tmp; + struct sys_thread *st = NULL; + struct thread_wrapper_data *thread_data; + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(stacksize); + LWIP_UNUSED_ARG(prio); + + thread_data = (struct thread_wrapper_data *)malloc(sizeof(struct thread_wrapper_data)); + thread_data->arg = arg; + thread_data->function = function; + code = pthread_create(&tmp, + NULL, + thread_wrapper, + thread_data); + +#ifdef LWIP_UNIX_LINUX + pthread_setname_np(tmp, name); +#endif + + if (0 == code) { + st = introduce_thread(tmp); + } + + if (NULL == st) { + LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx\n", + code, (unsigned long)st)); + abort(); + } + return st; +} + +#if LWIP_TCPIP_CORE_LOCKING +static pthread_t lwip_core_lock_holder_thread_id; +void sys_lock_tcpip_core(void) +{ + sys_mutex_lock(&lock_tcpip_core); + lwip_core_lock_holder_thread_id = pthread_self(); +} + +void sys_unlock_tcpip_core(void) +{ + lwip_core_lock_holder_thread_id = 0; + sys_mutex_unlock(&lock_tcpip_core); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +static pthread_t lwip_tcpip_thread_id; +void sys_mark_tcpip_thread(void) +{ + lwip_tcpip_thread_id = pthread_self(); +} + +void sys_check_core_locking(void) +{ + /* Embedded systems should check we are NOT in an interrupt context here */ + + if (lwip_tcpip_thread_id != 0) { + pthread_t current_thread_id = pthread_self(); + +#if LWIP_TCPIP_CORE_LOCKING + LWIP_ASSERT("Function called without core lock", current_thread_id == lwip_core_lock_holder_thread_id); +#else /* LWIP_TCPIP_CORE_LOCKING */ + LWIP_ASSERT("Function called from wrong thread", current_thread_id == lwip_tcpip_thread_id); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + } +} + +/*-----------------------------------------------------------------------------------*/ +/* Mailbox */ +err_t +sys_mbox_new(struct sys_mbox **mb, int size) +{ + struct sys_mbox *mbox; + LWIP_UNUSED_ARG(size); + + mbox = (struct sys_mbox *)malloc(sizeof(struct sys_mbox)); + if (mbox == NULL) { + return ERR_MEM; + } + mbox->first = mbox->last = 0; + mbox->not_empty = sys_sem_new_internal(0); + mbox->not_full = sys_sem_new_internal(0); + mbox->mutex = sys_sem_new_internal(1); + mbox->wait_send = 0; + + SYS_STATS_INC_USED(mbox); + *mb = mbox; + return ERR_OK; +} + +void +sys_mbox_free(struct sys_mbox **mb) +{ + if ((mb != NULL) && (*mb != SYS_MBOX_NULL)) { + struct sys_mbox *mbox = *mb; + SYS_STATS_DEC(mbox.used); + sys_arch_sem_wait(&mbox->mutex, 0); + + sys_sem_free_internal(mbox->not_empty); + sys_sem_free_internal(mbox->not_full); + sys_sem_free_internal(mbox->mutex); + mbox->not_empty = mbox->not_full = mbox->mutex = NULL; + /* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */ + free(mbox); + } +} + +err_t +sys_mbox_trypost(struct sys_mbox **mb, void *msg) +{ + u8_t first; + struct sys_mbox *mbox; + LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); + mbox = *mb; + + sys_arch_sem_wait(&mbox->mutex, 0); + + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n", + (void *)mbox, (void *)msg)); + + if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) { + sys_sem_signal(&mbox->mutex); + return ERR_MEM; + } + + mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg; + + if (mbox->last == mbox->first) { + first = 1; + } else { + first = 0; + } + + mbox->last++; + + if (first) { + sys_sem_signal(&mbox->not_empty); + } + + sys_sem_signal(&mbox->mutex); + + return ERR_OK; +} + +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg) +{ + return sys_mbox_trypost(q, msg); +} + +void +sys_mbox_post(struct sys_mbox **mb, void *msg) +{ + u8_t first; + struct sys_mbox *mbox; + LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); + mbox = *mb; + + sys_arch_sem_wait(&mbox->mutex, 0); + + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg)); + + while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) { + mbox->wait_send++; + sys_sem_signal(&mbox->mutex); + sys_arch_sem_wait(&mbox->not_full, 0); + sys_arch_sem_wait(&mbox->mutex, 0); + mbox->wait_send--; + } + + mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg; + + if (mbox->last == mbox->first) { + first = 1; + } else { + first = 0; + } + + mbox->last++; + + if (first) { + sys_sem_signal(&mbox->not_empty); + } + + sys_sem_signal(&mbox->mutex); +} + +u32_t +sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg) +{ + struct sys_mbox *mbox; + LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); + mbox = *mb; + + sys_arch_sem_wait(&mbox->mutex, 0); + + if (mbox->first == mbox->last) { + sys_sem_signal(&mbox->mutex); + return SYS_MBOX_EMPTY; + } + + if (msg != NULL) { + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg)); + *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE]; + } + else{ + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox)); + } + + mbox->first++; + + if (mbox->wait_send) { + sys_sem_signal(&mbox->not_full); + } + + sys_sem_signal(&mbox->mutex); + + return 0; +} + +u32_t +sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout) +{ + u32_t time_needed = 0; + struct sys_mbox *mbox; + LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); + mbox = *mb; + + /* The mutex lock is quick so we don't bother with the timeout + stuff here. */ + sys_arch_sem_wait(&mbox->mutex, 0); + + while (mbox->first == mbox->last) { + sys_sem_signal(&mbox->mutex); + + /* We block while waiting for a mail to arrive in the mailbox. We + must be prepared to timeout. */ + if (timeout != 0) { + time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout); + + if (time_needed == SYS_ARCH_TIMEOUT) { + return SYS_ARCH_TIMEOUT; + } + } else { + sys_arch_sem_wait(&mbox->not_empty, 0); + } + + sys_arch_sem_wait(&mbox->mutex, 0); + } + + if (msg != NULL) { + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg)); + *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE]; + } + else{ + LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox)); + } + + mbox->first++; + + if (mbox->wait_send) { + sys_sem_signal(&mbox->not_full); + } + + sys_sem_signal(&mbox->mutex); + + return time_needed; +} + +/*-----------------------------------------------------------------------------------*/ +/* Semaphore */ +static struct sys_sem * +sys_sem_new_internal(u8_t count) +{ + struct sys_sem *sem; + + sem = (struct sys_sem *)malloc(sizeof(struct sys_sem)); + if (sem != NULL) { + sem->c = count; + pthread_condattr_init(&(sem->condattr)); +#if !(defined(LWIP_UNIX_MACH) || (defined(LWIP_UNIX_ANDROID) && __ANDROID_API__ < 21)) + pthread_condattr_setclock(&(sem->condattr), CLOCK_MONOTONIC); +#endif + pthread_cond_init(&(sem->cond), &(sem->condattr)); + pthread_mutex_init(&(sem->mutex), NULL); + } + return sem; +} + +err_t +sys_sem_new(struct sys_sem **sem, u8_t count) +{ + SYS_STATS_INC_USED(sem); + *sem = sys_sem_new_internal(count); + if (*sem == NULL) { + return ERR_MEM; + } + return ERR_OK; +} + +static u32_t +cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout) +{ + struct timespec rtime1, rtime2, ts; + int ret; + +#ifdef LWIP_UNIX_HURD + #define pthread_cond_wait pthread_hurd_cond_wait_np + #define pthread_cond_timedwait pthread_hurd_cond_timedwait_np +#endif + + if (timeout == 0) { + ret = pthread_cond_wait(cond, mutex); + return +#ifdef LWIP_UNIX_HURD + /* On the Hurd, ret == 1 means the RPC has been cancelled. + * The thread is awakened (not terminated) and execution must continue */ + ret == 1 ? SYS_ARCH_INTR : +#endif + (u32_t)ret; + } + + /* Get a timestamp and add the timeout value. */ + get_monotonic_time(&rtime1); +#if defined(LWIP_UNIX_MACH) || (defined(LWIP_UNIX_ANDROID) && __ANDROID_API__ < 21) + ts.tv_sec = timeout / 1000L; + ts.tv_nsec = (timeout % 1000L) * 1000000L; + ret = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + ts.tv_sec = rtime1.tv_sec + timeout / 1000L; + ts.tv_nsec = rtime1.tv_nsec + (timeout % 1000L) * 1000000L; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + ret = pthread_cond_timedwait(cond, mutex, &ts); +#endif + if (ret == ETIMEDOUT) { + return SYS_ARCH_TIMEOUT; +#ifdef LWIP_UNIX_HURD + /* On the Hurd, ret == 1 means the RPC has been cancelled. + * The thread is awakened (not terminated) and execution must continue */ + } else if (ret == EINTR) { + return SYS_ARCH_INTR; +#endif + } + + /* Calculate for how long we waited for the cond. */ + get_monotonic_time(&rtime2); + ts.tv_sec = rtime2.tv_sec - rtime1.tv_sec; + ts.tv_nsec = rtime2.tv_nsec - rtime1.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return (u32_t)(ts.tv_sec * 1000L + ts.tv_nsec / 1000000L); +} + +u32_t +sys_arch_sem_wait(struct sys_sem **s, u32_t timeout) +{ + u32_t time_needed = 0; + struct sys_sem *sem; + LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); + sem = *s; + + pthread_mutex_lock(&(sem->mutex)); + while (sem->c <= 0) { + if (timeout > 0) { + time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout); + + if (time_needed == SYS_ARCH_TIMEOUT) { + pthread_mutex_unlock(&(sem->mutex)); + return SYS_ARCH_TIMEOUT; +#ifdef LWIP_UNIX_HURD + } else if(time_needed == SYS_ARCH_INTR) { + pthread_mutex_unlock(&(sem->mutex)); + return 0; +#endif + } + /* pthread_mutex_unlock(&(sem->mutex)); + return time_needed; */ + } else if(cond_wait(&(sem->cond), &(sem->mutex), 0)) { + /* Some error happened or the thread has been awakened but not by lwip */ + pthread_mutex_unlock(&(sem->mutex)); + return 0; + } + } + sem->c--; + pthread_mutex_unlock(&(sem->mutex)); + return (u32_t)time_needed; +} + +void +sys_sem_signal(struct sys_sem **s) +{ + struct sys_sem *sem; + LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); + sem = *s; + + pthread_mutex_lock(&(sem->mutex)); + sem->c++; + + if (sem->c > 1) { + sem->c = 1; + } + + pthread_cond_broadcast(&(sem->cond)); + pthread_mutex_unlock(&(sem->mutex)); +} + +static void +sys_sem_free_internal(struct sys_sem *sem) +{ + pthread_cond_destroy(&(sem->cond)); + pthread_condattr_destroy(&(sem->condattr)); + pthread_mutex_destroy(&(sem->mutex)); + free(sem); +} + +void +sys_sem_free(struct sys_sem **sem) +{ + if ((sem != NULL) && (*sem != SYS_SEM_NULL)) { + SYS_STATS_DEC(sem.used); + sys_sem_free_internal(*sem); + } +} + +/*-----------------------------------------------------------------------------------*/ +/* Mutex */ +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t +sys_mutex_new(struct sys_mutex **mutex) +{ + struct sys_mutex *mtx; + + mtx = (struct sys_mutex *)malloc(sizeof(struct sys_mutex)); + if (mtx != NULL) { + pthread_mutex_init(&(mtx->mutex), NULL); + *mutex = mtx; + return ERR_OK; + } + else { + return ERR_MEM; + } +} + +/** Lock a mutex + * @param mutex the mutex to lock */ +void +sys_mutex_lock(struct sys_mutex **mutex) +{ + pthread_mutex_lock(&((*mutex)->mutex)); +} + +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void +sys_mutex_unlock(struct sys_mutex **mutex) +{ + pthread_mutex_unlock(&((*mutex)->mutex)); +} + +/** Delete a mutex + * @param mutex the mutex to delete */ +void +sys_mutex_free(struct sys_mutex **mutex) +{ + pthread_mutex_destroy(&((*mutex)->mutex)); + free(*mutex); +} + +#endif /* !NO_SYS */ + +#if LWIP_NETCONN_SEM_PER_THREAD +/*-----------------------------------------------------------------------------------*/ +/* Semaphore per thread located TLS */ + +static void +sys_thread_sem_free(void* data) +{ + sys_sem_t *sem = (sys_sem_t*)(data); + + if (sem) { + sys_sem_free(sem); + free(sem); + } +} + +static sys_sem_t* +sys_thread_sem_alloc(void) +{ + sys_sem_t *sem; + err_t err; + int ret; + + sem = (sys_sem_t*)malloc(sizeof(sys_sem_t*)); + LWIP_ASSERT("failed to allocate memory for TLS semaphore", sem != NULL); + err = sys_sem_new(sem, 0); + LWIP_ASSERT("failed to initialise TLS semaphore", err == ERR_OK); + ret = pthread_setspecific(sys_thread_sem_key, sem); + LWIP_ASSERT("failed to initialise TLS semaphore storage", ret == 0); + return sem; +} + +sys_sem_t* +sys_arch_netconn_sem_get(void) +{ + sys_sem_t* sem = (sys_sem_t*)pthread_getspecific(sys_thread_sem_key); + if (!sem) { + sem = sys_thread_sem_alloc(); + } + LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_sem_get s=%p\n", (void*)sem)); + return sem; +} + +void +sys_arch_netconn_sem_alloc(void) +{ + sys_sem_t* sem = sys_thread_sem_alloc(); + LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_sem created s=%p\n", (void*)sem)); +} + +void +sys_arch_netconn_sem_free(void) +{ + int ret; + + sys_sem_t *sem = (sys_sem_t *)pthread_getspecific(sys_thread_sem_key); + sys_thread_sem_free(sem); + ret = pthread_setspecific(sys_thread_sem_key, NULL); + LWIP_ASSERT("failed to de-init TLS semaphore storage", ret == 0); +} +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +/*-----------------------------------------------------------------------------------*/ +/* Time */ +u32_t +sys_now(void) +{ + struct timespec ts; + u32_t now; + + get_monotonic_time(&ts); + now = (u32_t)(ts.tv_sec * 1000L + ts.tv_nsec / 1000000L); +#ifdef LWIP_FUZZ_SYS_NOW + now += sys_now_offset; +#endif + return now; +} + +u32_t +sys_jiffies(void) +{ + struct timespec ts; + + get_monotonic_time(&ts); + return (u32_t)(ts.tv_sec * 1000000000L + ts.tv_nsec); +} + +/*-----------------------------------------------------------------------------------*/ +/* Init */ + +void +sys_init(void) +{ +#if LWIP_NETCONN_SEM_PER_THREAD + pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free); +#endif +} + +/*-----------------------------------------------------------------------------------*/ +/* Critical section */ +#if SYS_LIGHTWEIGHT_PROT +/** sys_prot_t sys_arch_protect(void) + +This optional function does a "fast" critical region protection and returns +the previous protection level. This function is only called during very short +critical regions. An embedded system which supports ISR-based drivers might +want to implement this function by disabling interrupts. Task-based systems +might want to implement this by using a mutex or disabling tasking. This +function should support recursive calls from the same task or interrupt. In +other words, sys_arch_protect() could be called while already protected. In +that case the return value indicates that it is already protected. + +sys_arch_protect() is only required if your port is supporting an operating +system. +*/ +sys_prot_t +sys_arch_protect(void) +{ + /* Note that for the UNIX port, we are using a lightweight mutex, and our + * own counter (which is locked by the mutex). The return code is not actually + * used. */ + if (lwprot_thread != pthread_self()) + { + /* We are locking the mutex where it has not been locked before * + * or is being locked by another thread */ + pthread_mutex_lock(&lwprot_mutex); + lwprot_thread = pthread_self(); + lwprot_count = 1; + } + else + /* It is already locked by THIS thread */ + lwprot_count++; + return 0; +} + +/** void sys_arch_unprotect(sys_prot_t pval) + +This optional function does a "fast" set of critical region protection to the +value specified by pval. See the documentation for sys_arch_protect() for +more information. This function is only required if your port is supporting +an operating system. +*/ +void +sys_arch_unprotect(sys_prot_t pval) +{ + LWIP_UNUSED_ARG(pval); + if (lwprot_thread == pthread_self()) + { + lwprot_count--; + if (lwprot_count == 0) + { + lwprot_thread = (pthread_t) 0xDEAD; + pthread_mutex_unlock(&lwprot_mutex); + } + } +} +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#if !NO_SYS +/* get keyboard state to terminate the debug app by using select */ +int +lwip_unix_keypressed(void) +{ + struct timeval tv = { 0L, 0L }; + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); + return select(1, &fds, NULL, NULL, &tv); +} +#endif /* !NO_SYS */ diff --git a/contrib/ports/unix/posixlib/CMakeLists.txt b/contrib/ports/unix/posixlib/CMakeLists.txt new file mode 100644 index 0000000..ee8af05 --- /dev/null +++ b/contrib/ports/unix/posixlib/CMakeLists.txt @@ -0,0 +1,94 @@ +cmake_minimum_required(VERSION 3.8) +project(liblwip + VERSION 2.2.0 + DESCRIPTION "lwip library for linux" + HOMEPAGE_URL "http://wiki.virtualsquare.org" + LANGUAGES C) + +include(GNUInstallDirs) +include(CheckIncludeFile) + +set (BUILD_SHARED_LIBS ON) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + message(FATAL_ERROR "Lwip shared library is only working on Linux or the Hurd") +endif() + +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) + +find_library(LIB_VDEPLUGOK vdeplug) +check_include_file(libvdeplug.h INCLUDE_VDEPLUGOK) +if (LIB_VDEPLUGOK AND INCLUDE_VDEPLUGOK) + message(STATUS "Found libvdeplug: vde support added") +else() + message(STATUS "Libvdeplug needs to be installed to add vde support") +endif() + +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_DEFINITIONS -DLWIP_DEBUG) +set (LWIP_INCLUDE_DIRS + "include" + "${LWIP_DIR}/src/include" + "${LWIP_CONTRIB_DIR}/" + "${LWIP_CONTRIB_DIR}/ports/unix/port/include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +set (LWIP_EXCLUDE_SLIPIF TRUE) +include(${LWIP_CONTRIB_DIR}/ports/unix/Filelists.cmake) +include(${LWIP_DIR}/src/Filelists.cmake) +if (LIB_VDEPLUGOK AND INCLUDE_VDEPLUGOK) +set(lwipnoapps_SRCS ${lwipnoapps_SRCS} + ${LWIP_DIR}/contrib/ports/unix/port/netif/vdeif.c) +endif() + +add_library(lwip ${lwipnoapps_SRCS} ${lwipcontribportunix_SRCS} ${lwipcontribportunixnetifs_SRCS}) +target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) +if (LIB_VDEPLUGOK AND INCLUDE_VDEPLUGOK) + target_link_libraries(lwip ${LWIP_SANITIZER_LIBS} vdeplug) +else() + target_link_libraries(lwip ${LWIP_SANITIZER_LIBS}) +endif() + +find_library(LIBPTHREAD pthread) +target_link_libraries(lwip ${LIBPTHREAD}) + +install(TARGETS lwip + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +set_target_properties(lwip PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) + +install(DIRECTORY "${LWIP_DIR}/src/include/lwip" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip" + FILES_MATCHING PATTERN "*.h" +) + +install(DIRECTORY "${LWIP_DIR}/src/include/netif" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip" + FILES_MATCHING PATTERN "*.h" +) + +install(FILES lwipopts.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip") + +install(DIRECTORY "${LWIP_DIR}/contrib/ports/unix/port/include/arch" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip" + FILES_MATCHING PATTERN "*.h" +) + +install(DIRECTORY "${LWIP_DIR}/contrib/ports/unix/port/include/netif" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip" + FILES_MATCHING PATTERN "*.h" +) + +install(DIRECTORY "${LWIP_DIR}/contrib/ports/unix/posixlib/include/posix" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lwip" + FILES_MATCHING PATTERN "*.h" +) + +add_custom_target(uninstall + "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/Uninstall.cmake") + diff --git a/contrib/ports/unix/posixlib/Uninstall.cmake b/contrib/ports/unix/posixlib/Uninstall.cmake new file mode 100644 index 0000000..466ee4e --- /dev/null +++ b/contrib/ports/unix/posixlib/Uninstall.cmake @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.13) +set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") + +if(NOT EXISTS ${MANIFEST}) + message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") +endif() + +file(STRINGS ${MANIFEST} files) +foreach(file ${files}) + if(EXISTS ${file} OR IS_SYMLINK ${file}) + message(STATUS "Removing: ${file}") + + execute_process( + COMMAND rm -f ${file} + RESULT_VARIABLE retcode + ) + + if(NOT "${retcode}" STREQUAL "0") + message(WARNING "Failed to remove: ${file}") + endif() + endif() +endforeach(file) diff --git a/contrib/ports/unix/posixlib/include/posix/inet.h b/contrib/ports/unix/posixlib/include/posix/inet.h new file mode 100644 index 0000000..c7bc124 --- /dev/null +++ b/contrib/ports/unix/posixlib/include/posix/inet.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 Joan Lledó + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef HURD_LWIP_POSIX_INET_H +#define HURD_LWIP_POSIX_INET_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_IPV4 + +#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) + +#ifdef LWIP_UNIX_HURD +#define IP_PKTINFO 8 + +struct in_pktinfo { + unsigned int ipi_ifindex; /* Interface index */ + struct in_addr ipi_addr; /* Destination (from header) address */ +}; +#endif /* LWIP_UNIX_HURD */ + +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s6_addr32[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->s6_addr32[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->s6_addr32[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->s6_addr32[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s6_addr32[0]; \ + (target_ip6addr)->addr[1] = (source_in6addr)->s6_addr32[1]; \ + (target_ip6addr)->addr[2] = (source_in6addr)->s6_addr32[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->s6_addr32[3]; \ + ip6_addr_clear_zone(target_ip6addr);} +/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ +#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* HURD_LWIP_POSIX_INET_H */ diff --git a/contrib/ports/unix/posixlib/include/posix/sockets.h b/contrib/ports/unix/posixlib/include/posix/sockets.h new file mode 100644 index 0000000..2370bb7 --- /dev/null +++ b/contrib/ports/unix/posixlib/include/posix/sockets.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 Joan Lledó + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef HURD_LWIP_POSIX_SOCKET_H +#define HURD_LWIP_POSIX_SOCKET_H + +#include +#include +#include +#include LWIP_SOCKET_EXTERNAL_HEADER_INET_H +typedef size_t msg_iovlen_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _HAVE_SA_LEN +#define HAVE_SA_LEN _HAVE_SA_LEN +#else +#define HAVE_SA_LEN 0 +#endif /* _HAVE_SA_LEN */ + +/* Address length safe read and write */ +#if HAVE_SA_LEN +#define IP4ADDR_SOCKADDR_SET_LEN(sin) \ + (sin)->sin_len = sizeof(struct sockaddr_in) +#define IP6ADDR_SOCKADDR_SET_LEN(sin6) \ + (sin6)->sin6_len = sizeof(struct sockaddr_in6) +#define IPADDR_SOCKADDR_GET_LEN(addr) \ + (addr)->sa.sa_len +#else +#define IP4ADDR_SOCKADDR_SET_LEN(addr) +#define IP6ADDR_SOCKADDR_SET_LEN(addr) +#define IPADDR_SOCKADDR_GET_LEN(addr) \ + ((addr)->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) \ + : ((addr)->sa.sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : 0)) +#endif /* HAVE_SA_LEN */ + +#define SIN_ZERO_LEN sizeof (struct sockaddr) - \ + __SOCKADDR_COMMON_SIZE - \ + sizeof (in_port_t) - \ + sizeof (struct in_addr) + +#if !defined IOV_MAX +#define IOV_MAX 0xFFFF +#elif IOV_MAX > 0xFFFF +#error "IOV_MAX larger than supported by LwIP" +#endif /* IOV_MAX */ + +#define LWIP_SELECT_MAXNFDS (FD_SETSIZE + LWIP_SOCKET_OFFSET) + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + +#if 0 +void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); + int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +ssize_t lwip_recv(int s, void *mem, size_t len, int flags); +ssize_t lwip_read(int s, void *mem, size_t len); +ssize_t lwip_readv(int s, const struct iovec *iov, int iovcnt); +ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags); +ssize_t lwip_send(int s, const void *dataptr, size_t size, int flags); +ssize_t lwip_sendmsg(int s, const struct msghdr *message, int flags); +ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +ssize_t lwip_write(int s, const void *dataptr, size_t size); +ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); +#if LWIP_SOCKET_SELECT +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +#endif +#if LWIP_SOCKET_POLL +int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); +#endif +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); +const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); +int lwip_inet_pton(int af, const char *src, void *dst); +#endif + +/* Unsupported identifiers */ +#ifndef SO_NO_CHECK +#define SO_NO_CHECK 0xFF +#endif +#ifndef SO_BINDTODEVICE +#define SO_BINDTODEVICE 0xFE +#endif +#ifndef MSG_MORE +#define MSG_MORE 0x0 +#endif +#ifndef TCP_KEEPALIVE +#define TCP_KEEPALIVE 0xFF +#endif +#ifndef TCP_KEEPIDLE +#define TCP_KEEPIDLE 0xFE +#endif +#ifndef TCP_KEEPINTVL +#define TCP_KEEPINTVL 0xFD +#endif +#ifndef TCP_KEEPCNT +#define TCP_KEEPCNT 0xFC +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HURD_LWIP_POSIX_SOCKET_H */ diff --git a/contrib/ports/unix/posixlib/lwipopts.h b/contrib/ports/unix/posixlib/lwipopts.h new file mode 100644 index 0000000..1b38aa3 --- /dev/null +++ b/contrib/ports/unix/posixlib/lwipopts.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2023 Joan Lledó + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef UNIX_LWIP_LWIPOPTS_H +#define UNIX_LWIP_LWIPOPTS_H + +/* An OS is present */ +#define NO_SYS 0 + +/* Sockets API config */ +#define LWIP_COMPAT_SOCKETS 0 +#define LWIP_SOCKET_OFFSET 1 +#define LWIP_POLL 1 + +/* User posix socket headers */ +#define LWIP_SOCKET_EXTERNAL_HEADERS 1 +#define LWIP_SOCKET_EXTERNAL_HEADER_SOCKETS_H "posix/sockets.h" +#define LWIP_SOCKET_EXTERNAL_HEADER_INET_H "posix/inet.h" +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 1 + +/* Use Glibc malloc()/free() */ +#define MEM_LIBC_MALLOC 1 +#define MEMP_MEM_MALLOC 1 +#define MEM_USE_POOLS 0 + +/* Only send complete packets to the device */ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 + +/* Randomize local ports */ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 1 + +/* Glibc sends more than one packet in a row during an ARP resolution */ +#define ARP_QUEUEING 1 +#define ARP_QUEUE_LEN 10 + +/* + * Activate loopback, but don't use lwip's default loopback interface, + * we provide our own. + */ +#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_HAVE_LOOPIF 0 + +/* IPv4 stuff */ +#define IP_FORWARD 1 + +/* SLAAC support and other IPv6 stuff */ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#define LWIP_IPV6_AUTOCONFIG 1 +#define LWIP_IPV6_FORWARD 1 +#define MEMP_NUM_MLD6_GROUP 16 +#define LWIP_IPV6_NUM_ADDRESSES 6 +#define IPV6_FRAG_COPYHEADER 1 + +/* TCP tuning */ +#define TCP_MSS 1460 +#define TCP_WND 0xFFFF +#define LWIP_WND_SCALE 1 +#define TCP_RCV_SCALE 0x1 +#define TCP_SND_BUF TCP_WND + +/* Throughput settings */ +#define LWIP_CHECKSUM_ON_COPY 1 + +/* Disable stats */ +#define LWIP_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +/* Enable all socket operations */ +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_SO_SNDTIMEO 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_RCVBUF 1 +#define LWIP_SO_LINGER 1 +#define SO_REUSE 1 +#define LWIP_MULTICAST_TX_OPTIONS 1 + +/* Enable modules */ +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_IPV4 1 +#define LWIP_ICMP 1 +#define LWIP_IGMP 1 +#define LWIP_RAW 1 +#define LWIP_UDP 1 +#define LWIP_UDPLITE 1 +#define LWIP_TCP 1 +#define LWIP_IPV6 1 +#define LWIP_ICMP6 1 +#define LWIP_IPV6_MLD 1 + +/* Don't abort the whole stack when an error is detected */ +#define LWIP_NOASSERT_ON_ERROR 1 + +/* Threading options */ +#define LWIP_TCPIP_CORE_LOCKING 1 + +/* If the system is 64 bit */ +#if defined __LP64__ +#define MEM_ALIGNMENT 8 +#else +#define MEM_ALIGNMENT 4 +#endif + +#if !NO_SYS +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() +#if 0 +void sys_mark_tcpip_thread(void); +#define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread() + +#if LWIP_TCPIP_CORE_LOCKING +void sys_lock_tcpip_core(void); +#define LOCK_TCPIP_CORE() sys_lock_tcpip_core() +void sys_unlock_tcpip_core(void); +#define UNLOCK_TCPIP_CORE() sys_unlock_tcpip_core() +#endif +#endif +#endif + +/* Debug mode */ +#ifdef LWIP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#endif + +#endif /* UNIX_LWIP_LWIPOPTS_H */ diff --git a/contrib/ports/unix/setup-tapif b/contrib/ports/unix/setup-tapif new file mode 100755 index 0000000..d5c4935 --- /dev/null +++ b/contrib/ports/unix/setup-tapif @@ -0,0 +1,22 @@ +#!/bin/bash + +# This script needs bridge-util debian package or similar +# for other distros. + +# Run using "source setup-tapif" to get exported PRECONFIGURED_TAPIF variable +# Alternatively, add "export PRECONFIGURED_TAPIF=tap0" to ~/.bashrc + +# http://backreference.org/2010/03/26/tuntap-interface-tutorial/ + +# After executing this script, start example_app. +# Enter 192.168.1.200 or "http://lwip.local/" (Zeroconf) +# in your webbrowser to see example_app webpage. + +export PRECONFIGURED_TAPIF=tap0 + +sudo ip tuntap add dev $PRECONFIGURED_TAPIF mode tap user `whoami` +sudo ip link set $PRECONFIGURED_TAPIF up +sudo brctl addbr lwipbridge +sudo brctl addif lwipbridge $PRECONFIGURED_TAPIF +sudo ip addr add 192.168.1.1/24 dev lwipbridge +sudo ip link set dev lwipbridge up diff --git a/contrib/ports/win32/Common.mk b/contrib/ports/win32/Common.mk new file mode 100644 index 0000000..2260162 --- /dev/null +++ b/contrib/ports/win32/Common.mk @@ -0,0 +1,51 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +CC=gcc + +# Architecture specific files. +LWIPARCH?=$(CONTRIBDIR)/ports/win32 +SYSARCH?=$(LWIPARCH)/sys_arch.c +ARCHFILES=$(SYSARCH) $(LWIPARCH)/pcapif.c \ + $(LWIPARCH)/pcapif_helper.c $(LWIPARCH)/sio.c + +WIN32_COMMON_MK_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +include $(WIN32_COMMON_MK_DIR)/../Common.allports.mk + +PCAPDIR=$(PCAP_DIR)/Include +LDFLAGS+=-L$(PCAP_DIR)/lib -lwpcap -lpacket +# -Wno-format: GCC complains about non-standard 64 bit modifier needed for MSVC runtime +CFLAGS+=-I$(PCAPDIR) -Wno-format + +pcapif.o: + $(CC) $(CFLAGS) -Wno-error -Wno-redundant-decls -c $(<:.o=.c) +pcapif_helper.o: + $(CC) $(CFLAGS) -std=c99 -Wno-redundant-decls -c $(<:.o=.c) diff --git a/contrib/ports/win32/Filelists.cmake b/contrib/ports/win32/Filelists.cmake new file mode 100644 index 0000000..36e02a5 --- /dev/null +++ b/contrib/ports/win32/Filelists.cmake @@ -0,0 +1,46 @@ +# This file is indended to be included in end-user CMakeLists.txt +# include(/path/to/Filelists.cmake) +# It assumes the variable LWIP_CONTRIB_DIR is defined pointing to the +# root path of lwIP/contrib sources. +# +# This file is NOT designed (on purpose) to be used as cmake +# subdir via add_subdirectory() +# The intention is to provide greater flexibility to users to +# create their own targets using the *_SRCS variables. + +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + +set(lwipcontribportwindows_SRCS + ${LWIP_CONTRIB_DIR}/ports/win32/sys_arch.c + ${LWIP_CONTRIB_DIR}/ports/win32/sio.c + ${LWIP_CONTRIB_DIR}/ports/win32/pcapif.c + ${LWIP_CONTRIB_DIR}/ports/win32/pcapif_helper.c +) + +# pcapif needs WinPcap developer package: https://www.winpcap.org/devel.htm +if(NOT DEFINED WPDPACK_DIR) + set(WPDPACK_DIR ${LWIP_DIR}/../WpdPack) + message(STATUS "WPDPACK_DIR not set - using default location ${WPDPACK_DIR}") +endif() +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(WPDPACK_LIB_DIR ${WPDPACK_DIR}/lib/x64) + else() + set(WPDPACK_LIB_DIR ${WPDPACK_DIR}/lib) + endif() + set(WPCAP ${WPDPACK_LIB_DIR}/wpcap.lib) + set(PACKET ${WPDPACK_LIB_DIR}/packet.lib) +else() + find_library(WPCAP wpcap HINTS ${WPDPACK_DIR}/lib/x64) + find_library(PACKET packet HINTS ${WPDPACK_DIR}/lib/x64) +endif() +message(STATUS "WPCAP library: ${WPCAP}") +message(STATUS "PACKET library: ${PACKET}") + +add_library(lwipcontribportwindows EXCLUDE_FROM_ALL ${lwipcontribportwindows_SRCS}) +target_include_directories(lwipcontribportwindows PRIVATE ${LWIP_INCLUDE_DIRS} "${WPDPACK_DIR}/include" ${LWIP_MBEDTLS_INCLUDE_DIRS}) +target_compile_options(lwipcontribportwindows PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipcontribaddons PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_link_libraries(lwipcontribportwindows PUBLIC ${WPCAP} ${PACKET} ${LWIP_MBEDTLS_LINK_LIBRARIES}) diff --git a/contrib/ports/win32/check/check_stdint.h b/contrib/ports/win32/check/check_stdint.h new file mode 100644 index 0000000..c2c100d --- /dev/null +++ b/contrib/ports/win32/check/check_stdint.h @@ -0,0 +1 @@ +/* deliberateliy empty */ diff --git a/contrib/ports/win32/check/config.h b/contrib/ports/win32/check/config.h new file mode 100644 index 0000000..7ed591d --- /dev/null +++ b/contrib/ports/win32/check/config.h @@ -0,0 +1,29 @@ +/* config.h for check-0.11.0 on win32 under MSVC/MinGW */ + +#ifdef _MSC_VER + +typedef unsigned int pid_t; +typedef unsigned int uint32_t; + +typedef int ssize_t; + +#define HAVE_DECL_STRDUP 1 +#define HAVE_DECL_FILENO 1 +#define HAVE_DECL_PUTENV 1 + +#define _CRT_SECURE_NO_WARNINGS + +/* disable some warnings */ +#pragma warning (disable: 4090) /* const assigned to non-const */ +#pragma warning (disable: 4996) /* fileno is deprecated */ + +#endif /* _ MSC_VER */ + + +#define LWIP_UNITTESTS_NOFORK + +#include +#include + +typedef unsigned int clockid_t; +typedef unsigned int timer_t; diff --git a/contrib/ports/win32/check/stdbool.h b/contrib/ports/win32/check/stdbool.h new file mode 100644 index 0000000..1f504d9 --- /dev/null +++ b/contrib/ports/win32/check/stdbool.h @@ -0,0 +1,9 @@ +#ifndef MY_STDBOOL_H +#define MY_STDBOOL_H + +typedef int bool; +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 + +#endif diff --git a/contrib/ports/win32/check/sys/time.h b/contrib/ports/win32/check/sys/time.h new file mode 100644 index 0000000..d71d827 --- /dev/null +++ b/contrib/ports/win32/check/sys/time.h @@ -0,0 +1,12 @@ +#ifndef LWIP_SYS__TIME_H +#define LWIP_SYS__TIME_H + +#include /* time_t */ + +struct timeval { + time_t tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +int gettimeofday(struct timeval* tp, void* tzp); + +#endif diff --git a/contrib/ports/win32/check/time.c b/contrib/ports/win32/check/time.c new file mode 100644 index 0000000..b5947cd --- /dev/null +++ b/contrib/ports/win32/check/time.c @@ -0,0 +1,66 @@ +#include + +#include +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +#include "config.h" + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tmpres /= 10; /*convert into microseconds*/ + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) { + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} + +struct tm * +localtime_r(const time_t *timer, struct tm *result) +{ + struct tm *local_result; + + if (result == NULL) { + return NULL; + } + + local_result = localtime (timer); + if (local_result == NULL) { + return NULL; + } + + memcpy(result, local_result, sizeof(*result)); + return result; +} diff --git a/contrib/ports/win32/check/unistd.h b/contrib/ports/win32/check/unistd.h new file mode 100644 index 0000000..332e6e1 --- /dev/null +++ b/contrib/ports/win32/check/unistd.h @@ -0,0 +1,7 @@ +#ifndef LWIP_UNISTD_H +#define LWIP_UNISTD_H + +/* include io.h for read() and write() */ +#include + +#endif diff --git a/contrib/ports/win32/example_app/CMakeLists.txt b/contrib/ports/win32/example_app/CMakeLists.txt new file mode 100644 index 0000000..7dfe555 --- /dev/null +++ b/contrib/ports/win32/example_app/CMakeLists.txt @@ -0,0 +1,27 @@ +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/src/include" + "${LWIP_DIR}/contrib/" + "${LWIP_DIR}/contrib/ports/win32/include" + "${LWIP_DIR}/contrib/examples/example_app" +) + +include(${LWIP_DIR}/src/Filelists.cmake) +include(${LWIP_DIR}/contrib/Filelists.cmake) +include(${LWIP_DIR}/contrib/ports/win32/Filelists.cmake) + +if(NOT EXISTS ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h) + message(WARNING "${LWIP_DIR}/contrib/examples/example_app is missing lwipcfg.h +Copy ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h.example to ${LWIP_DIR}/contrib/examples/example_app/lwipcfg.h and edit appropriately") +endif() +add_executable(example_app ${LWIP_DIR}/contrib/examples/example_app/test.c default_netif.c) +target_include_directories(example_app PRIVATE ${LWIP_INCLUDE_DIRS}) +target_compile_options(example_app PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(example_app PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_link_libraries(example_app ${LWIP_SANITIZER_LIBS} lwipallapps lwipcontribexamples lwipcontribapps lwipcontribaddons lwipcontribportwindows lwipcore lwipmbedtls) + +add_executable(makefsdata ${lwipmakefsdata_SRCS}) +target_compile_options(makefsdata PRIVATE ${LWIP_COMPILER_FLAGS}) +target_include_directories(makefsdata PRIVATE ${LWIP_INCLUDE_DIRS}) +target_link_libraries(makefsdata ${LWIP_SANITIZER_LIBS} lwipcore lwipcontribportwindows) diff --git a/contrib/ports/win32/example_app/Makefile b/contrib/ports/win32/example_app/Makefile new file mode 100644 index 0000000..452af7a --- /dev/null +++ b/contrib/ports/win32/example_app/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +all compile: example_app makefsdata +.PHONY: all + +include ../Common.mk + +CFLAGS+=-I$(CONTRIBDIR)/examples/example_app + +MAKEFSDATAOBJS=$(notdir $(MAKEFSDATAFILES:.c=.o)) + +clean: + cmd /c del /q *.o $(LWIPLIBCOMMON) $(APPLIB) test.exe *.s .depend* *.map + +depend dep: .depend + +include .depend + +.depend: $(CONTRIBDIR)/examples/example_app/test.c default_netif.c $(LWIPFILES) $(APPFILES) $(MAKEFSDATAFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend || cmd /c del .depend + +example_app: .depend $(LWIPLIBCOMMON) $(APPLIB) default_netif.o test.o + $(CC) $(CFLAGS) -o example_app test.o default_netif.o -Wl,--start-group $(APPLIB) $(LWIPLIBCOMMON) -Wl,--end-group $(LDFLAGS) -Xlinker -Map=test.map + +makefsdata: .depend $(MAKEFSDATAOBJS) + $(CC) $(CFLAGS) -o makefsdata $(MAKEFSDATAOBJS) diff --git a/contrib/ports/win32/example_app/default_netif.c b/contrib/ports/win32/example_app/default_netif.c new file mode 100644 index 0000000..9af2ecc --- /dev/null +++ b/contrib/ports/win32/example_app/default_netif.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/sys.h" +#include "lwip/tcpip.h" +#include "../pcapif.h" +#include "examples/example_app/default_netif.h" + +static struct netif netif; + +#if LWIP_IPV4 +#define NETIF_ADDRS ipaddr, netmask, gw, +void init_default_netif(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw) +#else +#define NETIF_ADDRS +void init_default_netif(void) +#endif +{ +#if NO_SYS + netif_add(&netif, NETIF_ADDRS NULL, pcapif_init, netif_input); +#else /* NO_SYS */ + netif_add(&netif, NETIF_ADDRS NULL, pcapif_init, tcpip_input); +#endif /* NO_SYS */ + netif_set_default(&netif); +} + +void +default_netif_poll(void) +{ +#if !PCAPIF_RX_USE_THREAD + /* check for packets and link status*/ + pcapif_poll(&netif); + /* When pcapif_poll comes back, there are not packets, so sleep to + prevent 100% CPU load. Don't do this in an embedded system since it + increases latency! */ + sys_msleep(1); +#else /* !PCAPIF_RX_USE_THREAD */ + sys_msleep(50); +#endif /* !PCAPIF_RX_USE_THREAD */ +} + +void +default_netif_shutdown(void) +{ + /* release the pcap library... */ + pcapif_shutdown(&netif); +} diff --git a/contrib/ports/win32/include/arch/bpstruct.h b/contrib/ports/win32/include/arch/bpstruct.h new file mode 100644 index 0000000..1d81e3f --- /dev/null +++ b/contrib/ports/win32/include/arch/bpstruct.h @@ -0,0 +1 @@ +#pragma pack(push,1) diff --git a/contrib/ports/win32/include/arch/cc.h b/contrib/ports/win32/include/arch/cc.h new file mode 100644 index 0000000..ded66c6 --- /dev/null +++ b/contrib/ports/win32/include/arch/cc.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +#ifdef _MSC_VER +#pragma warning (disable: 4127) /* conditional expression is constant */ +#pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */ +#pragma warning (disable: 4103) /* structure packing changed by including file */ +#pragma warning (disable: 4820) /* 'x' bytes padding added after data member 'y' */ +#pragma warning (disable: 4711) /* The compiler performed inlining on the given function, although it was not marked for inlining */ +#endif + +#ifdef _MSC_VER +#if _MSC_VER >= 1910 +#include /* use MSVC errno for >= 2017 */ +#else +#define LWIP_PROVIDE_ERRNO /* provide errno for MSVC pre-2017 */ +#endif +#else /* _MSC_VER */ +#define LWIP_PROVIDE_ERRNO /* provide errno for non-MSVC */ +#endif /* _MSC_VER */ + +#ifdef __GNUC__ +#define LWIP_TIMEVAL_PRIVATE 0 +#include +#endif + +/* Define platform endianness (might already be defined) */ +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif /* BYTE_ORDER */ + +typedef int sys_prot_t; + +#ifdef _MSC_VER +/* define _INTPTR for Win32 MSVC stdint.h */ +#define _INTPTR 2 + +/* Do not use lwIP default definitions for format strings + * because these do not work with MSVC 2010 compiler (no inttypes.h) + */ +#define LWIP_NO_INTTYPES_H 1 + +/* Define (sn)printf formatters for these lwIP types */ +#define X8_F "02x" +#define U16_F "hu" +#define U32_F "lu" +#define S32_F "ld" +#define X32_F "lx" + +#define S16_F "hd" +#define X16_F "hx" +#ifdef _WIN64 +#define SZT_F "llu" +#else +#define SZT_F "lu" +#endif +#endif /* _MSC_VER */ + +/* Compiler hints for packing structures */ +#define PACK_STRUCT_USE_INCLUDES + +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_DIAG(("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__)); \ + handler;} } while(0) + +#ifdef _MSC_VER +/* C runtime functions redefined */ +#if _MSC_VER < 1910 +#define snprintf _snprintf +#endif +#define strdup _strdup +#endif + +/* Define an example for LWIP_PLATFORM_DIAG: since this uses varargs and the old +* C standard lwIP targets does not support this in macros, we have extra brackets +* around the arguments, which are left out in the following macro definition: +*/ +#if !defined(LWIP_TESTMODE) || !LWIP_TESTMODE +void lwip_win32_platform_diag(const char *format, ...); +#define LWIP_PLATFORM_DIAG(x) lwip_win32_platform_diag x +#endif + +extern unsigned int lwip_port_rand(void); +#define LWIP_RAND() ((uint32_t)lwip_port_rand()) + +#define PPP_INCLUDE_SETTINGS_HEADER + +#endif /* LWIP_ARCH_CC_H */ diff --git a/contrib/ports/win32/include/arch/epstruct.h b/contrib/ports/win32/include/arch/epstruct.h new file mode 100644 index 0000000..65898b5 --- /dev/null +++ b/contrib/ports/win32/include/arch/epstruct.h @@ -0,0 +1 @@ +#pragma pack(pop) diff --git a/contrib/ports/win32/include/arch/perf.h b/contrib/ports/win32/include/arch/perf.h new file mode 100644 index 0000000..d1150b1 --- /dev/null +++ b/contrib/ports/win32/include/arch/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_PERF_H +#define LWIP_PERF_H + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* LWIP_PERF_H */ diff --git a/contrib/ports/win32/include/arch/sys_arch.h b/contrib/ports/win32/include/arch/sys_arch.h new file mode 100644 index 0000000..ded1028 --- /dev/null +++ b/contrib/ports/win32/include/arch/sys_arch.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_SYS_ARCH_H +#define LWIP_ARCH_SYS_ARCH_H + +/* HANDLE is used for sys_sem_t but we won't include windows.h */ +struct _sys_sem { + void *sem; +}; +typedef struct _sys_sem sys_sem_t; +#define sys_sem_valid_val(sema) (((sema).sem != NULL) && ((sema).sem != (void*)-1)) +#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema))) +#define sys_sem_set_invalid(sema) ((sema)->sem = NULL) + +/* HANDLE is used for sys_mutex_t but we won't include windows.h */ +struct _sys_mut { + void *mut; +}; +typedef struct _sys_mut sys_mutex_t; +#define sys_mutex_valid_val(mutex) (((mutex).mut != NULL) && ((mutex).mut != (void*)-1)) +#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex))) +#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL) + +#ifndef MAX_QUEUE_ENTRIES +#define MAX_QUEUE_ENTRIES 100 +#endif +struct lwip_mbox { + void* sem; + void* q_mem[MAX_QUEUE_ENTRIES]; + u32_t head, tail; +}; +typedef struct lwip_mbox sys_mbox_t; +#define SYS_MBOX_NULL NULL +#define sys_mbox_valid_val(mbox) (((mbox).sem != NULL) && ((mbox).sem != (void*)-1)) +#define sys_mbox_valid(mbox) ((mbox != NULL) && sys_mbox_valid_val(*(mbox))) +#define sys_mbox_set_invalid(mbox) ((mbox)->sem = NULL) + +/* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */ +typedef u32_t sys_thread_t; + +sys_sem_t* sys_arch_netconn_sem_get(void); +void sys_arch_netconn_sem_alloc(void); +void sys_arch_netconn_sem_free(void); +#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get() +#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc() +#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free() + +#define LWIP_EXAMPLE_APP_ABORT() lwip_win32_keypressed() +int lwip_win32_keypressed(void); + +/* Threading options */ +void sys_mark_tcpip_thread(void); +#define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread() + +#if LWIP_TCPIP_CORE_LOCKING +void sys_lock_tcpip_core(void); +#define LOCK_TCPIP_CORE() sys_lock_tcpip_core() +void sys_unlock_tcpip_core(void); +#define UNLOCK_TCPIP_CORE() sys_unlock_tcpip_core() +#endif + +#endif /* LWIP_ARCH_SYS_ARCH_H */ diff --git a/contrib/ports/win32/msvc/build_coverity.cmd b/contrib/ports/win32/msvc/build_coverity.cmd new file mode 100644 index 0000000..f96cc63 --- /dev/null +++ b/contrib/ports/win32/msvc/build_coverity.cmd @@ -0,0 +1,26 @@ +@echo off +rem Usage: pass the path to cov-build.exe (with trailing backslash, without the exe) as first parameter +rem ATTENTION: this deletes the output folder "cov-int" and the output file "cov-int.zip" first! + +set devenv="%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" +if not exist %devenv% set devenv="%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\vcexpress.exe" +if not exist %devenv% set devenv="%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" +if not exist %devenv% set devenv="%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\vcexpress.exe" +set covbuild=%1cov-build.exe +set covoutput=cov-int +set zip7="c:\Program Files\7-Zip\7z.exe" + +pushd %~dp0 + +if exist %covoutput% rd /s /q %covoutput% +if exist %covoutput%.zip del %covoutput%.zip + +%covbuild% --dir %covoutput% %devenv% lwip_test.sln /build Debug || goto error + +if exist %zip7% goto dozip +echo error: 7zip not found at \"%zip7% +goto error +:dozip +%zip7% a %covoutput%.zip %covoutput% +:error +popd \ No newline at end of file diff --git a/contrib/ports/win32/msvc/libcheck.vcxproj b/contrib/ports/win32/msvc/libcheck.vcxproj new file mode 100644 index 0000000..dc4fe45 --- /dev/null +++ b/contrib/ports/win32/msvc/libcheck.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09} + libcheck + 10.0 + + + + StaticLibrary + MultiByte + true + v143 + + + StaticLibrary + MultiByte + true + v143 + + + StaticLibrary + MultiByte + v143 + + + StaticLibrary + MultiByte + v143 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + Disabled + ..\check;..\..\..\..\..\check\src;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + EditAndContinue + + + + + Disabled + ..\check;..\..\..\..\..\check\src;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + + + + + MaxSpeed + true + ..\check;..\..\..\..\..\check\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + + + + + MaxSpeed + true + ..\check;..\..\..\..\..\check\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/libcheck.vcxproj.filters b/contrib/ports/win32/msvc/libcheck.vcxproj.filters new file mode 100644 index 0000000..d8bfdfc --- /dev/null +++ b/contrib/ports/win32/msvc/libcheck.vcxproj.filters @@ -0,0 +1,96 @@ + + + + + {05d172f9-8ca6-4d9c-96e4-2b0480a8222f} + + + {eb9ccf88-7e08-4202-bb4f-5a51443fa480} + + + {3f044d95-ab52-45ce-b4ae-27797eb221b2} + + + {abb21abe-51c2-45df-bdc9-8e00ce7fe404} + + + + + Win32 + + + Win32 + + + Win32\sys + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + libcompat + + + + + Win32 + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + libcompat + + + libcompat + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP.vcxproj b/contrib/ports/win32/msvc/lwIP.vcxproj new file mode 100644 index 0000000..0184b29 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP.vcxproj @@ -0,0 +1,1040 @@ + + + + + Debug fuzz + Win32 + + + Debug fuzz + x64 + + + Debug unittests + Win32 + + + Debug unittests + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release fuzz + Win32 + + + Release fuzz + x64 + + + Release unittests + Win32 + + + Release unittests + x64 + + + Release + Win32 + + + Release + x64 + + + + {2CC276FA-B226-49C9-8F82-7FCD5A228E28} + 10.0 + + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + EditAndContinue + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + EditAndContinue + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + EditAndContinue + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + true + true + true + true + true + true + true + true + true + true + true + true + + + Document + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + + + Document + true + true + true + true + true + true + true + true + true + true + true + true + + + Document + + + Document + true + true + true + true + true + true + true + true + true + true + true + true + + + + + + + + + + + + + + + + true + true + true + true + true + true + true + true + true + true + true + true + + + + + true + true + true + true + true + true + true + true + true + true + true + true + + + + + + + + + + + + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + + + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + true + true + true + true + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + ..\..\..\..\..\mbedtls\include;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;..\..\..\apps\snmp_private_mib;%(AdditionalIncludeDirectories) + + + + + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP.vcxproj.filters b/contrib/ports/win32/msvc/lwIP.vcxproj.filters new file mode 100644 index 0000000..bb90c3e --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP.vcxproj.filters @@ -0,0 +1,1075 @@ + + + + + {51757ae3-05ca-4e6a-a745-19c9ffc62278} + + + {e40d58ed-58be-4618-9664-6df29e27f835} + + + {5752fd8f-90c3-4381-8b6a-86c09a2f9859} + + + {48a805a9-e5d2-4eed-b29c-02b57140a03d} + + + {8a8dba58-934c-4292-aa8d-d20e2b801bd4} + + + {20594706-d6e1-4503-bc38-f297892d752a} + + + {1075aec7-b001-47bd-9846-ed635687e26e} + + + {9b7b3b39-f3b0-4915-81d9-d66c3443c348} + + + {75f75ac5-73a4-4458-bc23-eaed529c37e1} + + + {97772339-4210-4a32-82d0-d25269d3e3d6} + + + {06467ead-0683-44db-bc41-6aa5a82490f0} + + + {166a3203-ccc3-4eff-9eaa-1e5648a7fb5b} + + + {6b889738-b59a-450a-b4dd-0d1986bffca1} + + + {c64c0664-acd9-4f2f-8bd7-78250f4b7b4b} + + + {56e8d041-f1e0-4b02-a173-563190c0eb4a} + + + {dc783ea8-63ed-4de6-b576-a87c318a7ad1} + + + {7822191b-1cd0-4ce8-a852-da0474977fc4} + + + {b22a3b7a-d076-44a5-9a16-1e6f49cd5a94} + + + {0109fdbb-3aed-45fa-a308-493988755364} + + + {32a9c4ed-7687-48bb-8b9d-482c2f6c7554} + + + {c6c4a1a7-dab8-4463-b155-07e7303b54e4} + + + {2e87d0f7-38a3-45f8-870d-f8622c20e9d9} + + + {45f6a578-1f4b-4741-9b55-5b5084ecc1d9} + + + {92215272-cad9-4cf0-a2e1-705f6220e2a9} + + + {bdd3995a-aa34-4a4e-891e-a13c5373d618} + + + {d0ce6e8b-4b30-498b-a1bb-aecee958df42} + + + {6db73869-23f6-48ab-8d92-c8e478e55892} + + + {65542a97-c588-47b3-b1f6-ae51645c736e} + + + {ffd283f4-44f0-4be2-83a3-8bd55f29e80f} + + + {d9456888-d299-48ff-8165-ff499e5a0ba3} + + + {5aa786e4-df26-432c-b32c-9c4fac00b951} + + + {8fb42d78-1e77-4208-b457-44f41c4cc901} + + + {81578f11-9d3c-4bc8-a518-6f78f082fe0e} + + + {f8d65087-0cee-46de-8d8c-dca719bf2a4b} + + + {91d8473a-deb5-4943-8b63-b43d86c7fa1c} + + + {15855a74-48c6-473c-b4cb-40ec065698d4} + + + {2c795490-531d-4a03-b30d-73760b09975a} + + + + + + + + + + doc + + + doc + + + doc + + + doc + + + doc + + + doc\doxygen + + + doc\doxygen + + + doc\doxygen + + + example_app + + + + + src\api + + + src\api + + + src\api + + + src\api + + + src\api + + + src\api + + + src\api + + + src\api + + + src\apps\lwiperf + + + src\apps\netbiosns + + + src\apps\sntp + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\core\ipv6 + + + src\netif + + + src\netif + + + src\netif + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp + + + src\netif\ppp\polarssl + + + src\netif\ppp\polarssl + + + src\netif\ppp\polarssl + + + src\netif\ppp\polarssl + + + src\netif\ppp\polarssl + + + arch + + + arch + + + src\apps\http + + + src\apps\http + + + src\apps\http + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\core + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\netif\ppp + + + src\core\ipv4 + + + src\core\ipv4 + + + src\core + + + src\apps\mdns + + + src\apps\snmp + + + doc + + + src\apps\tftp + + + src\apps\mqtt + + + src\api + + + src\netif + + + src\apps\snmp + + + src\apps\snmp + + + src\core + + + src\core + + + src\apps\altcp_tls + + + src\apps\altcp_tls + + + src\apps\smtp + + + src\netif + + + src\apps\http + + + src\core + + + src\apps\http + + + src\netif + + + src\netif + + + src\netif + + + src\apps\mdns + + + src\apps\mdns + + + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\netif + + + src\include\netif + + + src\include\netif + + + src\include\netif + + + src\include\netif + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp + + + src\include\netif\ppp\polarssl + + + src\include\netif\ppp\polarssl + + + src\include\netif\ppp\polarssl + + + src\include\netif\ppp\polarssl + + + src\include\netif\ppp\polarssl + + + arch + + + arch + + + arch + + + arch + + + arch + + + src\include\lwip\priv + + + src\include\lwip\priv + + + src\include\lwip\priv + + + src\include\lwip\priv + + + src\include\lwip\priv + + + src\apps\http + + + src\apps\http + + + src\apps\snmp + + + src\apps\snmp + + + src\apps\snmp + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\apps\snmp + + + src\include\netif\ppp + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\apps\snmp + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\apps + + + src\include\lwip\prot + + + src\include\lwip\prot + + + doc\doxygen + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip + + + src\include\lwip\priv + + + src\include\lwip\apps + + + src\include\lwip + + + src\include\lwip + + + src\include\lwip\priv + + + src\include\netif + + + src\include\netif + + + src\include\lwip + + + src\include\lwip + + + src\apps\altcp_tls + + + src\apps\altcp_tls + + + src\include\lwip + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\priv + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\compat\posix\sys + + + src\include\compat\posix + + + src\include\compat\posix\net + + + src\include\compat\posix\arpa + + + src\include\compat\stdc + + + src\include\lwip\prot + + + src\include\lwip\prot + + + src\include\lwip\priv + + + src\include\lwip\priv + + + src\include\lwip\apps + + + src\include\lwip\apps + + + src\include\lwip\prot + + + src\include\netif + + + src\include\netif + + + src\include\netif + + + src\include\netif + + + example_app + + + example_app + + + example_app + + + example_app + + + example_app + + + src\include\lwip\apps + + + src\include\lwip\apps + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP_Test.sln b/contrib/ports/win32/msvc/lwIP_Test.sln new file mode 100644 index 0000000..a6b89df --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_Test.sln @@ -0,0 +1,57 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP_Test", "lwIP_Test.vcxproj", "{8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP pcapif", "lwIP_pcapif.vcxproj", "{6F44E49E-9F21-4144-91EC-53B92AEF62CE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP", "lwIP.vcxproj", "{2CC276FA-B226-49C9-8F82-7FCD5A228E28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makefsdata", "makefsdata.vcxproj", "{0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|Win32.Build.0 = Debug|Win32 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|x64.ActiveCfg = Debug|x64 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|x64.Build.0 = Debug|x64 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|Win32.ActiveCfg = Release|Win32 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|Win32.Build.0 = Release|Win32 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|x64.ActiveCfg = Release|x64 + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|x64.Build.0 = Release|x64 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|Win32.Build.0 = Debug|Win32 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|x64.ActiveCfg = Debug|x64 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|x64.Build.0 = Debug|x64 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|Win32.ActiveCfg = Release|Win32 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|Win32.Build.0 = Release|Win32 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|x64.ActiveCfg = Release|x64 + {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|x64.Build.0 = Release|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.ActiveCfg = Debug|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.Build.0 = Debug|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.ActiveCfg = Debug|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.Build.0 = Debug|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.ActiveCfg = Release|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.Build.0 = Release|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.ActiveCfg = Release|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.Build.0 = Release|x64 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|Win32.ActiveCfg = Debug|Win32 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|Win32.Build.0 = Debug|Win32 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|x64.ActiveCfg = Debug|x64 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|x64.Build.0 = Debug|x64 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|Win32.ActiveCfg = Release|Win32 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|Win32.Build.0 = Release|Win32 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|x64.ActiveCfg = Release|x64 + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/ports/win32/msvc/lwIP_Test.vcxproj b/contrib/ports/win32/msvc/lwIP_Test.vcxproj new file mode 100644 index 0000000..22b39c8 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_Test.vcxproj @@ -0,0 +1,321 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D} + lwIP_test + 10.0 + + + + Application + false + MultiByte + v143 + + + Application + false + MultiByte + v143 + + + Application + false + MultiByte + v143 + + + Application + false + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + false + false + true + true + + + + .\Release/test.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + Packet.lib;wpcap.lib;%(AdditionalDependencies) + true + $(PCAP_DIR)\Lib;..\..\..\..\..\winpcap\WpdPack\Lib;%(AdditionalLibraryDirectories) + .\Release/test.pdb + Console + false + + + MachineX86 + true + $(TargetDir)$(TargetName).map + Packet.dll;wpcap.dll;%(DelayLoadDLLs) + + + + + .\Release/test.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + Packet.lib;wpcap.lib;%(AdditionalDependencies) + true + $(PCAP_DIR)\Lib;..\..\..\..\..\winpcap\WpdPack\Lib\x64;%(AdditionalLibraryDirectories) + .\Release/test.pdb + Console + false + + + true + $(TargetDir)$(TargetName).map + Packet.dll;wpcap.dll;%(DelayLoadDLLs) + + + + + .\Debug/test.tlb + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..;%(AdditionalIncludeDirectories) + _CONSOLE;WIN32;_DEBUG;LWIP_DEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + EditAndContinue + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + Packet.lib;wpcap.lib;%(AdditionalDependencies) + true + $(PCAP_DIR)\Lib;..\..\..\..\..\winpcap\WpdPack\Lib;%(AdditionalLibraryDirectories) + true + Console + false + + + MachineX86 + false + $(TargetDir)$(TargetName).map + Packet.dll;wpcap.dll;%(DelayLoadDLLs) + false + + + + + .\Debug/test.tlb + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;..\..\..;%(AdditionalIncludeDirectories) + _CONSOLE;WIN32;_DEBUG;LWIP_DEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + Packet.lib;wpcap.lib;%(AdditionalDependencies) + true + $(PCAP_DIR)\Lib;..\..\..\..\..\winpcap\WpdPack\Lib\x64;%(AdditionalLibraryDirectories) + true + Console + false + + + false + $(TargetDir)$(TargetName).map + Packet.dll;wpcap.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {2cc276fa-b226-49c9-8f82-7fcd5a228e28} + false + + + {6f44e49e-9f21-4144-91ec-53b92aef62ce} + false + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP_Test.vcxproj.filters b/contrib/ports/win32/msvc/lwIP_Test.vcxproj.filters new file mode 100644 index 0000000..52f7732 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_Test.vcxproj.filters @@ -0,0 +1,252 @@ + + + + + {e858c3d0-1558-4d47-bc6a-9d4a55ce3d3a} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {0582eefd-a68e-45f8-b93c-f828c4794f30} + + + {ed0627c2-099a-4da8-af0c-142003828f9f} + + + {4ffb2268-6fc6-44d7-8e3b-2a3f68b8d5a3} + + + {93b36161-88b2-448c-9c45-ac6f27b98290} + + + {6456d2d6-61e6-4c99-9f1f-1f225437a642} + + + {75bb877e-aa45-4e2e-82fe-946ddadc6a64} + + + {78411edf-fe39-4edb-a6bd-2833755e0342} + + + {531dd0cf-ec13-42b7-a3bb-b837382d4ecd} + + + {d71bdb12-c5ed-4823-99f0-2d537765a2eb} + + + {0b9db8c7-f352-4ca6-86c6-1a6c58482c5d} + + + {97f0ea5c-16cf-4640-a6b3-ace059ed2388} + + + {24079d2d-aab1-49f9-b0fa-57910a18b93a} + + + {d38ed32b-9498-429e-a02c-08332c463725} + + + {672a49fd-94ff-4126-8de3-e96c9c32dfb8} + + + {e5276e3f-3e2a-4376-aee3-85aafd12c77b} + + + {f6d95ce0-df4f-4988-8654-624468dd4ecd} + + + {a37e5539-232e-4d91-9c10-3d7a851b8c4c} + + + {a2a65260-5055-4a0d-bd0b-4a3ca3560918} + + + {aa359e5e-131e-4f20-9e5d-416f9ae76abd} + + + {bd6f1fcc-c88f-4b96-a267-401f6bf9898b} + + + {1098bc59-6867-48a3-afa4-b896510241d1} + + + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\addons\tcp_isn + + + Source Files\addons\ipv6_static_routing + + + Source Files\examples\httpd\fs_example + + + Source Files\examples\httpd\ssi_example + + + Source Files\examples\snmp\snmp_private_mib + + + Source Files\examples\snmp\snmp_v3 + + + Source Files\examples\httpd\cgi_example + + + Source Files\examples\httpd\genfiles_example + + + Source Files\examples\httpd\post_example + + + Source Files\examples\mdns + + + Source Files\examples\tftp + + + Source Files\examples\snmp + + + Source Files\examples\sntp + + + Source Files\examples\ppp + + + Source Files\examples\lwiperf + + + Source Files\examples\mqtt + + + Source Files + + + Source Files + + + Source Files\examples\httpd\https_example + + + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\apps + + + Source Files\addons\tcp_isn + + + Source Files\addons\ipv6_static_routing + + + Source Files\examples\httpd\fs_example + + + Source Files\examples\httpd\ssi_example + + + Source Files\examples\snmp\snmp_private_mib + + + Source Files\examples\snmp\snmp_v3 + + + Source Files\examples\httpd\cgi_example + + + Source Files\examples\httpd\genfiles_example + + + Source Files\examples\mdns + + + Source Files\examples\tftp + + + Source Files\examples\snmp + + + Source Files\examples\sntp + + + Source Files\examples\ppp + + + Source Files\examples\lwiperf + + + Source Files\examples\mqtt + + + Source Files\examples\httpd\https_example + + + + + Source Files\addons\ipv6_static_routing + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP_fuzz.sln b/contrib/ports/win32/msvc/lwIP_fuzz.sln new file mode 100644 index 0000000..11b52e3 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_fuzz.sln @@ -0,0 +1,78 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP", "lwIP.vcxproj", "{2CC276FA-B226-49C9-8F82-7FCD5A228E28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwip_fuzz", "lwip_fuzz.vcxproj", "{71B3B3F4-621C-11EE-8C99-0242AC120002}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_fuzz2|x64 = Debug_fuzz2|x64 + Debug_fuzz2|x86 = Debug_fuzz2|x86 + Debug_fuzz3|x64 = Debug_fuzz3|x64 + Debug_fuzz3|x86 = Debug_fuzz3|x86 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release_fuzz2|x64 = Release_fuzz2|x64 + Release_fuzz2|x86 = Release_fuzz2|x86 + Release_fuzz3|x64 = Release_fuzz3|x64 + Release_fuzz3|x86 = Release_fuzz3|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz2|x64.ActiveCfg = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz2|x64.Build.0 = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz2|x86.ActiveCfg = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz2|x86.Build.0 = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz3|x64.ActiveCfg = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz3|x64.Build.0 = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz3|x86.ActiveCfg = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug_fuzz3|x86.Build.0 = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.ActiveCfg = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.Build.0 = Debug fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x86.ActiveCfg = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x86.Build.0 = Debug fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz2|x64.ActiveCfg = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz2|x64.Build.0 = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz2|x86.ActiveCfg = Release fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz2|x86.Build.0 = Release fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz3|x64.ActiveCfg = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz3|x64.Build.0 = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz3|x86.ActiveCfg = Release fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release_fuzz3|x86.Build.0 = Release fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.ActiveCfg = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.Build.0 = Release fuzz|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x86.ActiveCfg = Release fuzz|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x86.Build.0 = Release fuzz|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz2|x64.ActiveCfg = Debug fuzz2|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz2|x64.Build.0 = Debug fuzz2|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz2|x86.ActiveCfg = Debug fuzz2|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz2|x86.Build.0 = Debug fuzz2|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz3|x64.ActiveCfg = Debug fuzz3|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz3|x64.Build.0 = Debug fuzz3|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz3|x86.ActiveCfg = Debug fuzz3|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug_fuzz3|x86.Build.0 = Debug fuzz3|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug|x64.ActiveCfg = Debug|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug|x64.Build.0 = Debug|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug|x86.ActiveCfg = Debug|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Debug|x86.Build.0 = Debug|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz2|x64.ActiveCfg = Release fuzz2|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz2|x64.Build.0 = Release fuzz2|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz2|x86.ActiveCfg = Release fuzz2|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz2|x86.Build.0 = Release fuzz2|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz3|x64.ActiveCfg = Release fuzz3|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz3|x64.Build.0 = Release fuzz3|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz3|x86.ActiveCfg = Release fuzz3|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release_fuzz3|x86.Build.0 = Release fuzz3|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release|x64.ActiveCfg = Release|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release|x64.Build.0 = Release|x64 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release|x86.ActiveCfg = Release|Win32 + {71B3B3F4-621C-11EE-8C99-0242AC120002}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj b/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj new file mode 100644 index 0000000..b055d6a --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + lwIP pcapif + {6F44E49E-9F21-4144-91EC-53B92AEF62CE} + lwIP pcapif + 10.0 + + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + StaticLibrary + false + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;.\;$(PCAP_DIR)\Include;..\..\..\..\..\winpcap\WpdPack\Include\;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + EditAndContinue + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;.\;$(PCAP_DIR)\Include;..\..\..\..\..\winpcap\WpdPack\Include\;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir)$(ProjectName).pdb + Level4 + true + ProgramDatabase + Default + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;.\;$(PCAP_DIR)\Include;..\..\..\..\..\winpcap\WpdPack\Include\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;.\;$(PCAP_DIR)\Include;..\..\..\..\..\winpcap\WpdPack\Include\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + $(IntDir)$(TargetName).pch + $(IntDir)$(ProjectName).pdb + Level4 + true + Default + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + true + + + + + + + + + + + + + {2cc276fa-b226-49c9-8f82-7fcd5a228e28} + false + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj.filters b/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj.filters new file mode 100644 index 0000000..f933f17 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_pcapif.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {0d38b8c3-e694-4572-89b8-fc6e825a092d} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {e5ce29d5-319e-4e99-978b-b88e8d6167e4} + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwIP_unittests.sln b/contrib/ports/win32/msvc/lwIP_unittests.sln new file mode 100644 index 0000000..2e38336 --- /dev/null +++ b/contrib/ports/win32/msvc/lwIP_unittests.sln @@ -0,0 +1,50 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwip_unittests", "lwip_unittests.vcxproj", "{6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP", "lwIP.vcxproj", "{2CC276FA-B226-49C9-8F82-7FCD5A228E28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcheck", "libcheck.vcxproj", "{EBB156DC-01BF-47B2-B69C-1A750B6B5F09}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|Win32.ActiveCfg = Debug|Win32 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|Win32.Build.0 = Debug|Win32 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|x64.ActiveCfg = Debug|x64 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|x64.Build.0 = Debug|x64 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|Win32.ActiveCfg = Release|Win32 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|Win32.Build.0 = Release|Win32 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|x64.ActiveCfg = Release|x64 + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|x64.Build.0 = Release|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.ActiveCfg = Debug unittests|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.Build.0 = Debug unittests|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.ActiveCfg = Debug unittests|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|x64.Build.0 = Debug unittests|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.ActiveCfg = Release unittests|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.Build.0 = Release unittests|Win32 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.ActiveCfg = Release unittests|x64 + {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|x64.Build.0 = Release unittests|x64 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|Win32.Build.0 = Debug|Win32 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|x64.ActiveCfg = Debug|x64 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|x64.Build.0 = Debug|x64 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|Win32.ActiveCfg = Release|Win32 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|Win32.Build.0 = Release|Win32 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|x64.ActiveCfg = Release|x64 + {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {18F9EDCF-BE44-4F9F-A7F6-5DCF2B7687C5} + EndGlobalSection +EndGlobal diff --git a/contrib/ports/win32/msvc/lwip_fuzz.vcxproj b/contrib/ports/win32/msvc/lwip_fuzz.vcxproj new file mode 100644 index 0000000..fe42ca5 --- /dev/null +++ b/contrib/ports/win32/msvc/lwip_fuzz.vcxproj @@ -0,0 +1,476 @@ + + + + + Debug fuzz2 + Win32 + + + Debug fuzz2 + x64 + + + Debug fuzz3 + Win32 + + + Debug fuzz3 + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release fuzz2 + Win32 + + + Release fuzz2 + x64 + + + Release fuzz3 + Win32 + + + Release fuzz3 + x64 + + + Release + Win32 + + + Release + x64 + + + + {71B3B3F4-621C-11EE-8C99-0242AC120002} + lwip_fuzz + 10.0 + + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level4 + EditAndContinue + 4820 + + + true + false + + + MachineX86 + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level4 + ProgramDatabase + 4820 + + + true + false + + + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level4 + EditAndContinue + 4820 + + + true + false + + + MachineX86 + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level4 + ProgramDatabase + 4820 + + + true + false + + + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level4 + EditAndContinue + 4820 + + + true + false + + + MachineX86 + + + + + Disabled + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level4 + ProgramDatabase + 4820 + + + true + false + + + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\test\fuzz;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + + + + + {2cc276fa-b226-49c9-8f82-7fcd5a228e28} + false + + + + + + + + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwip_unittests.vcxproj b/contrib/ports/win32/msvc/lwip_unittests.vcxproj new file mode 100644 index 0000000..270ba28 --- /dev/null +++ b/contrib/ports/win32/msvc/lwip_unittests.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2} + lwip_unittests + 10.0 + + + + Application + MultiByte + true + v143 + + + Application + MultiByte + true + v143 + + + Application + MultiByte + v143 + + + Application + MultiByte + v143 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + Disabled + ..\check;..\..\..\..\..\check\src;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level4 + EditAndContinue + 4820 + + + true + false + + + MachineX86 + false + + + + + Disabled + ..\check;..\..\..\..\..\check\src;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + _LIB;WIN32;_DEBUG;LWIP_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level4 + ProgramDatabase + 4820 + + + true + false + + + false + + + + + MaxSpeed + true + ..\check;..\..\..\..\..\check\src;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + MachineX86 + + + + + MaxSpeed + true + ..\check;..\..\..\..\..\check\src;..\..\..\..\test\unit;..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + Level4 + ProgramDatabase + + + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {ebb156dc-01bf-47b2-b69c-1a750b6b5f09} + false + + + {2cc276fa-b226-49c9-8f82-7fcd5a228e28} + false + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters b/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters new file mode 100644 index 0000000..bbac4e7 --- /dev/null +++ b/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters @@ -0,0 +1,168 @@ + + + + + {e351c538-9f2b-4a01-bf46-3ee8873cbc0f} + + + {5805c4bc-32c1-49cf-a35e-af58757e2d7a} + + + {173ba4ab-b194-4933-8e02-319044c2a8fa} + + + {70c655a7-f40f-4728-b586-33fd9598b355} + + + {a6b60d4e-4b81-44f2-9408-2e45cc769391} + + + {d454902e-ce5b-48ae-a690-e6490bdbbf17} + + + {d9501476-6102-4f14-90bd-35322fbd2fb2} + + + {b04f182c-1910-456d-9388-397dfe82dbc9} + + + {fd48ae04-ec85-478f-a97c-a7c8384a2d94} + + + {fe93fc95-f1af-4a1f-a086-c1771dbf4d79} + + + {924d29be-e5e4-4b25-8bc4-92db91ce4c49} + + + {4d24c808-c024-4aba-a214-e5bc276e124d} + + + + + core + + + core + + + tcp + + + tcp + + + tcp + + + udp + + + etharp + + + dhcp + + + + mdns + + + api + + + arch + + + mqtt + + + ip4 + + + core + + + core + + + core + + + ipv6 + + + core + + + ppp + + + tcp + + + + + core + + + core + + + tcp + + + tcp + + + tcp + + + udp + + + etharp + + + dhcp + + + + + mdns + + + api + + + arch + + + mqtt + + + ip4 + + + core + + + core + + + core + + + ipv6 + + + core + + + ppp + + + tcp + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/makefsdata.vcxproj b/contrib/ports/win32/msvc/makefsdata.vcxproj new file mode 100644 index 0000000..c5d2c72 --- /dev/null +++ b/contrib/ports/win32/msvc/makefsdata.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D} + makefsdata + Win32Proj + 10.0 + + + + Application + Unicode + true + v143 + + + Application + Unicode + true + v143 + + + Application + Unicode + v143 + + + Application + Unicode + v143 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(Configuration)\$(ProjectName)\ + true + true + false + false + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + + + true + Console + false + + + MachineX86 + + + + + Disabled + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + + + true + Console + false + + + + + + + MaxSpeed + true + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + + + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\src\include;..\..\..\..\src\include\ipv4;..\..\..\..\src\include\ipv6;..\include;..\..\..\examples\example_app;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + + + true + Console + true + true + false + + + + + + + + \ No newline at end of file diff --git a/contrib/ports/win32/msvc/makefsdata.vcxproj.filters b/contrib/ports/win32/msvc/makefsdata.vcxproj.filters new file mode 100644 index 0000000..0f0210d --- /dev/null +++ b/contrib/ports/win32/msvc/makefsdata.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Quelldateien + + + \ No newline at end of file diff --git a/contrib/ports/win32/pcapif.c b/contrib/ports/win32/pcapif.c new file mode 100644 index 0000000..6bf58f0 --- /dev/null +++ b/contrib/ports/win32/pcapif.c @@ -0,0 +1,1129 @@ +/** + * pcapif.c - This file is part of lwIP pcapif + * + **************************************************************************** + * + * This file is derived from an example in lwIP with the following license: + * + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* include the port-dependent configuration */ +#include "lwipcfg.h" + +#include +#include + +#ifdef _MSC_VER +#pragma warning( push, 3 ) +#include "pcap.h" +#pragma warning ( pop ) +#else +/* e.g. mingw */ +#define _MSC_VER 1500 +#include "pcap.h" +#undef _MSC_VER +#endif + +#include "lwip/opt.h" + +#if LWIP_ETHERNET + +#include "pcapif.h" + +#include +#include +#include + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/ip.h" +#include "lwip/snmp.h" +#include "lwip/tcpip.h" +#include "lwip/timeouts.h" +#include "lwip/ethip6.h" + +#include "lwip/etharp.h" + +/* For compatibility with old pcap */ +#ifndef PCAP_OPENFLAG_PROMISCUOUS +#define PCAP_OPENFLAG_PROMISCUOUS 1 +#endif + +/** Set this to 0 to receive all multicast ethernet destination addresses */ +#ifndef PCAPIF_FILTER_GROUP_ADDRESSES +#define PCAPIF_FILTER_GROUP_ADDRESSES 1 +#endif + +/** Set this to 1 to receive all frames (also unicast to other addresses) + * In this mode, filtering out our own tx packets from loopback receiving + * is done via matching rx against recent tx (memcmp). + */ +#ifndef PCAPIF_RECEIVE_PROMISCUOUS +#define PCAPIF_RECEIVE_PROMISCUOUS 0 +#endif + +/* Define those to better describe your network interface. + For now, we use 'e0', 'e1', 'e2' and so on */ +#define IFNAME0 'e' +#define IFNAME1 '0' + +/** index of the network adapter to use for lwIP */ +#ifndef PACKET_LIB_ADAPTER_NR +#define PACKET_LIB_ADAPTER_NR 0 +#endif + +/** If 1, check link state and report it to lwIP. + * If 0, don't check link state (lwIP link state is always UP). + */ +#ifndef PCAPIF_HANDLE_LINKSTATE +#define PCAPIF_HANDLE_LINKSTATE 1 +#endif + +/** If 1, use PBUF_REF for RX (for testing purposes mainly). + * For this, LWIP_SUPPORT_CUSTOM_PBUF must be enabled. + * Also, PBUF_POOL_BUFSIZE must be set high enough to ensure all rx packets + * fit into a single pbuf. + */ +#ifndef PCAPIF_RX_REF +#define PCAPIF_RX_REF 0 +#endif + +/** This can be used when netif->state is used for something else in your + * application (e.g. when wrapping a class around this interface). Just + * make sure this define returns the state pointer set by + * pcapif_low_level_init() (e.g. by using an offset or a callback). + */ +#ifndef PCAPIF_GET_STATE_PTR +#define PCAPIF_GET_STATE_PTR(netif) ((netif)->state) +#endif + +/** Define this to 1 to allocate readonly pbufs for RX (needs PCAPIF_RX_REF, + * only implemented for windows, for now) + */ +#ifndef PCAPIF_RX_READONLY +#define PCAPIF_RX_READONLY 0 +#endif + +#if PCAPIF_HANDLE_LINKSTATE +#include "pcapif_helper.h" + +/* Define "PHY" delay when "link up" */ +#ifndef PCAPIF_LINKUP_DELAY +#define PCAPIF_LINKUP_DELAY 0 +#endif + +#define PCAPIF_LINKCHECK_INTERVAL_MS 500 + +/* link state notification macro */ +#if PCAPIF_LINKUP_DELAY +#define PCAPIF_NOTIFY_LINKSTATE(netif, linkfunc) sys_timeout(PCAPIF_LINKUP_DELAY, (sys_timeout_handler)linkfunc, netif) +#else /* PHY_LINKUP_DELAY */ +#define PCAPIF_NOTIFY_LINKSTATE(netif, linkfunc) linkfunc(netif) +#endif /* PHY_LINKUP_DELAY */ + +#endif /* PCAPIF_HANDLE_LINKSTATE */ + +/* Define PCAPIF_RX_LOCK_LWIP and PCAPIF_RX_UNLOCK_LWIP if you need to lock the lwIP core + before/after pbuf_alloc() or netif->input() are called on RX. */ +#ifndef PCAPIF_RX_LOCK_LWIP +#define PCAPIF_RX_LOCK_LWIP() +#endif +#ifndef PCAPIF_RX_UNLOCK_LWIP +#define PCAPIF_RX_UNLOCK_LWIP() +#endif + +#define ETH_MIN_FRAME_LEN 60U +#define ETH_MAX_FRAME_LEN 1518U + +#define ADAPTER_NAME_LEN 128 +#define ADAPTER_DESC_LEN 128 + +#if PCAPIF_RECEIVE_PROMISCUOUS +#ifndef PCAPIF_LOOPBACKFILTER_NUM_TX_PACKETS +#define PCAPIF_LOOPBACKFILTER_NUM_TX_PACKETS 128 +#endif +struct pcapipf_pending_packet { + struct pcapipf_pending_packet *next; + u16_t len; + u8_t data[ETH_MAX_FRAME_LEN]; +}; +#endif /* PCAPIF_RECEIVE_PROMISCUOUS */ + +/* Packet Adapter information */ +struct pcapif_private { + void *input_fn_arg; + pcap_t *adapter; + char name[ADAPTER_NAME_LEN]; + char description[ADAPTER_DESC_LEN]; + int shutdown_called; +#if PCAPIF_RX_USE_THREAD + volatile int rx_run; + volatile int rx_running; +#endif /* PCAPIF_RX_USE_THREAD */ +#if PCAPIF_HANDLE_LINKSTATE + struct pcapifh_linkstate *link_state; + enum pcapifh_link_event last_link_event; +#endif /* PCAPIF_HANDLE_LINKSTATE */ +#if PCAPIF_RECEIVE_PROMISCUOUS + struct pcapipf_pending_packet packets[PCAPIF_LOOPBACKFILTER_NUM_TX_PACKETS]; + struct pcapipf_pending_packet *tx_packets; + struct pcapipf_pending_packet *free_packets; +#endif /* PCAPIF_RECEIVE_PROMISCUOUS */ +}; + +#if PCAPIF_RECEIVE_PROMISCUOUS +static void +pcapif_init_tx_packets(struct pcapif_private *priv) +{ + int i; + priv->tx_packets = NULL; + priv->free_packets = NULL; + for (i = 0; i < PCAPIF_LOOPBACKFILTER_NUM_TX_PACKETS; i++) { + struct pcapipf_pending_packet *pack = &priv->packets[i]; + pack->len = 0; + pack->next = priv->free_packets; + priv->free_packets = pack; + } +} + +static void +pcapif_add_tx_packet(struct pcapif_private *priv, unsigned char *buf, u16_t tot_len) +{ + struct pcapipf_pending_packet *tx; + struct pcapipf_pending_packet *pack; + SYS_ARCH_DECL_PROTECT(lev); + + /* get a free packet (locked) */ + SYS_ARCH_PROTECT(lev); + pack = priv->free_packets; + if ((pack == NULL) && (priv->tx_packets != NULL)) { + /* no free packets, reuse the oldest */ + pack = priv->tx_packets; + priv->tx_packets = pack->next; + } + LWIP_ASSERT("no free packet", pack != NULL); + priv->free_packets = pack->next; + pack->next = NULL; + SYS_ARCH_UNPROTECT(lev); + + /* set up the packet (unlocked) */ + pack->len = tot_len; + memcpy(pack->data, buf, tot_len); + + /* put the packet on the list (locked) */ + SYS_ARCH_PROTECT(lev); + if (priv->tx_packets != NULL) { + for (tx = priv->tx_packets; tx->next != NULL; tx = tx->next); + LWIP_ASSERT("bug", tx != NULL); + tx->next = pack; + } else { + priv->tx_packets = pack; + } + SYS_ARCH_UNPROTECT(lev); +} + +static int +pcapif_compare_packets(struct pcapipf_pending_packet *pack, const void *packet, int packet_len) +{ + if (pack->len == packet_len) { + if (!memcmp(pack->data, packet, packet_len)) { + return 1; + } + } + return 0; +} + +static int +pcaipf_is_tx_packet(struct netif *netif, const void *packet, int packet_len) +{ + struct pcapif_private *priv = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + struct pcapipf_pending_packet *iter, *last; + SYS_ARCH_DECL_PROTECT(lev); + + last = priv->tx_packets; + if (last == NULL) { + /* list is empty */ + return 0; + } + /* compare the first packet */ + if (pcapif_compare_packets(last, packet, packet_len)) { + SYS_ARCH_PROTECT(lev); + LWIP_ASSERT("list has changed", last == priv->tx_packets); + priv->tx_packets = last->next; + last->next = priv->free_packets; + priv->free_packets = last; + last->len = 0; + SYS_ARCH_UNPROTECT(lev); + return 1; + } + SYS_ARCH_PROTECT(lev); + for (iter = last->next; iter != NULL; last = iter, iter = iter->next) { + /* unlock while comparing (this works because we have a clean threading separation + of adding and removing items and adding is only done at the end) */ + SYS_ARCH_UNPROTECT(lev); + if (pcapif_compare_packets(iter, packet, packet_len)) { + SYS_ARCH_PROTECT(lev); + LWIP_ASSERT("last != NULL", last != NULL); + last->next = iter->next; + iter->next = priv->free_packets; + priv->free_packets = iter; + last->len = 0; + SYS_ARCH_UNPROTECT(lev); + return 1; + } + SYS_ARCH_PROTECT(lev); + } + SYS_ARCH_UNPROTECT(lev); + return 0; +} +#else /* PCAPIF_RECEIVE_PROMISCUOUS */ +#define pcapif_init_tx_packets(priv) +#define pcapif_add_tx_packet(priv, buf, tot_len) +static int +pcaipf_is_tx_packet(struct netif *netif, const void *packet, int packet_len) +{ + const struct eth_addr *src = (const struct eth_addr *)packet + 1; + if (packet_len >= (ETH_HWADDR_LEN * 2)) { + /* Don't let feedback packets through (limitation in winpcap?) */ + if(!memcmp(src, netif->hwaddr, ETH_HWADDR_LEN)) { + return 1; + } + } + return 0; +} +#endif /* PCAPIF_RECEIVE_PROMISCUOUS */ + +#if PCAPIF_RX_REF +struct pcapif_pbuf_custom +{ + struct pbuf_custom pc; +#if PCAPIF_RX_READONLY + void *ro_mem; +#else + struct pbuf* p; +#endif +}; +#endif /* PCAPIF_RX_REF */ + +/* Forward declarations. */ +static void pcapif_input(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *packet); + +#ifdef PACKET_LIB_GET_ADAPTER_NETADDRESS +/** Get the index of an adapter by its network address + * + * @param netaddr network address of the adapter (e.g. 192.168.1.0) + * @return index of the adapter or negative on error + */ +static int +get_adapter_index_from_addr(struct in_addr *netaddr, char *guid, size_t guid_len) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + char errbuf[PCAP_ERRBUF_SIZE+1]; + int index = 0; + + memset(guid, 0, guid_len); + + /* Retrieve the interfaces list */ + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + printf("Error in pcap_findalldevs: %s\n", errbuf); + return -1; + } + /* Scan the list printing every entry */ + for (d = alldevs; d != NULL; d = d->next, index++) { + pcap_addr_t *a; + for(a = d->addresses; a != NULL; a = a->next) { + if (a->addr->sa_family == AF_INET) { + ULONG a_addr = ((struct sockaddr_in *)a->addr)->sin_addr.s_addr; + ULONG a_netmask = ((struct sockaddr_in *)a->netmask)->sin_addr.s_addr; + ULONG a_netaddr = a_addr & a_netmask; + ULONG addr = (*netaddr).s_addr; + if (a_netaddr == addr) { + int ret = -1; + char name[128]; + char *start, *end; + size_t len = strlen(d->name); + if(len > 127) { + len = 127; + } + MEMCPY(name, d->name, len); + name[len] = 0; + start = strstr(name, "{"); + if (start != NULL) { + end = strstr(start, "}"); + if (end != NULL) { + size_t len = end - start + 1; + MEMCPY(guid, start, len); + ret = index; + } + } + pcap_freealldevs(alldevs); + return ret; + } + } + } + } + printf("Network address not found.\n"); + + pcap_freealldevs(alldevs); + return -1; +} +#endif /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ + +#if defined(PACKET_LIB_GET_ADAPTER_NETADDRESS) || defined(PACKET_LIB_ADAPTER_GUID) +/** Get the index of an adapter by its GUID + * + * @param adapter_guid GUID of the adapter + * @return index of the adapter or negative on error + */ +static int +get_adapter_index(const char* adapter_guid) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + char errbuf[PCAP_ERRBUF_SIZE+1]; + int idx = 0; + + /* Retrieve the interfaces list */ + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + printf("Error in pcap_findalldevs: %s\n", errbuf); + return -1; + } + /* Scan the list and compare name vs. adapter_guid */ + for (d = alldevs; d != NULL; d = d->next, idx++) { + if(strstr(d->name, adapter_guid)) { + pcap_freealldevs(alldevs); + return idx; + } + } + /* not found, dump all adapters */ + printf("%d available adapters:\n", idx); + for (d = alldevs, idx = 0; d != NULL; d = d->next, idx++) { + printf("- %d: %s\n", idx, d->name); + } + pcap_freealldevs(alldevs); + return -1; +} +#endif /* defined(PACKET_LIB_GET_ADAPTER_NETADDRESS) || defined(PACKET_LIB_ADAPTER_GUID) */ + +static pcap_t* +pcapif_open_adapter(const char* adapter_name, char* errbuf) +{ + pcap_t* adapter = pcap_open_live(adapter_name,/* name of the device */ + 65536, /* portion of the packet to capture */ + /* 65536 guarantees that the whole packet will be captured on all the link layers */ + PCAP_OPENFLAG_PROMISCUOUS,/* promiscuous mode */ +#if PCAPIF_RX_USE_THREAD + /*-*/1, /* don't wait at all for lower latency */ +#else + 1, /* wait 1 ms in ethernetif_poll */ +#endif + errbuf); /* error buffer */ + return adapter; +} + +#if !PCAPIF_RX_USE_THREAD +static void +pcap_reopen_adapter(struct pcapif_private *pa) +{ + char errbuf[PCAP_ERRBUF_SIZE+1]; + pcap_if_t *alldevs; + if (pa->adapter != NULL) { + pcap_close(pa->adapter); + pa->adapter = NULL; + } + if (pcap_findalldevs(&alldevs, errbuf) != -1) { + pcap_if_t *d; + for (d = alldevs; d != NULL; d = d->next) { + if (!strcmp(d->name, pa->name)) { + pa->adapter = pcapif_open_adapter(pa->name, errbuf); + if (pa->adapter == NULL) { + printf("failed to reopen pcap adapter after failure: %s\n", errbuf); + } + break; + } + } + pcap_freealldevs(alldevs); + } +} +#endif + +/** + * Open a network adapter and set it up for packet input + * + * @param adapter_num the index of the adapter to use + * @param arg argument to pass to input + * @return an adapter handle on success, NULL on failure + */ +static struct pcapif_private* +pcapif_init_adapter(int adapter_num, void *arg) +{ + int i; + int number_of_adapters; + struct pcapif_private *pa; + char errbuf[PCAP_ERRBUF_SIZE+1]; + + pcap_if_t *alldevs; + pcap_if_t *d; + pcap_if_t *used_adapter = NULL; + + pa = (struct pcapif_private *)malloc(sizeof(struct pcapif_private)); + if (!pa) { + printf("Unable to alloc the adapter!\n"); + return NULL; + } + + memset(pa, 0, sizeof(struct pcapif_private)); + pcapif_init_tx_packets(pa); + pa->input_fn_arg = arg; + + /* Retrieve the interfaces list */ + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + free(pa); + return NULL; /* no adapters found */ + } + /* get number of adapters and adapter pointer */ + for (d = alldevs, number_of_adapters = 0; d != NULL; d = d->next, number_of_adapters++) { + if (number_of_adapters == adapter_num) { + char *desc = d->description; + size_t len; + + len = strlen(d->name); + LWIP_ASSERT("len < ADAPTER_NAME_LEN", len < ADAPTER_NAME_LEN); + strcpy(pa->name, d->name); + + used_adapter = d; + /* format vendor description */ + if (desc != NULL) { + len = strlen(desc); + if (strstr(desc, " ' on local host") != NULL) { + len -= 16; + } + else if (strstr(desc, "' on local host") != NULL) { + len -= 15; + } + if (strstr(desc, "Network adapter '") == desc) { + len -= 17; + desc += 17; + } + len = LWIP_MIN(len, ADAPTER_DESC_LEN-1); + while ((desc[len-1] == ' ') || (desc[len-1] == '\t')) { + /* don't copy trailing whitespace */ + len--; + } + strncpy(pa->description, desc, len); + pa->description[len] = 0; + } else { + strcpy(pa->description, ""); + } + } + } + +#ifndef PCAPIF_LIB_QUIET + /* Scan the list printing every entry */ + for (d = alldevs, i = 0; d != NULL; d = d->next, i++) { + char *desc = d->description; + char descBuf[128]; + size_t len; + const char* devname = d->name; + if (d->name == NULL) { + devname = ""; + } else { + if (strstr(devname, "\\Device\\") == devname) { + /* windows: strip the first part */ + devname += 8; + } + } + printf("%2i: %s\n", i, devname); + if (desc != NULL) { + /* format vendor description */ + len = strlen(desc); + if (strstr(desc, " ' on local host") != NULL) { + len -= 16; + } + else if (strstr(desc, "' on local host") != NULL) { + len -= 15; + } + if (strstr(desc, "Network adapter '") == desc) { + len -= 17; + desc += 17; + } + len = LWIP_MIN(len, 127); + while ((desc[len-1] == ' ') || (desc[len-1] == '\t')) { + /* don't copy trailing whitespace */ + len--; + } + strncpy(descBuf, desc, len); + descBuf[len] = 0; + printf(" Desc: \"%s\"\n", descBuf); + } + } +#endif /* PCAPIF_LIB_QUIET */ + + /* invalid adapter index -> check this after printing the adapters */ + if (adapter_num < 0) { + printf("Invalid adapter_num: %d\n", adapter_num); + free(pa); + pcap_freealldevs(alldevs); + return NULL; + } + /* adapter index out of range */ + if (adapter_num >= number_of_adapters) { + printf("Invalid adapter_num: %d\n", adapter_num); + free(pa); + pcap_freealldevs(alldevs); + return NULL; + } +#ifndef PCAPIF_LIB_QUIET + printf("Using adapter_num: %d\n", adapter_num); +#endif /* PCAPIF_LIB_QUIET */ + /* set up the selected adapter */ + + LWIP_ASSERT("used_adapter != NULL", used_adapter != NULL); + + /* Open the device */ + pa->adapter = pcapif_open_adapter(used_adapter->name, errbuf); + if (pa->adapter == NULL) { + printf("\nUnable to open the adapter. %s is not supported by pcap (\"%s\").\n", used_adapter->name, errbuf); + /* Free the device list */ + pcap_freealldevs(alldevs); + free(pa); + return NULL; + } + printf("Using adapter: \"%s\"\n", pa->description); + pcap_freealldevs(alldevs); + +#if PCAPIF_HANDLE_LINKSTATE + pa->link_state = pcapifh_linkstate_init(pa->name); + pa->last_link_event = PCAPIF_LINKEVENT_UNKNOWN; +#endif /* PCAPIF_HANDLE_LINKSTATE */ + + return pa; +} + +#if PCAPIF_HANDLE_LINKSTATE +static void +pcapif_check_linkstate(void *netif_ptr) +{ + struct netif *netif = (struct netif*)netif_ptr; + struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + enum pcapifh_link_event le; + + le = pcapifh_linkstate_get(pa->link_state); + + if (pa->last_link_event != le) { + pa->last_link_event = le; + switch (le) { + case PCAPIF_LINKEVENT_UP: { + PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_up); + break; + } + case PCAPIF_LINKEVENT_DOWN: { + PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_down); + break; + } + case PCAPIF_LINKEVENT_UNKNOWN: /* fall through */ + default: + break; + } + } + sys_timeout(PCAPIF_LINKCHECK_INTERVAL_MS, pcapif_check_linkstate, netif); +} +#endif /* PCAPIF_HANDLE_LINKSTATE */ + + +/** + * Close the adapter (no more packets can be sent or received) + * + * @param netif netif to shutdown + */ +void +pcapif_shutdown(struct netif *netif) +{ + struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + if (pa) { +#if PCAPIF_RX_USE_THREAD + pa->rx_run = 0; +#endif /* PCAPIF_RX_USE_THREAD */ + if (pa->adapter) { + pcap_breakloop(pa->adapter); + } +#if PCAPIF_RX_USE_THREAD + /* wait for rxthread to end */ + while (pa->rx_running) { + Sleep(100); + } +#endif /* PCAPIF_RX_USE_THREAD */ + if (pa->adapter) { + pcap_close(pa->adapter); + pa->adapter = NULL; + } +#if PCAPIF_HANDLE_LINKSTATE + pcapifh_linkstate_close(pa->link_state); +#endif /* PCAPIF_HANDLE_LINKSTATE */ + free(pa); + } +} + +#if PCAPIF_RX_USE_THREAD +/** RX running in its own thread */ +static void +pcapif_input_thread(void *arg) +{ + struct netif *netif = (struct netif *)arg; + struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + do + { + struct pcap_pkthdr pkt_header; + const u_char *packet = pcap_next(pa->adapter, &pkt_header); + if(packet != NULL) { + pcapif_input((u_char*)pa, &pkt_header, packet); + } + } while (pa->rx_run); + pa->rx_running = 0; +} +#endif /* PCAPIF_RX_USE_THREAD */ + +/** Low-level initialization: find the correct adapter and initialize it. + */ +static void +pcapif_low_level_init(struct netif *netif) +{ + u8_t my_mac_addr[ETH_HWADDR_LEN] = LWIP_MAC_ADDR_BASE; + int adapter_num = PACKET_LIB_ADAPTER_NR; + struct pcapif_private *pa; +#ifdef PACKET_LIB_GET_ADAPTER_NETADDRESS + ip4_addr_t netaddr; +#define GUID_LEN 128 + char guid[GUID_LEN + 1]; +#endif /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ + + /* If 'state' is != NULL at this point, we assume it is an 'int' giving + the index of the adapter to use (+ 1 because 0==NULL is invalid). + This can be used to instantiate multiple PCAP drivers. */ + if (netif->state != NULL) { + adapter_num = (LWIP_PTR_NUMERIC_CAST(int, netif->state)) - 1; + if (adapter_num < 0) { + printf("ERROR: invalid adapter index \"%d\"!\n", adapter_num); + LWIP_ASSERT("ERROR initializing network adapter!", 0); + return; + } + } + +#ifdef PACKET_LIB_GET_ADAPTER_NETADDRESS + memset(&guid, 0, sizeof(guid)); + PACKET_LIB_GET_ADAPTER_NETADDRESS(&netaddr); + if (get_adapter_index_from_addr((struct in_addr *)&netaddr, guid, GUID_LEN) < 0) { + printf("ERROR initializing network adapter, failed to get GUID for network address %s\n", ip4addr_ntoa(&netaddr)); + LWIP_ASSERT("ERROR initializing network adapter, failed to get GUID for network address!", 0); + return; + } + adapter_num = get_adapter_index(guid); + if (adapter_num < 0) { + printf("ERROR finding network adapter with GUID \"%s\"!\n", guid); + LWIP_ASSERT("ERROR finding network adapter with expected GUID!", 0); + return; + } + +#else /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ +#ifdef PACKET_LIB_ADAPTER_GUID + /* get adapter index for guid string */ + adapter_num = get_adapter_index(PACKET_LIB_ADAPTER_GUID); + if (adapter_num < 0) { + printf("ERROR finding network adapter with GUID \"%s\"!\n", PACKET_LIB_ADAPTER_GUID); + LWIP_ASSERT("ERROR initializing network adapter!", 0); + return; + } +#endif /* PACKET_LIB_ADAPTER_GUID */ +#endif /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ + + /* Do whatever else is needed to initialize interface. */ + pa = pcapif_init_adapter(adapter_num, netif); + if (pa == NULL) { + printf("ERROR initializing network adapter %d!\n", adapter_num); + LWIP_ASSERT("ERROR initializing network adapter!", 0); + return; + } + netif->state = pa; + + /* change the MAC address to a unique value + so that multiple ethernetifs are supported */ + /* @todo: this does NOT support multiple processes using this adapter! */ + my_mac_addr[ETH_HWADDR_LEN - 1] += netif->num; + /* Copy MAC addr */ + SMEMCPY(&netif->hwaddr, my_mac_addr, ETH_HWADDR_LEN); + + /* get the initial link state of the selected interface */ +#if PCAPIF_HANDLE_LINKSTATE + pa->last_link_event = pcapifh_linkstate_get(pa->link_state); + if (pa->last_link_event == PCAPIF_LINKEVENT_DOWN) { + netif_set_link_down(netif); + } else { + netif_set_link_up(netif); + } + sys_timeout(PCAPIF_LINKCHECK_INTERVAL_MS, pcapif_check_linkstate, netif); +#else /* PCAPIF_HANDLE_LINKSTATE */ + /* just set the link up so that lwIP can transmit */ + netif_set_link_up(netif); +#endif /* PCAPIF_HANDLE_LINKSTATE */ + +#if PCAPIF_RX_USE_THREAD + pa->rx_run = 1; + pa->rx_running = 1; + sys_thread_new("pcapif_rxthread", pcapif_input_thread, netif, 0, 0); +#endif + + LWIP_DEBUGF(NETIF_DEBUG, ("pcapif: eth_addr %02X%02X%02X%02X%02X%02X\n",netif->hwaddr[0],netif->hwaddr[1],netif->hwaddr[2],netif->hwaddr[3],netif->hwaddr[4],netif->hwaddr[5])); +} + +/** low_level_output(): + * Transmit a packet. The packet is contained in the pbuf that is passed to + * the function. This pbuf might be chained. + */ +static err_t +pcapif_low_level_output(struct netif *netif, struct pbuf *p) +{ + struct pbuf *q; + unsigned char buffer[ETH_MAX_FRAME_LEN + ETH_PAD_SIZE]; + unsigned char *buf = buffer; + unsigned char *ptr; + struct eth_hdr *ethhdr; + u16_t tot_len = p->tot_len - ETH_PAD_SIZE; + struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + +#if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF && !(LWIP_IPV4 && IP_FRAG) && (LWIP_IPV6 && LWIP_IPV6_FRAG) + LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len); +#endif + + /* initiate transfer */ + if ((p->len == p->tot_len) && (p->len >= ETH_MIN_FRAME_LEN + ETH_PAD_SIZE)) { + /* no pbuf chain, don't have to copy -> faster */ + buf = &((unsigned char*)p->payload)[ETH_PAD_SIZE]; + } else { + /* pbuf chain, copy into contiguous buffer */ + if (p->tot_len >= sizeof(buffer)) { + LINK_STATS_INC(link.lenerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return ERR_BUF; + } + ptr = buffer; + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + LWIP_DEBUGF(NETIF_DEBUG, ("netif: send ptr %p q->payload %p q->len %i q->next %p\n", ptr, q->payload, (int)q->len, (void*)q->next)); + if (q == p) { + MEMCPY(ptr, &((char*)q->payload)[ETH_PAD_SIZE], q->len - ETH_PAD_SIZE); + ptr += q->len - ETH_PAD_SIZE; + } else { + MEMCPY(ptr, q->payload, q->len); + ptr += q->len; + } + } + } + + if (tot_len < ETH_MIN_FRAME_LEN) { + /* ensure minimal frame length */ + memset(&buf[tot_len], 0, ETH_MIN_FRAME_LEN - tot_len); + tot_len = ETH_MIN_FRAME_LEN; + } + + /* signal that packet should be sent */ + if (pcap_sendpacket(pa->adapter, buf, tot_len) < 0) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return ERR_BUF; + } + if (netif_is_link_up(netif)) { + pcapif_add_tx_packet(pa, buf, tot_len); + } + + LINK_STATS_INC(link.xmit); + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, tot_len); + ethhdr = (struct eth_hdr *)p->payload; + if ((ethhdr->dest.addr[0] & 1) != 0) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } else { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + return ERR_OK; +} + +/** low_level_input(): Allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + */ +static struct pbuf * +pcapif_low_level_input(struct netif *netif, const void *packet, int packet_len) +{ + struct pbuf *p, *q; + int start; + int length = packet_len; + const struct eth_addr *dest = (const struct eth_addr*)packet; + int unicast; +#if PCAPIF_FILTER_GROUP_ADDRESSES && !PCAPIF_RECEIVE_PROMISCUOUS + const u8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8_t ipv4mcast[] = {0x01, 0x00, 0x5e}; + const u8_t ipv6mcast[] = {0x33, 0x33}; +#endif /* PCAPIF_FILTER_GROUP_ADDRESSES && !PCAPIF_RECEIVE_PROMISCUOUS */ + + if (pcaipf_is_tx_packet(netif, packet, packet_len)) { + /* don't update counters here! */ + return NULL; + } + + unicast = ((dest->addr[0] & 0x01) == 0); +#if !PCAPIF_RECEIVE_PROMISCUOUS + /* MAC filter: only let my MAC or non-unicast through (pcap receives loopback traffic, too) */ + if (memcmp(dest, &netif->hwaddr, ETH_HWADDR_LEN) && +#if PCAPIF_FILTER_GROUP_ADDRESSES + (memcmp(dest, ipv4mcast, 3) || ((dest->addr[3] & 0x80) != 0)) && + memcmp(dest, ipv6mcast, 2) && + memcmp(dest, bcast, 6) +#else /* PCAPIF_FILTER_GROUP_ADDRESSES */ + unicast +#endif /* PCAPIF_FILTER_GROUP_ADDRESSES */ + ) { + /* don't update counters here! */ + return NULL; + } +#endif /* !PCAPIF_RECEIVE_PROMISCUOUS */ + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, (u16_t)length + ETH_PAD_SIZE, PBUF_POOL); + LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv length %i p->tot_len %i\n", length, (int)p->tot_len)); + + if (p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + start = 0; + for (q = p; q != NULL; q = q->next) { + u16_t copy_len = q->len; + /* Read enough bytes to fill this pbuf in the chain. The + available data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv start %i length %i q->payload %p q->len %i q->next %p\n", start, length, q->payload, (int)q->len, (void*)q->next)); + if (q == p) { +#if ETH_PAD_SIZE + LWIP_ASSERT("q->len >= ETH_PAD_SIZE", q->len >= ETH_PAD_SIZE); + copy_len -= ETH_PAD_SIZE; +#endif /* ETH_PAD_SIZE*/ + MEMCPY(&((char*)q->payload)[ETH_PAD_SIZE], &((const char*)packet)[start], copy_len); + } else { + MEMCPY(q->payload, &((const char*)packet)[start], copy_len); + } + start += copy_len; + length -= copy_len; + if (length <= 0) { + break; + } + } + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len - ETH_PAD_SIZE); + if (unicast) { + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } else { + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } + } else { + /* drop packet */ + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + + return p; +} + +#if PCAPIF_RX_REF +static void +pcapif_rx_pbuf_free_custom(struct pbuf *p) +{ + struct pcapif_pbuf_custom* ppc; + LWIP_ASSERT("NULL pointer", p != NULL); + ppc = (struct pcapif_pbuf_custom*)p; +#if PCAPIF_RX_READONLY + LWIP_ASSERT("NULL pointer", ppc->ro_mem != NULL); + pcapifh_free_readonly_mem(ppc->ro_mem); + ppc->ro_mem = NULL; +#else + LWIP_ASSERT("NULL pointer", ppc->p != NULL); + pbuf_free(ppc->p); + ppc->p = NULL; +#endif + mem_free(p); +} + +static struct pbuf* +pcapif_rx_ref(struct pbuf* p) +{ + struct pcapif_pbuf_custom* ppc; + struct pbuf* q; + u16_t len; + void *payload_mem; + + LWIP_ASSERT("NULL pointer", p != NULL); + LWIP_ASSERT("chained pbuf not supported here", p->next == NULL); + + ppc = (struct pcapif_pbuf_custom*)mem_malloc(sizeof(struct pcapif_pbuf_custom)); + LWIP_ASSERT("out of memory for RX", ppc != NULL); + ppc->pc.custom_free_function = pcapif_rx_pbuf_free_custom; + len = p->tot_len; +#if PCAPIF_RX_READONLY + payload_mem = pcapifh_alloc_readonly_copy(p->payload, len); + LWIP_ASSERT("out of readonly memory for RX", payload_mem != NULL); + pbuf_free(p); + ppc->ro_mem = payload_mem; +#else + ppc->p = p; + payload_mem = p->payload; +#endif + + q = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &ppc->pc, payload_mem, len); + LWIP_ASSERT("pbuf_alloced_custom returned NULL", q != NULL); + return q; +} +#endif /* PCAPIF_RX_REF */ + +/** pcapif_input: This function is called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that should + * handle the actual reception of bytes from the network interface. + */ +static void +pcapif_input(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *packet) +{ + struct pcapif_private *pa = (struct pcapif_private*)user; + int packet_len = pkt_header->caplen; + struct netif *netif = (struct netif *)pa->input_fn_arg; + struct pbuf *p; + + PCAPIF_RX_LOCK_LWIP(); + + /* move received packet into a new pbuf */ + p = pcapif_low_level_input(netif, packet, packet_len); + /* if no packet could be read, silently ignore this */ + if (p != NULL) { +#if PCAPIF_RX_REF + p = pcapif_rx_ref(p); +#endif + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + } + } + PCAPIF_RX_UNLOCK_LWIP(); +} + +/** + * pcapif_init(): initialization function, pass to netif_add(). + */ +err_t +pcapif_init(struct netif *netif) +{ + static int ethernetif_index; + + int local_index; + SYS_ARCH_DECL_PROTECT(lev); + + pcapifh_init_npcap(); + + SYS_ARCH_PROTECT(lev); + local_index = ethernetif_index++; + SYS_ARCH_UNPROTECT(lev); + + LWIP_ASSERT("pcapif needs an input callback", netif->input != NULL); + + netif->name[0] = IFNAME0; + netif->name[1] = (char)(IFNAME1 + local_index); + netif->linkoutput = pcapif_low_level_output; +#if LWIP_IPV4 +#if LWIP_ARP + netif->output = etharp_output; +#else /* LWIP_ARP */ + netif->output = NULL; /* not used for PPPoE */ +#endif /* LWIP_ARP */ +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif_set_hostname(netif, "lwip"); +#endif /* LWIP_NETIF_HOSTNAME */ + + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->flags |= NETIF_FLAG_MLD6; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + netif->hwaddr_len = ETH_HWADDR_LEN; + + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); + + /* sets link up or down based on current status */ + pcapif_low_level_init(netif); + + return ERR_OK; +} + +#if !PCAPIF_RX_USE_THREAD +void +pcapif_poll(struct netif *netif) +{ + struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); + + int ret; + do { + if (pa->adapter != NULL) { + ret = pcap_dispatch(pa->adapter, -1, pcapif_input, (u_char*)pa); + } else { + ret = -1; + } + if (ret < 0) { + /* error (e.g. adapter removed or resume from standby), try to reopen the adapter */ + pcap_reopen_adapter(pa); + } + } while (ret > 0); + +} +#endif /* !PCAPIF_RX_USE_THREAD */ + +#endif /* LWIP_ETHERNET */ diff --git a/contrib/ports/win32/pcapif.h b/contrib/ports/win32/pcapif.h new file mode 100644 index 0000000..8d67ea4 --- /dev/null +++ b/contrib/ports/win32/pcapif.h @@ -0,0 +1,32 @@ +#ifndef LWIP_PCAPIF_H +#define LWIP_PCAPIF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/err.h" + +/** Set to 1 to let rx use an own thread (only for NO_SYS==0). + * If set to 0, ethernetif_poll is used to poll for packets. + */ +#ifndef PCAPIF_RX_USE_THREAD +#define PCAPIF_RX_USE_THREAD !NO_SYS +#endif +#if PCAPIF_RX_USE_THREAD && NO_SYS +#error "Can't create a dedicated RX thread with NO_SYS==1" +#endif + +struct netif; + +err_t pcapif_init (struct netif *netif); +void pcapif_shutdown(struct netif *netif); +#if !PCAPIF_RX_USE_THREAD +void pcapif_poll (struct netif *netif); +#endif /* !PCAPIF_RX_USE_THREAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PCAPIF_H */ diff --git a/contrib/ports/win32/pcapif_helper.c b/contrib/ports/win32/pcapif_helper.c new file mode 100644 index 0000000..9cc889c --- /dev/null +++ b/contrib/ports/win32/pcapif_helper.c @@ -0,0 +1,172 @@ +/** + * pcapif_helper.c - This file is part of lwIP pcapif and provides helper functions + * for managing the link state. + */ + +#include "pcapif_helper.h" + +#include +#include + +#include "lwip/arch.h" + +#ifdef WIN32 + +#define WIN32_LEAN_AND_MEAN + +#ifdef _MSC_VER +#pragma warning( push, 3 ) +#endif +#include +#include +#include +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +struct pcapifh_linkstate { + LPADAPTER lpAdapter; + PPACKET_OID_DATA ppacket_oid_data; +}; + +struct pcapifh_linkstate* pcapifh_linkstate_init(char *adapter_name) +{ + struct pcapifh_linkstate* state = (struct pcapifh_linkstate*)malloc(sizeof(struct pcapifh_linkstate)); + if (state != NULL) { + memset(state, 0, sizeof(struct pcapifh_linkstate)); + state->ppacket_oid_data = (PPACKET_OID_DATA)malloc(sizeof(PACKET_OID_DATA) + sizeof(NDIS_MEDIA_STATE)); + if (state->ppacket_oid_data == NULL) { + free(state); + state = NULL; + } else { + state->lpAdapter = PacketOpenAdapter((char*)adapter_name); + if ((state->lpAdapter == NULL) || (state->lpAdapter->hFile == INVALID_HANDLE_VALUE)) { + /* failed to open adapter */ + free(state); + state = NULL; + } + } + } + return state; +} + +enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state) +{ + enum pcapifh_link_event ret = PCAPIF_LINKEVENT_UNKNOWN; + if (state != NULL) { + state->ppacket_oid_data->Oid = OID_GEN_MEDIA_CONNECT_STATUS; + state->ppacket_oid_data->Length = sizeof(NDIS_MEDIA_STATE); + if (PacketRequest(state->lpAdapter, FALSE, state->ppacket_oid_data)) { + NDIS_MEDIA_STATE fNdisMediaState; + fNdisMediaState = (*((PNDIS_MEDIA_STATE)(state->ppacket_oid_data->Data))); + ret = ((fNdisMediaState == NdisMediaStateConnected) ? PCAPIF_LINKEVENT_UP : PCAPIF_LINKEVENT_DOWN); + } + } + return ret; +} + +void pcapifh_linkstate_close(struct pcapifh_linkstate* state) +{ + if (state != NULL) { + if (state->lpAdapter != NULL) { + PacketCloseAdapter(state->lpAdapter); + } + if (state->ppacket_oid_data != NULL) { + free(state->ppacket_oid_data); + } + free(state); + } +} + +/** Helper function for PCAPIF_RX_READONLY for windows: copy the date to a new + * page which is set to READONLY after copying. + * This is a helper to simulate hardware that receives to memory that cannot be + * written by the CPU. + */ +void * +pcapifh_alloc_readonly_copy(void *data, size_t len) +{ + DWORD oldProtect; + void *ret; + if (len > 4096) { + lwip_win32_platform_diag("pcapifh_alloc_readonly_copy: invalid len: %d\n", len); + while(1); + } + ret = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE); + if (ret == NULL) { + lwip_win32_platform_diag("VirtualAlloc failed: %d\n", GetLastError()); + while(1); + } + memcpy(ret, data, len); + if (!VirtualProtect(ret, len, PAGE_READONLY, &oldProtect)) { + lwip_win32_platform_diag("VirtualProtect failed: %d\n", GetLastError()); + while(1); + } + return ret; +} + +void +pcapifh_free_readonly_mem(void *data) +{ + if (!VirtualFree(data, 0, MEM_RELEASE)) { + lwip_win32_platform_diag("VirtualFree(0x%08x) failed: %d\n", data, GetLastError()); + while(1); + } +} + +/** + * Npcap keeps its DLLs in a different directory for compatibility with winpcap. + * Make sure they get found by adding that directory to the DLL search path. + */ +void pcapifh_init_npcap(void) +{ + char npcap_dir[512]; + unsigned int len; + static char npcap_initialized = 0; + + if (!npcap_initialized) + { + npcap_initialized = 1; + + len = GetSystemDirectory(npcap_dir, 480); + if (!len) { + lwip_win32_platform_diag("Error in GetSystemDirectory: %x", GetLastError()); + return; + } + strcat_s(npcap_dir, 512, "\\Npcap"); + if (SetDllDirectory(npcap_dir) == 0) { + lwip_win32_platform_diag("Error in SetDllDirectory: %x", GetLastError()); + return; + } + } +} + +#else /* WIN32 */ + +/* @todo: add linux/unix implementation? */ + +struct pcapifh_linkstate { + u8_t empty; +}; + +struct pcapifh_linkstate* pcapifh_linkstate_init(char *adapter_name) +{ + LWIP_UNUSED_ARG(adapter_name); + return NULL; +} + +enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state) +{ + LWIP_UNUSED_ARG(state); + return PCAPIF_LINKEVENT_UP; +} +void pcapifh_linkstate_close(struct pcapifh_linkstate* state) +{ + LWIP_UNUSED_ARG(state); +} + +void pcapifh_init_npcap(void) +{ +} + +#endif /* WIN32 */ diff --git a/contrib/ports/win32/pcapif_helper.h b/contrib/ports/win32/pcapif_helper.h new file mode 100644 index 0000000..fd1c527 --- /dev/null +++ b/contrib/ports/win32/pcapif_helper.h @@ -0,0 +1,31 @@ +#ifndef LWIP_PCAPIF_HELPER_H +#define LWIP_PCAPIF_HELPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pcapifh_linkstate; + +enum pcapifh_link_event { + PCAPIF_LINKEVENT_UNKNOWN, + PCAPIF_LINKEVENT_UP, + PCAPIF_LINKEVENT_DOWN +}; + +struct pcapifh_linkstate* pcapifh_linkstate_init(char *adapter_name); +enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state); +void pcapifh_linkstate_close(struct pcapifh_linkstate* state); + +void *pcapifh_alloc_readonly_copy(void *data, size_t len); +void pcapifh_free_readonly_mem(void *data); + +void pcapifh_init_npcap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PCAPIF_HELPER_H */ diff --git a/contrib/ports/win32/readme.txt b/contrib/ports/win32/readme.txt new file mode 100644 index 0000000..87e09d0 --- /dev/null +++ b/contrib/ports/win32/readme.txt @@ -0,0 +1,26 @@ +lwIP for Win32 + +This is an example port of lwIP for Win32. It uses WinPCAP to send & receive packets. +To compile it, use the MSVC projects in the 'msvc' subdir, the CMake files, or the Makefile +in the 'mingw' subdir. + +For all compilers/build systems: +- you have to set an environment variable PCAP_DIR pointing to the WinPcap Developer's + Pack (containing 'include' and 'lib') + alternatively, place the WinPcap Developer's pack next to the "lwip" folder: + "winpcap\WpdPack" + +You also will have to copy the file 'contrib/examples/example_app/lwipcfg.h.example' to +'contrib/examples/example_app/lwipcfg.h' and modify to suit your needs (WinPcap adapter number, +IP configuration, applications...). + +Included in the contrib\ports\win32 directory is the network interface driver +using the winpcap library. + +lwIP: http://savannah.nongnu.org/projects/lwip/ +WinPCap: https://www.winpcap.org/devel.htm +Visual C++: http://www.microsoft.com/express/download/ + +To compile the unittests (msvc\lwIP_unittests.sln), download check (tested with v0.11.0) from +https://github.com/libcheck/check/releases/ +and place it in a folder "check" next to the "contrib" folder. diff --git a/contrib/ports/win32/sio.c b/contrib/ports/win32/sio.c new file mode 100644 index 0000000..0b64492 --- /dev/null +++ b/contrib/ports/win32/sio.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include +#include +#include + +#include +#include + +#ifdef _MSC_VER +#pragma warning (push, 3) +#endif +#include +#ifdef _MSC_VER +#pragma warning (pop) +#endif +#include "lwipcfg.h" + +/** When 1, use COM ports, when 0, use named pipes (for simulation). */ +#ifndef SIO_USE_COMPORT +#define SIO_USE_COMPORT 1 +#endif + +/** If SIO_USE_COMPORT==1, use COMx, if 0, use a pipe (default) */ +#if SIO_USE_COMPORT +#define SIO_DEVICENAME "\\\\.\\COM" +#else +#define SIO_DEVICENAME "\\\\.\\pipe\\lwip" +#endif + +#if SIO_USE_COMPORT +#ifndef SIO_COMPORT_SPEED +#define SIO_COMPORT_SPEED 115200 +#endif +#ifndef SIO_COMPORT_BYTESIZE +#define SIO_COMPORT_BYTESIZE 8 +#endif +#ifndef SIO_COMPORT_STOPBITS +#define SIO_COMPORT_STOPBITS 0 /* ONESTOPBIT */ +#endif +#ifndef SIO_COMPORT_PARITY +#define SIO_COMPORT_PARITY 0 /* NOPARITY */ +#endif +#endif /* SIO_USE_COMPORT */ + +static int sio_abort = 0; + +/* \\.\pipe\lwip0 */ +/* pppd /dev/ttyS0 logfile mylog debug nocrtscts local noauth noccp ms-dns 212.27.54.252 192.168.0.4:192.168.0.5 + */ + +/** + * SIO_DEBUG: Enable debugging for SIO. + */ +#ifndef SIO_DEBUG +#define SIO_DEBUG LWIP_DBG_OFF +#endif + +#if SIO_USE_COMPORT +/** When using a real COM port, set up the + * serial line settings (baudrate etc.) + */ +static BOOL +sio_setup(HANDLE fd) +{ + COMMTIMEOUTS cto; + DCB dcb; + + /* set up baudrate and other communication settings */ + memset(&dcb, 0, sizeof(dcb)); + /* Obtain the DCB structure for the device */ + if (!GetCommState(fd, &dcb)) { + return FALSE; + } + /* Set the new data */ + dcb.BaudRate = SIO_COMPORT_SPEED; + dcb.ByteSize = SIO_COMPORT_BYTESIZE; + dcb.StopBits = 0; /* ONESTOPBIT */ + dcb.Parity = 0; /* NOPARITY */ + dcb.fParity = 0; /* parity is not used */ + /* do not use flow control */ + /*dcb.fOutxDsrFlow = dcb.fDtrControl = 0; + dcb.fOutxCtsFlow = dcb.fRtsControl = 0; + dcb.fErrorChar = dcb.fNull = 0; + dcb.fInX = dcb.fOutX = 0; + dcb.XonChar = dcb.XoffChar = 0; + dcb.XonLim = dcb.XoffLim = 100;*/ + + /* Set the new DCB structure */ + if (!SetCommState(fd, &dcb)) { + return FALSE; + } + + memset(&cto, 0, sizeof(cto)); + if(!GetCommTimeouts(fd, &cto)) + { + return FALSE; + } + /* change read timeout, leave write timeout as it is */ + cto.ReadIntervalTimeout = 1; + cto.ReadTotalTimeoutMultiplier = 0; + cto.ReadTotalTimeoutConstant = 1; /* 1 ms */ + if(!SetCommTimeouts(fd, &cto)) { + return FALSE; + } + + return TRUE; +} +#endif /* SIO_USE_COMPORT */ + +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum) +{ + HANDLE fileHandle = INVALID_HANDLE_VALUE; + CHAR fileName[256]; + LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu)\n", (DWORD)devnum)); +#if SIO_USE_COMPORT + snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum)); +#else /* SIO_USE_COMPORT */ + snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum & ~1)); + if ((devnum & 1) == 0) { + fileHandle = CreateNamedPipeA(fileName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT, + PIPE_UNLIMITED_INSTANCES, 102400, 102400, 100, NULL); + } else +#endif /* SIO_USE_COMPORT */ + { + fileHandle = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + } + if (fileHandle != INVALID_HANDLE_VALUE) { + sio_abort = 0; +#if !SIO_USE_COMPORT + if (devnum & 1) { + DWORD mode = PIPE_NOWAIT; + if (!SetNamedPipeHandleState(fileHandle, &mode, NULL, NULL)) { + LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): SetNamedPipeHandleState failed. GetLastError() returns %d\n", + (DWORD)devnum, GetLastError())); + } + } else +#endif /* !SIO_USE_COMPORT */ + { + FlushFileBuffers(fileHandle); + } +#if SIO_USE_COMPORT + if(!sio_setup(fileHandle)) { + CloseHandle(fileHandle); + LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): sio_setup failed. GetLastError() returns %lu\n", + (DWORD)devnum, GetLastError())); + return NULL; + } +#endif /* SIO_USE_COMPORT */ + LWIP_DEBUGF(SIO_DEBUG, ("sio_open: file \"%s\" successfully opened.\n", fileName)); + printf("sio_open: file \"%s\" (%d) successfully opened: 0x%08x\n", fileName, devnum, LWIP_PTR_NUMERIC_CAST(unsigned int, fileHandle)); + return (sio_fd_t)(fileHandle); + } + LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu) failed. GetLastError() returns %lu\n", + (DWORD)devnum, GetLastError())); + printf("sio_open(%lu) failed. GetLastError() returns %lu\n", + (DWORD)devnum, GetLastError()); + return NULL; +} + +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd) +{ + DWORD dwNbBytesWritten = 0; + LWIP_DEBUGF(SIO_DEBUG, ("sio_send(%lu)\n", (DWORD)c)); + while ((!WriteFile((HANDLE)(fd), &c, 1, &dwNbBytesWritten, NULL)) || (dwNbBytesWritten < 1)) { + } +} + +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd) +{ + DWORD dwNbBytesReadden = 0; + u8_t byte = 0; + LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()\n")); + while ((sio_abort == 0) && ((!ReadFile((HANDLE)(fd), &byte, 1, &dwNbBytesReadden, NULL)) || (dwNbBytesReadden < 1))); + LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()=%lu\n", (DWORD)byte)); + return byte; +} + +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len) +{ + BOOL ret; + DWORD dwNbBytesReadden = 0; + LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n")); + ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL); + LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret)); + LWIP_UNUSED_ARG(ret); + return dwNbBytesReadden; +} + +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len) +{ + /* @todo: implement non-blocking read */ + BOOL ret; + DWORD dwNbBytesReadden = 0; + LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n")); + ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL); + LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret)); + LWIP_UNUSED_ARG(ret); + return dwNbBytesReadden; +} + +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, const u8_t* data, u32_t len) +{ + BOOL ret; + DWORD dwNbBytesWritten = 0; + LWIP_DEBUGF(SIO_DEBUG, ("sio_write()...\n")); + ret = WriteFile((HANDLE)(fd), data, len, &dwNbBytesWritten, NULL); + LWIP_DEBUGF(SIO_DEBUG, ("sio_write()=%lu bytes -> %d\n", dwNbBytesWritten, ret)); + LWIP_UNUSED_ARG(ret); + return dwNbBytesWritten; +} + +/** + * Aborts a blocking sio_read() call. + * @todo: This currently ignores fd and aborts all reads + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd) +{ + LWIP_UNUSED_ARG(fd); + LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort() !!!!!...\n")); + sio_abort = 1; + return; +} diff --git a/contrib/ports/win32/sys_arch.c b/contrib/ports/win32/sys_arch.c new file mode 100644 index 0000000..84f5775 --- /dev/null +++ b/contrib/ports/win32/sys_arch.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include +#include /* sprintf() for task names */ + +#ifdef _MSC_VER +#pragma warning (push, 3) +#endif +#include +#ifdef _MSC_VER +#pragma warning (pop) +#endif +#include + +#include +#include +#include +#include +#include +#include + +/** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is only + * called once in a call stack (calling it nested might cause trouble in some + * implementations, so let's avoid this in core code as long as we can). + */ +#ifndef LWIP_SYS_ARCH_CHECK_NESTED_PROTECT +#define LWIP_SYS_ARCH_CHECK_NESTED_PROTECT 1 +#endif + +/** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is *not* + * called before functions potentiolly involving the OS scheduler. + * + * This scheme is currently broken only for non-core-locking when waking up + * threads waiting on a socket via select/poll. + */ +#ifndef LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED +#define LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED LWIP_TCPIP_CORE_LOCKING +#endif + +#define LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER (LWIP_SYS_ARCH_CHECK_NESTED_PROTECT || LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED) + +/* These functions are used from NO_SYS also, for precise timer triggering */ +static LARGE_INTEGER freq, sys_start_time; +#define SYS_INITIALIZED() (freq.QuadPart != 0) + +static DWORD netconn_sem_tls_index; + +static HCRYPTPROV hcrypt; + +static void +sys_win_rand_init(void) +{ + if (!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, 0)) { + DWORD err = GetLastError(); + LWIP_PLATFORM_DIAG(("CryptAcquireContext failed with error %d, trying to create NEWKEYSET", (int)err)); + if(!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + char errbuf[128]; + err = GetLastError(); + snprintf(errbuf, sizeof(errbuf), "CryptAcquireContext failed with error %d", (int)err); + LWIP_UNUSED_ARG(err); + LWIP_ASSERT(errbuf, 0); + } + } +} + +unsigned int +lwip_port_rand(void) +{ + u32_t ret; + if (CryptGenRandom(hcrypt, sizeof(ret), (BYTE*)&ret)) { + return ret; + } + /* maybe CryptAcquireContext has not been called... */ + sys_win_rand_init(); + if (CryptGenRandom(hcrypt, sizeof(ret), (BYTE*)&ret)) { + return ret; + } + LWIP_ASSERT("CryptGenRandom failed", 0); + return 0; +} + +static void +sys_init_timing(void) +{ + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&sys_start_time); +} + +static LONGLONG +sys_get_ms_longlong(void) +{ + LONGLONG ret; + LARGE_INTEGER now; +#if NO_SYS + if (!SYS_INITIALIZED()) { + sys_init(); + LWIP_ASSERT("initialization failed", SYS_INITIALIZED()); + } +#endif /* NO_SYS */ + QueryPerformanceCounter(&now); + ret = now.QuadPart-sys_start_time.QuadPart; + return (u32_t)(((ret)*1000)/freq.QuadPart); +} + +u32_t +sys_jiffies(void) +{ + return (u32_t)sys_get_ms_longlong(); +} + +u32_t +sys_now(void) +{ + u32_t now = (u32_t)sys_get_ms_longlong(); +#ifdef LWIP_FUZZ_SYS_NOW + now += sys_now_offset; +#endif + return now; +} + +CRITICAL_SECTION critSec; +#if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER +static int protection_depth; +#endif + +static void +InitSysArchProtect(void) +{ + InitializeCriticalSection(&critSec); +} + +sys_prot_t +sys_arch_protect(void) +{ +#if NO_SYS + if (!SYS_INITIALIZED()) { + sys_init(); + LWIP_ASSERT("initialization failed", SYS_INITIALIZED()); + } +#endif + EnterCriticalSection(&critSec); +#if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT + LWIP_ASSERT("nested SYS_ARCH_PROTECT", protection_depth == 0); +#endif +#if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER + protection_depth++; +#endif + return 0; +} + +void +sys_arch_unprotect(sys_prot_t pval) +{ + LWIP_UNUSED_ARG(pval); +#if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT + LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth == 1); +#else + LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth > 0); +#endif +#if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER + protection_depth--; +#endif + LeaveCriticalSection(&critSec); +} + +#if LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED +/** This checks that SYS_ARCH_PROTECT() hasn't been called by protecting + * and then checking the level + */ +static void +sys_arch_check_not_protected(void) +{ + sys_arch_protect(); + LWIP_ASSERT("SYS_ARCH_PROTECT before scheduling", protection_depth == 1); + sys_arch_unprotect(0); +} +#else +#define sys_arch_check_not_protected() +#endif + +static void +msvc_sys_init(void) +{ + sys_win_rand_init(); + sys_init_timing(); + InitSysArchProtect(); + netconn_sem_tls_index = TlsAlloc(); + LWIP_ASSERT("TlsAlloc failed", netconn_sem_tls_index != TLS_OUT_OF_INDEXES); +} + +void +sys_init(void) +{ + msvc_sys_init(); +} + +#if !NO_SYS + +struct threadlist { + lwip_thread_fn function; + void *arg; + DWORD id; + struct threadlist *next; +}; + +static struct threadlist *lwip_win32_threads = NULL; + +err_t +sys_sem_new(sys_sem_t *sem, u8_t count) +{ + HANDLE new_sem = NULL; + + LWIP_ASSERT("sem != NULL", sem != NULL); + + new_sem = CreateSemaphore(0, count, 100000, 0); + LWIP_ASSERT("Error creating semaphore", new_sem != NULL); + if(new_sem != NULL) { + if (SYS_INITIALIZED()) { + SYS_ARCH_LOCKED(SYS_STATS_INC_USED(sem)); + } else { + SYS_STATS_INC_USED(sem); + } +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT("sys_sem_new() counter overflow", lwip_stats.sys.sem.used != 0); +#endif /* LWIP_STATS && SYS_STATS*/ + sem->sem = new_sem; + return ERR_OK; + } + + /* failed to allocate memory... */ + if (SYS_INITIALIZED()) { + SYS_ARCH_LOCKED(SYS_STATS_INC(sem.err)); + } else { + SYS_STATS_INC(sem.err); + } + sem->sem = NULL; + return ERR_MEM; +} + +void +sys_sem_free(sys_sem_t *sem) +{ + /* parameter check */ + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE); + CloseHandle(sem->sem); + + SYS_ARCH_LOCKED(SYS_STATS_DEC(sem.used)); +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT("sys_sem_free() closed more than created", lwip_stats.sys.sem.used != (u16_t)-1); +#endif /* LWIP_STATS && SYS_STATS */ + sem->sem = NULL; +} + +u32_t +sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + DWORD ret; + LONGLONG starttime, endtime; + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE); + if (!timeout) { + /* wait infinite */ + starttime = sys_get_ms_longlong(); + ret = WaitForSingleObject(sem->sem, INFINITE); + LWIP_ASSERT("Error waiting for semaphore", ret == WAIT_OBJECT_0); + endtime = sys_get_ms_longlong(); + /* return the time we waited for the sem */ + return (u32_t)(endtime - starttime); + } else { + starttime = sys_get_ms_longlong(); + ret = WaitForSingleObject(sem->sem, timeout); + LWIP_ASSERT("Error waiting for semaphore", (ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT)); + if (ret == WAIT_OBJECT_0) { + endtime = sys_get_ms_longlong(); + /* return the time we waited for the sem */ + return (u32_t)(endtime - starttime); + } else { + /* timeout */ + return SYS_ARCH_TIMEOUT; + } + } +} + +void +sys_sem_signal(sys_sem_t *sem) +{ + BOOL ret; + sys_arch_check_not_protected(); + LWIP_ASSERT("sem != NULL", sem != NULL); + LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); + LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE); + ret = ReleaseSemaphore(sem->sem, 1, NULL); + LWIP_ASSERT("Error releasing semaphore", ret != 0); + LWIP_UNUSED_ARG(ret); +} + +err_t +sys_mutex_new(sys_mutex_t *mutex) +{ + HANDLE new_mut = NULL; + + LWIP_ASSERT("mutex != NULL", mutex != NULL); + + new_mut = CreateMutex(NULL, FALSE, NULL); + LWIP_ASSERT("Error creating mutex", new_mut != NULL); + if (new_mut != NULL) { + SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mutex)); +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT("sys_mutex_new() counter overflow", lwip_stats.sys.mutex.used != 0); +#endif /* LWIP_STATS && SYS_STATS*/ + mutex->mut = new_mut; + return ERR_OK; + } + + /* failed to allocate memory... */ + SYS_ARCH_LOCKED(SYS_STATS_INC(mutex.err)); + mutex->mut = NULL; + return ERR_MEM; +} + +void +sys_mutex_free(sys_mutex_t *mutex) +{ + /* parameter check */ + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE); + CloseHandle(mutex->mut); + + SYS_ARCH_LOCKED(SYS_STATS_DEC(mutex.used)); +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT("sys_mutex_free() closed more than created", lwip_stats.sys.mutex.used != (u16_t)-1); +#endif /* LWIP_STATS && SYS_STATS */ + mutex->mut = NULL; +} + +void sys_mutex_lock(sys_mutex_t *mutex) +{ + DWORD ret; + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE); + /* wait infinite */ + ret = WaitForSingleObject(mutex->mut, INFINITE); + LWIP_ASSERT("Error waiting for mutex", ret == WAIT_OBJECT_0); + LWIP_UNUSED_ARG(ret); +} + +void +sys_mutex_unlock(sys_mutex_t *mutex) +{ + sys_arch_check_not_protected(); + LWIP_ASSERT("mutex != NULL", mutex != NULL); + LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); + LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE); + /* wait infinite */ + if (!ReleaseMutex(mutex->mut)) { + LWIP_ASSERT("Error releasing mutex", 0); + } +} + + +#ifdef _MSC_VER +const DWORD MS_VC_EXCEPTION=0x406D1388; +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; /* Must be 0x1000. */ + LPCSTR szName; /* Pointer to name (in user addr space). */ + DWORD dwThreadID; /* Thread ID (-1=caller thread). */ + DWORD dwFlags; /* Reserved for future use, must be zero. */ +} THREADNAME_INFO; +#pragma pack(pop) + +static void +SetThreadName(DWORD dwThreadID, const char* threadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + } +} +#else /* _MSC_VER */ +static void +SetThreadName(DWORD dwThreadID, const char* threadName) +{ + LWIP_UNUSED_ARG(dwThreadID); + LWIP_UNUSED_ARG(threadName); +} +#endif /* _MSC_VER */ + +static DWORD WINAPI +sys_thread_function(void* arg) +{ + struct threadlist* t = (struct threadlist*)arg; +#if LWIP_NETCONN_SEM_PER_THREAD + sys_arch_netconn_sem_alloc(); +#endif + t->function(t->arg); +#if LWIP_NETCONN_SEM_PER_THREAD + sys_arch_netconn_sem_free(); +#endif + return 0; +} + +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) +{ + struct threadlist *new_thread; + HANDLE h; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(stacksize); + LWIP_UNUSED_ARG(prio); + + new_thread = (struct threadlist*)malloc(sizeof(struct threadlist)); + LWIP_ASSERT("new_thread != NULL", new_thread != NULL); + if (new_thread != NULL) { + new_thread->function = function; + new_thread->arg = arg; + SYS_ARCH_PROTECT(lev); + new_thread->next = lwip_win32_threads; + lwip_win32_threads = new_thread; + + h = CreateThread(0, 0, sys_thread_function, new_thread, 0, &(new_thread->id)); + LWIP_ASSERT("h != 0", h != 0); + LWIP_ASSERT("h != -1", h != INVALID_HANDLE_VALUE); + LWIP_UNUSED_ARG(h); + SetThreadName(new_thread->id, name); + + SYS_ARCH_UNPROTECT(lev); + return new_thread->id; + } + return 0; +} + +#if !NO_SYS +#if LWIP_TCPIP_CORE_LOCKING + +static DWORD lwip_core_lock_holder_thread_id; + +void +sys_lock_tcpip_core(void) +{ + sys_mutex_lock(&lock_tcpip_core); + lwip_core_lock_holder_thread_id = GetCurrentThreadId(); +} + +void +sys_unlock_tcpip_core(void) +{ + lwip_core_lock_holder_thread_id = 0; + sys_mutex_unlock(&lock_tcpip_core); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +static DWORD lwip_tcpip_thread_id; + +void +sys_mark_tcpip_thread(void) +{ + lwip_tcpip_thread_id = GetCurrentThreadId(); +} + +void +sys_check_core_locking(void) +{ + /* Embedded systems should check we are NOT in an interrupt context here */ + + if (lwip_tcpip_thread_id != 0) { + DWORD current_thread_id = GetCurrentThreadId(); + +#if LWIP_TCPIP_CORE_LOCKING + LWIP_ASSERT("Function called without core lock", current_thread_id == lwip_core_lock_holder_thread_id); +#else /* LWIP_TCPIP_CORE_LOCKING */ + LWIP_ASSERT("Function called from wrong thread", current_thread_id == lwip_tcpip_thread_id); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + LWIP_UNUSED_ARG(current_thread_id); /* for LWIP_NOASSERT */ + } +} +#endif /* !NO_SYS */ + +err_t +sys_mbox_new(sys_mbox_t *mbox, int size) +{ + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_UNUSED_ARG(size); + + mbox->sem = CreateSemaphore(0, 0, MAX_QUEUE_ENTRIES, 0); + LWIP_ASSERT("Error creating semaphore", mbox->sem != NULL); + if (mbox->sem == NULL) { + SYS_ARCH_LOCKED(SYS_STATS_INC(mbox.err)); + return ERR_MEM; + } + memset(&mbox->q_mem, 0, sizeof(u32_t)*MAX_QUEUE_ENTRIES); + mbox->head = 0; + mbox->tail = 0; + SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mbox)); +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT("sys_mbox_new() counter overflow", lwip_stats.sys.mbox.used != 0); +#endif /* LWIP_STATS && SYS_STATS */ + return ERR_OK; +} + +void +sys_mbox_free(sys_mbox_t *mbox) +{ + /* parameter check */ + LWIP_ASSERT("mbox != NULL", mbox != NULL); + LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL); + LWIP_ASSERT("mbox->sem != INVALID_HANDLE_VALUE", mbox->sem != INVALID_HANDLE_VALUE); + + CloseHandle(mbox->sem); + + SYS_STATS_DEC(mbox.used); +#if LWIP_STATS && SYS_STATS + LWIP_ASSERT( "sys_mbox_free() ", lwip_stats.sys.mbox.used != (u16_t)-1); +#endif /* LWIP_STATS && SYS_STATS */ + mbox->sem = NULL; +} + +void +sys_mbox_post(sys_mbox_t *q, void *msg) +{ + BOOL ret; + SYS_ARCH_DECL_PROTECT(lev); + sys_arch_check_not_protected(); + + /* parameter check */ + LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); + LWIP_ASSERT("q->sem != NULL", q->sem != NULL); + LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); + + SYS_ARCH_PROTECT(lev); + q->q_mem[q->head] = msg; + q->head++; + if (q->head >= MAX_QUEUE_ENTRIES) { + q->head = 0; + } + LWIP_ASSERT("mbox is full!", q->head != q->tail); + ret = ReleaseSemaphore(q->sem, 1, 0); + LWIP_ASSERT("Error releasing sem", ret != 0); + LWIP_UNUSED_ARG(ret); + + SYS_ARCH_UNPROTECT(lev); +} + +err_t +sys_mbox_trypost(sys_mbox_t *q, void *msg) +{ + u32_t new_head; + BOOL ret; + SYS_ARCH_DECL_PROTECT(lev); + sys_arch_check_not_protected(); + + /* parameter check */ + LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); + LWIP_ASSERT("q->sem != NULL", q->sem != NULL); + LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); + + SYS_ARCH_PROTECT(lev); + + new_head = q->head + 1; + if (new_head >= MAX_QUEUE_ENTRIES) { + new_head = 0; + } + if (new_head == q->tail) { + SYS_ARCH_UNPROTECT(lev); + return ERR_MEM; + } + + q->q_mem[q->head] = msg; + q->head = new_head; + LWIP_ASSERT("mbox is full!", q->head != q->tail); + ret = ReleaseSemaphore(q->sem, 1, 0); + LWIP_ASSERT("Error releasing sem", ret != 0); + LWIP_UNUSED_ARG(ret); + + SYS_ARCH_UNPROTECT(lev); + return ERR_OK; +} + +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg) +{ + return sys_mbox_trypost(q, msg); +} + +u32_t +sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout) +{ + DWORD ret; + LONGLONG starttime, endtime; + SYS_ARCH_DECL_PROTECT(lev); + + /* parameter check */ + LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); + LWIP_ASSERT("q->sem != NULL", q->sem != NULL); + LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); + + if (timeout == 0) { + timeout = INFINITE; + } + starttime = sys_get_ms_longlong(); + ret = WaitForSingleObject(q->sem, timeout); + if (ret == WAIT_OBJECT_0) { + SYS_ARCH_PROTECT(lev); + if (msg != NULL) { + *msg = q->q_mem[q->tail]; + } + + q->tail++; + if (q->tail >= MAX_QUEUE_ENTRIES) { + q->tail = 0; + } + SYS_ARCH_UNPROTECT(lev); + endtime = sys_get_ms_longlong(); + return (u32_t)(endtime - starttime); + } else { + LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT); + if (msg != NULL) { + *msg = NULL; + } + + return SYS_ARCH_TIMEOUT; + } +} + +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg) +{ + DWORD ret; + SYS_ARCH_DECL_PROTECT(lev); + + /* parameter check */ + LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); + LWIP_ASSERT("q->sem != NULL", q->sem != NULL); + LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); + + ret = WaitForSingleObject(q->sem, 0); + if (ret == WAIT_OBJECT_0) { + SYS_ARCH_PROTECT(lev); + if (msg != NULL) { + *msg = q->q_mem[q->tail]; + } + + q->tail++; + if (q->tail >= MAX_QUEUE_ENTRIES) { + q->tail = 0; + } + SYS_ARCH_UNPROTECT(lev); + return 0; + } else { + LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT); + if (msg != NULL) { + *msg = NULL; + } + + return SYS_MBOX_EMPTY; + } +} + +#if LWIP_NETCONN_SEM_PER_THREAD +sys_sem_t* +sys_arch_netconn_sem_get(void) +{ + LPVOID tls_data = TlsGetValue(netconn_sem_tls_index); + return (sys_sem_t*)tls_data; +} + +void +sys_arch_netconn_sem_alloc(void) +{ + sys_sem_t *sem; + err_t err; + BOOL done; + + sem = (sys_sem_t*)malloc(sizeof(sys_sem_t)); + LWIP_ASSERT("failed to allocate memory for TLS semaphore", sem != NULL); + err = sys_sem_new(sem, 0); + LWIP_ASSERT("failed to initialise TLS semaphore", err == ERR_OK); + done = TlsSetValue(netconn_sem_tls_index, sem); + LWIP_UNUSED_ARG(done); + LWIP_ASSERT("failed to initialise TLS semaphore storage", done == TRUE); +} + +void +sys_arch_netconn_sem_free(void) +{ + LPVOID tls_data = TlsGetValue(netconn_sem_tls_index); + if (tls_data != NULL) { + BOOL done; + free(tls_data); + done = TlsSetValue(netconn_sem_tls_index, NULL); + LWIP_UNUSED_ARG(done); + LWIP_ASSERT("failed to de-init TLS semaphore storage", done == TRUE); + } +} +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#endif /* !NO_SYS */ + +/* get keyboard state to terminate the debug app on any kbhit event using win32 API */ +int +lwip_win32_keypressed(void) +{ + INPUT_RECORD rec; + DWORD num = 0; + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + BOOL ret = PeekConsoleInput(h, &rec, 1, &num); + if (ret && num) { + ReadConsoleInput(h, &rec, 1, &num); + if (rec.EventType == KEY_EVENT) { + if (rec.Event.KeyEvent.bKeyDown) { + /* not a special key? */ + if (rec.Event.KeyEvent.uChar.AsciiChar != 0) { + return 1; + } + } + } + } + return 0; +} + +#include + +/* This is an example implementation for LWIP_PLATFORM_DIAG: + * format a string and pass it to your output function. + */ +void +lwip_win32_platform_diag(const char *format, ...) +{ + va_list ap; + /* get the varargs */ + va_start(ap, format); + /* print via varargs; to use another output function, you could use + vsnprintf here */ + vprintf(format, ap); + va_end(ap); +} diff --git a/doc/FILES b/doc/FILES index e588575..155a82c 100644 --- a/doc/FILES +++ b/doc/FILES @@ -3,7 +3,4 @@ doxygen/ - Configuration files and scripts to create the lwIP doxygen sour savannah.txt - How to obtain the current development source code. contrib.txt - How to contribute to lwIP as a developer. -rawapi.txt - The documentation for the core API of lwIP. - Also provides an overview about the other APIs and multithreading. -sys_arch.txt - The documentation for a system abstraction layer of lwIP. ppp.txt - Documentation of the PPP interface for lwIP. diff --git a/doc/NO_SYS_SampleCode.c b/doc/NO_SYS_SampleCode.c index 71f1c9f..b263420 100644 --- a/doc/NO_SYS_SampleCode.c +++ b/doc/NO_SYS_SampleCode.c @@ -73,7 +73,6 @@ main(void) netif.name[0] = 'e'; netif.name[1] = '0'; netif_create_ip6_linklocal_address(&netif, 1); - netif.ip6_autoconfig_enabled = 1; netif_set_status_callback(&netif, netif_status_callback); netif_set_default(&netif); netif_set_up(&netif); diff --git a/doc/ZeroCopyRx.c b/doc/ZeroCopyRx.c index 0e8219b..600b13a 100644 --- a/doc/ZeroCopyRx.c +++ b/doc/ZeroCopyRx.c @@ -13,7 +13,7 @@ void my_pbuf_free_custom(void* p) my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p; // invalidate data cache here - lwIP and/or application may have written into buffer! - // (invalidate is faster than flushing, and noone needs the correct data in the buffer) + // (invalidate is faster than flushing, and no one needs the correct data in the buffer) invalidate_cpu_cache(p->payload, p->tot_len); SYS_ARCH_PROTECT(old_level); diff --git a/doc/contrib.txt b/doc/contrib.txt index 6f0d7bc..2a44857 100644 --- a/doc/contrib.txt +++ b/doc/contrib.txt @@ -55,4 +55,4 @@ features of Savannah help us not lose users' input. 1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and you think it could benefit others[1] you might want discuss this on the mailing list. You - can also ask for Git access to submit and maintain your port in the contrib Git module. + can also ask for Git access to submit and maintain your port in the lwIP/contrib subdir. diff --git a/doc/doxygen/lwip.Doxyfile b/doc/doxygen/lwip.Doxyfile index 3477722..f68fa0c 100644 --- a/doc/doxygen/lwip.Doxyfile +++ b/doc/doxygen/lwip.Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "lwIP" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "2.1.3" +PROJECT_NUMBER = "2.2.1" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -762,7 +762,7 @@ WARN_NO_PARAMDOC = NO # a warning is encountered. # The default value is: NO. -WARN_AS_ERROR = NO +WARN_AS_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -2205,12 +2205,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2224,15 +2218,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/doc/doxygen/lwip.Doxyfile.cmake.in b/doc/doxygen/lwip.Doxyfile.cmake.in index 063c288..7bc0ce0 100644 --- a/doc/doxygen/lwip.Doxyfile.cmake.in +++ b/doc/doxygen/lwip.Doxyfile.cmake.in @@ -762,7 +762,7 @@ WARN_NO_PARAMDOC = NO # a warning is encountered. # The default value is: NO. -WARN_AS_ERROR = NO +WARN_AS_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -2205,12 +2205,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2224,15 +2218,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/doc/doxygen/main_page.h b/doc/doxygen/main_page.h index 06b7937..4766c3a 100644 --- a/doc/doxygen/main_page.h +++ b/doc/doxygen/main_page.h @@ -2,14 +2,14 @@ * @defgroup lwip lwIP * * @defgroup infrastructure Infrastructure - * + * * @defgroup api APIs * lwIP provides three Application Program's Interfaces (APIs) for programs * to use for communication with the TCP/IP code: * - low-level "core" / "callback" or @ref callbackstyle_api. * - higher-level @ref sequential_api. * - BSD-style @ref socket. - * + * * The raw TCP/IP interface allows the application program to integrate * better with the TCP/IP code. Program execution is event based by * having callback functions being called from within the TCP/IP @@ -17,23 +17,23 @@ * thread. The sequential API has a much higher overhead and is not very * well suited for small systems since it forces a multithreaded paradigm * on the application. - * + * * The raw TCP/IP interface is not only faster in terms of code execution * time but is also less memory intensive. The drawback is that program * development is somewhat harder and application programs written for * the raw TCP/IP interface are more difficult to understand. Still, this * is the preferred way of writing applications that should be small in * code size and memory usage. - * + * * All APIs can be used simultaneously by different application * programs. In fact, the sequential API is implemented as an application * program using the raw TCP/IP interface. - * + * * Do not confuse the lwIP raw API with raw Ethernet or IP sockets. * The former is a way of interfacing the lwIP network stack (including * TCP and UDP), the latter refers to processing raw Ethernet or IP data * instead of TCP connections or UDP packets. - * + * * Raw API applications may never block since all packet processing * (input and output) as well as timer processing (TCP mainly) is done * in a single execution context. @@ -59,7 +59,7 @@ * receive. This API is also used by the core stack for interaction between * the various protocols. It is the only API available when running lwIP * without an operating system. - * + * * @defgroup sequential_api Sequential-style APIs * @ingroup api * Sequential-style APIs, blocking functions. More overhead, but can be called @@ -70,22 +70,22 @@ * paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP * code and the application program must reside in different execution * contexts (threads). - * + * * @defgroup socket Socket API * @ingroup api - * BSD-style socket API.\n - * Thread-safe, to be called from non-TCPIP threads only.\n - * Can be activated by defining @ref LWIP_SOCKET to 1.\n - * Header is in posix/sys/socket.h\n + * BSD-style socket API.
+ * Thread-safe, to be called from non-TCPIP threads only.
+ * Can be activated by defining @ref LWIP_SOCKET to 1.
+ * Header is in posix/sys/socket.h
* The socket API is a compatibility API for existing applications, * currently it is built on top of the sequential API. It is meant to * provide all functions needed to run socket API applications running * on other platforms (e.g. unix / windows etc.). However, due to limitations * in the specification of this API, there might be incompatibilities * that require small modifications of existing programs. - * + * * @defgroup netifs NETIFs - * + * * @defgroup apps Applications */ @@ -112,7 +112,7 @@ * * Add sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr() * (for FreeRTOS, mainly) * * socket API: support poll(), sendmsg() and recvmsg(); fix problems on close - * + * * Detailed Changelog * ------------------ * @verbinclude "CHANGELOG" @@ -123,6 +123,11 @@ * @verbinclude "contrib.txt" */ +/** + * @page cmake CMake build system + * @verbinclude "BUILDING" + */ + /** * @page pitfalls Common pitfalls * @@ -131,21 +136,21 @@ * * The most common source of lwIP problems is to have multiple execution contexts * inside the lwIP code. - * - * lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS + * + * lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS * running on target system) or @ref lwip_os (there is an OS running * on the target system). - * + * * See also: @ref multithreading (especially the part about @ref LWIP_ASSERT_CORE_LOCKED()!) * * Mainloop Mode * ------------- * In mainloop mode, only @ref callbackstyle_api can be used. - * The user has two possibilities to ensure there is only one - * exection context at a time in lwIP: + * The user has two possibilities to ensure there is only one + * execution context at a time in lwIP: * * 1) Deliver RX ethernet packets directly in interrupt context to lwIP - * by calling netif->input directly in interrupt. This implies all lwIP + * by calling netif->input directly in interrupt. This implies all lwIP * callback functions are called in IRQ context, which may cause further * problems in application code: IRQ is blocked for a long time, multiple * execution contexts in application code etc. When the application wants @@ -171,12 +176,12 @@ * implemented in tcpip_input().​​ * Again, ensure lwIP is _NEVER_ called from an interrupt, e.g. * some SPI IRQ wants to forward data to udp_send() or tcp_write()! - * + * * 1) tcpip_callback() can be used get called back from TCPIP thread, * it is safe to call any @ref callbackstyle_api from there. * * 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api - * functions can be called when lwIP core lock is aquired, see + * functions can be called when lwIP core lock is acquired, see * @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE(). * These macros cannot be used in an interrupt context! * Note the OS must correctly handle priority inversion for this. @@ -186,7 +191,7 @@ * * DMA-capable ethernet hardware and zero-copy RX * ---------------------------------------------- - * + * * lwIP changes the content of RECEIVED pbufs in the TCP code path. * This implies one or more cacheline(s) of the RX pbuf become dirty * and need to be flushed before the memory is handed over to the @@ -207,7 +212,7 @@ /** * @page mem_err Debugging memory pool sizes * If you have issues with lwIP and you are using memory pools, check that your pools - * are correctly sized.\n + * are correctly sized.
* To debug pool sizes, \#define LWIP_STATS and MEMP_STATS to 1. Check the global variable * lwip_stats.memp[] using a debugger. If the "err" member of a pool is > 0, the pool * may be too small for your application and you need to increase its size. @@ -215,8 +220,8 @@ /** * @page bugs Reporting bugs - * Please report bugs in the lwIP bug tracker at savannah.\n - * BEFORE submitting, please check if the bug has already been reported!\n + * Please report bugs in the lwIP bug tracker at savannah.
+ * BEFORE submitting, please check if the bug has already been reported!
* https://savannah.nongnu.org/bugs/?group=lwip */ @@ -232,12 +237,12 @@ * Use this mode if you do not run an OS on your system. \#define NO_SYS to 1. * Feed incoming packets to netif->input(pbuf, netif) function from mainloop, * *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt - * context and put them into a queue which is processed from mainloop.\n - * Call sys_check_timeouts() periodically in the mainloop.\n - * Porting: implement all functions in @ref sys_time, @ref sys_prot and - * @ref compiler_abstraction.\n - * You can only use @ref callbackstyle_api in this mode.\n - * Sample code:\n + * context and put them into a queue which is processed from mainloop.
+ * Call sys_check_timeouts() periodically in the mainloop.
+ * Porting: implement all functions in @ref sys_time, @ref sys_prot and + * @ref compiler_abstraction.
+ * You can only use @ref callbackstyle_api in this mode.
+ * Sample code: * @include NO_SYS_SampleCode.c */ @@ -246,14 +251,14 @@ * @ingroup lwip * Use this mode if you run an OS on your system. It is recommended to * use an RTOS that correctly handles priority inversion and - * to use @ref LWIP_TCPIP_CORE_LOCKING.\n - * Porting: implement all functions in @ref sys_layer.\n + * to use @ref LWIP_TCPIP_CORE_LOCKING.
+ * Porting: implement all functions in @ref sys_layer.
* You can use @ref callbackstyle_api together with @ref tcpip_callback, * and all @ref sequential_api. */ /** - * @page sys_init System initalization + * @page sys_init System initialization A truly complete and generic sequence for initializing the lwIP stack cannot be given because it depends on additional initializations for your runtime environment (e.g. timers). @@ -274,12 +279,12 @@ Call these functions in the order of appearance: The init function pointer must point to a initialization function for your Ethernet netif interface. The following code illustrates its use. - + @code{.c} err_t netif_if_init(struct netif *netif) { u8_t i; - + for (i = 0; i < ETHARP_HWADDR_LEN; i++) { netif->hwaddr[i] = some_eth_addr[i]; } @@ -287,11 +292,11 @@ Call these functions in the order of appearance: return ERR_OK; } @endcode - + For Ethernet drivers, the input function pointer must point to the lwIP function ethernet_input() declared in "netif/etharp.h". Other drivers must use ip_input() declared in "lwip/ip.h". - + - netif_set_default(struct netif *netif) Registers the default network interface. @@ -326,7 +331,7 @@ Call these functions in the order of appearance: * from pbuf- and memory management functions). Application threads using * the sequential- or socket API communicate with this main thread through * message passing. - * + * * As such, the list of functions that may be called from * other threads or an ISR is very limited! Only functions * from these API header files are thread-safe: @@ -337,43 +342,43 @@ Call these functions in the order of appearance: * - pppapi.h * - sockets.h * - sys.h - * - * Additionaly, memory (de-)allocation functions may be + * + * Additionally, memory (de-)allocation functions may be * called from multiple threads (not ISR!) with NO_SYS=0 * since they are protected by @ref SYS_LIGHTWEIGHT_PROT and/or * semaphores. - * + * * Netconn or Socket API functions are thread safe against the * core thread but they are not reentrant at the control block * granularity level. That is, a UDP or TCP control block must * not be shared among multiple threads without proper locking. - * + * * If @ref SYS_LIGHTWEIGHT_PROT is set to 1 and * @ref LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, * pbuf_free() may also be called from another thread or * an ISR (since only then, mem_free - for PBUF_RAM - may * be called from an ISR: otherwise, the HEAP is only * protected by semaphores). - * + * * How to get threading done right * ------------------------------- - * + * * It is strongly recommended to implement the LWIP_ASSERT_CORE_LOCKED() * macro in an application that uses multithreading. lwIP code has * several places where a check for a correct thread context is * implemented which greatly helps the user to get threading done right. - * See the example sys_arch.c files in unix and Win32 port - * in the contrib repository. - * - * In short: Copy the functions sys_mark_tcpip_thread() and + * See the example sys_arch.c files in unix and Win32 port + * in the lwIP/contrib subdirectory. + * + * In short: Copy the functions sys_mark_tcpip_thread() and * sys_check_core_locking() to your port and modify them to work with your OS. * Then let @ref LWIP_ASSERT_CORE_LOCKED() and @ref LWIP_MARK_TCPIP_THREAD() * point to these functions. - * + * * If you use @ref LWIP_TCPIP_CORE_LOCKING, you also need to copy and adapt * the functions sys_lock_tcpip_core() and sys_unlock_tcpip_core(). - * Let @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE() point - * to these functions. + * Let @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE() point + * to these functions. */ /** diff --git a/doc/mdns.txt b/doc/mdns.txt index 0c28970..12ac04b 100644 --- a/doc/mdns.txt +++ b/doc/mdns.txt @@ -45,7 +45,7 @@ This opens UDP sockets on port 5353 for IPv4 and IPv6. To start responding on a netif, run - mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl) + mdns_resp_add_netif(struct netif *netif, const char *hostname) The hostname will be copied. If this returns successfully, the netif will join the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast @@ -53,7 +53,6 @@ to port 5353 will be handled: - .local type A, AAAA or ANY returns relevant IP addresses - Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses returns .local -Answers will use the supplied TTL (in seconds) MDNS allows UTF-8 names, but it is recommended to stay within ASCII, since the default case-insensitive comparison assumes this. @@ -71,8 +70,8 @@ Adding services: ================ The netif first needs to be registered. Then run - mdns_resp_add_service(struct netif *netif, char *name, char *service, - u16_t proto, u16_t port, u32_t dns_ttl, + mdns_resp_add_service(struct netif *netif, const char *name, const char *service, + enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_userdata); The name and service pointers will be copied. Name refers to the name of the @@ -100,7 +99,7 @@ If this call returns successfully, the following queries will be answered: If your device runs a webserver on port 80, an example call might be: mdns_resp_add_service(netif, "myweb", "_http" - DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL); + DNSSD_PROTO_TCP, 80, srv_txt, NULL); which will publish myweb._http._tcp.local for any hosts looking for web servers, and point them to .local:80 @@ -109,4 +108,4 @@ Relevant information will be sent as additional records to reduce number of requests required from a client. To remove a service from a netif, run - mdns_resp_del_service(struct netif *netif, s8_t slot) \ No newline at end of file + mdns_resp_del_service(struct netif *netif, u8_t slot) diff --git a/doc/mqtt_client.txt b/doc/mqtt_client.txt index 7fd93a8..d189a35 100644 --- a/doc/mqtt_client.txt +++ b/doc/mqtt_client.txt @@ -3,11 +3,13 @@ MQTT client for lwIP Author: Erik Andersson Details of the MQTT protocol can be found at: -http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html +http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html ----------------------------------------------------------------- 1. Initial steps, reserve memory and make connection to server: +You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MQTT! + 1.1: Provide storage Static allocation: @@ -19,34 +21,34 @@ Dynamic allocation: if(client != NULL) { example_do_connect(&client); } - + 1.2: Establish Connection with server void example_do_connect(mqtt_client_t *client) { struct mqtt_connect_client_info_t ci; err_t err; - + /* Setup an empty client info structure */ memset(&ci, 0, sizeof(ci)); - - /* Minimal amount of information required is client identifier, so set it here */ + + /* Minimal amount of information required is client identifier, so set it here */ ci.client_id = "lwip_test"; - + /* Initiate client and connect to server, if this fails immediately an error code is returned - otherwise mqtt_connection_cb will be called with connection result after attempting - to establish a connection with the server. + otherwise mqtt_connection_cb will be called with connection result after attempting + to establish a connection with the server. For now MQTT version 3.1.1 is always used */ - + err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci); - + /* For now just print the result code if something goes wrong */ if(err != ERR_OK) { printf("mqtt_connect return %d\n", err); } } -Connection to server can also be probed by calling mqtt_client_is_connected(client) +Connection to server can also be probed by calling mqtt_client_is_connected(client) ----------------------------------------------------------------- 2. Implementing the connection status callback @@ -57,11 +59,11 @@ static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection err_t err; if(status == MQTT_CONNECT_ACCEPTED) { printf("mqtt_connection_cb: Successfully connected\n"); - + /* Setup callback for incoming publish requests */ mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg); - - /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ + + /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg); if(err != ERR_OK) { @@ -69,16 +71,16 @@ static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection } } else { printf("mqtt_connection_cb: Disconnected, reason: %d\n", status); - + /* Its more nice to be connected, so try to reconnect */ example_do_connect(client); - } + } } static void mqtt_sub_request_cb(void *arg, err_t result) { - /* Just print the result code here for simplicity, - normal behaviour would be to take some action if subscribe fails like + /* Just print the result code here for simplicity, + normal behaviour would be to take some action if subscribe fails like notifying user, retry subscribe or disconnect from server */ printf("Subscribe result: %d\n", result); } @@ -148,7 +150,7 @@ void example_publish(mqtt_client_t *client, void *arg) } } -/* Called when publish is complete either with sucess or failure */ +/* Called when publish is complete either with success or failure */ static void mqtt_pub_request_cb(void *arg, err_t result) { if(result != ERR_OK) { diff --git a/doc/ppp.txt b/doc/ppp.txt index 8b88b3a..a713cc5 100644 --- a/doc/ppp.txt +++ b/doc/ppp.txt @@ -195,7 +195,7 @@ static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) { * * Return value: len if write succeed */ -static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { +static u32_t output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx) { return uart_write(UART, data, len); } @@ -404,7 +404,7 @@ really know what you are doing, your move ;-) /* - * Fonction to call for received data + * Function to call for received data * * ppp, PPP control block * buffer, input buffer diff --git a/doc/savannah.txt b/doc/savannah.txt index a98418d..1665999 100644 --- a/doc/savannah.txt +++ b/doc/savannah.txt @@ -102,14 +102,16 @@ Archive the current directory using tar, gzip'd, bzip2'd and zip'd. tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1 zip -r lwip-1.4.1.zip lwip-1.4.1 +Alternatively, archive the current directory using git + git archive -o lwip-1.4.1.tar.gz --prefix lwip-1.4.1/ STABLE-1_4_1 + Now, sign the archives with a detached GPG binary signature as follows: gpg -b lwip-1.4.1.tar.gz gpg -b lwip-1.4.1.tar.bz2 gpg -b lwip-1.4.1.zip -Upload these files using anonymous FTP: - ncftp ftp://savannah.gnu.org/incoming/savannah/lwip - ncftp> mput *1.4.1.* +Upload these files using scp: + scp lwip-1.4.1.* @dl.sv.nongnu.org:/releases/lwip/ Additionally, you may post a news item on Savannah, like this: diff --git a/lwip-2.1.3.tar.xz b/lwip-2.1.3.tar.xz deleted file mode 100644 index 9f897f7cd3ef410487b4019bde4f0591c8855eea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4192506 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

i#rj9?%G;erhXw!o*# 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 z zAB4TDY<-PQ6jz&HAXpmoujF~WnT9*~D!dH28V!Ns@xawR!>&kqF$GF4(yaz*lM;f* zp8Vbb$Vs{laXNcQQ6PNF&~NjK{E8Xkf+g?JxfX8|#etqjnkmX|C#|slC4_LNMHG`d zN~$+xpIJLWi3zG?zD^eK;UyB9&SIVPX1C zy6Y98p~b9YcTUa!kAW6M$^ewPs8DDE=g2Ft6C@)-U}iE~IbF7&rv+T%)Rp}om>$E= zzhptnepo0m(E<+Yn1p#RBH_SaQTs%~{4f*CUmdhCDP;yt6m=QGBB51dUK9jqDhlP$ zK#;-Oku!J1TV1B}l&4ZLK%bzL0gFwN_+b%A9XsabmwM~Z}Kkb@Jl@q@9^j|N9H_oN1&$=0?0+g z>4;JwgM87gihr^v@sSIOpCq#Fj1Qo10W zdGQ;fOK{=W!U;xWfYN<@<%Od$C7du_;<1M@Ff3CxmyX5=_SO$Dgp6kRLNUw?VIhcg z^uR;?H7el&G~$^7Lv+Eg^!D7gx&UWzD1&#_1A2*Sz8x)2u0ChVC{P(l(5!S`ZGD?`AHu8|C5LXuhg#a|SpaHS zHdZJuL_g+KFak@MyjM}Jl(Q5>cCd%-i_$C(`Cb9>H9|%zBWMb#D4wN{g}fzo-L46+ zQc2tE@9?H0R8T~@c(IFWm_Sf_+v9ON#t-*hcF2!wCrd$*?nbz1j00A#T5b~T${xTW zqLd#2poXnt>2OiTr=*Vhag0w_3v`YX!f0pfj!Ogk#nlFX>FO;mFSDb$%`>di!mBxMf3 zO-Qyv?;Hs<6Y}h+fDjgdrxt4A^laA<3ker<^S9kdBsQU_gQIU0#$}c;`s+2$YdY8d zX}l#1%qO9!Me7|?o-N+x9=@ca42Z{QVNY0{QZV@sfkR!U$VGlaxgzRX&^ahV3VgeH zt>SR(ekdirz1LQ79J4$F?xR5d*`5Ss2r77sd`u1LlzFmMr`mQtG|x&dT^SEDZb4+6 z#}-{t^&N=PoDNBorqZ|iQGI>;HH?>A+V?*t=cm6)&4fJRek~aMitAh@Mm9Ocrbe(Ctc+{S@J>F zd9&ZA!47V}3JskwC+-oIz80@5^c_OykO^Hu+1CS8hz`9#iO058`unwV zf-;XgO%Zbq=L^Ry5$1EKrMb93`*e^e;ErNJ+=ERR-y(==R5@om>)uX~par)n^=26p zy;S5E{_0X7tu@)8R7EmRAi|TWP;QdxT4oul;k~TGy3yZ(dGt&kDdcK1yrm_UU!)1JQgs9+-S+JWP}p zNBv3d1hB7C0ZVb627HJ8xc7yM;(b>Y1l+*ZOr!akY%E=EHP9SANC^5_vot3M297in zgbb{~A!%Yd#25ZwA?%qo_pZ G=pAN5!kA>mnvRCqW>RVwI8SK*8lQxPsZabBia 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�pLg|8p& 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 z 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

$s{FyE>xFuB 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ℑ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

rY6B-6i%%m8le5MiU6h#d{uGELYcH7GB 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 z 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 OadVtN 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

~}a^2VG{cb{Lxd8FD>)~hA=?3Jk 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

ZOCLC4LX3F_a4XyWAHZ2uivc@me> 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

2fh+I1$q>+adSQB{T42<5R2JrLmYmMm3Nf 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�MG<`ug}46*d&{neyq0>G?4^Bb;MIjK{@K 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�Mi!trai(N|UbR$7 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ÞI;F^Np%fd6sG^vqU%?%_YQOm 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

e{8bVrw>w+RNQl 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

;TXB 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�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�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%0D+^$pZAE`lut# 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ℑ5uU+FmKn3%g z%*Aql(w{fz_l0l-`ZIh`o`@^#6yUl+=RoJW)9hRZ2ZM9+9so)D*6Ad$Yj-x8XW_WRlNOwPD1_$QKQ!M_jh0r`2n3U{}IE$*~sI6&jpV)z6=O*2k+;Q zStU<{9G*D3Nn`I+7Hgi1?!f*leX55V0A+Z&y`pK&@3qZs%pKkjzt`8(laEa+_abt9 zeBO>;unY69{m%sMKZ~14?p~MIH#tf+uM$`$l5{B($!YICkFO~UWl9^tw+-r6FWvfb zCqw<+&kQVUewe%G=T$kicI>&jTNp#=4=W`BAv~^Q`wfTe&HbDROqAlRwb0wJ4Ot5o zRz=^Gw${nPrNMZzl_4=FnF*m}$Xyf{<1HAvksmz*eV+LFZ}Uo>MpH5*+;aAh7oA3u z>#@pQL184zl(mX^q#4-T54Dr^KUN)0SC-CT4{%VdBd5nTlK4vuL8kPKGDSn^&0l%92j$GMq zFK7Cg?&Ok03iyZ|964sQ>r<0J+Pq9*I$l6II2(E3ETVvd&OS~Hk1rkDdsd3WC-mNS zkym|IR?u9_>4qnz-r*kZ)%4Kh!KDu2I%(aBL_5TW6>ZE|Kw!I%ak4+&h(Ik>FySX!?OnJV8lhq7lBA( zT9oLJv;%~>=x?HB^4?z>4vC*E(evfmfv)+U_Z@wYJ{Qh`douVU;=JIJCjG9>D+Qk( zy8&SK!0@Dl33GcFEA+5iP>fM{a%1>xG8@eZEuRZ*3}6p%L=7U!SWbh$P;97vlNv1% zrt6ALXK&CZVP&Zzf3q2{$sk>+%PYe)l}6D_Mm+2mYtwl^c0zrlG*v=~C(v#T$5Q!o z{1Yp81Rh+d={M%)#muL=CMmgF>(lrw&#-DtTg0N*%S~buWXh`3d@5a2cuUviBo(}9 zu!nu7j(7M!>2qEZ6_yb>JTxtCG1KhM=sp}_6DCj3iDeAOoMzI(5JEAxm&w@C-o>+{-4boTC=-YVpC#e{!m{t_?3EEnh|hCV$+GBU&? zwE_!I;jHYUKc>?f1caVNyk{KU~=MvTJ68j9a&!5z=c6|MP#vt%x>szZOkUK@a4O~#WwWx&x zIb*hc3TH8dirO~UC?aH~)5)(1-qKsicpXzQ*%_OoH?*R8V)CF9oP$^&hK+{r}QP0zn-GqWq> z(!T)x(`fct`+X~1C^0;ij`@q}4dyer*tH ztCIdOto~(0#8(H?27mL`2%q&m1!|kIC^%*4B2O}?Vh8B%WKeeFG$JDtUD8{Gf_-!I z{(u~|s6cN)!rSjtK30a-&2T_9TnG$<){rh{OXAkUl$z(8HZkH$T%h&JDGVw;VPQUb&J8`*J>loDouYS@YA!_ioahaI1%ps9b?Rk%D4O6GOIl z-)=g7eMP4F_hhMvMq2e_Rr6}rneHh8kF1K?bsH`|%J0htSNtR`Mi=l%(l@J=olQ*6 zAju+J`cDriCqTq^vdlq6(I3T8qVTZMz-7r$DDO7m;}hY%eIJXt9!8wu60Sg)Bhmv= z4z$nAq-0v4QafSf`k#Kp_n7e9SI?#W0ZUG-xG|E^0>US8Uv|@>#NgG+KjJUD-GuyM zLIM}@T=~zPxm?!>P~dCZ$GN+V7b__9{`&@}XJ?1aqFqH!HWu8~0;O=V)%URi8^3r~ zKQ_boV0AgU(u9Vi$*a8EQgpQ%=U&C^G%6ehi+mb7?sqHrOmt4C!ik~=5C1Jp{|@bf zZLF_NfCD>w;NO4rOyR%6)Y^qCS_U|>Lj!rv+cVmXkgkQEmm(Hj;y1)dbNehY=bHXS z-GAC9GFdR^6rYjydj-w|y?H$?W*}^^pv67hUgwSN&esmz{^9 ziG%ZX7nE}?;Te8D@AtP5#o1>84+Wn;uFlfE-C5ntA(*a3ywc@HnE$)M3M$@VYUJq7xgXb##xZ{}Diz?Toxn{D_ z-zxXJ{eT_R?B69{H>n~|GR!#riovt%8Ni%bN;QLxy}8w@G%0UARc0m4o|2qAbqx| zLX+t)JI3-55@oC+_=vpmH!0()Bx|&};PVaRFw91$RzY?DT|dwMsh_PCSWrP(ldQ=9 z-})(pXKfPet29gi(uE&kRTD3H&Dh1yE-QJUE>^Z6Lkpi4QCWiS4Rb<oN_F+!ixBQ)B_#e1Vz5i!Ic@1|K;cw*-pUEh_}=+0w?=cwBI&*7TS{A%`bAU z>DhuZm>2wm1M!f+49Vx5(#I)=9qtb8ZUg8Nq6{f3zu@u64SDYQD&6)jr%(B+6CZw2?+~HB4cpN1nyK~!%L_(fn zeVl8g@`kRiIyKN`r^&O)J=-?-Ry#i6Yk@sI&fU>1rq@VjfpdN>jiDHrQzMJwedgvX zqx}f7@la@ENHV24%Sx6yFCF!#Nf{7TJ(l{0-<~8t z8J)alk5GAm^>YU7kkN4-G28rRpx&h4Arc=^9ybbGv*Ka6x~(R``{YbyyDi;E%*W9KWbO#DASjQ-_GzE%HV*B}0sY*me9?>l__TQ%rALVXE#N4(Jg&9$$Wv`6J6c(-@0epKi$&_*gYHi$#}@k{O05Bs}Axldu}n=bvuD+6vI-JAylua&EqkYnG2MFqrAJTmPJTVzBH>;q3*IL=Ybx zG3J|>*jBs$Y7$c>JzP$Rz`@x0j$|Wq(yoXZ{yDRYx^>kGRr9lm|A8l%0tr7vFCr)b zx+aFQ6%-dt0C~Tw|G6_pqSkQk`lf!H=j0!88}5IL+Z>z^^t5r*%6U9hul+aE&1KcVN! zsi;Uzr|_z)DKwR`@>E8V`j?8^X)s5sfIl?TChCzI2J3o4q({8?)9q!bsg205X3SLjd@n0h*1f0(n&SAka{?cz5#DA@pe#N7JQZ;e z{j~db-Ob_A^Zs3%ku0br(&f&Od+WxOHk2w?1S+Xgm;EH}{vK%6P7(+F-tmqL4KPcT zSvJ&+QXE-C!UzhsAa9EpR}`YXm7YP#c!G~Yp$^n)Q`b7#M}AFpB!si}jl$}6?DZyx_#6P5}P z0CvyP7r1m__mmw+>*9TOaGLpnz1{EfL)4((jsmswy13kXwi~EE0m0GDb|aEq^JW^${ej2+yi` z4y7;7JyB!_h&dn9y(WMtd}!}O5_Q+yQWTB(Pe9=S3e&8m+!aU!_pjuk`c~9b{O{ z#)f)?r`khMf}exzQ%w0$A2JG;5GtDem6R$&wZg3JcKk@wCdA!&SyTW%6Eb=DZMo+o zM^*|-=B_i(jA`+ECkYtDi&tEWX;N0WzWFY)YZnLPV^0(0W`jP;Z0 z%oT*uI4q~jIV!RLhqQMJj|5(ueJ8eU+t$S9#Ky$7ZB1<3wr$(CHL)hi?pf>GAJ%@( zdCuDBqVM{uZ@PZ}s<#R<1T!!)N&SUpZ;U%8&cn6AXw!45s)f;ieTnWOyP~Fus8v9* znz5Qz2`Rm2uHCk{w>5tZI11Gc58M zf5yZs?t4a3rR0C7+CWiv{+Wj+wW11u&$z+Gwa&lrIZCZScE(x`A_9QVW{bn5B3J4@ zZy0M5AHyA<2<@P(ZG18lo>Ak{$EA&zcyr>O&>}67v<`KuD6KvDjsn@Hi&#x@p`>D& zYE~XcvS&?jG84TS`ESGoh9)F6Om%iDdF14L8En8u`G`uyNOf%o%RZa6#2?`936iws zCrwBzd)wO0M5v@(UtzaX_lPDd+8Z)9UgZwXtom$Zq>EdtA@J>P8W8YVO&L}VYf+C& zc#*cf6#k2{BeqieZ9zKmlgIRumQ|@9ngb=dmhO<>na1Vo&EX%6emxNJ@jE31+}6e1 zyY&>OO>|OQoTM(+B;V)=5S)yI@rON|7Vlqp*n-*0k)js5Rvu36L(%gELt5t8*f>=h z5coF)r?rz;u_9|982n}k=(M;8Yg2UpHQ!vi+22%upb>)2wr=ZQs4<*z-Kq=)#$ww8 zv*Mw1Gn<@z1@|cn$3(R@PJMm}>$oLqt${3@2laVz<=J(mxVGck(7vS`>KOJ#B4Pk7 z&RZwg#e#y1Lrm*Dl53e%_Q}2LO0i+^^!D12qRvEy?tOQ8h~M^p2bv*3JWmX?)rVLC zmVcvXkj}7tX0^b&tg)56H1$@jVcv-<1lE3t{XPdR!I557Qu7Dk+RI`CtUa5V=0E!1l>W_Y&eYF9_HJuwUf z6C4B|4%})LAtaND@0es5f|m~)zM$_)?4upkhjp6(FY?WM7-0mWH$N8PEimvmBR1GU zpfEnCmkzcsj;|KSADwpvLtVxyXG(5MJ`uPm%Q#J6+ATfc`wip`UQXA1+CYgDYvt$j zind=?)hx-HHS#+_#vj|xCj$x{yX`FHIZKq#DLwyk=XJP;IsF$sIRRJlZ2vbb_xDgf zDrVxJXI?%-yWE-(b15RDvw`RqOct{{CCL%Fp$(ay$FQ!#zy(XxL1zlY;T9nwO|X9& zdxaB`yI@He{!GVTTwPI`99bp(0p@fXO27=aiwVLUJ{z)Apg?bZkmI599m1MFo!Iq) zSzdzppO4X}rwKTO02s9c!05kqsOF?^U}gOOz@n1t&UjaEvH!`UHvg|I`ui`7zWfV| zGC=aR{0P`}@&d3Zc8{mDrcXj7T0+|_aS|<5z{w3&UfuGVJt8eSjPKl&5*yqwL7-*e z5_A7iMTuqn-?)woxa!^`ZQQFJj7-JK1(*56-?$EVI?}*JUyIOW=mTjIAg(h!0ZR$B zWg)?)ZAr0-U|8%hJMiNGLpKF{L!jF&C)-2f_6(JjvRFyw zfJe3_r8P$G{H^LqHoVPGG?`ilMIEyGfGD&Lvacb+o0yb4j7%559yEk5B0pH}XCkd` z4qk$GFwjK(_t7KT27Zk6ye=OJ-7wHm@h|~@SbaowCe$B6oy2tkW)g91&;N8n3;*ea znk9*yB=G@Il;gjn=veGOQ1oLWGaB5#;7Z=*N{(kq$&Ob@?p!Z)$lX& zJ)lG=7aw>S9Tf-Dnv+?sLe_2cOJfL{qtict)+snrf31O{;^Do}_3%Q%uK9z7HKV!Y zgNiskEUS0bHYco@n&H9Js0yt*&ORRJZ5F@^{lp7qh@J}pOp}u<=SmDGiZP@FrBpYy z6Iwkf4?L{Ir?H4?>+(w1jKxZ*$KG3P<vf`dzUi^okW@4cRhC(FN_1H>zS+_)@1PU^388`UUEDgV z3nw7>vtpBGG9`TzjaH%OPsJ*ZI{QzXKay&Kb|n~b{nHx!-cUk}(W3c|^QAiQh)kOs z8|QH`(LGL3^LULkFV1c;CuO@)$M|H)-zCvFJ}s)1#-gJ+^v}>$o@nKyuasX(>*t&` zGyHmNH+bO8ou%5ILxC2`1Uoa5ZUlI3QS4N*AFWgF5=h}{YVijW2Tt>1^%d<1V|via zt`XFSprGhNfm6;?6JA9*n$v8qdE%-d45c3q1bfBEWPbKRpcsb)@mN4Bfwh>|4}KMo zxxJ~XBzr*UgkPU%>eIj99-NWiQ)@4+K#d@v#jS2?GKh&S5b~8)W|cRNmdkKA$*9AX z{G4B7hs5oMw?VLF=l1=&jx<}jj+pdghX8ef4`bN+|rG?efEnR+Sf7HCK$5HqA zP2U6=G+)$)H@`=|jWPVti_T&f-6;DkTq%{$mq`N0+ zeh8Qw{@^;YA^qZz!t?Galxf2IOj1jA7U31Y4%KD;MbYWaYMC_|qE;DC}0F*LkNYAgYdoTHp~7_D;h% zc(O`W_A{KiSU!_+tQvq+!g}1dhSH8>UmHT>`>kE#qcvU7qjG)p8M-_rby z2|QJQ+a$2#6>E~8P0e<%o9y(k6&h=(4|Zq z*Kf!SmAT#x^C$s|gV#QtjNuxvMtjqAaV$ejB`5F4;F+)X?96J}XlK9iLrF-XR>J80 zGGnsGFV+T5xgMhi31w_Z=R}?^6vVINLgN}8>qr>6?!9$Edfn~rxZ#sYh#Vh{xp0am zkPShDFM*QDRN5shl@W!zrsUNE?1-DsTDi^`(h{qil*O_I8KaKAlKP1b_AW*6knWoi zVs~&AFv+Z^|B5t%U2t>%^M*eLc27LLPyCHRS1e7uf%e%U+lWO{;rcl9d$a+eEg>jS zX5Z?EJ?w*nYG6;(j>eI+RU0C1` zT3uxg%1YJToTTU+QaR((DM5f4Sna8x6L-q9 zL`_as6e=P=bEZiQkGs^c)vHtYHVl@JNzGbLv zcGOQszje4?kbG^h03&6I#(G{i1F1^;eiLgIfgYJOFtowJrND9^4~ z;miIulzGljo))-O>&dc-f247SMC40TgfetH)*xZ3rA-g~ygI}lwr+vXSZ#K?NkoB) zxY;}E-Ca70H>%U?1r-)Dunvd&!o0*YZ=5rf*J5YGI@H%P%bcrT&G-$5t&8RG!E*hX z#>}FheURGnD-8?3S2a7i)zmE^p#$bg40oDVEUST<1@6#HEr%`iMcI3gX3oXQoYBSS zOANBYZQ^~LBXEN?p3-gzHoU(d*NGIO7zHrmk` zyLzn{ZOZ{n5dFD*z+I@7K3SL666qF8FUj}gc7-Zgj8Gp{dUBR^f#b25UoSP*qoV4! z?g95OB-IbaM#N>cylX8DNZlf%d$byoZc&@4K*zA)KV;iVktx{Qrs_n#pVEz{wHCcX zYYQ4YeP#r~z%-^hp3*_N1QF`Tg$faV-0Ve*+2=8 zNNBAN>6X#RVHyWl3zVEIoZ!XTNPA(1WCe7n!|ou})CW{1F<+=_nuF&#sHNoj>pc0b zZIL>OwU_XO7o9nvsw0HGH%K!HN-kMcL6X54yYxM+94@5e#^+L#V-a~&)e_87k=)Zv zr=1!|Rzj!R<~QSSS#RqYlp`D@ewkH)30F)``R1O8SbX#Zy=B2n8QgTaY2XKd)n6c2gi<( zx5dg;u~OET+;&Z~(i`(f>4DactRL3Iw(Pfml*d^GZFppCMwcwlU}c#y^t-hnl$pxp z7Ja&68JuFj+wJwau}eR z-g9Xoo22)Mm;6G6dpKY___}Zy(Oo(M5#MI-H8Swtu6l2D#%83dcTSG3k}rnA2Dd8- zMf*)HTvE%>?Z_XUUtym0w%JpnVk|Ai!C&IhhT6|4F^2Oz4R<9#^fR15+h-Ku)jqd< z?@bn381y>HR}~p*SG?^1_-*=nN8W?XN#>>N8SJYRiAOJwT`o1Ng=khHJ#tG#TVcpr z&dXOVh+38PtJRgmTHv7as-aQ00&@uFKFbvrcj(ai*FDo^a<0v?Zh(vY}CXrQ{J1|4l-PFP2X#M4MJ z(%+;OA&-i`>!$fJ=P9#KZje-7VP9=3U8yxFU2PGkoMVy5C~5f4uVM<_M!DOB%6H|h zq>~1eu24kJL?99(2`WxAg=_zSOAOq`9^$$y zo%_a}Zuk(d`n-6|F?{JQnH$AECIesBBL zHGtwFK7ZGacuDIuZKo9XkkGM*X2kC&8_IHWExZ+^hSZ^%9OO_u4Jm#>fSLZ_Y{-Na zO3chIumGP&ra34%KTo{C8(B!I@$ziA+iMB498=`GC8F8<{1^0I&P3D71R%E!0KNaM z7}bA}>pv>$Vy~bB7*RvMJkbU|r3g)^=90p2pThgtL$krQyf;cIG23%Ix9>A!Aaq78 zqCf=38-r|!TMQ^A+(4*E+(Gy(5fzhEUWSGo|5Qn_?jHn+g+@MVCe)3)UD6uq#>*pH z{bsh+xf!+|=MP6+%VEAehyoLg1Ln&Dja>f{CY$gt&u;3n!0dvYR#|Y8$~K;GoBC0S zUitAvHGJ_erm@~{%9}HQX8OYXH>Y5o%m8;aMvm?_hW{JZo767={mqD9*Z(MR)~3RR zfEY0p<0atW6Q5Dw-zuC+R()rd-J8Ajb-kyg!=>bW3ywE>ZprWlwt;sSw=Ky z(W^vTlJ3$RU#HuW)$zuxKG*Yy*9-zQ7PJh>esf31d)0&e-6myg$p;(%jS`qEGQa-2 z3i1Ty!af~RBFMXKvX?j;UzQeVMTjM))9(&<@NnQr$@3@Ih5+9h0seZ-0%rlSQvvt% zP{LU4zN8r}iX}Ld9krrv0nd+`6wVki>_+Y_*=Tpj2->6k;abQvNOIWYJcwp&+&D%- zkh#%mUhKZY0(lWi;#9GSh!#`QlWgGzTGu<$>BX5ONKR~WJ#yU%k{<(*qddR;h4=eb z6*|L^g2&VXg80^h+ubK793$+)$W`f+kq&{rm6Oi~4BJWM2A$v|uqf!g3Y{p=Xewrf zKOSiTd9A(0Yc13js681PO^`zT02k>V?y9yGItc*zqm;yTxaax;lN7}q3H|oG31Kg1 zi{#MKr&trlWRXsHc4;g;JjT-o^{a0kcWd3I9hdSMSlsus3}_|xYaZJYvj^&1F^VPs zNBE|np;T~2J(-U>Ck2skKC3WRi*-hAB59dGEoT-8l3*$zzWjg!`sJaJ4nlGrk2%*8 zZoOistf=4=MAo3>;pc`Z>MqvBm?m4Y_KnD zo&yMJq=Xs}1=bO8l@)sS*;{#5t*$!R9D$OF9M_!vBV`vkN_=lXC&LJwWs?ye5=(8g z7xs~zlU~BsNG3OJIulPsj|}LT2ja%V@>Yl*X}J@7`r!y&K76!V*g~uCm&9-2@vGF! z@qkMoYugQraqRs5j`_)`**SkD6XF76U0pq(-bnL90Z=%n^&{)MQEu2@$rS2? zwB8AjOxjh&%5F8SN66^%ydB2d?5390kT$WSEDmJq@R8%`|4}%XFW;J2!#o$gaN`mO z(&8A#$TS_#>K`W>xoDly0Futwkk_8~bo*%Y<0IC`L-r)4^?lfT31JaCpu&G89uBb` zKdXDd7gBe9iutSs5+#{l0>2PYIQNJYMj!^fz&f>P-*vsH#$CNlqvWOBncOUrK1h`g z6+xR4T21Mucw~Gbt7z&KGmkw5H!Sog?uH9oHtL3kR>9{^ycwg`s#hC(Nz+~EhVOwZ zdFJgJ4pPt*J#JL8z(vUKhkbP$puU;4iwUaQ(k$ySDQ4!_d=&etSah*I!-4#2sd`_M zEiR*W8C}7GK~u_F?S)EMF=azVv#LHX%y2vZZ`=xB0GGXuw(w z2$3bPRmtJO-u$sZEG>*XF-=w3YSy#@b9e_IR@gO6nJ7LGkW4~y8LyD|OjBk!s+G>x z{DTpnoIyUB0gL{p!>FtMDLu zp6^i(-1`}{Q*P$UGKsnx=FkI*?+K)SFQEy>lLmKcX_mFRUgA_vPO>Nbw@ucVY_No( zWxF2idEovue!1=7ang5xWm&V_9q1pi*1(VRaCM`RTO{P&@jf7)O_je15(`M`B`JJ? zv&r4c4%B>v4l#SCu6)Lc3IO#EttHzjmCKqU<~_>ulUkOY9MNldiFF?1ImV-%DmCd=+}Y&S+Tb*^28=Rv&(|CKc&#hRZH2}eBkK%B zX1}srxLdz+Bi42?_sxf*0s+SoV-Kq%M$jmpTtS-#X}3Nhuiik&(2Z5;b_qDWJm(zk162jelB zCm91aL$32is-0hvfJ(Z2O_`J*ihxQw-+$3dRxV&yf0J_lfDhNdV^#c51!3W6{Lfap zZ#UfrWtJlG)`Ac5kZWvty`=L2J~>+f$D9M&P6EF-s-3mrr5#(l=Cb?+BY}}gjBG!b zmui@3;=gQayo=O}U!^{5rW%1t#1Iam3c^F`{ z!jkO&hxYl8MAX}$JU@c zo=-2&P!5;RPa_SJgNbD@qj66@Szt5_iRL$=Su&<98cgW+NKP(`9O;eQ;@AE(iiS5F z!|Y&dpOrz)9E2Hvz!_}Xv{baA(GBr=8BjCEH?n_xhbr;D(Cr5`?&r%WSrig!c}vbc z5n>@oU^>P^`&cnWxQsrsLcW{!@gC_;8Kgqb!$>;H+`e&z!4EN9ZxKsWh!*XacA^-2 z#eM6O$V%VPK1vO7N+#D%#5Boc81~MQ6Be>w;uIhP0ofa!hKx4bQBedaAnq`e5(b-s zNE8Yq()5?ba1;IWUDm10$e}a&NG?pu3>HP40tkJPIcaQpIjlTh@v(0j3Zr~Pgs{DQ zs}mNa6SRZoi!IDdF=p(=sLH56B@G1#<)w^*Ldz&)yatsjJ?Y9+civvygR%& z#bdN1=W-e%k+Cq>ke}_Q8z(D(?EGl~3Y zBG2Nj8Fh1~!tf_Ds~AyZ&!8_zO{gp2?^*Pdj%P5BBE#Z`{H8~-I`km!02J*H%W!-0 z`*wf|+M7^HG4-I_nuK4F7KxBnt{64kK9z_tfE5+eC!TVwG^Ue_SxHZ{Stq_A9y*YO zHmztLBy5&)Tv0}d{anjgx=HEsy`3&=6-5!}F_5I`n*bkn^zc4Aw^hl>NIWFCH=F2q zLQE_+C$#wF_*j$xPd*Uil4U6CvbIEp>Tk)*I#j38Ih>VEmycG6w>q+X$x8(rIBd3- zLeL+;GmCAD~G!oW?KLq8Dj;BESC|LEP$Euw&w`r@a zQHp6LmG45*+Z1`lcKlAX*2qQK2RV({2{YIjtCs*(^`osvi(^7L)CLmFnSICnP}bQ8 znB(FR^k~~KHe8_J$~`$AHcVosQ2VgMH%Ty1CPEZ6P)_(G2!fZ*QK1p;MakFg?}oCC z5;w4-2$^geg60fi(lj{ertuArGr*GIoRRcwpBL56N=)56z$%ic`S>rP#Z_JMXM>Ii>u`X zVgVX;Xgm7_Wh$z>oZY~DK$BXfsH2}5mgN;gXeQ;AbBcRx%Cm;Q;2tbjq)-)1@o+xi z2jZ2iW*bCkcT9?mRi5YqiT(4m!lrRlTGmzu_&~F9`mKMYr9|>n?OX+>OrK$|yHTwx zj6y}G`d1UXOwn?_DOD9TpSy%bt4`q(F%G$Xs=GQeyLq@)*jtBHl9)4@F{(g<&+()=iM#Znv8Yr>I+ zIb1T0JDWPr#1RftH1hU+Yo*0gW;ki4O@<`g=dZNmiU|K~YX?Wmi(gb2#alN@$W$aS zx-M*mIbaWbnOR28V3J#YPpxqak#5YA_hHvZ;?+y7N$1)cFx&QqgwklQp%>vWQ9^1f8yel3+bTg%qmAz6+MYJT_*eYfn`W;Bvd5Nf6ouJZ3Uch=b z8Paq(eb$u9f%W01r?r;lqA&e8BewI~x{i~^7B2)TsqH1J62tNAj^LGn*D5^Vpg+=W z(EDV5wxRk~qa*OHHj~|rx$Wr=sFV2ETO)bNhSlrxb+LW9d>!*PFNa2@f`EjY6jz4b z`-WRO8>@3srm}@Z_nvWI15+aUs0ga0+pkTToo?-M+SYxtv>^_7tis!4C$Ey*uvFN` z_qdWCN~k3D^<}(L^~Q4$&O2}a1=Q%>YmUGv-g37Lq*;{UJN#YW?tUZ`NVpzuXDhGW zvyC64Tulm*%nq|`oX_@jbsamJ;uqvJF@-W7xzWqm>4t7?G4%oxu5O84uBV3w#+JK1 zG=($ju(`+)(*h|gHEc+cI%T?&(xA19cpud%vfsep6_ED*cms918)8Vp1SvU{)#b(4 zb7q?Y>NbmB;QviREyH^H}gud!0u zW%pjRxhtpdWNW`=_kMUkU-6@0l=gzYQIg>S#qCdrbdh&&srZ3lA6yiFcs>txhxdvx zv|v-EFNi*eP#Hl? z$g92W85j8Hk%3jVp>n7NO`HJnjy~4+MkRtEJ5oK@!yZM#`v?7Oqdx6~(eFDV`jY6{ zx3*kMFGK{*JW)?^H|!TWm;1TGJWD%?ztF8cWszAkTCY5;1DMW)@}$$9=gnIJj}^}3 zo)qr_Z3-67Tj>GYgy@$ReCF*_$-bCQoi-P-Zerb?3fo$r&5lPQ8}Hgr=@HI9H3IL1 z>++d!Cg*+8($u^jYeave3eQYA0i>z;gyK|%)pSyQ+;@iv(U_ysCJf zg|=K;gtnm}B)~e)a(2U1h+JY>`}p^i*FB5ts6;gb2a!ysXzpF8*xrbd1sI2a@vmlOwef!s%+ksoQCwqUo>6Jwh}vs8i;Lq2ABhj{4P;6QC5jjAd|9Uro+b%f|DoNo&qzMGst5u~}1No^m~$QXijr)t#g$zSzttHi^y@gj~injutwCR2MQ=AYJX?!D~wd26Klq~>}wmnVfp zdUVtSwjigx#EMfnWVHV{J<9SoUs?Zo!^1JPFX`b?oQ#Tc^uXb>*8!p)M*?loC^R3AG<^0$^PBsHuoC zz;Mu37LE-2v0LQf1bikV49NYpEMhQJP|YO6i}IBwStxi ztg)i+SGLw-*U_r87{gW~?|wgEA(Z#P>A%->^4#77TdqoOJnZ*)e$Tu;+SM_Pnzr6* zARy66h9hA{Plvmf^_1>J%&aR&pVUbB>Vs!o!xXOT4Rz!Xb9{izoAGQUzQ+Qc9P<+f zruAeN*&Y@A8MctnAiklq!ZAN zATQ@%S}r(Z`oRYn38Mk(H(3fGVw%DM6^V5R?jxZp4^c>@k5l--I)CPIP*&9c)*l~E zg(MJ!CaPo@pOOGGQMc$BMYVK;Jm^SNrGS821|(2t_-aI*okv({J57q@q*#=Hyu>2` zr+t_(Z!s3t>(j^l(*YbP!<@cQR_lJu!LZDN$TR1=i}1-M?j;RJ*l|Omz2za?roXSv zgbm#!xVhF)@pscSHV>+*Zq?=jjG8`fneCd?++)9sBZL)xa8NBSXnfYZ0RJRZ$x=*l zwqxKsTAj z>GebkV>p(_+hbU7Fm9jcZ-4s?GE=-ut(HdxDtu9+W9>7_77i1s0Qz^c*NcDVy|c=& z^h$@L3{Yq=K~I_6?kw%OBU2GY+$uazD_yThs~0(z-s-K*Us+Whpf5a;4)M zVE6%V<40aJ$DP_Ghr1*76EEnEk8(Cl(?fFIH-x&}UN>vV4=Frr-KG=xS`xmRG>8wU z_mRR!m(kmhf_?{`h;Zl5aUAK}t)OpBW?8>2-E!#4GoLb1V9Kr=_m$r! zG(zJwxwp|Rtrd!f^P8N+!1%3M&!sxXOI3&`O<5*W;_))Dp6g(1KO@Ipfew8P`>VKG zZY8G4w|`d(!w$K~zOx*+!Me(JOc!;8lxmzA1nTtYSp`|Z=-X2_1oK`QG2tzw64=~ z!JTpoMla*+_z`~oJ)jsjI7^NeLH z2EQw^iJzhrDVGk=0ZUAPDXWS#k5SEGb%_^u{i!P^Jk zGI~iXOxA;`NyxA&)t>imw6Ru`XH!&)w(ajm9Rt{^hL2E(-%`4)-K*fNngU(+4#2I# z8dxLn#CRE;_Itxa@nQDDgIMAD^}Sp&y2F3y4sdH*4TK7?!aM+7wQVxpCGE!=OG*d} zr5%v{W{_>rPh>iVz=9)LoeH2HV_aVE{wC_V+wJ*Xd@yU5)@6WJdXq9@J`8LTsEJ6j zo>CGd#jC&dh8-^zb=mMchSHQ(eS*acL2_&d8a`4grAr9ru4`Z-d0C7%!l&r~CWQue z0xLHpCf9Zh!lcat+QK17?beIG(GV!9#Nx65Pr~T z=r36)PXzVZ>G0G6?4OgIHEtJ1wF3oELvL!SxW_AA*t`7_?6qjrv1-8;%n!_uvb^ zv{k(ZyHpoWj#uvrVuf((TJfFuK`>Pj7+Rx0KdjIP-4L>2Gz#jGIH&!~@YJ>A82zE$ ztZ~(sIN0c!G8$8sb9f-AopUf7MYQ&@cYx?VpH)I>-<^twGW|2_XwPP0>a*R?mR&a2$rXoMj{NQuYM6~wIp)TW`Qh06UKy-0Uv(Q1`Gl? zZ)TP6^8`)eOG{5}eWv@}OQ#S29+%=SlutG!JY^WxqJrQ}-dtEl-_}9i>U1fs^U%MW zQ#I0x>xX-1=p(s;X#*GTG_Bfg9SI};bxPO4KA@VZ^bhVg7QFi~2(Z3;;qwGmC?yUe zg#d(pf#EOlr%#&>vW&fXaU0K9pO#G!@11PVn)py=AQfS}y+#J^i0i2iX;IKnxfGdf z>@r8rG}GrC^TmP|{!WiBySO`$aZ~5MLm=YhN=d( z$})JF!4;?DV1W%u;}qKg3uG9wj2<4%Rf5?MdADSMd97}jRc?&R zxhvJz*KSQbqMfp0WU-}DDBmiZTtha=E$ zLNs|21T=Y-`x4dgdm0b{{ac_T_=ntbkv1OR3!Me$V46}F{ zpG=3ElijIRa*`Vnp~slMTixBzvuz;-=;^ry$XhtvIIh&Y<%f%#W%6+6I^m$m?rG&g z8xE1w!bfOu?qJAi?=Z)@Xp!!^r+WiUHPN)3l|7~wxm*OHbr@ock6EA{zl#!vbdl?< zB)pP~f{I(WI_>fU3r58ekO*Ezc*3VAOvN7ak9T={WMp zZOsR75q2=8vkLQNSV^(9WNB8nXO0d9sW+)NQ)6B6G8hv4nU0VnZCM!;Kx6%a`!6N@ z7Zy+zGA1$spzss0QvL7w{{LGETR3JVY+2wi0h(k#P$N8X#!p>Y6Zs?|O<2?G;4Y%- zR)V{|RYroq>s?O!17cZE7UGWo>@V15!;egv@ZH{aQZfJ0=B)|&@6JFtXra@x=}qLc3)=j}ED%oWM++<2r1m4l9#=P;5Ao31>Ll&Q zJqDsSr=nx#8i+yAI8*sZx&_+J1+qcK{nF@Ev7ENJ^|OLHVg2)3(RwL3eD@bROu`Z| z8iu@S);dO{Jh~veT{Wu=A{7YQ!+70HZX?9GFP*H%`h+($<=`pGtB@j#KZz4&WB})+ zUkuer!T2`5zGAg3x0EDO5jf3eS1!%`_mJac#;;rIepPLDlF$$|Hnwlp8l$lm4tHGV zQ!+R8IEQ=%+;&ikOCn*Su#*{vXItdxv@hb3A4}`rA=21u^lN~r?+D`>lUNWjUM*!(iPg$kjXaEX73mnubvgp4G7oqqrwv2L}i(HO^`* zfZb~0uisrhX~S5@c?3;oov-$nY@AThYw8(wK}V@2?l9NXU3x% z;7LNNHF_PA5!snZfeFR*@1Uj}(fycf^_(OX%qUIg)M;Lr4TdtAVnYMhsjY$h4%K77 zPr7*?lIZ?is(`{8ULTnO4A5`I1hZpdSs3w)w97z?1!16Cu3p@cyY)E^M^igY|N70~ z;y0Sai0bIY`INv&!GQSIEUctByh~lOg{$qmhBR$YNABMz{DVQ)N=>KFPVPA54OhkA zG7({M7(0rA^P9?CW6mE5ncmX7z?^w9FSAwwBCuRm5d57}?tCgKMfkyer#{4-P%vP^ zFs|rbitzaWg+m5~p*Nhu3p#G*QbtT66e22GKgfuD;sH__6T_)RBc6f8@@B^UFc|a0 z7~C-^fpo(?tLd4zE2C!&U`X&Xqqw6paY#7a;0BS3KAHfJL0|#q4)zE%bj5r&H{v-n z<{x2mY7Cyy?o7b1@oc%wPa4&-l{PgS1Xu>@NGyKqs`Wnj^#U24Xo@?MYjYXTgm~mR zsuHn|0+0I%6+etYg{h%^CJ<>UZosuEI0|dO0*AItUvT|jN&M!0b zd-Mp~G&@1Kvl0?mvQsLv<B@6i}YYqB)#A0DpjRel-E>@26)~w%=ms@{UH)lr60) z^|tzGE&4=vc|&8c(SOQ9se?*wFQjqd{%OPbK*A0Z&{W+>eR$m;RP0)sTJqZxoGUJm zFp@LKBz=s`V=MM1kzs4}?2F!>jqRN^TuB~|bXl9Wv2!wk9KEB5%z6-KcbRKTfc90c zGpA2M(=BHe`GtaK&PRU&UJFvxg667XEmRPms)6_Y7bGx9G7^J)NfUMLH{qQ#)hKP6 z7b!BvYKaO7+e?pb3E_37A8e$dAFL%pdL{?L4lS*csvG@M)1vm~Q_y@(IOV7v&_ybs ziT08AMFJyBito(&U`9GRLX5dyU|4Wl0zyQcpt6y$-;pN5*;>tr{Q3HW&X`axpa{DL zNPiIcqg4ZLkg9PtfH>lwP4=x^KI)rODLv_)91-Cy%?-KtR`)XV( zsO^O3&zzMYt0TOEl8AR35pWU<-Epth!0Q*BaS1}LF=5@4gT`Ftbn-sBuv^ElyJTO@ ze$=F?+?*FF!rbY;Jx$9f3b#wOxNiW0U>OE>)uu8qdDl334$56F{W8T$wfMF#Se>bb zQip^7k)el^HN(Arz;v%+(C)uz(*x7UU3b+H;bPluM4AI$@krUO8?Z_~Lk;U^t~ zL-<&V6X(z0BU<|en=4&%#2bt&f;`$n2RVASyK}m`KR+Ej-ZvfwqGly1I928wzg)SE zchc{aFh#(z)w8|Z2k^41Yig$TR5Lz?wa)Rr_~2OvvUfOS_c?h(nMWF{fb6Y9Ac_fK zWldgR2xE|vR_ZoIr#-pRbPKdi2-1pT!uxepdGUy58{-$g zo4UMhF{@=DB8uUb2@}WU=_&$N-~3fSl$dHmWnCJ+=gX!Zz)k`+U*R`F!GI@A0=qKy z4(Jl#0yhL&-A&%sYMGcPtcA#CqhfZr5Kye7=arYQAX_9I_qj5#beIKdvUJv z^7W8&dumtUqWZckgE;+wF`k3VSr|<`W?4xM8S*;2I<@mV@?!#J4t`I?sF4md36Zu1 zp}MwI>AjekDqbw#xa9I(FF3WuD>sae3P()q5Q_BJbD5lIAB8%bMMbsMp;k~k&T=ni zCoxc;+Ox=e;&zR$$28*k#UMjHjB_{fs7>;r)VY|7Y^Hg_l&;%J@50j2ZQz?arhN4B zL7N$?Y&%c~ca{Kx(Y_Oi^Sp*LUm=AT9s2V?Q|OgnRV#!ut(;to{pMFz9r2B#7 zNC@@bFO5@EArv=mRo=_5+#DRW~+v@T{$Kut~Ndkwt!6o)OGKl$0L=WPC+kR&8^me7x`WDbaekU+D-nm}*VJ6Y9yk>O8W&W5i-AxrtAi@B7u6hTm ze6bBb7iD|)5A<8@XDk$;yMLjE=&+W+zYN$HV5iAk|O`ZkvK@Spa_9- z5Fr!SGM{*<+kPQpU^}oce2>3MZh#855**PQX(AYkkwmFHaDmm&_c8`J0~t+7C%JYR zIdx-3bzl-?PeE$Ii(=grCV5t8~+fdqF+B?Lj+G_<9fNQi9t?8 zkQG)u^_QpeE+*j&VwsuCY14Qc3P4p=e|G7gbwcf7*x&!Y{%?lM-_TL%i6DV5w>T!~3~Yy$y7m(N!MfE;|>2yh2;VoBZoCT?vKt)Op2RG7OIK($*BT*?o4m`R`zao zW#}0bbJZx9u)2Q6N2fW-yswa~Y z^IQ-lI^@BE5&6vJGN>O^?(u~J+k&uUMzA3v1|mS_@!n($$OcZ(QRRFU)KQ7C(T!4- zilxQh%u)oN*>r`0i`oo~6~nG4G1_w(<-m9|-xV_tEQ2;LZ!@P%F`30bkd=NeB?#Wh(FYh5 z;^XOUT(v`+jTMW1xE8^0#(U**G#de$qTRAoFdA}3!7ydB!W_E$`Lk&y`r{}WU~36C?u8$YNLSUt7on8OE43~URnvSc0DXD%!dpjS5hJtz$`RZkxw>C zh%>P`@5;?w0T?WKvCE~Q@ugrt+X9W4(VoLjFiZjIB8oOeg~V4t);gU$LB?_n$KL~* zi8;+1!GsN?Om^e@SB zI!;fbDnruM;j30-bbXB_c_r7W$E(`1FC1iu11jHQ5H$EGXPmsCB(x^N1^-N^)PGI?)6prCHwK>Q9f3Kqt8!b ziDl`!sG620J}`>0Z#1GMq8t!{6%L`Sof1tT@4|3%q5M#&a-TbgOxC+(BA zZQHhO+qP}nwt3RFZL9OE>aN>Wzv}+q5o5%T*dyLG=bH1OwsBoT`iU)!9`#sMya$N%p!MNU0|4-vI7b-o_n?)5$rOhJs*XG?}_Bi_QQa-^vq`@ zX_Ee#O)bheer4*I?@y?lcaDqi!R zy6heAh`N#2yg6kZXbvhmvKA+`1EM&qSdKZ1HCuQTEd9v>&rYRxTY!Xf( zDnnmV$)ebF_e`%L{aorW9gQIfi6>IbrLCo=7~o+yO5?i_IOy=m1!`$p_SKNAAvoY) zJON&C*?~u-BIptG0_6_T&sBHlZPCh<$dHR}jR3Q8F~+hupJs{ERr;)Ub?AV%qY#E2 z?zh$rS&YzOZ=@*WjuP6#>-U>0vggyLjiBDBvR<#_7HvsIIH>s>%gms82jXuF{j`of zYoxJwf?E773whI$UZ54`6;kmHkf;7~Rz9QzXm>!!B5ASt`VYe$h<{}U0TcD7+ue?0 z%;Qr@2K&lI0Tfg@br5*-vFB*1<+duj0Ur6*d&Q~zM19i`p|fRtzt8!s&w-1##14Vf zVe1DW@r#90ij}jq;rXIX0AXN^Ui$bWWwxJ{d&Afte37}(O)mgvE|BkaG`xPt z1T=ulMr-2k<47m}0C*D0(8Q542HgHqP>6fdfXWDX60eQ_mY2h)ciLH4K$GU^^~<65 z-<=Fh&Q<%aJn};LTpx^7W@!DDD1l>|Yuv$){o0ysqXUZvDdNeQwY z*y0NgYn1sE5nmBb6G2S&Ps93UYx`EnT}&`~_{?|aZDVJHzXs$zy0JLHtXeh4B>1L# z`z%|UOIR;i#1=oyt{eRecv%g5QugxjRg6~;z|2RgeK6a`A{^I-KH`Y{p>WBSJZoJ* z*xFP9eIwk!n=a=)-pD^6-^J08EqW(Frx(gL0Vj36kib5;dYi_v*la*}a$I=;*_bHM zXJ2=_4O_=ZfEMaoV5uZMEMsSL?B_~$gwPg}_8uhrPqoCN^MtLQMb$z_Tg6xu#1>Fo z|BjW(jl?dlY+qUGksICIuHkeL+NQ(rjT1L;nsv#YW86(2B8zpJ%sc6ek_Fo8AgkOF zcbbms#p+{ppQQ|zXSlJ0h-nuWqR&2&1G~rEz2|(Qb^gsv(+___iC|IN;b0X=HR7AXVK$`|1qx(K1 zss``B4TdZCYG%U(YJnnNj=H>J!O%X3b*uJew!%DxD6#T@#xdhSx?n~p9=>s(Y)!ya z)M&;!r$E<)Q}x)Xp7sdAHKPS0J(qG?8a}OmS6K`-2z>R_MdMhmpLbBD7YNqh1vb2} z<#WyJH$Y9JV=@TRrCW+wrms^f$4DDo!k@xS%A_neKBK)~X$@_*{#x{s=22jOgZ}Tw z)Tk$ZKg!=@>KxF2^O*WSc53D&Er97^z;?Z5=!-TKK3k;D#04M{s7Qbl#nYsKy1ln( zptRenQ-ORFd>;FZ+oms`0800)8#iFCu0pO<#Z8LD&!62_aZ@M1JlMQabY(8wJva(f z!)d_6%?uPo==8Lx&yi4{u{T=Zc%%ov-@rYRo*a@vSL}ImXq7oSicqBbFs!4gFthZ7 z5$H5`I`SW%gyUqz4w!0gaI*T7U~2HyN{V<^0;17LMq#eeKS_Tn6mS>+_?>dfgZbj4 zA~E`a>J1|&S_Wet+FXVNwlQSJODM*L&@l@1=!(|Dh%Uoge~hCP1T_Cps>~-Sq##ME z^dX2>Gje~$VgwZ2$*I$k;6)UuAWdFwbpP($|Fb@hfmlW}R;{*Bkru$P28K4xbO3lo zWBpix|F66LpA+PH>2yRNGyuT(Z!hitbvMwjbgldU5%2!9u`{iy?zq8%;4@pxm);W3 z89xNvWuVCzQ%#&RGCJmv!DY^;XHK6lmR#i3l=!m^Ds~=r^v~rf4?Pn6d7!mZ&F`XH zH)aMdRCngXNK4AV!RPJy;ErH!ed}6xS-;hjiHk6o7ew!J z5`;CLY~%x|h6v8u`5{9HQU)P%gWZ(=5-UOy5taUNKl9*$m3Y>TRlzWv+!nzW3F|4&&H0hpuCF>k9P_SB%^y3A^1H(i_xM zMGs^r4TE2FMHWBq7x1iHyMjnv0C(=Ycv3fd(C0c5d9L(7TNjQ$BmLTv9us_+{r|LG zU39B*JFwM8Mz`)w3z6Ff-qIWE2M+$i;ZOYY$odw-{8ybI92dd)i8#j`4gx1pN_LRy zk{OmnZ0yee{Y zxdFBTLZJFZ-om@k>F?-C8P37Zu~3?$-T9HM%C{1}(~{7hFuPnoKsY`U#n@PqG3boL z)4q4Qz9fQ*VkPz>2Ez&!QL%2fwCy;L_-=^S;tRF)w}hv31=f}G*gm#SFGXngz<-o& zL#LUXKM)Cz;zr%*y)6Uk1q!B?p`RZCWyJ>|Z%sPg9@<8XWz*#amK-@fznjt8GU|I} zuhA0w%QG}@F-$wDCq{^{$Y>yR2u5 z;PMQ?NS|9`5#*&sQ9{Q|+jAO80fU))0dC;apx76sJ%{m%U{lYNgfdVC3WobZ43!Up zQ_u(CVVpI$p$4iOt32U6Rzj>|SI58<1aZ_p5HL#nM6d_yOyYbY%_8we0HNz`Ylj#vx^UY7HYH;-aqY>)1H2u30chX@1RaJt;w^+V~nI_ zQT>o`$F=teNPY}c`}oA=`E>w-K~qjkQzN;U+7ghR)T&80-Mo)uj%Xptow+a%oTBu& zhho~_a-KNehNa~&g_b0Rl&XQ;^*@tBobYAt*i)p)DO=(WD%5SXb4_Ia&mf0D{#mjZ zv-4iHlOB?D_PMPZ=<##+ndfV>7E0LNyPaacAaxhdGq^F{rFCnff1Sq?*U6X8YWs^ctoop@K8%&w0?J(8 zAs?GI4HC;75&$5#s!QsIqc;)wCA+RZ>R>AFe>c)yc$rUWl~mc%mj7PPv&UlpNjU2) zzQ#=FX!IQIcN4;gih@dQYtb;lv z(A&MYo?c2yzU`bQsXete1l$Xl$a;!^ps;cT*8E2kTe?=yZw|f+H>f8|i37UrEZZdN2ev_iS&UF9rXlS4nUC`_4W-EEqh0 z9NK9s5A*OrRuFq^JXz%Myi7c5{OK{)quu})(k~pLfl;0CoH7lCjZdcr2c+eQ>hNJG zc-eT^xaH2HiVR{MLrsWSPvL6v^wP}AV|~j{`~(FT9zd`8*$SOHSI$h1k~y(`PVv6k zF&}AXW@TvKXJw|R=UKuc{loj7U{qU!jTNQnJFL}x!UotJsq9)YQ%#N}wPs{yL<1Wq z7Yg@wUq9E{m?SswX-dkmP9aj_t`YP+N=VyskmcY4BI2x>X{IMqji+w)=(>_5Peuc2 zFZAg%^v%&)_|^Dc=nO+rWXkKDvl+3X0ATpN7m#f3$rNTtZ{{(|O$b)yeD>XP zPom_Qe)Nc!TVhPbab{P$g#3O~Mws`|+{OCCwWC{qgkg6dp=YaO|g#m++e3aPS zOMri+Q~w&JA=1oW)fB9m8GauEBbwP*xR9@05?QXTCA?ti#vxb(WW6%Y9BFO57bcb$ zJ4SX8!lx8d;VFQTuNps9Q2lXt>l+1>LloJ{aX?fC)uqa{}d#u2V{ z52B!+}E-cv$Mqg0aTJYLOoGw~w(&T0+@cKb8~cLwEx&((g>` zjWTo)npd6EQ{0oq$Gca#wgCG{7wkZrx70S1qZK#)pNF@`7qV#}R*2{;4-+#?gbWlQ zg4Y}65w2A^`yw#?zyA=+RB+p~6JSx`TZ^TB|GG0FK2(pdlzxfds~-&2 zSbS(-w9b`oOAgI$J!Tsk=V?>WYkYr7%039Wmu{cE0(01`zmU3)wP-@hv$%Jt*Siw>V=Y`vAGspg7wdM7}ZYwP2XvJZg%gx zk|O<-s~J|Ym1%127d@dq_+D-$%aM22+Gp5(nEFLR<1pR$Y=d}wSbizk*_^XT{QZzr zxEg3aVzAgVw^?bPX*5pP>@sHUlG8l1`*`~c39k43&^c7(5_Pi&!KXe;HbW9 zH$O(-FP%WD@AVcwFM8D3;uqAc2Nm?ng{u=kR!Z6P=Xk7jXRtPu{3QHL?HWfK&OOUY z3x^V?68vX(sT2a+F7$T@1Nm+8VEk|R z1^;U#_=R96N!udR|GEZWsPgTEMzN#MYGHz6XqfywO>0U@%FPYjE}mr8OYlCt$U^*L zTO?b9+sEEqj5nOT`(KB9$9FY1wl}zV9vvB8Y#h89W3D{x+ch21yqxAHy6-J(Hp`XP zj-M_LUhcjh#Gt;D+uGbdy*`eAxDDs}_(9)@+V|^#K%bWm!%mA{kI&vc9PXZV2Rz!( zHlA#lZ`OxRlJcO#MMEXp=@-{pEK|H&)naV9%8_8z9|_j27{?!_mS!CE%f{0IhaBFo z+B4vdzTh)yY2 zVJ5&C`Gs3S_?r-MGJyfFejTyH~OPl=}{*p zEE*KG;bmShVfwXh#l>0d3pKoQI8VZVh##pTt3d#EW~D$H2=W=BAhTu5#uu_zW>gR$ zuL;{>@WU~uVhA?kZz>(SNX;Dr-;a4~MzpL%JV*g%@R&+Dw)I@O*$99El`S|~=d{;4 zGq@9CpV%07fff{{sH~U9xInzn#jfCYp|8{3_y5l<`A<5<5;oTC8U_I1iR1sC!eVP^ zY3%gBk||eMmWl@~x17BK&YazJfd_1G;lRX-K0Gal`Swu+21cU z#GEcVCw)g699OABDNXQKlAQ@&_tR@nW}g?+?CA}Ce_45Ze_=(4!b?r?BVr3PBc_L` zc%wJ8;oDa6_5y>8hB_z;x(hS4CjmO1l`44*(G_Dp(OVd-C;+2p3_u10$9DgO+g4qV|j%?u4vrT zbvVIBEY601_WJ`z*(B6Jcjp{eop$>IO#>-(;KI-g{K{%eSf2FrpsA(|d0@UqBQuE- zNLxeP%H||I4!hKPV?coyaFlUX;05v6knFP4-TG~yv9VOth4>{V&p%6veDkZZa zLK20H1)KsxWO|VI^Pk#9?G|2%lCuqE#AiLS3Mo^%1u4oa1r2<~Tl%f;ewa&H({|yJ zQ44pCF4`Y*s_sJ`Y=(sfg+b~?0pIvc#Ej{)`fwZv)-50s?-Rd=)$n`Y@F+#>u?sAL zqx)-23qla1#8)NTaZQjBirsGC^e%N)A0QvnYGEXSq7hHjZ7pVwgpYKRFu>MV3tN)l zwoTk7IDV12{Y7UT!)fN7_NP0}JAKn7{Ba;L6Oenw2Zv(jJ4L9W5EGL^4pErl^oc`M zrqHKPy611EdEi4PygIjj6apg-5_M4RVoh>Sb>O>4Kk6&?fdaQZtYbY@oNY9DoVg5+ z>Eq7@W!e0w*)z$9$d2~DAH_wK9QGVqaCGh$2OsEMwKMhE4E47s_= zOX^EFm8+bdw2dG~t3=;GKB(1vFMEo}Z8PVrFbhbJksVdiHf5TVfnpzp(ruhbcf-zf zGXOxLxzbemW|0vANGUk4ZZ-?~keX%8-sVPyCsAX#V~8ewoKpricVm$vP*Ad4Xowvw z4>1ZgUS5-##ZjD}C|gERX6@9iuIOvWtvwe?KhtwZItxr%vUQjaXMye9&2Jsnh>)7# zxmAeHF-Ig`ipaBNs0Om{!6SGRWl%3cdw$=|RLV)<4-cdg4-__lFL0)3CH<-~*+5LS zRqu|Y0(cXrVdx7P1?cdclc~2@HNzt+AQzfG zt1w?i1+%MQwV_KHugT7X4*4v(IKL*jgv%|IvtV{bDdeOnzi;Q>EWwDhw$Gqp4ExIu z5-(<;{QNDx5m{?zozBLG2FjRXW1CjpuoV=ezpXF;!9Qk%u{eY?jF@If8VVN)^%6FB zjiKc8iwwsE(3L|t#NMIvam-w!%h9xB|HkP_4wMAf%Jx_Dh~Ki1-ELur9H}Q+X5bKy zs^|!_#uccTo~Ne96W5!nBLWZE@yNe2g^RoKog{Se5{Qi7rF^5Bvm`xMY9rK*>Q);} zIZl#g0G|h`K&IR?pIml(NT=DG(R2;-Mf$rvh=jVW6o>T1nHNejg@kIg2B>qx6PAkb zP=cd(+(v3m8)OV>xIn`+b!j}3-VNP@{N5IXuIb{(>X`C2ouz$?)fe&0&#KS2mD$jsvr&;-YMKtFT#OaXbV^+D=fk9^LO3AUA5ebL(&DXc1o`dro54i z?dzp-P_URMBMEXpwkIOktl{0)27Qsl+YZMJ5wOK4j1NFrbOItl{mO3t(buO9w1VGd zs8*{Ewgva|)I*l+of@}*12MO1Y??f;3DT&cs?p!b zX=i&fGM62xHkAgXSCi1ck##PiJI(C2pDnKna>k&q45Fc^7F^z~C2iT!Flvl3;H>}9 zfQo{zvzp&LmFMLgFjLgopRi8tpP1$6%)m7R`~x-1)b3tr)E+#Q+bZzbS^7}H(kOW% zq;@0t@Q^4oRwL_wQK*_IUW~^{z(x2r-J5B|+p^6M)L`gb@CQE5-(s$|X*F&7(8gNH zv5~cXsp7HdHoT~n0e^y#6iqXMVQo@r_Tw~p!YupSzzOTO#*b9pW50Ugw{_v9y}&G8 zSdA5`J;=1BTI%l+5)7urY4jcOdew&rpXJnzdoJEB2R{rr>m~1c+qLm9>|=aKi2f4& z)|ZYE#93vE-y-(*KAZY8t!aOED>ISM)y=6$+bzo{V@o53!2XAn>aRwYY6O`kbq02k^Slqr>F*&uFJaG+p50Qq^bL2Neb(@H}f_%V~ zRI%rn{R|Ksd6jjvWn>2wNn=e5g|>4rC;>dmXjrakq7Zge5r!m$9M_B3FdF!tfqk|B zTJh+Op3IZ727T$0gmt93c909uW_mbRNhX&sYG$T2W&F?Q6$7~z!^`--t)dtWMel6TzO_m{E#&aiDQob)L$=N3Pa%KWUl0<; zeT@;Mu{wHNt>HoRFTY$dRixaGz4m-Tx*`1NUT`C38Cynhe;9Zt#1+gM*&eioG|?}t zwUH{>I_kZg(RU4*7uJSYc-@}IoCJUu`hRC(=tDeHI9Wn8h%M{Hg;e4Ixh8IPvAkaX zEks=9aM?*+nV)t%KCa@opt(1PjzA;~eZ>}2wKT7fIa;zcHMQG1I~o8X{p%EUSxf0KYwrNY`;Q4WspEHd98B=?oM-=ps;s%ms4`w})k z@#@dhXIgo`m9KrlqvQxF0d<;1gw8eDif=ay81oqIB^@R1VoE^Sh$S6!3s-r9gLZP@ z_(`GZO=@vf*mPyB*&ZR5Ddal_#XhA5i5EHk?us$FPykOlE&Dt zrQ>Zgy>n^9y?(zr(H;lci>0BStlXc%9W<$fmV;i3`{>szeka`BmmK#NLHok~7v;Z$ zLHp%MlRTLcR*qS>Byh^HK7oSX$4!TL&on+#f-H_NBt0YYypuN2mg}{y$>?cmtEg=p zc(FCLHFVV8yzT70*-^e-+`QaaFporCEfFMMOhgI*6gCA4cq^5DBMW5yv*}wbrs28< zE>EYq`YxYYkIC!UrdPa1c5mobuk}lfRyIDOt*<;Zy&gI(sVgg#xzR;YzQX$=h?PF_ z4Y#lWy#^`1!1$O$okHPI4+`-HN9v?MMSi~Js+Zs=JAnCi47{`ZUbO+xFAFT#uWULD zXBpO;bBoa`x#x?_{Z=oYyDnD1T9YnR8d}2=R_2>MtX^;)p)SsJd9wDi6)W`8$k}5h zB@2!4Fd z{M0Fvi4h?!SrG__dHmsH{uubOR42XTgpDb&^idgFX`unXbm=z1euH(rUfX@V=FH6b zc-7)d&ZW9-Gjg+~bPcbqT3wq9xMkRB>9SFSh4eD*!U`ukB>uek9AfRCk^O>sPCPY1 zN>C;WAlskB#*D-G6;gAZ>N>qOx^(_v;Il!c!ulXvTfiV%QUF13VhHmJRD66%PZ3s( zB=gcvth-H<@$q&)dGWb#=@+G^1xX5sYM(HUa*+@R|90~Y&-!!l0;vRDxITtKq9G+? zVX4e#x32Rk`~H;cNL`NC*=RyyTF8ocvC9N{0*y-8dk4IZpAgLjl7`OLKEu9Ibw>I; z>0|KP%S?h@129pz9>TzcF`qfmff(+G*zCiFOOn;fl8B53cr9=2lsgZ$ScReLn5p}z zGxxugpZ}P_d7xQIKu7=pQO5uM3Hkr6F4OjOJYYij`S~RY!4xq{@4p}2KoC(TB~;^>gZ(UZ|gC=&+%YIZ|n35^LjgeZILj9f_2Q;C5Q?qk+R`N&+I(O*=nIItQ5|D zeSO_-2)utj#l)Aif0}EwOmcp$4FVEpdE#wLDtbD zet>(mZ9Kg$a!nxxm5u0sI!Jm!pw5-?0QDu4*eBu`QJ;xSys7QQ1nHjRAmxSa@nvL_ z{Hv%XM67e@Xzzo>!UUOfo48Fa>lPBpq&fD&;_VjXWLBhSwqA+iirAZ5qF&EuhgWal zHSnq}^v1`HT|nj!HgJbu%69y>WM4r@cuMx*BeHUZZ1$8)!i>w%3uQ-iK|W_**F7G7 z^t6)f_!JnO>j3g-lt>ut&_3xiV&o6{KjO4Q!Hg5`q`TLmRP(B~T`vC6hS* zo}+te;s4=#$GCL*I)@tN{V=r^RNhAzk+N`@Iu zRQ3b+N6sDoLkWx!=q}DDm88;Ig!igh1&&O6gRE~K(%tkt3%NSpu!1>xFqg@U}0A>gE;bRfj_x0U}42%;?R05 z;x}v*Bl0o$$YwhJyD1~)Gk*wU%P8KFnJ}ns3vl0xtF0J7qqeU!o53Pk|!* z5loeppiqif{wMCZptvm1^Yy8?z!($5-(y6+U?t$T%-I}r{Er8Be1)VD(N1$R#Rw6- zdqI-?sXGBjTg%@m?VIB-P$sZ6Ev>qHIUh!ONI)h-VSxW%81XWGK}~js!^@(%XBiZ7|DA?UfL+rkU;O#C`Fm9CBbC za03mxWafkLp5&CzJ0@U9*z}cy(Xc9Dmowwv1@|A}cC-brK6I6Q`lRV_B~rl=z^hpM zz_>1s&y_V?@kpq;Mc>$hJ2mMdvBSw|_&68JF^f~{KWi>!@RXrH%gj8Dfs4k8gO>p} zGREs$(u~CmV+LQw3HLV9_E;YYbPh1ARQm2?rKUUnmu5BwloT4o(0wJNg;L zZ+8&66aGUEF=+P_F{_8473V3&$0D&gPz54#WX^Ze$t`QC!CkN`BV$R};DN?Aj*@k0 zS{CTx`4Dp684Nz}=0{?Mv%Z>=aa z0$qLiF$8wx@`BEQN~v0Y8-!m9=9c}SL8Y8eYHusaUu51gBz=mccqwOM8YpKV5}JW4 z6LHVx(D}5!U2PrhJ+IfFp{%K_s(3U$ZjRnGnk6XacPm;ueC)Xf%=J4x;XKPl-NM9` z1-YRIXnoCLXP!OcT9*inyZMGtgkCn7Ir^C+JiGZE`_s~pl91w9{q)6N8e%B#Zv+DK zeafk6f5BzrsY3gB(KGXLLU^8^(U`h- zL9o*>8I0{KCK=qPkdM+`GG}hEdfKxpH@3?ka1Y*Gg{6y4wAg%pzEK&-OrzPU$^q{+*n9mSw zH%JGFd+fr^8En+1^oClrHj1d6V301Uw>|o8-RY0G5+hoQb7M70STqWPOcHRW@ur z>g0VM%!7RVpDVd&`NhybGcZ!n4B7-Th6J~^_9%}2aAB$Rl^7{B#=$Hqa@su^xI)l0 z7QG{H7zaU2w&0i`(S(_QV28k4`t~nD`)uH}wPyQQqIU|~X5IM+ z-dfk8)m$xfgR0WDX^bigp>|~EDgOCzhc@)Jr(h ziX~lp2$$8mN7*isV}04&B$J;?zv3V@cvN%rM@BDr@qx^=$MWh9MTxd8$UI?Z z=A%F8guUm;`X49*emR5&a4CAZ;BFqs9`Z!pi3eIg7oD~Z7~m)=oRrMkHc%{Dp>y+$bC(zWx?P7#KRZiXCBXd+bfM#>c^dHC(wQt-`-Q)*h##ps=W*&9= z%%A1U<0(uP)Iv1Bi^_R|U4Q?67?2ooJ(erGS-<%_HA0{j^qltI5;fXarf5UZRy_-4 zC>jqwl6b&R&lJqU6;331&QD z^N@kMSz9u!`6XrewNvB|%>Yug5}|(jqkglsq@+WD@RW~xf$SqJ&jWq?L(R{w!s4`T z>(8lvd{8u0MU{#2ug323?cAAinTZk%;>6;_{LrtD0nQM*5Q*sfX*|HkfP?ya3a@4{ z+_TNpqI9mddkfGtbZKbj4PZUeZPVtMo9k&}-E=qtXlf~Y7&W#VCSrS;aEO}^TYl}N zUOtXrUt0lr=vo|qI%@%}fs`G#eBw(%FW;e@Av;e7TbNc8K(eRd^b&*g>cWDwCrw~r zKE7*CPeD@wm@QxAJygHvi`?K8+Hq+gDzdDblxW35?fjoRNmniTwXXX`m;on!ODq*_ z)N9Buzk(%c+cJQvYJjyUB2Xz_1iRprzp_hD!ML>|@*DAa}c3uiOk` zdkro?RjYfm1IQDqng7QvW7kUKv4TEY)MqJyQF+ul#jJ~j=_y=y^6l0Ay%dYPV;#DH zwnk8nu0=1y3N-$_%c6ADc-*?4=8h0^kU-6^cyvQI<%)T1sCITSY(RuryfH!`Ik z`*`j7duHt^pmObHhf{L}x}Hes2=S%&XLaRs(b(~{lE-81d^6RbdIg^)3au{a#t~~H z$8_DIDOFOoGn+9XRK4?@v$A4CU_W^HF4KUjdkM>(Nh4e6N^-3Ur%;%H^Er|k0YU8_ z^j;FuW!6axe#>+n;0XmABfFHzosDF%FC~aa_zE8%fs6=4rcGc#Pu8{Ezg+t@z+f`+ zZx)0{AYS&Qz;}EEAVUgT>zI=!vLa59N6xQj7{Knn>E)r)s~wj_gGhspLB1RGt3O~K z{#c?ms6b~5NvzhN9caQ=VS`-QGL9*oeezWWoQv>ByFGJwZj}uDToJ8WphmqPE31 zWdj}gt;%&sUHI@S%@&Rs8XSxbWhLU3Z3q-z^4VNRYakvnK*<^4g=UUSpAWKvv*17U z1aFUGDas+-8lFa7DBb3hBE}x2mF4HipIoO?$l!8>RolxqjBo$A8j`ylO|h$ytrpmy zLw?H0^+>MgBQ_C0L{v;VS^#wf#ZVs8X8v)5Ig=}_DJ!WZIl!uVe}RxBXrf&cmh2ad zT_U)jAx7a{f(OYiQM9BKF(ZWN$wtm0dzdDCW98yP3)$4O_P<;9{}nN zJvE27Q3M}`5%>Y9WmdrZ(H0oQxVJ^YN>UEjp11z{t|1Q352MI%w=R}qv zWyqsymjqSxevXhm-4HdnMHJ*0fM=d<#*ywr4&{zv)YL!?;a%U=>#5 zFK`_wcw@WW?fY_c^wDUG>L0}&e_{s2uk9e5JX^xxREkZtP<8CBhW?Qxo-_+x5oSRU zVrjLxsndM-sbf(4c*(k6Ia0fY9;htw&^tU2tu4*cie2OObPev15O0PB2MT>jWqGjzPGZ{1+toDa{1I8hv1DICgNp*Z5AMQoJ=2wN&*! z2fc0t%m6J8q`AEF#^PJmxw2XmKbKWv4g&URe2<|PtqQavBma$wf3OA2d8X^<`2GEJ z>uLDIwU%I?1RNRS`g8hdSX8Y0?bqjSO}**mp@&CTa;- zDf=ifhM^16BTSy-Qeq6>aZi~L0(4ALACWvxcp;r!G1=N9Ns*oPX*{xAR(c+JR=)qV z{nCJdoz(fEm~g~djo0P??EY1U@!r#Lfsf5glS%~6Yxmx!Ubr)}4Xxu5-7#FVOzH(G(`jHF$ZNvk- zT-~aeogVC4_EpG-QrIkF^^ZXZiaH67Vx^gHQj6m5L7~R{h8Sv#K&wVtbR0(lh;%qI zP}V7d;i3L%1Fj%sR7E_Pmr8XlelqGda)*RRhMUV|0ld+-XA)DN;#KxK*U12n~h z(~`$B=$2dMSGCR#+G;R9i78yLUPUIdrFW+TAGUJqJ@0>l=fH`{d|ct+o^v6=Qga_kcr+Ra!>M5DF8&ZY@TR&}Rn zY+%T?DhIz@b$k?2?Aspr^W>q+@iP6y=2VYU|`WJbD z|0ah*{C}#3mw}Y5U%!f>)o;Y$zpEPlk6cH}bPX~+Oz;cWFsc<|!~wBPkXoIdKM0Zl z1R8|0i`5`%arHIM?i2k_y7S~x3A-;*ZP&u_Ve!Gy}9oVccn3)1&BgBgcBC1Ru+tcBm_Awm)G`9?e^9W zY|=%b%|6r%&HSWZNtT>L{Ht<^zac`af> z2Jz}BQlc3xjmbszb~g9Yuz1ROt$bW~@XQS%LC`2FkI6MZQiKs_IwognlM|ubP~+Zl z!?mE#6j<{}w4u zi08t1$mL&*tYg&O?j>}2JRcs1ua_21WOaCbT0HOW&n`x5bG$}>oU3!KOkAypHE$L< z*R4qWnd6ryseU;C-W=Dh$m@zsrZ=F(1C+}OfjrHTFB02+zgx*89nq8Q$x4ujBQTQ) zts>2q!T(GVR_t|K+^J>A*)$;_J)L4I>+Gk?Fo)-uw>L-1ku=NCnG`Fi&vC1BG^yD` zePPr`-=^;tS_rE-#+7WEkHV@2nNPPc+Cu4A2|t}ad^EWjK?<4C#QZFxk$y}ku{jjnW% ziV>nJMlkT2i~g)1k9Zd^>e|+%UhO3dEF)asC{**4!V3!wuhKh!if-*%yXqB9IP*c% z2qwtIEE3|3^v!!&Bd_{)^IZAV0-yMpbsx^n_el(sf);tkRsk)ejT~e3@q+otpg@1L zY+@ymiBGA3LC$ds0jr-k@P8^_I-9^8acHJ4LlAAQX=4iW80R^r*Y$snuTkUmbRODV zN5kjJUhs!n#;z(G8q+)RE6Mn?fJT;2KI+o8@o3RjJ`S~$_LHeTBK=`#0ecmM+W{Zj zVSb(I4BY|v-^FRn4ATMP->iG(pI?&sf6su>wR13c(PjIe67`b0<}Y0X#b>9M4v_zE zd`W7xWoru(9SyQ-J>jmoLssH&99GOi4gNRhXeyKWNTS;5gH_ z6c`#*`X3}K=r5AB15?=H&mfadRu?C6upX|gx)#{(Fm#S*`>tc{*s5yWa5`oa(S6h? z-?ktGkOG*YEHJ*@)Iu#W5<-D}nQoK1Jev?7mpxQ_RDKwM98b7O)3P8CHGey&c!EP6}F&f+B+X+Sy%^BNb@3Hi9Z|cV`ccP*Wd> z;_Ry3c8Gn8;82HhOf6mS^s)uCWT2rq;HX<6z+mVa_sWV@8&Iikj4`&?qL2AdQ^OGU zfE5rS?Xn~1Q;2+b&128B9|;dI7a12{KIH({RVx+bk2qtvo;V9QA(0LO@c?!bh^~4T zDguJ9_~o)|*aeH7(|_<{g$hdUesp06gr!lXC&;A-r}i>|eNoBCqYC1Mx*&5Ev$r!Be4mm3%G z>_Ym9)EdO(aQK1r=k+ZY-^+4i;A4Vy6*XNui0m^;k|%*l8JX>TrzCG}di`nsh00Jm z_zMtOEGS)=d>7y%K=~RVeg_I-jWrrBR^eqf{q7Em0^X9TEGUEhb9)zlQsQ7x_UaL8 z)8<1iVwYVm7;~+@LGX}Ez~jZ~-@togmoXvPGFH8`>vi)0!%}f$v!u@@g11MPNY-*7 zID9c#zQU-9D((?HW`}hpxn&sU%@kd$OYE5J;oDl1cs4BLQF&zYbh^e$M(8t<$)?9S z3KxKMl(+~q*PG;ZL`6)zMRU&lUiZF=q#ED!Ws3U>Ze1{Gn~(yPV#~T3Y}Hsun@6>- zMfpRTWNw5qX@~gp7Bw`24In+~$gl2dcZkq=!E&@2R^qQ*W?pvj`fefnCFkQIc*3~Y z^OR=+=EQ2p6183dD$rXvT5E?(s4C)UbxrMtX#}kx^rt7=&>jToUdA!${k@h_2etvDZ*r^1b?*(F)AQi&`vD5BV)^m(c~Q^5ad zWeLS^Y*cN1j9dkcRPuikS!*7jV=$%6;Bx{p{W#R(&X|n}8JnC{w9&+JOWQmhhiAU> zyM;qAJ8C$=mYr7!REP7~t&wJ8?eVI>sG#*cR$SH&zgrm+MGZCN1uoU3>5(fQ9ZEX> zjHbI3F*Qr&gkXLMFcYtgfD*9S*&oyHYB1X9ZLIbB_jUz!cOkXjCz)qc&>=Gc)~Rud zMVLhCQE-Ui?ZQeltEcU9V~ci29BUaF>j=NJb+}oN)FGLkDBz2Bm!GRI#?oP}AlXBX z=dZQraP^O?BJ7`4uQMuJ)gceeX~A1(s-NOmT@>HZ26pM5JTQ_sg1BxN=mD2fdAgKr zF4HyR7Fwv9$@9rPc|RrKmM%p!ny3)n`$t%Nug&ZzQ`aMYR4n1AlC7@-o53WCjxx?$z-2mik^FCh*yog;t%g1J5y?@Jh0Lp2SmR zWuxiG3tj)NP8}*5G-eV|Hic3?jG_dMhwZ?`0!{*d3SqY<9?R0B7Zqd;t&x+x9 zs3P>YoH5*}nGZ=*qV&Wes;pDdTuN!__Uq|WSzr$XA)*l0R{a`vCOrDyn%f09Abg7a z99skh)fA13Z*8&67M%GHj%=7gbBmcq8Q{peTcbMCBd_)ytEtk9kkZ@-d6KzC_5UI5 zoq{C$_N~#ftGaC4w#_cvwr!)!wr!hTwr$&XSM|;RKKI1_&i8coy$|ytBQkQunz171 zSmQSUYOmA8aWrhFPn95Veh~%vU9qEcCpd{`CfwE)1fvpUBuGo#w@NxlfK_nr{rUM; zSW5`b)PkmMw@6$yvSMQ2waqT1?3$luAKHr4gc0HO`*-wG9>~%vIFVxePxfBq>g~(B zL0gksS1;i>Hqt~&HswD?kbx@-x+u$#nnt$@FPjKjwb9pnj3@B4DvyyyXbz6-m@g2J zLT$TP^Yrk)7_VXw2)B%Vp?uNbmU6|{9f`<&Q_n+gGxBn$@R{tfpdVBrs zO?2soVA1#IyMFT;;q$Yeqxr3JZx_@5(y_tQyj+2SYc(X9#n#VyfweWa`b&Ml4{GUe zW*;n`&RP!~sQe6v!Zcmo!Nj7oYxKl&^x-+Ty6-~c!+ujV4z#i_*I;8W#c(3D5w+m2@Rr34^cwxsgyX792xhG8$7Qm=XWAxch z$~BY}{JjX8A@J{~|E~tu@JO6TP6!|%4J05SrvKzt{~KM^Xjm=+dRxD5>cZz0vm2Vh zJ5bZ_SMG6#6$Q8~n@Z*vR!IAzV*hSWD^f|Id_G&>EBMZ>CZuBgy z9_oCPVeP)gxPtiL%XfN3C1J_+UiPen5{vVJ|l)CN>EoP+(=~H;b?)< zn!rtKg%$;{=@^@%4ED%miwen>4JU}DYMb@7$(*pua-o&d0)aOtM}d?9-9d1q$y7f@ zq5>pCDFqUAgu`|WBQ8p%6^RSd6-(T~%W;9wmd+$@`AO@k%T*$^+U)ro;hoEtDA|e# z1nPutItkEnB#%1LgFePvqbk@tElX@w#f91v1^n6oY2{BHaYvh@j% zoPMdFdxds5*U&VeyWu6#)kP!0DZgygz?SKj1&p))*nZH*^9b>gv&S|3Lk`?dQ`ftg zhY2dY%a|B>>#%Pm0wz&dDUO8^9B>zzoFZPY+5%kYTmXe^h-4L%XQ@cFN4k#0@Iee6 zgdR&r9Tu2hDlQ8q2_sful^W^9RfN>?ndx}*LLRPc+uT5qr~z7k8>n&eL5>A?*`yr? z#n6GKIC(*m3PCf}SPb6*2?sM4Pj!J{aNHiQeBEcx{i7vja7(WP^+%Dm@=_fyu~r>& zyvxqz$o4lY>nZ}RXme711Zw>JyK>R<%7q+$ujsYLhvjStAEd55`Z+p5$Q(C}0B!+1 zXmWPCLLezy5_ZoO1AZs{Wst*`9{fCkjM*Tmqo->bHwlZOg+6e}|d!wtRw)rXcyI0`a=^@sEORZi{?J+jCvybbt zr*DhtW<{=3h{ZiW=gCZq_7Tp5kM-w~0z3`*1P~8S&gWd`@CXvkO}k6-o8Z_~NK_IY)W|}DuQOFF>$&NxZ(l_u{JQwyxUzd`;Y>r+t?6A$hotI;P2}V3u z;RG-p;GP)@!{TGw${9LqC_P)qsO#>mBXp4@$zfuKHJ4u!_z{j-(q!vuKzFqCF0Se( zR6}R_SE#3zt5zF%Rg7Q7*3Eok7Pwda40J999{2`SEbo1T@Fp1kj=g}n;jLk+FZBG) zc_vO;W8GZwMhqg-!O%*OyVMPc-d}G?!uLEr>yf$J5$e(s5Pdl*Meat?EgI6JNI4qO zpC^jC0(vK*VV1$b8e^FiM zcgx5{r39X2tl^wucz;jTdGD@$s-d!`EXemmcYvuNAD+gcxR}dxd$b%o$>nN}UldJr zs54|qbk3d;Gt~85n}UC2y=4- zxUDTo%EX?+2?g3#nto&LcZRr|c{OITXsi47q7{ygj(!N!AjcU1`))j()HJv21^FRTx84CJ6qx~LCsiRA*$OOl=&34U=BXODoAX^%y6w8Wtv zt0c(`MbD1K)S*YV2Q>TT44J`{rvHG)f-w_>A!ju5jKsV}eDp`pw+AYl&{~Cmn1Ejy zf^8}A2bHl-?t-T`y$kDUL0gx91&POHOU=2EdLD!g${mMx)vg)}{6zq+e zx#&DS0UcShTOI?J<3dW_Z-oDO;zBSPgu($%TW-Mm-v(+s*jTz489LEB*qP^q^~iu2 z;s*F*pcm-sC$TOm%_(p$seq+WJc~<-LH$ZNM--(KlAJ>{LuNZt!Icz|VnZFChtynv z6lxYF4KF-%x`_A)^1`L2^!gjb&wIxU2`Da9+984jLY7r}RKfu=nbV-yo_h4g0TLp# zvN4S6D`=u>QS8Xu_s%FSZu#~6gBq3m<=4A!BOK#NZHatpgX6PwhJ#aaMr&ki)S-7{ zoelN~y5Hwyty9?`f%t|u2HFFT$W0DLnsGx(6INq+Pm9$j-=EG&N4k-#U#E_Pr5Cr) z$ojPo=*7gv%bl^D_&0P>ORz37=N=vsjKEYrM78RTK z$J;Rf-q?RUaGebD^XLE)&cSX0v(kQnH9TZb4{a1Ixn#2ONU%Oc1H zXh%Bsx)@s_M|u-ZO@avfJ9FV+Q${5V3&-F}dhOS>Aw%Qpa(MP!lr(FPpVSd8{BZI$ zh%p)$e(1F`Iw+Cr?&2iM&&T8W9@Lyg=R|Cg?Kqy49+vz1mLihfk$mnut4*IaeQd~r z#BzI7<6c_75xM^DVj9{sPU=kVO+t4^3v+1G4PMHJ2?y6!`cE%=V6o_Y=N;W?RKp`> z1liC6pJvHkd|&iPYzT{G`mg@%NVuc7uW^*NTMs}ld&ez7dt4%AN#ds=+UeW9hr+`U zYfuAAFeX?^MEM*ZnK=!BJbBK#9+Zs*|7Ds9rD>?)M1E=v0gE3{1?dhIH!sNQ(i9NJ zXlIQ&ZVHv;;Q8l-e_V7AJOYRzNyThBfOnrLzKsza*b#_C9)(1C?6A&+-XJn8pI^x= zLj)|um?EhPv5^btf_UC!MM*Nh#58cPqPo_n0M^P3kIetd=RGx8gRR$O#^fj?WgByy zdWKK|DSo;A@?*q>2)s{URa0=JcaTk`b%K%l{JEoUh-;nXNG+I52;VRrmlZthtFi#( zux0~n_>33x#+E}DLIuou*5|tt*m`WWS^OWmr0*yBb*X?N&Yg|z9ZKuKk3-l2EMzjO ziT3@@5HeCZ(jc*MknrrsXhNiuEYdd?s3bVdd-b8n-$FWVK}AWCg(SEsu@j)A0gO{h z*moZ6Zd$SUWywq|YI3+zB{APb;X6R7oO?|j-SRgt3rz*Y17f9O#l-JH6+$BXQ8__d zAe}@%6DpRwVH5U=#aj~P(Xb>|p<28?&AL{xV-w?FkC3gS*yQ*;$X6!jlTEX?FgwBubyTMjESGk8XjGdWc7EbUG9V=qi)wdm97Iqz&J zLJfKmwvFypOw-1?+&GX&qxka_!!kpbSGT(f#J`Mq*t-@yJN4HA{Yy$BOCDum9gd8o z0)VdXWpYz?(d1EjHFk3&U2Fc0xOB(orEyNsf7lWh-ec#R$imnJqn2y{TXOPmwxl$J zoKqsP=D>gsz?MvewZCb8Q?|&7(EC!aWSohQyK~G6wqu2)W4<1eh82iZ1KQY~Pg%{} zL{vqt4=$tlo<-iz(E!naH#nc2u$Dsk~<6i6)O={?ql8 zAQ=w|Mt0;C{6&|!K9)h}IXiy=TuJ&hg=2EQZG9t*>%xT2kSQ~}{;2ARJ7tYyeSi9- z%zLh3vC7-;0hr^_v_`&Ps-Wl-i8C92%wBz{>&?{M|KUm)f0&A6rx*j5qMjnOY8}-S zw2}9_g4!zexLkdS4QLj*?jiPEQ3O$Ww@eT&)Eoe~60zi+s05{TG`~nrRyMaBnM>5M zqVUKR09R7oQz1MVBbWmh{y7Ap#r|+6nnRLvQ!gBC+FJZ22(BJzXE903T^G(TplIbf zJfpibN^BaTiH;e3+UZ*DidHU{HT5t^`W9(PKnh3B;fWi<1?u#vojbN4j-HIj?G}ak zQTEj_L*bhHur!!)qGLPH?1^o41iS2c6&;1t92mvo4-7Edfojfvf!jPiK`_t!0oQ@> z(-Ayi%@8fg_m92@)ucWYKzG1$1!f8VV< zHzk@_CMFjXNu$f>oP6S)@|59DUdf{5FDgsul6Z;Pq1T6+1+`38x$z4gD;C|$qDxoRSgSZ(~{@kaY3gKvX#sZ zl^x00Y2wqz0siQ0-qx?oKEwM3{D3Tv`^V4($Kr^3S56S$m#V~k;{Ag|s+{h@oX4LJ zgd~asPH<}pX&YK@f%y;Z3%=V`LTOM6SzS71CwRegqf&{6hoB5f(7vtOH&DJN~G9k1@uCvO|RQ^ zGs}cae@A?hgAlbYH>6aGxN26U1(xsk%8Oc#AB#&$(N;oBn1T+<~PZ>GH5YBKt%Q z$0*bT%l1Bf(ZQ}?_HKx}R)6W09e*;~zJs1MfBr((UBe|v)2Ki;!?(h&UCi7?~zeMd0^XkE}Ng zN)kD6uK#b0@ef_HEDB=l58w{!0gL{B$sznV#;|g>o$7}fU<4%jdFK^QUBi(pRZ#{#jSG%P?J`(xUTs=w8e2T`*xR z-<${72qTl+OB7^N+yMbggZh!hoNtLHZTFntF9mM~o3{lIl96%~5}Dqq8OUbst=`d! z^Zzb&FDpTeXa~ThJCgqtF8#lD2<&x0!17(rKcgm^gi?$W(@p6(M#qcXOm z0k;jhaDQ{3Vkw5!t^lBZ8I(Bl5$Dkt7mxS5_nyO7hMS^_Xp*Oc=WPm!*LVO}+MMB= z<>BQQy~W29@D0+6A?H5fMEcnXD0Dg9_CFysr#5xld^~ydG~Tf+_Bp`oeUd|~OC@ft ztF2aG4=0^@TTo!|z?O)>v^8ABhJy&xI#l|(hol^lFyMM#mOU*#)5Ds;ns9SZT!a8K zWpO0wMGb#1#5k;@z~$xpr|+6)hn@U(Yt?Djl1!U8F0DT%o-%0$CY zPw-ntK3yQ(=q3AR?n_h_@l(wS(@=w%@a$NqoQ8l-F9*;DFt`vBbuiAtqSO=OjOa7Y zOoE>F7_c9_sbGq7!Qqq_9bs}2@E<2LU=xI};Cq>w2?#ez zg2AhhhNE4mdZO?qWiRAWGnWPVmSP~T!-&)mVU+P>9KRt8t6P)8KVS}&?Cc?aM`gmq zr%6M@DQXF{H*dQH8R7rrdwi>a(AoD9vaY^+lLJCbQv4i`O9siULGqJEzaz8>!vrp7 z4Q8Y7q9+Cvx_JR+JyI zhHP>gHRUkpQ^^^Iu|IXTW##9g$XsIe&<-=3vYqS*c^vFQIFX-5T!Y>4oGyIk;np+s z8Ie%WJH|%RYF7q$=S!N@B=qTtzJ@(ue5_XMcH?==Lb=(y8ZF&=3jZmt98i4ZVH#@r z0RDhs)vscwY9bn;bu4J)GQQM$obwBb)|SQVhgu$sH__-@eq5W6L^^U!Dti_f zd{w!b>|Dl4qz34sdAWbKllN8h^9nN`&G)_T+yT#iDuZv?2KEmwbLWKTL?3aonVHrU zUf@DrMBO1*K&67wBqicl{OMn$&iB3qwn$U+S6lWH^Ldd}uAf~&v*Tl7BAWsLoN_5t z2h{7eYJQ8SPqLij3l*!J@h^Z^=VeR1q|;lul+vElPTMz|6aC86T;5?8+Uw^{1X-re z1IIQBSZ>ogD(P<{5A+<|DE2yE+iXfs&}zCN34x*PsvXJidq@9NJy~sN6K?NVqF;I$Rv=ZuFiL`)aWz#u;wNzS6=Ezb_B(Lgv zV#lZ7%Gw9`!THTBE4oQHJFRs||0yWPk*YwbSQa1&^Nm+R*hArbF1JM{wZa)$bPHtJ zx6DOTS#uaUj#%hb1nVgfK5YYk~-WpJ4W^Z>!V-|sjJ)2t0)BK!NQz= znzKU*)$6y*Vf`yh&Y*t&M`eOFY`Hakt)Aui9n4Lcxn*UA5ES^?&4Sn>?3v41Bu#xd zy2(h3Q7{2)k~T8B_h=Qec+qtYdu+si{A1%jDR1 zyOe&PN2CRbp%fH>M@ECfW=hjvk4Vi%S^8FR&Jquo9BL_FUJW(W?AM<*<&4Aa%Xsm6 zb60NmAJ^=7E?w>Gmvd&lyJWIXL>QHibF+{7$AmtnKRn?Bxqn^;OUgnk3k=Slwhaf`DkmIJ#rE>mxj)y>eLgKyXyrp zgxJeXbluQ?i;4-YB!g*T2lI-l)R?$rZX+yL@?u)q`!zIeG2c%)o9m=}0c36Srd>2` z(}MS!1lN6-7-?`nPAGiwiZ~M1rthUMmow4wN$us=AP5K@U5Wrj2x-u5q9K>hd~v#k z>_OSuJbChDeGH3OQ^pverUq;UoY!AsmpgjlX?G7wJvOHO50y=5r4`j~9cmxQcjmzr z*D@9X_&BNY1BA99c;>3I%CRb0B3}_e>-YiJvO(()fLBOjwSDli1H3%0fj6nT-J5OV z8ad|xZO*GjKW~SquOG8<8~hSTJnZ zt8IO*qN}E5VvL>rkL&1Ko2virg5-dBSz$1N(dJe=wd4#0QOl59{UA$299?9qI7`ra z-^-9lfuh%Hs7DRx1^%CaZtrMpp&J0?m;j+*{~4hBN5U7HFb@+3=S;!MM?V|-{{{i3BC5wz*6t=f&62v){UYD zficH9?R9gp6&@rxr~xz@?r=xB#bk9%6b%#HR5G*pci-?+#y0k2!dk(%#N%k;kZD~- zqXW)E@DMmAm3e!eC7s=W@54X#SleJf#&AF=8ZssjkkJ1Y*gClyyBONI7y}}c4Q*`f zjSXGwo%Hpc>Ho=19@h9THtkd$s$XzokCRIM1}h&IuNEN$I2UtR$tai(OG*wK^P8t? zuwlEDl@6|(G`0ED(!PeZ)9dc!{%LU@1@)3vOyZWHhu0_C0Wpl=h8JNl_#F7-&FABS z?4p&&f*M*qLJo|=5|iIE1}U~>2GX!yt7fB$$Ce0V|H;Yk)YcNK;4Y0xHogFUt&LbS_TIRk?T|aY);Ub^NZh!3y}@m2kdj=9 ziO)~K7yHSf9sbDp?%VKA!-Q*ooVMl=mmlku249YueFSzSgH&q_dpnR*Z;%(WV)bT+ zYrNs-8a0N}DyACr@_l-vDRM&}f?ZKaaG)f1d3dqSRtqKfJXKb4)nE}YaYgLIEUB!R zN$cP0IUc$w$)Yx!8PY=}oX}MKw}lXYu?7?8dhm=2w_;TB#1iA`CvH<}Gq|C712%hF z!g`!aN%D@`Iv*k#BlAF^af|3)ADVQXwq8nJtWY~s4)M;DNHKCKmEbNa1_~KEtj{W9 znbO4DD`aACL(2K1hb@eQY#pI9uc*lKF+!!64P;{fZRUpi6-psO!PhYL)+{+D;v!BL zfB)qG_#+vuqQLtspnUoawWYX<4mL_i4q)t9mb?MPsio8uiUSzNTm5d?DAL<&oQ}mY ztS=(ORX{3SskBCXg0DBHqaq?;QA>6SGWXz0!Nuc2hlyLD5L8*9%4NQBrm?VG^VIyx z=Jj+aX3rxnH(xUjU=Q~YiV4%{LrGt5ZNBEHnWm8FARB6H89&!><@K;D)YaTvJirzb z&Mw2Ctq{_8{z$!^<{)Z`^#3Ahwll~kKBOjBlq-gy`3yC$E#;#PX8C?S1t87LwA-|j2Ax0fb(^Z`A^L#k6}V)tXe1(m{*m9f zAK_l}*#rQE)}^u1lubkNCZhd9`lNxhmzdP*Ra7`TICf27;7ikX89)AbR?_xUA-9~& zn;Em*5%U~8G<}p8&n$}0hHse|#Yfx<6{N$V$`CO@=s2(sjoo(2b`X+hdxc(vZ49rP zdtdyzU$kz_4tlA{n#lcI%TUe+k*B)Z%#R4P_rcN)rJcMo$PcX!U1k)jLc3=TteRNh znP?@cmar+(b-tla-?^h1>{H*pwk~q_GoT@VN!t18LimB2XVcyz=N|8BWrL?*&O)U|EPn6|{N zEXXCo#8%>w5droi_SN+)Fk zDXvkaD{xk8@{PyhYkJ5ZaR@mM9Hj4R;Y1(s>R`-Mdrys)x{w{f* z$j1r-#70gKB_{CLO02#)k7;H-xvkTWE=05aGOq>jj?vv z*-k{prRMpx(%YHUpSZZ86s5rtA(ml;pD%{Ew>;Q&!dPBK59~`&j3oCd;>p9GD2qzz z1m|wmqEf7r5Ft}MKh|t^u3e?tWO&?Pc-*~o*?Yb7cCPC`dm!aXBQFu#^%}Xdf0yp4R#|DrJj%ZJOjl*NC<9src*X)?Md^n}Xov7$Ohn$1ta3 za7=V1qH%PestAk%^KFnE*~L9ewK>N72FlZ7ry{eLedA%Om%?DfT3?-m#WN}oaK%gGJ&09k^bH3Q0wn^@XQ@VUWL!u zmbrm0K9?rVa#j3DQc{xx@Pg5zYHnr32$5ThPTF#x-i6#8`{m?$T6TXQLiH!j5+LW@ zF^8Loj@4N_)aRi-MAUQ=Dw~T^R{)azdxOmF?~wlKVBR@H$6MVF^YGaUJ4c{_{|#wJ zJv3MwnW&qK2JPTDs+N+LJU=TW|7ZIC1fCXBD0)`alTPH6>ph5DgYGqMWxs(+@k_rc z2)t$b9VHzl?4oMouTAO-7GZ`LzVKU#>^dM&(q@Ncyt!B8?^cCrb&lAJgC9YIJU~#C zE?=_wj#0tt>ub9QS0Q-Xl7vjN9Jo8Dm@OlWX~K^iT3U;}M}%P9JPd(5Y_#ntIu}6e z3k#{}TrDxm2=W*9xTz!N(uen(0)p!p4($T<#=SYll8wXAD()4O9ZnWwKbP#x94uJc zeWa<5tKO&nq%g48qy7B9`_iE2kkCQ^$NMT^3H<*(<^c_AQ_}!K3lR)JXb}%tCv3CZ zq6|?`k=cAd)oV#9=k4wlaP)J*58m}qMb#W_V;mgluOL5OR8+5T$m(QuAh9*Y@9MS+ zfBWR!9`{oef+@Q|vmqM={0`PL{%HjVb5LGp#p`a?&97s(dJsObH>a%J}n2FQ`;#BU3n4J`*gP0EQm*^+Jq(G>oC% z3n-$zY_lKN_=)_mdAs}P>4a_GE4ZIv<+6Y8;v@3U`{47e08&w1(q(q380`VTAYpKK z&44{WBK&g}B6!$nUSH#jwiipM7jH{iE9^?=>ncKgmLEe0hrde!bVn|+x!orq8VO8j zUAqN*;vPW4Mc8Zx`;`gt|9p1m)5qZz zJ(}IQ)qmA9PohF|OlJjD7r!uTyh@#e(YN485|t58;#}7@Zj$Lq5WV{jc5WKu4;p12 z7tR|ZIWzq}VvNIjS{kQ8E~6yOe1Z{2X=g=6Ly7_m8$Xz~HxH3JoG)%Cx)tR&4(bkt za+1W-fm5Ne$r(D|HOUqULC!avHy0~Nz)h5?L7W7OWCCI)Qcz0?uMfm7HSpv`o94Ma z&#tUmD;QfZdHK%6I-30c6vokmo8YEU>nJ=Zw`%1b`RjeOJh0GmW( z$%grO+kt$>m3rTLupw!rUL(vme znjPHzdC;+caf&gf-#Kr=4o$QgX105#jRES}ManK{^&=7f5tG>VE$PUsz=OixPvnO3 z(|Z}(7as)ZbYwec^4Cn)k3=B@P9s#W|mC2 z=4L1Um<@+P5+KP*N@LJBL=EubPH~kTT}+GV;5$-gr=<2OYJ40&=XwwK2s zS;Y5Zx785R#z&2{aLg)I9>P^IW@Xkg@W>nP>3%UT{@wMvc*%QNdq)^jOV4-Dt1hxI z)XJews^RClm4T;HgARMGf31IYM=p5-l;!Wnp&ioCHVzuXTeSFm!|W1Gm{aTuabF9k z9wu2&wt~|94TB!MiXX^j`e%Qz&HW!574G%TK$-E*CTSrRCA!-Lf4NvESf(7)9VDB> zDn+yWaSg6Tl0>Bdp<~UelQC4~rd0v(#GC3y|fiCc$Htj}h;?>PE`McV@ zevcRH=Hyj&`19)e74$-;Xm_`M=zg(h+b`r8da8uC1r6%>>X1@mc0JoyEQBz&Nfh;{ z7zvlK(Bt|^D59HgQ=Pc~lk9w9Z}l#Bx+y*HtPESRZIJdZl77Sx*PF)Gl? zfhm2Zp_7~y80(v}UNl1PXgY)NV?zPLICZ=|mfQ5;eXV+P>uB9Z3-+l{?v!JQ-1ON- z#Ld{bys#)b<~ZD1%?LP&1slY);! ziUAOCh{l1O|DK~J!-+XSjp;<)qy04x^}stBr4+`&IzR=P{oyr~K*s~)la@8r&~B~; zaazDW^g=>Z;-SL$Dg*v*5qj(=orfS3&O7K9G{=M&>>X&W?RK;dQB+&vY@XH+Z%!2^ z@?ba%Oy#ny~j+5Go0qg+NT3zT-hS2<~C-v!eo6lk7ysU248sO*ggFHHHk&0Iet z0m<_Z2^{A^q%DHK#*lX&nBr4#R3DJLKj=t|axJxLjkWMOf8SURx_v*-jk^NNzw(mo z#Tqisim+34a*%}kL_t72_aVdr?;MWu5_^P|@r0c-r8zE&RyiZdj%4?>+0?_&%|B?+ zJR#)hVmy@t!pW~YV#Q>aS{Um|Mxiy%)`a#7YY0GlM&mq1pJ>xS%`wLU3^|3qX)l8N z;qTxmLi$Fc)7yk^=hj_?7+8OzY&YH*)te%SmBK#}DN2$|k=aNHKzNaJBgS2j!)7x! z+TL8UGE&9RW_zG=I?ScN{$=s8Kr5C#%LWyxP@Q*n-QfzrhMRLGc348Vn}q>#j_PXz zU4*7p|Bz!-=sG%6FmzRffP3{41O^SW<%D1ZH4~$6u@tP>R~o&5nwoNuC=AvS;b4wu ziqqQjN=4}ecHQc028~wwEu-#)*PzmzcwO*#O}rV7U102KF)D6hU>9PStF=|EB!Ihl zL#?g3b4IGO`a=gM_Xp9aD*}E7E((8Mn4AfAx%-QByC!N2@=XEC4Y7_DX8KM*oDegJ z%K%h?T`+K<5BJm4VD}nQi1j6X>Ac#WF+ebj=;?CB7+GHSiOEje;qv49p;5$qL##6Q zFbsi(xDOQ!7tmb6OH;2%0k`U0M3F{4qBY6EB$rXJk5hVciJsmXwWHKVYx%pp3cUFd z{Fhv7lmP*OOI-TzHx+)Yt}RB8DRfut0@n814sK&^&>tlo7Gz^06suzKv`;l-cOZRa z35;{T5C$Nbn68{fXG=d8=2F)u|Me7{weX?1{BV{9{YyIvhbTky#AJVmC2?(=W{b<+ zLBF?NV7Kmc9s7=yS$ilPq6p~_*w-pz_Av@{dvA=7#2fp~J0!*cdky|5cJiLiyD$dF zJ1M+4IH%q0?ZD~craM=(2b%9~plI@rnrDwYIHy|k z)%+BY5hg#ceZayaN<LuIP&36#?D_N*Cbp(`zFbau~UfQnw2r3AwD(?)rgu9rWkrj z+6~iq;{tMXNI9)yYuvvNpmSJUp;yta)^Zni6?m^HZ=3~QfxKcg84ae1Mxu}OcefuS zsolE@YLr#&fldA#w+~ig{>v5c9?pjbPm_|yP2$fNraGh-ZOm>5afENjr7>3$Jr%Hj z89j6fR0hg5THHpAWwgLt5m^0 z{6$aQlJ^HaC9w-7SEcAX4xZ3@c~B-#^l>7`jkzojc)Sokrkv$xEcNP7aCd9TD9Ca- z?8dx5?C_p>ycIz8v*T+zwwH$k<-oo*CofE$O<1(C<4U)p%V zZUF1#@k`jh1O}tp4reN$ot@iFW6LnYkhI13>k4QF{9?QUvpkGaOTp!D-~HYh3*CNH z6!Uk++91m6?86D&-vc}?Kj;FIx016|qPXdAL0X6P^5pt%D0<=7C|Y}J{F=Jp?VPjT zoQeEz2CBq*DpB+R8`ob&oy13H;f`xIu4LYgij@Ik?6>)p2kNtFz>Tu-F;LRC<&iKd z957XWPe3kn^pNQD`Eq@>O5iTEQFyZez3_F^CiKzVaqWh3l^bfu){nd9gP}opL7UUJ zA@7HyF?`x-pn>byuh63|A_p<-L4KsoTh>)?-B4DE;s&_jL zU71blX}g1dN%@&?N?fQeW!u{RGW0RvD*4?z8ZXU?O4s??BrOM(-ubk<@TvC>scH@N z%Y(z;w#GS#oAQ1?jM9O4sf^qoGugCrh^$Z8vqoBB8_+*}xQSW;J2-?c54*HN*nSqh zw1U|_ND})PsO4}t4N^`_j6J*yPAB<{hRh|JD?5SKK`S-Ep+!PVm!~_0{2Ure^gEin zJT(|HF|D69?lkz9u()m{!TTY#PW4VBEs==TSQT-%-&dEHdXtyAhp+F~&izM@e>R98 z2$1Hq=%X_b4uiv?xyHyc?AApPH-pqj`-BF)vwCC7ZSdr5)za+hvIH)aVw1WBnPV{e zZ>%jpmI14e=c8Li+S3B~EPZALTk1`KR6_PS1Nzw&r+T%|mQ8YQcK9V2L?pO|#-G2!FO{V{&64?Y&zGPYV-i6ra`` zSK9n|`{TxokAL$$U^CgsOxuq5q~iALWKTgSo;M7mbKrrl`b8M6vk9^f#4)`i38vMC zZIWzCKR54nV}S~(M6iCwN{5;Dqe@ z)DhM=*$yd846l;5Y%6VTd|pCmN@k7eHMn(P(nBSpvYefzVm-SEL(@>dsHRt2Yeo;J z0!bmJcB_7Rr;=fw>@3sP+mxp7+`w28iK%*#2Z$N?g_PJ89=Ul7? zZyoKj_s6>_AhRr!ekAC;v%KR<-4dpF49%@i!hdJeoY%T)36k8M)EI9FMix}a5#GIC(8rY2mL25;_aiFiC@Lb_Ky~`MlHw>p?W-D z_m190Ox9x``@PRNb^q<6<@2B!0g`ZVih47N6;*r?7O3b;dILf{?gykhsl(TU_^n{w2ZTfprj- zs1;B6Dei(xm)pxF%$b&5a#n-tNjOghUy&~*_$$^9EQTc2M~Fp8gc0ba$t>O!9hntd zGebw5HA@kOTar=LkjNt6dmN-+Nwe-f`c%UoJn$zN$>rl}cBJW}vsuiq*ot-ec-o|B zh{$&vSufpPu-TIQCoNTUR^#0>G8Ot{B8`JdnZF4~ZxF(5I3bXpaEpg}%6%^S>`Nh> zs=S0+P3U2J)l0wtYZMmn*r>$EW1S#^@#L9^NIeetncV#lRM1KsD}vfKmS^4jCzx3Z#*dNhpLKu9u`DW4Avqyi+YlkkOZuw^ zZqaFpd;%M>ezj47iAM^fOWn!mUbuSYOsAO%_bju&<(twOgX9k3UV+Z5mM^QF5Le(f zzH?W={tn&2ex-*xaVpzlNvC7$U~qx{qTm_Un==ibNnxu&12=o3MMdPeEMgEutWTF< z7Kzzd5EOyiy|HZ`tFY8h2fKi8c6^Q8D&jIPp6@g#(!F*TO778G7G1DB5Yw<0QTL)P zP1`8nQ=Ab)F<1X?b_(W=ZP1{0)TwT3Ti9xANDg`j`h+sV_8PDdZ7c{LWqW-?(`AST zQmv!hvDR;IIt*@LyXa%yLTS%;=~ zwYqopj%41Q>Inwm%N2aHaN<;IRlx*0_GydAXa1|%nvYi0 zmWwA0(4BsR(P6`~LjJ!k+$pCAib{Jjvl?UUv&0}AJ;Q~EiM7yMBJJISVt$fy7p^lw|ZhXi9xsU zU34S8g}UUw7zvv%;kB;63;f3`uHF7t_PEo~9UCzy-->tgE4K~C%6tUuJX&;#b)x!= z6$$k&-#eVSe@|xgXqy8i)O-Cxf<4kB--Y+|B^S7A5s7R6%3pruLvG#p)eg@0IylHU z^cDLmkm=JlgY0&BbQPyIxt*WJ>ecb7Um^oGBdA%dyxwT=P+F6*Lb45&cq^e|I_o7+ z_)zH;X3;9|Hx$eOlp1>*JUj&*T3lZO-x1!BC_-gpiA=2-PRK+1FjK=FERYL0fWU7f2B#eLJ$8e@&YYWGaJ z4px;DkhRY}P4=tg?+wwvi99qguC|&CDh1Suu(mNQsAWqM5|>(1N+M3w<**du7_1@F zRZ2W~GUz_z3b~T#MA6b3r~!(;YYz7ozc=dUMUP*??m?D$)qdV2(d&hdZ{KaE({8`z zHNK^}p;SdEB0O9q89{(fhXT3Bq>g3JD>w!85&!l&Al-Ke17Qh9oPkH(iVnOfl$yEi%$G_DnY zr0i7<7B5|W-eU(e*LmOwW8$*T3Z8uj7Tu`)r#2>+ysstIw=MYI6#0&~Hqy>*?5OZ<3|_&?@*B?E-mGrF?-QGcho`Ies`10c*H?Lkp*B+qmi=go`qD%%glNJX zcK0$fZxB8ci_XptSn#-Mc#t?^=R$npZ$H*465n2)utA41&Q8}taG4z0^H3(S3~h}= zrynMqpr~_-plWGy!$gjb>WaQ~H$0VD;%MF>U}zoH`ogukIQ{+tX2UHB-}#f+$eEPd zQd?qgZ| zmr&WYKL54Eq|G`NBM=W5UUXeLC~ZuZPO8}WoLI(~oX6MRnNR&#ZdZ(ZpvLSBnicpz zrbhn&cIqNQ(?Jqv@0y)j^Uc$%BqG1$AhIJmkn{3CB+ zaQ?5U(SPAFfD&k~-)it*((YVhlT~J$$ynQw+~Q9Xm(^QUl5K zXp1DD7xI7?y+q3J#HpJB1~3`|3%MfBvLYvT#vajFN&6D@c@^x z2?|2RkwPnZcq1`J&bQzi0?1T%Ek#ijiRrT@=eA2Spf>Sv^4qu32C7hq&jT? zkXDNb2uS2V*+L^HOA~WbK>MM-rJbdViJ^<(e@lp#v905fneMuJ3u{LPhfFaz5pM!S z`3Nxb=25)2WMYG3S!b5-t*BF8y-${iOf*I=GJEBiZ z%=FNz606>ObrfD8WJJ z*XS@~hRaJT$|Z-5a2e$EaT5f^|LBPBg8_4?x+uk~OV6YeGl)?ZOJ-ntVS_RrQho`R zDuo!pW24Hdp&}#@<8y^-jTENC0E1A~XR%=bS)_s|Db`-l0ETZDnu3(1I9#^^Ga)+c zyBISbXBjD9i0{mFV1ta5EA^|#fZ3ZAkzduA66!p~JqjSlXl_R!?n@;7kS0XO{w{hN zIXopx7P_I=CVx@C5E)hY>Eu3Tx|9Yi#pWVo)}Cz-`#7(81Uu#y42WaXQs5n$dT$*J z$;1bm0DoF)2$*s*a8z}bjF-f+G(aP98eDO)oDc{sOAhI6{Gb{!8%)MXQ=hC>yQqi* z4P1h=onjs|B!ZLPX`=AS=jbgK|1{Z|MVtZwO}fZmvJfqRm!j~og8Tm=?H&6&?U!xe z*tTukw$m{?w(WFmt7E%k+qTuQtxh^lXa6(rInTY%sNlH>$??Ru##n z-Z#f+q1sXQC|$E_L+e>C9>r{w4HOq+WRS$|i^xF(WK!*ru=L@%2oMc>UF+X(`^2NE z)xcAULQ>`%cFh^t`C${GX^@K?i6L2}BIa*k#d;QNW2dn3vGs_wWTODW{7vevPT{68 ze&OFqs!dQGr8QS*il|v(5BK6$Mqpy#bbmq+ByzY(w2?ld?J9QyXD`)fIa*iF-ils)C3Y9uKIKck! zr&_A(pv^skWZ&dCOlFVF*cv3_v?EAj^uH^%OS0l5W0UzhYBRmszU;j8CFw7;>po+&k=(Jgs#am3>0<#3)6j#&Yea8B7ik+Ps@DLLu zvhty3{-p^bsUYGKF&K!;FN!cg+EQ@DZa_TwmyK|wB}C6Ou_6qLL|x!z#$mfn4ew)l zM2*HzGJCdaW4gp*X^5jh6WY3`AL()x?`u9e%gFk`EyGi?;jB%l*T`Us@Yg|_ARjK2 zKaJ~b!ntu)v^)nb2t!cjExvlo2K%d+*U?B7s#A+e8D1SpM0K*=ER)sRNo8*8KfhSy zhsM3{=FR&&_U zTP!n11yoOoq;MciW~2wl&r^N*-M;*s2fFBt*3GWwswor#A%2Z+1W$T`8<|&KtcxSP zNJKn8!o~dU;?LSCDCs`DwBU5T@h|*EWr8Rlua7^z^N;x~Ija)5(3WabA1Qlk&8#x1 ze;Bo@lu>wy2obf0hn}>P>ph0S+mI{vBOha&UHR^jKw1w>ot2bjz?Q8UG%GhNOg4WS z5Sd4Bf=<*T2ejG`c>LsGQlFVW9r#68f26H?JD%ZJdRfPCtT_okB9kl?aS;9xa!vT) zIg9?S1KsWUvd^%>mCM4J2JI45+2On&@%nak!^@yL1EqXXIKHyQ*DC?6tL z!4iq^2p{f-?aq2;a4)|LTDVf%g8wlr9l?TMwVgW-ig(wfMCH-d9{~a{F zD*r~AtwaE=aTq>8uZ4CVT7s9>-q@6wZ9!zwrvUcwrJZ)DU9G0Cq!eK<+84;^`Dt;Z zQXE{|BJewzA;qH|Vs-X{TUZ^(dFXpQGjjdFdbi-oJ)-Y$d-nR}`h{{(5Dwc|HkyK( zfuDt~6vmkjVuR3fPJmk^8_SYA$>M#NdeJs<_;gV$_Day-mU(N)ecd`G~v z+a|)g@30qeQA4vJQZ`UKBYZ5nN{eJvxsl<$}?TC$ri=E>_)&S`T%o!lcaw)md7c z3%p?K`RO#<8w|N642x5!Bl!hE7OlC+dOEI zR8@2N$n_Vo{IKA|hWKq!*U6;W?-3gIA)oK?+gqtt5%PmpsW$WNJC!EB*q^%n*Y!8O z@kdJC7#GGv=y|538-I|5cGJi*7tJtVV@^(S(nlEO* zkG>Z%r))jJp(=No3m1eo(2v2M^xv;n8v<5;VFPL6WuEsU{hTh`rCYXFGj1KbyU30$ zZS&5wdKrIvFRwaQGqwbQkP66?YHHV@*^aohwPx4fTvb=3Y;7w7;bv9yQ`72z3`@N% z?}A)G^{SKxfdX8A>U7W+-EZRQ)2Ed8I z3m$f0)&`!|{9Vj_*2CZYo>gZ6MO;6i9v1%pU(5lHX3tCk%3}a1){!gHy7J}TK4P8{ zTDa0pBc|6asxtZEGE;Vp9C~cST;K>dW7Uh-aHeV=awSput2O0G{5-{0*gMhmT2#U- za`?|y)cx$?^E$>mSg`N&5aY4M>O*sARmvPz{T9)a9(r1ecXS9HAJ5?5l=HJr+(U|u z_L^G8*NySa3)!q5n7K@6bq>c2YZ*X1t0rvi&S!I%8WWYcfl`Xu36NP7@Tf3YEMQ*G zf3BFHBZ4HFP7{bY%qgy+)9IQ7e<4Hia&BYA+xqiw+dFABzS<1}to}^I|M~XLe{>Hf z7RC-7e^X~w8s~uRok$Ic2d0GHuCp$S zut@54?JDU{@cB zP?Bv8;uo{m2N{pL=@1=Z6vOms!|pzNoC!JHDH@rDS<2OHcG(aLV8K+}-oWb$w;A41 z%6#(x({USpDEFiXM8ft3D#M(xoEU{MNN5Nq0o%NfUvK+>L z(6FPYL+^jd!h2!s<76NtIso=bJuBmk>fTI2JeG7PPE|rY)zDZoz0qz69ZIBUX}LKA z_DRXPL$xhTsHvx>5qsASN9#Z6DrE7JVo@CF`I&c|!!c!}OFzA7K-v*)&*I`@^+@~k zq0McdDrNyoFJKJQ=6!zcwh(zJ#V~)mG1;z-Sk(4^%f)G ztHkh?3{GvsRI+r9DDDHxmHC;->7U>a&4NFOm=fH-q`m?j^#RYN>-FTuGBDml za+d_@g~@+10v6punb~%3VrnRAR#p^=BeRV3#dvHoje@u)=La}83beD++?BVBtN5dI zL;fo&1>D6oME%#wa=!_)%ITNTkR8pB2>Q*oh0MkImgy~m=VsA2(pv~eua1t_Cm11X z1(mOAN|$an>&q$}Nc>yJy&LQ2N!O!yUFS)z?8(s+P`tSEnX{pBair=SW~W#=L6pNJ z#t?*08ItXn#zkFU37_xv96M-j@^)P&JQq6)hf&|ejJ~tzK)Yp1913kPtVA^}r|h^* z-v2-;RQ8Rr0_9;Ls%45TN}Me%N@$;IEi+)Thdbl>=PoH{N3RJp(#Gx<>$g|JBVbOX zLA&|BR^vfGWIi#wY>CXDna=4I+{_{UOK6#-@z9tU)~afMsW7~$={ z)T^G5Uex~VYHeP2`kH*pyJp%cWZBha9o_U!x-C1IhOmuJr_}vMx=yS4U~t4IqhScO zd>1jiwbs-POpG5;RfJPp23DnGp(~j6$AZ1RtHlS%h#mqm^uR_|=h%H#%&oWI5SE%eR98(#CE81B z))x_!{r=hhcdavqSx8r|?69Vs7&ILswKVi~mE-M$vpNM7X&*#R`|5Ig-uJ(rY#!p1 z4d60Cgx}ReF?pmV(^zc#SSX|Ak`Y)#p|>(wMN29$?F!Vef5<^2*V_fY5WrjQ9_OK< zQdsIHhjZ7U_{7+<7*w4RS+G*KMa?{lG!mdYK1o~goqbIv!aF-lSozu>A)~T-e&_0} zDL7>T+Pzp-QNO9-T{yG%p*(l5<+t-lfFix&Pwp5Py74;HWcx@cmXWhOsU6I9=L?<( z%cH5;O>Sh%{LT9A{J`$qKle)zJ=-M$en6<_NleeI8OeQ5f#zDR#UL1jo)cbO%p<#LT8!v*qve;8EY7$S~r&w}^l1=x5Fszjfi*2T+CtfHH9YCp!A64F5-A z=p3{*67Quvpja8sG=^Na)Ij>+HRrXQSJFex-5c4w-a4K*86I2TA1hs;1emWxrPqW# zUXF4W$z+6A1e9ZA2f;o*0-o=Yc*Bq;1?g-XPUPuQiInzK`5{e9N{Mu-6CR$N>Rvf= zTjZ$-=d;Y56Qd7Y`x{4Wo7kQKsm1YTo#00|y8~eX>kA+gw<>|AgL4u$#Ya)h{Oa?8 zjdLbyz~ox1G36n$xM^WpeT~4p-vm8z`18g%;^XFCCFkmBXw9Bg?;Z8{umvwX$Y>4a zj){a>D_r8P#J*PF;AP(v33Pg=821@!QQLaM$>yvZWeo(HBRx+E?4sZgikYxb82Fqh z(Y1gm*ZDYliTxs}5J)vsn69j5mEG!tV;hB&h@cd8>N^CdW}BP^x3Sur#FAkPXJ&UJ z??nSD3lTSG7Z3qq95KnzX!diS#+b|{37T6=%ke80uGw=IT~I=?`xDEoFAbU=)wQ;> zwWv`avIO*@W(ptb7h+wuL6yWhQ9bjnn01Ok+yc=yeujc-!nmAvQxPB=;XVx&>eh^{@ig`vc!L+A8p2{HhCGIz zFixUbjv-{z2QN%g$tLTN4sA+AxqxmdwoRn8IB+XI#DuhnUJwN|CIqEY7d`QuM)0Ml zMl&a@3wCdm$M#JG)gFk0bLXy~Ai?{wVj`cke_|u5tdVDA-XL&>+;$ANSE?5-9bwP= z3j_m->iLtdcYZf->-st;;x!?hWLfS8(T@pgi;S%Z#Ql!K!LN|DV1R8z3hZIn^7`CW zse10e_RyM)*M>5ny%E~Cd|jT{grzzQ9gv}Xv4oBWLtxm-)0$5XkM^`Iiix2z`4^Gj z>r61@lHxVumdLSDp=F(xuOMA~{}Kk)e-nm`e+dJ7+7dt*`u-sdxVJct5dTFO9{v^v zzE#}BPhq%Ds>YESHVw{>DUr7r7#TsPwQF#Jo9RO}PGAnY_MRf$d|;m6a+4J3TG_aQ z!L{JpbRuA%DZ2%18B9x=Tn^kUQQ}5wnXsF){0ePXDpy0xOtZ97#*s$~3Rp5IMFTA= zgHyg99R)*iH=Ng9_=jS-Cw7q&vy{_@S@;~XW4Pzz8=k|R(8UoR952KhW}WEHvUwwQ z7kO%%Hi``*B!K zx)7L*J(^pVNUuSB_fa|#XY=V{?UWYdp|ctRaFcwi3&_#e`=d5 zprupe55uDBwwQ!YuEed&Rj{b0p^%ttz%}vXEcM3;QB%myKT#sf>XAPot(y#L4++nj zNjYKWUO!3kQ|;ZjqjjEcCJ|v-ojGDWYDbpRdeFd{h>sc z5Bd%H?V31YP+lEH(tNZ_L$}B6L$JuwY${$noOSD1fG003Bt(Z~8DpWvwTr=0=gzMm z?)z+`pfwoIQ2^&3{!HQ74}T-^0aH?PrW>bk;Oxns6KZ4J^cjV& z78DeyVB-FL^UAlxoU?L(D)<9bf%`vF1v_WJq^+H^yQ$MZ5Rm_-VQ6kfvFQYhwxk6S zAm(i2*uvvoRp2le`$%`#*Y!m79cII0^|1mxSy&Z6-lCd zb@-r~h?N{U*q@kN=QI)ABqg0H+Wk&DCib15H$V9M@-n0rNAAqR^SkP)B?r$$bylVC z2%aG7`mP+T&g`!GHf`sRV74H5qX$C4Z+NZz^tB+VFm$A`9082*x$q|mi5Nxl5>Yr* zV*_?V^tx-kK540PxV1r#g~wy08MY|Dm_0wpxRuqW03Abhmc|T3oCaT_8dIK1d|tX* zyQq6*HHJs5uvhZccF#2PK2uFfGkz#HqYXEe!LYN`n^~$u1h5eaGdC*J>Z3A17($Ky zoZb7Q&HD^fO$#SES7dG^vZnb%q>BpP1&0(gEw3pZF~%JZ;%`))O_(&F^sq@epZ3Bk~X;89>P(iRGr87)n9gCEvTv#E~Bu zB7Dy)ZwWIzAZxpTbH6|M^Lc3MYgIzzN(=` zwA&W>L#9)lyX*4us}FddD`i0i!}(>beWurVh8W|uv%%FR-anK9HwhhwX4o_^I|jkn zYGCg!JX|L%b{E{k2n?I`sh^W?&X$n$^73pn^)Ye%t05?SDeiRAQ#_914Qhnes89K- zZNXST>$|RRWo0#Zi*ZS+lpM`(c1yUEL4P3wJSpWmPTCF?Dr*2i_6n3%eb` z;Ag3RCf@K-1e3Z_r!0tl-U4&0d>vbo#9%6GP}Wj4cLKe^yKB?K;aT7>SO8%t06o&c z7D%JkyMJ(_x?M3YhQ+MuQe%JiylvNP7fyL3w>b3(k=2RMUwgrMdtMc^_E_nPFz-oc z4#G)x$A1&HNUVgtAZpx3=m(!3)b)t_jteQzagq9{JzTCXzxmVeB7zBWWGC=s0!9Db z`|DR=8RPt4vS{jvaf;K@_xT{kt7xpdzLso72Vx00xy-3f5qJ1#kec#F!Z@jx$$emU z$u7T<2s+XDt5g4c=fRD=`5{i@jFAvA|E)DVax@E@<*R@#YSj;a26C~oW@sMQS^Ho@ z|4>aTt!g$C-{p3&z~S=I;sd2C;H$f&BLM^KU-?RUgFg^Q$|Mh}r!`LW0b9uUZRe;= zJFb6eQx54Du(&A$`T{+qMf;}g&woQBsW;yUXg%Sfc-Qbx!7CQ{g2t^7)O275dE z%`+R(o1~2$czid=D4~JQnJS-MZt}{WaJ0W>Uw&!Y;^(y&$}9?!WW$WvQO7I(hH!ML z^i7wn-(H(~kL%R>Jd}*tijf)`$e4n*T7@>OW0lV#<$5jnTyH{CN~mpa6pbC_ayhclKzF_vlH*Z1clZr!mgs>9mIOJ!;BQ5xX+|Wc zwjpK4xH-w{ChnKFlH$(2;-6sRE1hmWyEaSEc^j~Jch6NYHVy)%95{U6c7P^>=L~%y+^@T+%~qDrP8HP=k7AFklZ0vD&-Ge{Q}5F#Y-nQ&!y+GBB7lsCQLEv+C6&~sF^|+?hy2y*g@70hWNfLd-l7?GgTR3dDTr3@~ z(X&+RoNN3(Czdft{R29QPD5Pdh_8IF{++KJwYz^wdqn~H$cb@N)FlIF6LNLuWlXPr zq}H-ehI;9zcK?OIJ$K2>%M~mISWLR4a=dz#h`(ap_0M!1Ps<}rnm)&YpJKkI`|06}D^#j&jcu2@3@mdgD$j zCCa~M#hcxkn-X4$#pLAhd1}PR9yeTl#ngW%6kLy3pdV{wRj?Vg{&Y*)=U84sXn0cSz=UlIqLuaJbG;8PPf8K*FhL9Y5d_yMRiXIn#cmd~vhByX-VYeQ z7d6Cn;hL<51IwHgne6YY-T6GlHL&pS;9YGDNk61A&}o%Kpl{{JPYi^3cVauG-8X)h zab9_JpM$uxS6(B$N|Z#NAuIC(6VgTo!i~Sy@fcedXM*1g$3ROj&V}i6rU}X3@|UK{ z8*!$v#4J6Gdm?Ftq+ZByry{Hd&ZE~KHi?G9&~vAsZ9TXNJv6YSFb`IT)O-$=Lr!~&|C6RS-W1`dM1>&Ad7 zc&m+#kppDcqBGua;PCMpNSs^h`jz`#pet^+-)6pe@)AK}VAp}^>>&&_6+ZN9%eJ8d zL)QnDGkG{`G>S7q6u3i{#3P<6)66KG; z>85u&fnwH`G|*CDP-B6`QRJgU=<}OY+)x^r1yH`ySx!XBjK8(SkT_F4gh5E!Xr}Pk zWneg77|8QL1Otf(D2LgK$W=tpx9EA@GV2V5t@ZM_FPW(FR983PQ)T&5r1*4p`w5@| zh#s`PXF~Vz4CAAo;v{4=+Gd%yC*mbs+dQ&`MS^9@R1;r@pcra|tYv|cy>04;Op$dl zT3t&+*uco#qd@Viu*0ob36)9Fb5!4G32A4Wy7#C%Sa+D!RxDQajb225Jg3Me%_$u} z$?Qd5tcnF2RaA5$H#wEiyldVqba|MQEnEt}@s3uhmPk%GR^zB8WoNt|3oZVB!GD>` zv=Rz4CC^lWc0VIHU(C6st3pedQUpQgB#BW!F^D8>FKO3COM|SX>_v^c{T>+iY}2(9 z@AXcrSDX8ez-U1f=XVAV6Uh#*fqA(CA1=rA1WTHsdrKOHuZ;0+$mn(Lx*qH1gVV+j zGms0tzt@jH@Y+%fYDnm7C~fCAbyGvX9Rdf{cXZCxnQy7MdCY%od(~SIODjVLdI)L| z>k!WOVxL5MBomWKc@oaxcjuyPVI<54j6O(V2|(8Th5`ZKug&9eep3Opi!&&_2=nc+ z=|=qx78Y%RK@}enLx(=@b`FH%3m(N%_QzJOE8p8PRO2ouRB2VcW&do8BQ8Fk1ZZgM zOY;nedoTXil8Fh|fkDN#Z-{ier#QqHPOmtJcWmnCdyP~qD+2<1mzfKE^Y-7JJJ(zz zX{96szEJM(j&sw3e?M_!M#una!N7l%3fF={~DrxUJA&+W-;xkzZC` zDOk&%BX*OE8@MMe=6=#_7NL^djwp@fJNB@7 z#L4A8)jpxvhn=@v@%bP^*6@+@Z%_C$TlL6p>{!SoFNI2=#%GYL#d~_=it&x#wpA#@VrkXWW-j!Fg(0`R2$*sms zWxQLvz-`#vY9wQ6;aw2$@cz&n*^TLxT?5AGh2kK;jkUctju6m!NN%}z!GUmI{W{g) zR!l-!=_VB$=*xSI4FciE-+$_} zPL3dm?W+d(Bu)UIj%GrNK{s{BA=2ID$D7+|iMf_oNfe6!Zokx^}M8nb5cuzQh!!qJMcL1sJk?l9c?B zh}ZhZX^v?cGV2HffMecRM@;+JV&57RTg4!mk<+80u?W1-CaU~ZClzO6r5L7;Nml-A zri!lo&rFrz-!oNmx|bi0$S5An|AS2R4oc1rWgfUKGbR2t*{-<>={x9p?>@Vw_j!pK46?I%lVOVxPyj#4W zENDL}(vYaELKG7?F#xH=2s?Fwm_P5EejOj8H|Ah~>(3{|&rEgwKgd)!Ltc*lZ!=XL z7tIVJvMr@ggXF(j=i(-s)7x+&<1{o%m0LM-W%n=B6*eAYm^pul`Zy#@lRr zPK_H*@DGFJ_n7;^^VaXN_W#W~-`fvIZ_(ljJ>K~|(9?I^b(CQDie+iP0Ash9nD zlkLKu;Uq3*=)@H8(8I~fGbx`HUDa>$wzsW1Y$w}yub=P;nD_Et!Lojp>`qN%#P6on zEbw`jY}Tl~=$m{_st!b|JVuSlZm{+R6=8~Pstvv8i363x%DJ@tJ?fcfuN(LX%!BsE z(<#Y1bhp(o+8(&g&SwN`;#kXkRSSVzoLConlyt+jCti>FGl7m%rD{*|d}ESSaz z7_3YP5CJmPpFcRVwf`+sl@xY#bhmm98q`NfgdzT^#XVA&4r~A76~sn|kM^idtWtIM zgZ+LG)v#8f*K_@taT?;W-76#z7dGW9v1Uq6XBQDU)*jzS3iYzN`8DY5^)_x+45W-#L!^8Sn!o^YqskUu>3EIaqV_}G3%M_Uvq1${obz%{yf1I=8U`L9>h>Y_K1it zh`k4FdrOfyE+h@!VmV!-t|VnR`8(Z>KkBHJ{k{wj1BkCtE-qjU^0BZEN@*t^o{+d1 z$r}AWLmwd0sbXrId@@YwUkC7@-*t5G$;W&I;*Q;oi%Z8&=(M=B!eZN=qiw=ir)`Eq zd3|dflwd3&bO!MRe4dybytNOo>B+SbVmbO5U72xfQOW6LaAUrsvq%lt_0loe7zijh zSHu78d!1W20hVose#YwZL(49!-)qJK_~e+15QqQ`NaZq6NiJ*q^vQo<$numD@rNT` z>m8<{bJZjRd~(l(HJ|w1N-5@FnZ8tH;NelDMY=mXv$Ay|=v-)bnAfpHNk@07IKNS* ztEyFC&AEhQScbmsorde7{X%hyL5&0^%;aJZ4Uk|q7-j&^z)P5{MXREa65ByfSH(=Z z1l(xEek>g{aN#k))bsQ)T&>Lw&g?Os{624RmT1q>%6XaMW5&Mc$F5aK-Mz;yXBR!z zdbo1@hjMxsp|?t}WWK!!W-W?c?XCV85Y%$_l`}oYx;KYS6RlY01RwT5IEemYFRUZp z=LC-jM|#hG-@%j0Xl7DhOZ;A$CY*qr@Iz`OhAL1lK=pfYidCq=T|W>q@*>@=IZbjO z+_0>L>b5`C+30QFUNY2C{0R#XHH;xm4u%tt0p#R0ZH}qob>eEvG|oqUAFt3Re3YeK z+|Jg!mE%SD3CkS~O%($ajxL(YnD#FT12P8@ImlanI#5iog=L@W9;R)Ajmyi-ut&t$ zSCfClr_5Fyov4Jv?ynIY2>mFD&1x5#m|TVf8q;TOE%0P?{d}1|ZUY@z2&i2<>-KaBff-Muhedt!v{he->LVBXQtszw-3BJq4OOkaAY?}J!++|J?*X0Lyc~|VEh%O(WSGX zxN2n9+86qd&xJmF`}r1|c~1^g5C)1n`irm`n(g@cPQ$iBA2$48$PGdj2SS?9>dbXx z^gmwtk401^7=^i^Sq<{8XZQAYkoaMd;#9IqoSbg%upN#9jk$C<;!MX7B^B@W_(|YRtB0@ z)ZaOc>DSPW0%~?)KOpG z)XwF<7l3(y0JzwaYkK}a0JSo;xF!@Y{Xx}+p41t0w>P%48!Gt=1kxrHg}p_l`vSgkT6JbDv4S(_yxIGa96%)uT%3DWo>{y-jk46GJ&MkTk zu@k-AIDL=6qo5>^%c*}6^aU*_3)xSKOd?I2kT?dGVw#a3LnSr`bsK!^KCr}jmaL z`ZFh;dyu3frp7Eh73$tTvf1&z3V>+RX5IP~8hfd6yPcF7J1=hb@TEtRCfHGz@L0M4 zoq!eP;MSLWWT-COFC{y=AviMC^jdA*9vEkq4*hP#u3~<2>D((wduMgp{Xk?4JDqFp zt1prGB3*`IDml1(8;B;a$toWhQ_0y&?5KaKz_q%$wzNJEFXW9aqEDfRJXiMnyXYCn zYMF|;MtaIC{ifSeGQC*bBR7*fg2E2(t&jb>NfJCbCQHHiaA=eDz}~wQc1t#oMA1nE z^;l~@g?@w-rz>2>`cwkqHG4}(0SJzQdzPdtBYVycB}zl$*o$FHxj4e$)bWuqscSkc z@2*#Ngi?ODM2avz_9Qj4m$EdU;g_Cv**2Kz5;a_eT_-=b|#;no&yH; z<5%Kwec<^imQ09S(_fFT==rsumcGiuGLQvLmoQ9_@O4?j{WA0A;<3=oBZ8=A+20>m zd_Ap7?2?nzQD&iTv`hIsX5x#$g}FPFPvT z5ZbUp&f^1d9Icp;*^Vv|{<17VOl)?X(o;BA(+iVBv7lgCPKMd*agZk1F!p}cihe>Q z8~ByDiKaj4v0=vTwkT=5(1t%;(zxZA_5yL!*zxV*rA<5uKpbRb9$wV0jthu~6tbvd z9CJBojHb^F$Hx8;-Ev=lT?Vwi#(Sjse1j!?D|%%~p3dFWP?U=-U3Yx1i8ab4;_X^bKN z7KkWQXXt$a#kSE?_nT3BCiqWS@;pxJZ))Ns52>9Ne z1%I;kn}X7ba~@&>J$OC7qF%Se*t8UEoVqaTWMd8P$+H`2XH?P{QR1DggtCB>W2IyB zzs|HAo}%SovCSz80fK9RX&MxzXt?nNzM$?8$(x%$};4^XpqXyF|;TuQ(4gm;8;zcUzy?Mv2SavX2 z7*QI8u~HQG8UtVYYDPt>M$?sCtwyQkgaf4VbGfX<&~UV&=lE3!SM52=hrJJOzu`0KK*N{I19ydN zEo;=aDSc9v;2C~lxMg_BV`+w*k{_r}t&*eJ3KR?NgGBDeA)Y;FtCL(!600ZfagS~t z3ZN>MIZuZ@JPuKJ@LhF7`-sr-&&n^n?-A@o&{Kva4d@Kmxu`kB36)=ltEfoQ$wY8W z)W^AzlAPt^pe%N{%a0WOJYgz=_8VyaY(Zio-hc{)x$mvSdC0R0*C7{WBgiR0&uG41X9g@1AN; zZGFckHNRSVb-km-8xb+?wJdj)STLG8c=}pX%*RBg? zjX<6oU6*E1?Q!1uWx*RtU_6)PZWyJDAy5J`F3p!Bqw&1dfg#v!C10dwopSQ_W|Jd1 z?eH4MkQ})NT>NYwIiNK9*6dqf9-8QgY-nCMfTZ2i z%4IZUn;LtB&1FQ#QgWMK<5`p;An_>(ve)cC^$bCOm-0>*-eg!wI)sSTh_z$ba0;6$ zZur;aF}k`Vd{RZ0PmB!iWAL`OMM)Ej(RSMozW-2oU6>DsscYgS?80zs9mE?!ql%9yY zIo)5C&a1_PUlohSD|-+)xep~qCTva-l%_Eli%roP8+RQsY%R}*qp z(V2L)A$m+JHBL3DRlb`sO*=>&g|J$8)v1k#zQ5^#W>ITt#2}MO1_xjT{4Sc1#{;@* zGJXD$fyUA$WVYmRe--`YzK$ITqhampoB}t3byaedW-3*p{LC!uorx)zwDyvaL8J8o zlOVp!Y8J_Z|NFc@hD8+4El~zsI+qGTSAlTLtAFp#p(d0k4Di2#WLt6Pd%$kV)>|X3f`Q5s?pQXJq1K zh13!Y>nO}+&4^C7w6{_TSMnJgdtKyR_`-pQM!@yJq=w(9*b>~2lo3r(6GW4s9^4&+ zOPCfxKL(>w)YAZLq^>%LsC1z|t)82u86jH8NYB5`QmK{IVNU>_`AWbu{~x6zrY;tS zP5@^9Z`)r7FieH^ZM%jEqE1~q!xpNs%9d=kRc@oC3d$p6oNvc=w#Huf=Z+hW$y!2)%n5V4xcMpABKPCsV)vg+Tto!AaJqa&AG|tD zivEJ;!}pJ`sq)*J4wdj`j_e1Nh zz&Yov`K0wlmja-9gk2N>8_7bA%CvF!$ws0u3-a@l7|f;oVwquUt8JH|=MICmh^K}# zQVfR+oUl%`P9uV{vGFQrPPRZ2wYm`T9|N96h;mq>A`VzFQJ#_o)cZ!PM~Vr3CoWPo z-Ku$*U9_S}!g!z1yp9xTc~rO7zFvz)eL4V|Uo!cG=6Ta}ag&%QuBHLd{1^r?B2T(Z z1&B(~`a;^Ts94!Z=VP#e$%}^;j!!g_EpFhKKCo_*k0jf&$r}Z5{TFdRb3mIg=n6n1 zZ31M6&4bOQiewfY86%}iKG8^Y02+A&KqLFL8^8or^5INOI*FRjyvZW9oqUv-;lNyr zPe_E6k@}PA4xM<4Iu@^GzXM#KK(5+P*C)aqXdU+k;QEa2Qy$81Bk!6XsU>TFHMC^v zD^27$XaYdYDROPrVWB@d>V9os#jg0pab*GTST3tghS=Utg_&%kXy@U_@S@7%B z|ITAAFS5_hW_WHEf1|y{I0Sea?l~Y~hxT2*AB4*L(BDXy zVbdAVJLGMhi0lM32x%*1`!3T?P01xfUU1YPTug)v3<0)JzM^y$fQ?j|Hc{tY1hA1t z@8?p!fN81`Gt&F+2HUq+eMB%jl9M(qNYFUq5ApjiE8jfsS}+7n5LqY zOUKw|r~A?an5MGUbTK$0DxTm1yM7ikzO(Vxhb6`um(djEse1gJrfSDU=0?0{C-Wc_ z3(L?Kf3hg?SYEqS-m4jrF-NG`RO0}!kDfGPmg zyh;2ur&o!#n(6)(V45mE+kargoEZW7)pkMTFeXH%MoBZhwO5c|kQ5x?{nrL*0Uf*z zF>|l_iSXRRZS&Qd6u9)!U81l#p88bpn*?9Tud$TQB!o&2fPo!P#-IMm&a_YqR#p)S zUd+rJlMIr1vZU&(jId5KVm>yFwy%$YtgIsdt2!ok_inqcW_&#F#Xsn}nOO8cpNmwY z`w37+FE{-B_Hm8l3WYkavd#4xe3SDIq) zX~H*q5dmYID#}Q0hHW!&KGIL{ic9 zeTNlIGQ=bDlT4#84p=nx*DBOo(Wr0x*Kk#kPMIz(Kqu@J-xZSqI`QcBsS`n+3oB_4 z6FIWcD&}AV7aQ0%wr<(LB@28AxgTe}?9(mx!#Ht*WI`A;r~gQZTd&|zQ|ND#Zn<}{ zNy<@7HzG(9sYz1A%|bFj>$o|=5^A^T`iyCk1ES@=7h(8@i7AD}G17zvBS~~=sdkA3Yy>#{9@lZfm84DKAKxBiU1(F(t zYp^9iN~9WB{J_NXNQ9fdPqSm6c?Sn=^>loA*fWW}AK)mf$q6kS2>bPXIAHNQ7+{dL z#Mn?~3?x(7XD`Fn@Nx?XUut@_k@V*TRl5`73%DW~T~qOai4j7?V>{-9$jg+_d$mDy z!oahG8FnS{6yeI6O|wCJ{?`2pNI+_d%%{2}HHg|}&tNyRSqu%_dGlw(m;00xv$(*xRCs0lWpZL?Z_X?I~eJiv%1g~oS}7c zF);0ak@nVaS?>84FJ00g-QC?FB_)l7fPi#&H`0hms&s>NcXx+$gLHQ{=YG&Vd(V95 z{4nSI3(s}I`(B^5)@y04m<2HcI^f0UZ~4+fWz%c7Oj%R$SKZVKGXCse88F=u?h2h9 zrqwj7vuB@38UjpcKq>mta_+IF?#7)F?RNBy0sOwD)^b>ft#|bZ5~V2$oX#V~7n~S= zCxro=S<|@aEJoMW6{F-i;4RMZ?T~wl*H&>To1rF6O@z_{t{IM-_f^wBzJ4GmsmR9v zV-a7Qm9sf&rG~T!-pvM;GG%!;*v&d-L~dO$q2fr6@{OzJ@g4LV#^obMH)#FH=>NEY z?Tos9adyYfkJC*g7$&nm#xRO|IIiVNU5VYP*T>>B(i?B4`t3`fBoTavGt}^rV2s^+ z*AZ35ughY&=jid@KEXT7f1|41R$E4gh_U~%klr~8JLPIh$xQi!u#NVMhQ5}L?Wc14 za};M$Ht_Z_Oj1&-pu#9vzo`OwaB;Usilbm3g2wclVIsev60L+i9$W(nE^S|4`Xm^= zsJshpmemlaBp6TOA;W`uf!HXov{`t6Mu$gUX$D9ZN2eFja3_>l3zMu zJrxyyHSdhf(S}Sp)?D)?hw#xlb!7Ngzw?z}m3(-Mk=tV5gMW+1_mEXJo=^OIhD)^8 zEVaKF-?|LBCz5y09u~YfI67{hQY0xs+I&iH(kTh=#%_UwGak)qSb-wg%r1Pmn%c{G zy6J*}cvn>@-1>QzvpBtgLnS*&sXaiuX=DalvOD#q z73c}+u&)FqB?QbFrX|fdt06-aVPS?3x_Ov%nw+35-wMtBu}*?qjEb zzz7)@1_=!0#j<*xRbIXwJD;aExp3ZK@x00d76w=2GbI>@6w!6=h5#8yRE(%M@gGN< zCCe5Nq&inGc1Xb!Ka?_zuP^M6~4U@i*R1{jAhJ7oXSAmt6OQV z8lZcX|J=QL@y)`B&3N{p?&%ZzEZMpav$C10uHXJSCl%l-zg-=~ZDV0}fq9>({g=QX ztPS#%u_@Gh78tL6a)j()I-TCdE3!47+>wEe+!H@1Ws6e2WvQVy=Ql>8H%Qn%)9l8bE{_ndX#Bli{V@a6syI zo!dynL)JLh81lA2h5?D{T6Qd`5he^uHp;Bz2{p7;+|Qgb)q;7#1=hvm>F_bLsSWi4 z=w7L^g3HDDKYBm4u{ckIGe}f^Da9Dlla8s8-wT{hZWI&;?nagV^W6YkWx{|Negq+i zbQH+muv$f5D#~%JCan*Rh(#R0-3aE(5c)otWQKma8(&XFPNpX^oahx%T)fSc$L;9S zAK<%qAYA>0^TK8}Y*J&f{JDEY`Toj%T>5rucAoTCb%+nSJZer&Q`6@XFpkZMN!85_ z=bmc0S4K#qYuZqoz}@haOgZ}ZyMaY4Sy+29#wq}*5GLM@*nIT+ZaB;n{Y`7=a8nWb zi`JkG&>A!WT7zdbanV%vvU59#)*$Njh3+@40XaLGB`xcFeP1n&30ncuKWPm;n+5=_ z0nism-QYqf=Zi`HdOaVX$eiI8uEVCXYnIuRU+CKheqi7KBK$*3ok2pf5(mXLPGPY^}15-p4##0m-89F?W7$9C{#G^e&F&U&$hFAX&7)`?WX& zNERu7DFTv3NTMu}-$2Qt5=dFxlmpB2UX8R8ZBVjE#S{NmN8PH1jZH8>Yf$2Ic$~9v z==&MUt+xZCwDg@M+W>ez;tNvSV?W+9c*Lpc@f@qNl3L zwMpbbhB(X0lX}O{jkc0jpq1P3Npa_;-?u*HH!0Kgkuf=vo$)B$s1rs;CV-jJwdy;q z5>EAdh5kL5J(T;U*JPg(3n{{fBi)GWybm6Iq!tHvNk5}*A*9}Iha+QQS^KKv6O`rc zRlS*yd%`d-4WL@oARl2tX}mnrK=FHo#iYk8wxIR(#je25O&=*wGLW{9Hmf)%@%+uk4#}W%f;tyl7+!-~dSMcM2&2@Czv*O99XllK5@0 zAT1&FFD;?R4QL4~-9K8Q<68VYt~*g!P@FhLLNcEwegk8)i`VV{|2bGckNh~qd@2hx zaSJAZCaxb$d^^jfiWFmQBUxP#t@}qgSs~6KbR>PTFWLw!ykK;CqwlIdN49=u&D+cd z5=P~`XF0tU&cL$cUqXlz|X-Kt@#lLq-hvI4$FyGB%Y3og_l_io!o6KX&4x zPRr?KlvDn(6X=w>lL0${?5zeA{RBbCP#vjMK%g8pU@Z7`==7E2#VU5z)A-QqU3VLo52cDbsf#)U@;JJwtV7G?KdOQRx zLII2hiyJMM^k&}L`8$^@;sd0h+*B>{{7`t)1cLLcJCvZZ24r2<46A@-Q)K0YMmtUB z#>4e>fYGos8T!mC314O3pWAz#usM#Q23%n6hCHgXIsACj zTVS%A5Ec>u&1-WB3Ys=#EsZSFV!$}pK+bagu@jsIeg{o07x(1oK|#}C&v`N+X!@Dw zPZO6lr?{AnxdsTD?$TNSK~pl8D`%K>{!`DR+pMA>KRaB&PIyB&S9%TD2}QBtE4Z$J zonUN`oI||8o_0 zfM_sTXon82&0TPEhPPpAngnW19UfH0$aMeS4s3K7td8( zjBNI;k|wTi_gStO->p$Mtl;1BsjZ9|8f;ezf&+{O8@weao85{Jawnwm%R z3bU#5g`rXLn6)9s7ZH`^sfp82Qi@3x(e66(6b2AGp$~@EUWzebHHMwERh>j~?)s)( zu&i4%BQIQZiL8};?r{^kN3J3|XZnPOcX9c4?uQm^M)CS(;{nWpOxWdeN0>YPyjRxr z9Ni)urKzigbR_vXGZqa^5$@! zF!W3PsTOa@fGf~&*`R^q^O%Y;fKzNi`sWH%|KkdrRpJ@|S760XhMn=hTmjNR7nM`s z3P1tRN&^4mv(kqT&X#)C|J{2SmDh~6f`i%<_p@s4^rElH>64Skw<#vH%+VIPcL_hp zdLvmUCqP;D^MZf++=j4;m%z*0L)M-jWBuTcnppuE{!8@wT2luFFCJl(0+2S0X^aUdjg6+{jw13D}7Mfl%vkR{F1=o0&f<}BxyDbx#m`9Wl~m( zeTKyNXf#vu8P{{n3i;c4=-YyH&wX|t%E6?^jycnSS0&xUY|yLH^24^-c_dY0fM@8E zP&o2rq3-tx@%O`hC(BA5Ip8%D|%%1n{Wz&>2Ja z`T0?a3Jww>%Rp}cXoDd@8#vU8_aK$}vtx3Se&TJ{w}B2ZDW{tf>`BLQ^NZFGQ#sG ztA(a#Y^m78X@n)S?rdP)>u<%PXpKPe;GyEci!wl$Lq-p2r&~hZh^=#syo+4+ zLM7~PhCgl7Iw@>ukORnT^vS%9&WQo1GHXs{j{bB9xj z(I^g6toKUgG~t726RNT$F64@<}{seQHd`!!!)K=WYHHHqnU9d``$ zlJbE*MTT%ol3W@*a zmY4vN!p6Z--_2Uj3WzJ&11H7E()Pd7ekv&duj2iCcrKk)+W&ZO^4YqVN(_fE_&c(+ zcD*>dJ#d$kRr!tNNC;rQora813jHxOJ>3<#}H0F*{#7ZIyk7euVzPdMgCsY#kOiRegC zv^)m3f(gVBMv&5QGJ*Hr6vd_Kbrs3j#;170=lNS{810Y=+oQHmFl^cLr2$IALJboz zwr6VoD2?}o$7W_Iy$`S#T_74<`{&#$z7Bu}rvT94$UDSZp+r1(ymBEzp(fRMrm=F5 zULIav4n4qn1ba;=6r*uY0;gq3?rPlQVNe^^7}tKj*SU~acKf($-2Kprn)z3zGlS3v zKTvQ9Ft*YCBi$r_8`~PF*mRcKoWR2q0dq=lH=bYVk`m$Q2N~mTkYORF9SI)ALQQ?p zEE)UGF}4$FF&Q{5F8q;y85UgA3{bES)HAkwYBpn1K%aqs{SNDdxf}ntVet-3(?Q>9 z(x~Zg!veEhOn0B4UjW6n(yrf?Ki9IbcjATdcE8hOBc^9;8IzJekf_7EVDZiZpYa`KLUWAv zGQ9NOfffYUWl1e|oDksxFN0$9J^lVm26q;R$LxVLsJ$DpOq7NxNh+wdxo7N;`ZM-N zBEl2yd=$_c>cKFj2v=>gCmA(0uR*s(o5$y%=u>=Xq&I9TvJWpK^E4- z$`gEx*=4tE{Z1{ntW5ESm#rWe@N&*mX}sJTySXIPQ~X&4As1{q3E8ZvOldUVF3yp$TaC70^ zx}Q&WIs}lOB)k(hmxORdm6(4TO-5wK7>ojtpTHLPfW?O5WTCGI%|9&&U;4!K&nSVM z>hDsk611Nx*f5u1i$xlK5u-P}O9Dn@f86d%IPf=?a?r0=we8ba*8MUv+e`ca1;f5m z%I^k%-m;4yV!O*mo|5!MfawBUu*L+PRlNL0@kx7WcnoJZQTEjFgOB68)1Ok_&+&rj zpZ_t5GLF89JP4eDX5b9`PfoR&ffa}gZDe3-^G{K+2RPN3k1aXRfu`t}Q2M{EYDCZj z6KCD0`DeeO>7%PlIJ4Qf5{|6YH-h=C+vLv*uvg(i1Yeqyn#2NWdHL?HR~P%x+LfX` z-95ij^kf>G-wbV^6Yh51nP!EI46@L|DMZH}v9<@YPU=MuZk@S4@_aW>2pf(G{5DxJ zxWdlHILyP%EAIj$zml;oic%A@Lr6g2YAq@A23h6}lE`6yZ2=JQ<ijEM%k!9iRMXYbXqLgvT z$UBM9&gg@cf5b%PvEoxMWIITtXCptv#Hs8Ly56;rn`CPq;~}JY+&scL%O2sVz)j-@ zx@<2EjWM%jv)Ux;bHN<*zG@vXD38h4Ba0Wc#WrmGIHiRkYM}Sz9B2!c( zOu#pLi747Q31O%UV^mLLE%SuT6LjdwD@Dwz_1X+FR5;6lQ3)`kuMXN#VV`zTj|^%` zq*CshkXBpOEf#`BhrvzlzRJCD2uTqr!t#=Vimg*tqIHAL7U4-mScru6Ma#j^or_2v z8FL`DnM?S|g}d(_(B$RXa^=_}1a{X6qof_4*S?cki!DS%aXI%wMtDxG%%E!sky zZ!knuutcX98jnn5Ya56)9q%F>rI)sOV6<~C&R-ZdD1u^5ipdv1tf?G`HPxR1v8F%^ zAl7u-?7tvmhhWdw(BN^5Fw&i@2!cdc|8BGKxy7c`jUQwZx1MEw0Tr6t#h{Xra!4z^ z?d$?V=NSlx>~}-bdqaZWH5*5n-{P2CPfIcZh2~2Hyj&rG1sd3+!teJ%>in%CeU~$a z>?P1+xHYhH>Wat3sLJom{rW3IQ~9M?e>w|tAZBHR(n$SKT`mb33UZb2ZQ}EPf2*XW zm|3{SqkZ$M$Gh}a1!!l6kb@D((cs!AssNG}U*uqfB=)EQ-m$=d652|sP^vKeTosKv zY!CM09Kk9k0=!fL=1W~5wknKpTUdTnocB#V*7#ne5|>%{eU68J8CT6|lW(KhiS{_< zHg-*UQ}zIIvWC_P9nO*mm(qyH{1PlF+^U8{rc%y@)Cjz9#i5$m@GGy6P=`&XAFlUU zh=(Z#`0upC7B1BD7gnoU`&>9 z=R?GEH+;k<5Kk0+mu+5DFeXCfkg#Mzw&o;1`r7(d{)3i4Qo8h0Z-`gy1`-*^>5+(wqQbukkpbn zCJKqzpVza>nJ2{P3`Kk=t`mgaRahbT-+^J$y^(C4pI|AIW{e@`uavZt=Qw>LOOm3L z`CuRIkm`p~dS|QXz>Sw3`RdI_x)ldC%46X~Lt#8@njSsZa_ra$&+U|#Wlv|Akxq(~ zB*>Od(bHe}#i&(oZao)ir%E`l!6LY4=;ZE5f0;HN3+2NVO%v8OVZc*h>43j>0vmU> zzk7lU>^`1$Y` zor-`qly-{mw{f|=l?R(zI@Ycb+X}w6PcmD^r)K*W;sZ=WAEEP?um8i4#?jn+3o@jm zfjjX(wVeOliN7rf50E4Men1E)^6Dzf5(m_rnb*6m*FZJrO8Sta;hQKf!VOMR z)jy~U=7DxR^FV(VgDeP;La_ZY@ixf@sj+oWT8e!Etis3E78SsOl4E`k)$k** zYH#N7RfsoCP|xOf?Adh(-&)S1-g)duBw!!jta@G$nE3v>-?<)31FprZy2V ziXS9E0RC0zhFYoCpu#XR8gu^b$yT(vqn?wpy5lgFEW1Xj$mY&R9b30R=^?6RNH#7r zJw%CwPo!MVq;a&kkem#z^nCDejU>vZI`fA^l<{aj2#6BcuRU+F_1vQX76D2*XhOh| z6p0>~5Wu^tZ;l=;G~NeH>G+iovy6Z^P}J{xHl=@wZtFzkXXKH*c7BV5+p=Ak#N#4? zDm9q=IAuJIE8(bQtanp_to6D%n|q4II|hscG$9a?1g>HE!ay9mR8jDC5=2zKNOv-Y zhze;Q!$(!~?nuTu5n-roV>C}JQCx{pSKo|newsIYJk7aqP!J8$j%dQr80`~T%l3So z9y3Q4qGmGyJW~qutS})M6F!#E$bi8Qq{{p%THy zb#6mceP2LNssUAJT~O8eq2Vs#>K1b3SsTQeB?(DgjR*S!+MpD1gsVNA(*z@_#ZL2Q z)8Y0yVkLRkWHh`xa_th}La@TcyI^`ki4wz5(b}i$<4uaaKelgl#dSA>Yj?*0N^T7C zxT7@dlk84kf~3lM>jB(FV`F;*jrH+i0Pr{gav>%_xC<2%hd(Za4d6oHfm{e!uX)kO zC?4pfrOQjEMumU6M zf>|kx06`T?&IC$<+mQT)2nfB7QrZG8L|+MnCy#Q{<)t&rDF6h`JDXmjiwCOC z7+5xcT!^-@O@r+!L1@5*D8XBBvRR!ip&lfGUbg=3-6|XH)M(_z*R|`ZNYj7XpoNu@ zj<|?jeI%Z}@sM|b!shd;*Bs2u#2DduL0}TbR7#MBxDr?p;B>OsFQfMRNXWirm)gNX zDzI&i)o;z9Vh643BxsKTe(!nBh{-gHnM{zJ@+$mDHB`7LyD5A46fLsaNjeFULy0d8 zi;Ble9x;K5xcZZtDhlG&Aoj8EjbU)7!f?d=(W*+)7Yoo%Ssu)>jrO3`d4xiM=^mNyL>CRoaKytJQcWvhv!Z0;-p!)mcBcJ-uFCG9y+?Xf(WHy zJWFuRDxO?v)Y6)fTzHH!X%t8wAc0vKe_Q6EcrIO7Vu?SqGPJkH6nskJeE=kyYj_r@ zx>bc4LL+WJ&&pVzBLy#ij0WYbe!b-to$>BMMtK&`cQQ^`L^l@xzR zm42v)sT0x|9`^%wgxUO8deE>8beKHs`K}B!Ff4=1w@>YR>f$&17EekWJPv6`&Vw>h z1L^pK+?4M1yV}6MDpuTz{mU@`cfCNmu0suqDt+7U!YlBewR1XI;%zJCxpL>9f9^tn z>oGWx&xEbc#3ErBQ5w&v8mqCz41{yD`!RR4Du z!s59Lu@5q*{X}6;AZh$C;eQluEQF_oHn1J3nCBpypIGG(^;ZaU4!80#POFff_4zBS;{s1hX=%6X7Wt ze{>L6*pRNPCBZYhT`F(odM%*eV^s|@r;RNEb2=JiPV-9O?cM^IXz95q+mAuxj9W@x zv3Ng^F+OYbJ7&*#O;EvZZaO`bSJz{L+z2OqmD~~~BVkDxD6Z}@6?FHn6Ph)=*c-CO zRj&^KH=@`l8E_*MY-TM1H^TW#%hQ8A>UW5mmz~xdZR-YeK2ah8He`}}Fi8&adAzK3 z?KQOWQXmczS3ccCU{m}QcX~OKCySuF2A+PpVLFQRZYUtF zR2Qqx#aL&dp5c8XSq5;BS_cEa727}C5s;M!ptMplkXCZkbOG5B2UcHt?^-_uL+ya` zoj>pm^sskT04ofXDFSMI4kvu-@4kM(w`m_^%x`2Ckr|-(WZ4nYMR*n$vy zDC>Y1;XPv-Zw`c9TXIt19h?!EwwuH3lzA-ivF21DX`K zLSf^1s%V-z@MxO4eo_2~@7isQUl%TA4XcuEHp#k05g_`sIE2Q8;ug|U<TtwR*8IB4YUa@zW{d;|zNwbyc5i^)OO_tNC zbCai%IVR!!ZPT(n(L{G4(^v_-zSki@8@l9m_yxqi7aYg^R+SscW|HRh$Om1W>my&K z_e+s+p0@ro4YZ`JZ)Jvd6?X>vFxaIzn?J`jGJjkW?%G>@ z&vd*7!;W4{gGoKpCZJfZRWn z3@sr46lSUM78m zl=?mHYyY4&o-z9qL`9Ug*OV1YexJt3`YS~h3fU60D8%-P@YUu8b~C+{#7+6ie9bx} z7W299f=tzPVKRyWt2Dq;xIC!}Q)K4*cIYd^`96G?uH8)A>k7_OknkfV3>5mBmIY20 z3zz>fDu69qXBdyD;H7GmqPBG4NOxqslEg%#JE{*kBzjv?(#A$YwdL4hRAJiUnQ2^m z)4cRPSNFuEF}uW;V~;Ru{=2vMIt?0UKcckwEL?gcEX1r|{zS`hzPo(208K&+_)DKs z7nr_SEhfAb`RYoZt<~Tl=AAM8vs@w6G;V}s%+6>$2)AmN+^sXDAV?msmL!n1*EDqg zo?}F#IXtSdDmQxEBabn`7F@N;V)w$5TQ0lRhHQt-{yX7kQR8y-VIM3Zgn}5BWiF!u zsR`;67q0|}ab-AG7UWDGKk_ezO~v?0hvU6NFe=UyTv{InCs5kPU-0qwj80qU*gwT; zh@@bJG^R0)5oHm7YWetjpX4g}d*HG_$bzf31$9nT zizo8C=Kc6~9G^y2Ye(41PEKh*ht3qXg!PA-%)CDs4qg3fGvVQfk&|@=jWy#_sdPZg zV9tUOKKb1;cNCVWgR)ZK7BPS%eLONJOKpy_HB;Tiq)2j!=4Oy`rZ`P?9b15Sc(t`C z-i3oK@gT0Q{ev-Uj^S=CLP61vbh!A%TfCRvr)GKI7mQ39$@Tf-6{}HqIp*DMD3ssl zBvrIZ%wT9O^=5*Jav$J3s)v64HM&9cNpa(Qp|!(QC?B+YSrUz*c1Z@4fle43?q%{! z;K~;g`}VvS>uS9bV!`<>^*$DZ5w}5Kcktgd`)sLWpuW#|Ay3oPtKp`|gI1Y7la{Q$ zf5Fp)r+$fFHyGD7PH|-=q;Nq`glXNNW|#R3r=L)HKQ_Oo{p-h$^+?TPXe3wx4B4J? z#!`W4%Mm6kH{+fPM&(%*)8vdP_G4QIv{`>Rh=trTj+icn7YUjNXz$#7_a9wCxK$bX zHw98c>^AIC&1V_vENAP=0w3)2!=WM=kVnO_T`2+s`VFQgz3jgin7=&z3dwcdGS4bE zZXU;2BA$p$P)WdY5HxMcfuF2avp7HWwAixoIJBALy8Y6Q`z`#68kD8PA~ATl_+rZB zZk^oxVO+I1{}+jI%S8G49nIys2DIZV2;GVYrYwPw+!-~=?F6M|Yw>pD<%g(|1D=ns zIO{ikUlZntzXwK$?dzTAdAD7MHmxb{yJ%_`?&)A%huf`mtn7&!Qn}E}aJ_uQW)8x) zDvMwaT&;VYa$QCQSr~b?)n7$$?RQ&?-8Y%eSo+{8#6!M=4;YHOI}V~4uZXu@>0qu_qa>0jz!ro4rl}nl zmMldoJEb6OJWtjuzN;!vG1)hOY_RphkMgw>G+Ol5Rm7+MnWi{78tN_A_Y^2Fd3>01 z9g(iWCu!g}R^6}2kh@kyb0hDMsbatL@qUK>I`{~;L>h&&^{sYW_zjd%T))0=PXM3y zN0XRB8`z@^XhL)djA;hOX4_7(rp^_n1|}HU?D=YqamE3}&6a0dg z$TT1;k4kdt%Pqs3UsQV67-QTWHm~b7ubvpU)b7~EUeI4jUl-gl_wMuw-Yl)gol|?- z1hsrT+WmColU1+3OkCj!BP>rW=o#m7vhC{lZUGM(Eh`qSc8GOP0d4`&2i&*7q}xYk zW$vYWSNkj5+~bh;f}kC`1{0JIEv~$L9(TKw_@r?VcsNo0S@mI8R?&GvD_-pP(2XX2 zD?W{^^pIC|)TwVeUsM}Rx?X&9`;0M=irR?#Xz%y5CZ~>DTk`PkB-X0w-7=T4MFx?Q zyn;jzbLtb(#rjz8RXnS}Rl2)MWH2lf3jVI2r@S)TFtG$0S4u9V6hYALxAqS9VLczb z{;e}oK^B}@##%IR6aj-pv$9%zVyB1tTL-zDW-U3SfY%0;_9wNm+KnbCBH~^raVm}5 zt2oEL*j8WMZpvy-1%iF5Pb#)}HAn~0(ZvH^lea?mfAdBw@mf{jpzuH#NZE#u>WIZ4 zL6la%Ua07>yQ!%OUBGW~N{9J@G=MVwmg+@+|5JRq&&ysR&Xo#O&jCJVgf>Gh@gbd0 z4n-7rpBtc>3r7*_)Yp&J>bxkMJE?twdWuVLvHz|sfq2n6xukc{04v%F;(vV%_&*iz)5eeyNsWZh*d}+JH1g2s_xv?$#NJ9H$JQkRoG8#Li6z3+;zsAO*5;r zYrIxJb1`}vIAfJUXhg}&m$}9P9=fBy~-Z7T2zrk233I zG0snil5--C$a*dsYZe<)T#l}Z+^@E;XO-7$=Cb`cRZ!yLW zOqI{~-wg75Z+NMddv;lV(4JkkM0=C8lU+u1?2urnUoIXdg!cup=0|p1D|t3Lx%l3g z0_A(zqy{%CGpfZkRS`nW_>xcLJ0@mv5gELje*JxkYp~YKuJZwn4!;(hk2cMGDPP3= zNb0$w&P<^0piSmsPf!Xs8pe0LI{is+3QG>n*y533(6(LPTW86_fE#rNpZ)?%>7CDl zC<7$qO6N;7`R&f>w-hn($y5V9%qVDy*}#5mm@0LLS&W11vUjcf9DMeJG-Hpqs&VNB&mC1|{R^efVKDNk?>h7rZZ% z4H~;{banZ(0CEGfWP*alb@NN6%)A^m&F1I=d&DpER;0eI%I=`BR30!^rOMPtDY@1P zH`2jA1fl>&RC3|3*eu;f)8Z788cZVU3CuLn4pgY9B86|DN|d5sNGsNgI&Tm3I^o+p zD(Zo?E2Zb63Zu!PD=mi@ReTzEK6mkjXZ?lHS*9|#jU9dtMbf0il{oNvf*3P30u#*< z{gqhT844;Mk6y)KUT={wcRDLe)qAf5JSIbxf*Tb-J4bKDrs?8q|I1OF^8v1qevYh# zcxO%T0{%;t8njK{$|C*O!>0SPsdPoLnl9(pl%~O%5f)Uvyt?ie%bR*4$Cc^JU8v?b zrV^2Uq4p}eOl|$uYw2%(zyu62syX#BMuXcr6z;B)#wT=Bd$7 zf^*-iCv8Axy|7q99Mwnx##r{4%jB4~Uxf_F<_!DeZ|_lNz58TBvbB7B@xByc#GH?- zKGe;wiM7Ux*XVV|cNhIQ6l;QXo7S@;vlu?Sw}WihY>DhuBMHIXXk^yxj!@((7_TGs z!0A2vv~)IDRW7FF=78nK{1@oCW{YEobAc+Re#BCpbf2dn3s4HmNsD#%Vm0^3^w>H* z2|rmU_}Iya)X|$l_}ay7;J&htBy^fzU*H`MNmd+JywmmKdi&v}{LhnB9Ah6_?d^*X z*ib*nO!G8hKf?C@6h;wyr{-XJ%%~x8N{N0(uw)!bNE@m_Mk;kC$~=`ADafvKp^3j* zwCNN^c*-!;CKah)r)h80SHVa3p1GWA%>w6Oxtq58?cury6w~C zQZB)~)craKbBT^ku9}4vMl`Rm*`*ECj&ljdDCV6Miwx3bl?UI263&ZXNh<|0eUGj{ z?OgKj3?gDlKxMr=u0$gjlAbOg4>7--sZRZ#FRb&T*dYXMw>}YK+P9cWUA9L_e)}9@ zAR~(cQ(I;|3a@~(g)2tVK;bI9DMPcEo|aaXo+Moe9?cVryW!h_*f|(!7@d(78*qr4(;wSY^tA))?yY4 zS9BkN&^SlHKA1hIY*PQ^`tCB$1tuQNk+rE2t>7^$qd|A$sE5^oKc?`MNH5#%YX*M>8=WgVgfgE|NllN3{p(YicKa%7M|tqMuLd1-w~|JTuWPxvaaM59Tsz zjC>0>T$nv=f zyOo>4LzKtHMHdSu4e1*ltY3_KR~iEQ$b6_0$8Zurr0Jw|&jk{WcJ9pId&?8+=|y<+ z`;)i(TgwfU$>R%?v>o+CA`IOe&BB|X6f$AhF@e=_o69332ylzfL{tEywWI# z*jN@p3}1+%3)729$*c_9tQQXIBk-RJ()bebrC-{B5$tt^I{YyWzzno6o*0!hyQpm( z|%JHXl zyd9)qVX|&&wCLo4wD*CpGi)ZxX#S?(DJH#VTGJf&fikpq0~;RVyySGbBBmsj&exft z-QI1jJFR4qq@5i#o|KrI+rhQqSK*;hi|;QSE|h$tl`DM;!K@Zk35Ze>iYSnfnl!tV zVS{swk$bSio#!wwTNwQ4dg?QsUJe)$SzynY_%?;S*vEQuz#cg{RUi~*q)s%Q4AsUd z$XzE89sdz1Fr`-vdyQ*)hna~DZdG$#A$(U>``A)?r_}P|HBDNGE^DS}345tdT$gwk zvHH99`2IcP-c-H%pK1?eafetwFh6cfS5h-vSI83+@deX19rPx?p=w9oBaVBS?|jy+ ze}9h~mvGQ31g(1Xnag&RPa6k^QT&@J*XHv6DVCP|P};4=HpF?CKdexPWvbsjS=<4Z z50-KE^-rw!xA#HNEX=AeOTG)XsciVM*Y1x%pWr$TBzfdBNoHwG(Y4BTS;cgrOIzF# zOB)P;8NSiCX4jvYAqXE3`%tQ|Le^d(xtTJD?K&U*CB=iqCM#}gVHpx#SctK(`J@8& z>@qypy5uN+*Fr}X%ocukqudR$(ar=`=-1#ua|MOeW+`%id&AfvJG3dxEbVPfgl;Hh$T#x9tewG6oq-OqWVXqzsk^Q64v?&74 zcb+c#vfo?G>NiE4u^}3`S<75`*QeBDO&{KmS7gB@#H%3?>_> zP@#RD;wrGJY@G9Q7fR|AiD)H*8a=ZJYn@Mk(0Tz8TGJO8KkQg2Tv@ozVgJ*StEJG) zS7l2kw83QJ76+ZE8I!rU1Th0*QjxNbT>DY;?$?tenbv~u$(W0}_uaSi+^`@GFPM)V zJ?>!s{y{+#F3YirTcB>O2M}%f|L}uaIhgzhzyI%K3kp0J5yo@&G2kDp1rWer?hnBK z(B1ou6`~h5uo7#0RLdgH}(R8RKy>?DEx|iaE%D#{8Onqy=SE4 zsHql^jqcJ%V0Jaf?ik3=!{(KGza=<)B2A+1|J z4FxfJAh=lV%n>Q^IwSEKFm>(0CfYM9%!x^TV+}wox28Hnhd(Sg<`$K-*puw^Op)gS z^!L&L%dH7ux&4#T6ZjXS2Q+}5$tZew!S+oJnyOd6kaZ>YRV@0}^8otzuep6-06oVI z{X2-!v;N-Q0BMaIJ~9vw#Oh=x$!lmAGm_C_6QmY+O{SU=#;+vCCZ1IerN;GZ1+n{7h3--w7H(r?Bd^09bCA@t3QTf0b*051@m}wMQ4Qf0b+b z+)hbM-aPt_wN-KW6%IPZ9Fi5e!FS} z8bIIsJ%GLmT5kwpFq65o5&hdv%WMBN$(faeh zx>OcHO=uuO4`sgelS&EfImh}$pi2j^bL)={5PIt2@C%($ii;{OE!ez)om=dGlxyLE zo!ftwYhUlsAv~9B`JT(QkQ&eBTE4%^wXlE6wOutQ|EF9Vdtdl(<=U)&44^-kYo7X7ii7a=zSffjy%Knv5XJU(}b-6zW;@5&S%Fw)29q39)nCg)G7Pd0e!Y^wFTTvWL| z{moj`nXFV2%HIZk`TAL;;+C_Z*$u1RyMJiDO#coHxzzl~onA>p_nyJk)1;`PMlV}7 z@>3|5gDF%(gDUDFbve25jp&OJKzZF(q`CP}WO~@q zr~&0nlfFwRqtQD1InWYaiz~evi5Pzsx;J>J5IkX3K$HV#*L}wz3F}x|D)yptPWSf5 zm@R9EmaN&U@Jj%bH0bW@L{$bz@wEWL!z!vZr|AE~3XOt!H4VRAJ1!-Hij6l^( za348q`+vdO7I{Iiw$p@2I$-Y{lw=9!2KLV71Y3Nh?cc+lK6b=RGe^LInzf6W6uc<} zF$&C7Haao>uBozrHEU1L|2hL3_PESPz!`|?dt<*-icIkL8E^^GSvCUBfR!(=>-o0Q z@?~W!n-(a_G6#yXux0=O$4IV(LTMn%(tuWFYX*5n0*bOo5>x%m2RSN#@jM@-|sA*QVw7vH|3d zXT)6Dx&BbVD_HF#EW+=6aGzW-y+QHDf1ui$U5PY-c%w1ObG#9HoML?v!|9ELSbKC5 z*Bz1ehf%>i?n)tpc3~gx$OHX9s5YSa)N`v~xt9FCNrTdBZ~p+4V`)JHax66s^F8mt z@Emq`>CWtH4Cbp-%6+#_h9MkmY=oQ1e_jOvf&{fD$ONl<{1Mldv-}B;?cGtF+*baFOQ8|L@416TVsFmty8EE%Z-FPk7lR zq~+(uz}*x1JiX@m+f@STX(gDcv*ezs*_u`;Qk-4@>FJg}4Q_%kd{OJRK`}DT)P4&_ zNY@&Ev?_d3T-PQM()NiioyY5-u3^KpyQthDl;)jG)K~>vA{C)X(K+tbS%ufcajCmX z#=TuDf-uT~#VT|!&78lEM&5W40kTSb`xVs_(z7mrkRxX8?qUHcFeDF$igJyE-98Xh zZv+Pj3o|ZB%jOh=HHF`M77P{qN%^3*?K8T$$rgUlVei_|sk-^R-E>(Ke|FaZc^t`7 zX-I}|L}^j`seafhLzM|XiL|#LvOO`V$?nLIm-q0P_X2i?gUYOLPNqS=2fg{7MXFZN zD;3@_a;kc_kgsRwhTP+YFqj4YFu1%T{YXLa$K>NUvGfJ^$-$J&v80y!5JG#d7K_9~ zL|e93#FICRd~8BA6XQ9xgUzsSBrh+Tt;r7H4+o~O&Q)t~>)%xy-f6^7AIuP6wFHTx zZF_|HaT+aAmo_zd$>iF6IF}R;W?$5ROIdF3U}HwH3_aIy+rWh8*n0HGWyo4TG(s~= zf?m4H(~b;(IHH>pcs-^341#$}Ls3M(i z5D{xYMEqBLfAc>P@#f8YeM3uQqu(!ve@2D5IS>^!;gI;uCll(BcQ5`y<8cN(7#cC5 z(3L5F;du6rr$&Q1Po^V>rEK7Z_&wb&F3w4_lnA_9y>PxstdpN^PF^kQR4y-*8xH2K zCeZhZ5(s!Hzz&u$BCokrX#T{$ypensFfSqpv9^u`$awE#Q5W`Q?3#gT*;;2YDYw8T7nfk~Dj~|6VDZk-+dO zC@f7=_j3Y4Ck96^MqovrI8*y3Pu~mKQFJSVn{3lX}7Y zbSs-IAO@8)j{53W-AC_Y7(p)3w*H#0$BGs)m+ASyQy+e?1nR1c&XVPhZ$WTVJ2_0t z$^Ou5O|}-MVZ2{e8#9TT??bq2+kV3Ux05)F>~MNJs1N^^cW}M@P6N7>ba@2d630u@ zn;~v&`G-Opxa}eV6`jsn3<&Ot27-Hj`~~+c7asJPNyGOQ)qJ0@0#bijq%cS^-e84f zBSrjzdlEgtJ#mVKnM}zWCGK0h#t;DgW7Z%2N+!Ns!+!L_A zkb|oj&Fu;Jlf945)b8JIL^zl0SX^ppc{KY4_f&dZ0o(CSvC$p3{5%$(re0g9@t>7)f$MQA2r>-^HlYgfz z^>i!y4eLaqo3HDK^}C}r`hUYcMSi;E`83qAlL$m_n@&?(|DPey!+#*q|M74rD>#AF zkbHuB+Ncx}1g8#PrY>v4y&e};QF?scn0A^fpgSXd9_0{}1lRer6IXouWf_C}Fg*v$C7vbQ=~t+# z{m9rq|Jn-Q;JCJUGJ7_*f=CG;P}(70wAg7$&p1D~?-ixngB~|E-_WHwYk94wzvgf? zq#ts+S!4C??W|veJ%g?ox#n;lo{rh{4W9p7L3)70;HU?i#P)K2b|-pW@J$os5rjkj z9p@0VeRtK;5)vSQ{6+WNiX$du?)>{!Hl-SYaoTik((tkV3Def(x!_QV^3#qOrdO#t zqLEHLPwy9|E%gc0)&yYM-U_twRr%@fGY8p*pbVmybYsHWynRaGW=Q4n#-h8NIv_^0i=zy)aICvjEB{} z@Q$#+LuGOtH=q?Etke&iurjG)_m^h z%~59ny-jLvo8bK0G$ANA#>&o3?(*WNTV{XfhF6FR7brI-o4gcr5B<(PK)I0!56TT~ zAUFJ0y)2S6PFqfTFj3oCQXKLU1UsA4Y6PmzC4W4Q8Yp;&YHPk->E1`PFvCF9pf!zS z(bu5nxWHXTkO=oocWL;X+^&d0^!V)GZwpLiarg%yI6Q!|yy$-eTlhzCIKQ(q(zh}< zwfU1C|Dr-u%-6$!l)(#K)_7uH$2X|*!jlc5=gl=x9)~K@tAEf~$-d;dXjoQ&s*6}A z2JUQMk_RvXDyyrXgGJ;ZVX(syjZ}ohw~e#@(RnT-fhF>P2!ka+!eFG>CtKlKA0R zn2Iq0^HJLMOb1r7W zx{8o@!#G-Ql4V_I0ofvbd4{c72lRW`gYS$J0WJn$4!{M>0hh0VX_GRmm!qAei{oS1 zW&?jJeL8!49-7^0`z~+Q1_o88kO_xP#%rzkmsbGw_z4V3WBd zgWSQoy&6Dm9uqcfDDdZA9o|o}2MaS^$!8mG{@22Iy|0OqUhF!4_*I)%18Vcm^*-Oj z*?6kW2&Frj^Zo>qrZ-+-tyANya$DcZEF_Sl*=6@ z_^G18^mqn0M9deFFtygNw)r0))?GMW`b4 zW|Ht79g2^CNDE>BX@L!;LzQ72PzbnBEYlYczjqcQ(98>e9O=UM4oAAGE)Uvh@7x7u zRVYdBsPXD=DmXm!0S1CTh~YD;cL(-e5CDAA^G;jjA7LQ5U0ytNwmg6VfKN$B9w@nS zKNo>kE=dAz7MZAd@mi2TV4O>SuK{>%@B(0Hr&fw5z-JJW1iF702=JK=06x<|fKN=| zZ!Cc6`PYIt3krl|@syy}e6w32Q*V@HQY`X8i$o#-hE4&%&`+F&zrfH_T))83Kc>=` zauc4w(2VA`^h0tOO%7e6cUko@8-#Q)+fF<{=nHx&*BSu{ykA6rX^4e*<`560XOFDs|>UK9Nj&9 zD##pdcmV3gPWQIs*xEElLLS0%9nBwlD(g<8oj;BC(&p%JgP}{(3e+7Z@jUmV6|W87FI`@TrFIHw z)F?(6W>wl7seh)L2~oypftj~mz>95Ld z+#VA$Mp=b4X$oDdX|VhKUMULUQG0~UItoh3j!HB|v@* z^`rSMf_-IrZaLly_2FdF@y)lN%+vw{GyP$nvk9#R`DtIBGj=b?r=U<73>85p!lYW+ zrTcv%v=dfw*p^*E0E;p_Fg)70{} zWO7YKs$cc>*5=+hRc+sRS??>oAC*LaY)%6p4tN?eYJIenvNN0TavqyC_&P;zsO=8T zuthKehTHz5D9;%--T41=b_FmT{?D^302dtudXS_5x4C6~a;4#1-;ip@OG#S!O!>^m zl=S}jAOZNGecQ37ARi4i@uyZ-M^Upl3gRPT%D$70Bo8+p*V{mXu3Mw*UwlyD4C|MV zMn8rjvERj2K;7+=tb8nekmE|y-f*uI_xgZ|Lo@qt*8u!L`yUVeseJ`!+b{KLQzfuM8(eNJABR(0Nsdr zD(SfBlS~N6Gtj(%zi;LIE?Ne#jR7M1>GIw7 z4geRO1K^_B{}UHI@JmE*{!d(V0Dz13iUe@cY9L(nI}k2M4S+Yw)sPCMeC>4m?jog0n0%9_mi%0$SZr;6=Hp(Z=#&N(i2v%Y%}Kh3tn@w zh(smA`Z6OsZ!Udva9CJ%+($1rmmP_zNwiB3qjp)I;H*M&|KflnA^ZLu&1ZY>+xstS zsC3G(sB8{_34}=Ws}f&WsWg;t*->Tms6?h_05ieaM592O0B}qtPrGn>=mZ6i>aoA&h>{uuM_Y>qq9E0xv=j`ftMEu9>>fdI8 z-%^^TuK8+A@C+)h2F@h{z8U!@->W0wVpj@~QwkSu%(S{6-g^)(@!Ys@Ke*lbZq%Y| zT#cVOzXJ%OYgcE#y)?{#mu5No-(DK%|LLV!lL@Lh`jr)byfn=4ATQ0p!+4$oL|xwV zgg;qPvUZ00N)pwtJ>BLZX7x^9ip3G7+0%nng^ZJmg1Sk7Bk^Sbl{JI2E*@ zF~d!<6DFFAE!AXm^IJjK#_SRMa>Q$@caN^4meQ0 zjcyL8B(yO4<#2xl12XLY6bwXy1Owo%KkNTv+wo7q0L*W}z#iKK7wnT@VEvzh0qFbt zhfe){ATh$s@b#a>G)HM5F^#Kz*qr{Q7Aqhyn{E;d`ivyJPZ&V#GZF;4+RcBu+SMy% z)(eOLy+5Q0N5d)EO+oLEQl`FONzJHnljWQudO%DAaNeH8G=Fj4Kw=uuw&NdS8sPnr z@$oYFNlf$Cwxh{#{>!Jzz+c-AQ$bI%;o-lx9Vru8h@p|>>I-f^a6b7^_mCMvWn6!h zX#8QA+h83Dh-vEo5}3VFS%)o+PWnGBy_f$iy#a(M0?mIez4?^|UZ?Sw|5-GFfQ zrXY}+re^k$rYS5BwD%6EsN_0r>FN4$tos#YrkP#p0GVkt8$UjoX=*`c8klx(^$xtT zy=K5n;{r0%Q2Vqx!7f4XC|+Bq{V~(ros0e$xV9`Cq!r-R3;4@SQ_o?Jt6e(WwfF78 z7Q}h`;B;31!-#Zek{=~1$BfWXtysQ=4Hw9a4W_4k$7KLv=2uToFB9m_nKwx5Xrw8m zyq&Ho@JGH*ejE(ATgZ5%AfhzuRWEwhmc&Z);TcX)03baRelG7X%?uEwdu+JBX2|%= z*$f!@rHRVT!!8`geE$rQcr`NtI6o zp!$O)HECt%X)BJK2W-U|;!#ND^2`?6%h5bNrCB=H=29y(kJ)-O7J7itfc2e1PiW$H zU$JtHx$GonIC4Ac$H`Juh@5k}pmHJIo<;LeXdxKXB^kwc*1DUzWN+L zV@~%cu*8~jz-2azIWarU6q8t3lkj&4 zlit`;X;?XkCUf_mZ!GDxG7*SjVWe}55#N}MdKkUxRR%98A5P@a?3yl#rd$y=+w>t; z*7L?`;qx-OWH615M!slrzwl$|D+q3`x7q&Dsnj+mW&VuZ5{~vg9h+V(Uq4gA6`|1X zi~00^yfYXq*B&uBeNK$h^Sm7h{+DcwIT zw$69hLug45j6j(N zFuuO%*AO)v>|w?N8z-&KcodcY%9`q%SV76J$w7@OlEv_i)n<-UA6JUqrzge=Nz`9S zND&4?4#neqy%t0Hz1Ns>O>)(ot>ECiNeE zi`~kpe)}!RSNTcj0zKq@%V}6QErO=Iio7v0YWm*rf6Bw z?d)^hXbh|k>scGkBBnhiR>VCU!S!c{L}nEbVFk-NgE;9`^iaO4_lz|s;q&2d6ADYJ zY$aP4N$A9y1^L4L{F;)UXQoAjl)fB5wy>YC&MVeZy`a)=u;nIMR@!zajHSav!~4v6 zXf-vXSVa6$BCP&=gq93S8pkgTD{09zda(aPSX|2_bxpIzTqQi0;=N<1^SsfhFzg+L zGJ}fOi*hTR#G3cl+AXSj+qM)hziULBQO|0)tAo|S2eY!sk23`Lhz;bYQke#E7@G(? zW?rni@u@6RC@}xHBQRa&rcr%Job+aZPO1DZG!=csIFYr8#?~*oL?*3OOCpxEI*(B& zP9lT>A2!0Ek?fW}jO`}XqDIrK(U<^5Die!<+HoJ>??G?!vP8J@ny!StwR;pVC=tWd zAa4o%HS>#>;qtDN@pOyfx3k_2UE|u(nWn_g37m&+_QO$qUk({4MTs-=2nwFeuZoK< znYlv1URaLvuF$(FY-@Glm57Aq+c2-ou1yvu#1vvMr`B*HeBR2IC>Vqz-n5wDJD|%} z_hFGi`<|$ro)YFxpW(`h=_^5$@~Tre{N+aylkSnMb#3oEE8WlH9BN0b%eB}AG&))( zPRQ1ywbLaf!mo#zh>`EZ+OO2(Zcf6$8_+|+ktPt1WV_$)UgWs)4ukFxNks9JcMlDFwUJu)F{MHsZ6*bfm5MsQTD1u!s6=KPjXBS z6|c+t4?S93Wym#aO`o!nR*DW4#re&!^&50v*jXaiQJ;kzQwxPJRzCCmByxPm*Mc4ddTiBIN9knaM554zC zwddO_7nz-n)`^6K8P#r!aS4O_zzIO9$r^-EoA6&o6BZy^szw zkKDmuA?43oj-t;UHB=usFEX9Z9gY~@cmc=fds0dIJPG>&mo}DOC`VZEyf(M_i#%|z z34U}rD`d`}FFZ)~9|^ywY<6A=6!7<8>pOXbPkN^KS?iuB114m2+1PSBtzv05vLHR7 zv{&_dxj}jYA#yoeGhWeH#B{%e=Rp=$f7BVO(n7_td|)T>JHf*9X6`eAoC*&QqGu2I z!%bU{wNmA9tlfiCwnio1en|!yQ-N9EXFnuVF}%#Zhoe>TELeU#wMTj>G^Fy=QSIje zy1TQ@c@uR>d-??Zsn3>L3ZtR2yH1vJK+ucUJIqK7(b^k@+k%&|uM3tcGy26RjS`K{ zr&K@rfBIDV60O*zyI|loZ&dvT;REjKPA_>1sTnm|iXeFjF}=aX>~xvPfX$gsFl)mP zuQf3q2W#zIOmyuwGLwv(E#9tu&b9y?-RyfEy}3nR*6&%CXEEc(X-eWFQ>y-L*(Mp% zkGvD0f0Hu#_`S_IZ+&W(_Cq75kPCszTRl>w_Ru<#U=K$B1Ck#544li9D~;-d*!(h) zdEgJ4#m4st81LVF))wO$+MJWco(;PdJf1*RD1<}(T$mXJePJg{14qM&PG~0)&%9ZX zGX>99$}Iget=AXJsFC*zvP;5FX9q*X`Kp#T<@k^HSVjE=eG!I8=4mddn-N{hv;N8Z zN%d$S^)$gJIRrG#;0WW@i~O=rPbbpk)R&9S26t`1@4pp6{bWZ!w+yQBGiW|U92Ba! z$(;L6@v#>_8>0-&hgNo@p{luua!YaQH5RI`%5>Q3Ps`e4NV`WkcSj3#`3LGyH=?O} zPs3~@S=kcZ%+x&w$IuAq*!TKSqi{-Wx^)(%)Y2s{)4zLRR@@ly&`tG+CXcn@y*gD| zdR$Swx`zJyg9dc0Du3y%I{_@=ih+Ywj{j~M_xpp!!rpO2=p)dce?Ia-UY~8AZKjfO z9>E@{&ok)cu9yg?B=C4v(Zz9U?+Nff%7-?V_J>cOg>|wdh}}DVleczOy=QqCJn;B| zTLk*V$DWrv${zYT6RQ*D9>jE;R4X;t8c|N5 ze68R{!qto&dPr|(YHrJ9GHB;EO#fQ@<}C~+s|Z|5#dnoGd4d0^L*7NJCCvdV%W0tN z@?W_|o<95RjP>p9jr1M#e-~X`0q7&fKcJ5=QzE|MhHId?GV=yi*{``WM3?jSlXl7y zG%N7jJ|graT;O$ee)-^V5eAwS?B9=1=Y8`RmpWa2u#HIzQ|SGcxXxA9r|%)ylOom0 zs1XxF;d+q(vW*Z?{<4i2em3p9da1>$6%^6%0BkGShpfaU_#n#OYXO>boh||p-s`=) z_FG)0=fJko8uAStKk=C1)3#EBQZXiQF-lu=?(2er{TIZU)!UP^9aOnm*lU~?FEqlU zY@-APQH`M=Rjca>5|z&a9iTw65$7HG3A=!8n6aFz;|IroS_t)jSqN|aWgvfz3XVr) zKzOf^?jN(LtDBv}cuB0dBBR)#$?`VKb6~P8v}PVH@!nO;4pF7cM@}{kPb372HMge} zGKm08t|C|y5d+P|_}833=J%W+=;tXw_riRG$BRetG$)7$<^+%|Kr8a%mx%C>Y{b%# zVD4$KJo;y_TxG=EV`f_PsXr7XI^S5>JF*G_c<|<*{C^RF13^S!kZUCBH{5HAMQIi; zF>DxiI7%`;e_b6TS{C5J!~JER+Wa$EHWIU#1PzuqewE`3|5=Vl{zp0f1yGJZ0(0VC z0m|{w(8&G9e~Hfjn5RIZbBtu9HE2*dUKTJ7^Mk9}k~}NPpQrr5WLYocNkl07S1Ypc zf3za`e+z7Xi3tC0MYetJLBA6<09ujsPN{PnzeI$SPa?v9wIU;OV}L#76hH(9i3kaI zpPh46JUHgIHgLBXpRu|v&%b!McV-vj!|1YEYo9Tk@In=gTLP2VyU}@{T<{#!ip1rV zBvD~vm@1&VcW=R+wqk%JHJ0a{Lm&1BUp32n-2Ev-amnhzBu; z-Jsp$uJ%I4k~{Y@*)gaQUXNf`1T#nrzwGRzyY7*PB+8Q(Gbv&clju!oSkOkKlDCjt0QN` zCMqx->bgaIT(+pt%7gzz6sHdT{nuO79{p9lX<&B^>c?ZKN5~IvA%{2Sm>0<8?aYhTM z_w@Y-4A=dKT{qc^Z>T#nl*84!;XR|);Ev{`jtVimpRt6EhxzLzP!A?3Oag|Ysu;#Y5Ye5=I<%!vlOVGc9HOhqKpYHk>YL(i(W36 zhCTXvwAMN>_MhgnGdjaeqpmuEdn&{(Q3E!r%(kNfkV>TM?&p5g@$SlN2==XJFeM)< z;*w7$2_D|8W>L65m60RNeEVgT&2VyPXL=pjK^~EtiJ8w}Dqxu$Sm9XK0brjp`Z&t0 zZZ~}gliI`}bE^1Tt~j5!?Cat1?tEU|Gzq>|2I?&cNiX&tU4PYE#GdLc0li8|X%!}PD!%$2hXmHvoWMr1iVU&e>%|J*rjE8@cn|S2 z666L4_UjN8lJH6W+*3*>o($AaVDcxl{{YCXcxV=7}8ZPP;VI(s^PX1 zyh?J%idV-@!jnA?$$jBMkpzQ7KBjkx8V4Q#= zH{mUh03!>61rsQtHP|RK(IyS#2wRIRc1^ckP9SgRIa_gx9`McgTzYX~bv2M6LFsZ` zWj>Ccwb_!{<%dfcA`LYROr|9XuiE&Eq4g%ghc*<_Emuvyy5)qNmUtIAOq2*^PoqUw zjj67Ez+0AXF-u{3*No3`FftN~1_p_wmlEH(u<{a(`n@ zhA*4mT{(?IbnEuRv(28YF0A1`5!?wufB)rYdkFbgKhCl!4f3o?847j8z|zh2Z;}&T zkaAnkC9tujH>j=_4Bps*XZ9H0nUf@S9xgeSZed{yh;R?fz5ZmdNNz^Olt4jW{*pIt zGUrE(iVPeUZoOiDxeu@1+`X6Cu_DE@v`>Rb2C)m>&qBm|XrGhPx3j^JFk94?2{VfY zQp$6>{csA-lBQTXb{^AxrrKq(5!&HSHp9kaqN6jQr(NQqx#PehTHc7kYHG};K4;m= zMhy3=z?~~b*;r8*7WLFDEP{7mE+FF=D(RW|7mnQK6vEtB>bG!^;Z+%B#`3vm-;&D= z_+jqlxXy&4$p|sVVy*BL2(?JbQ*XZvy%-mN&jwdu<&L6dNq9xA*)_Gwd^Z~_ih?bP z<^@M`31yq!d%qg3`DOh|5?GQ@v+pit2gK)#YU5Ww8op}#6jAf4lohscRLH#;j%C1J z`*tycz3g$jC*^r)FC)pZon3$hjnNBrN@`HKl8fWKPeN-kaR!-s+c|JUcYrAncI$n6HqRE5 z1`MeAiaINFm1z)|qbUzcFZkJ7TyJhh@5WQVQK-3!FEx8zt?i?p+>uX{VlM>Whq3;A(0Ap8KGLN?d6OGvYR}Q@L)~yUTT&Y$6GuswxKl=}h5m&h zru%Amf$K5ZFdWakkco?(ok0a6!w60y0R|=BR8SeF&S0}dv!Wu6S1WBhdGzAo%jekN z$rQ5V;9xB-JRiCQE_`)G`EQPhuOeOal)JICQio>OXQlj9MhHxn(BM#1ZAX3iHnH(v zN>CDB201eu7ULAlFsZ`p4;sV|8E96(cvLlrX!^iqCo_|$v|E|w(|lorsXCucW!2y0 z2{#m4qE!<6*c<=}iGeB$0TD2QOWzu$D(H)s2|pW|`!m?vYD=o7Pw)#^ufMP^4<@O% ztGKvteBp<)WV^ds2mkbLE)%W^_H_8^Dc(5J8-Z@JBbP-&q4fD~)m8GFV#}O?*cxx3!IhW}-*5P@4Qk04#7Xql@VP!@bfsauCap*-^UjZx z@)g7}`?z8nXA8@!WfkmxLv?bGMToA7fw=mEdjg9D)hL<4yzArU0KSXK8w1(77S1(Q zbDM!65^=Br>#qp~c(J2OuB@YiF1V@G((M9?7Jq zjGU%+_R9&0ZGqHccQnex<9lqvjiy`rV#f9prUwJP3a!qfMGA(0_%;{MTrX!)w z8|#9jIr*|3i-@tyi_Zm*Gl)q}nPp7`)x2}JaO0$l+Qy$kn_tiyv{JEcUe$C>z)?rJA2M6@YdY`)I`GI48 z@Q&O)cD;C^bvfQOHMkn_`+K|-oDQAh;7U5E%ESWL!p_!~I@MV7Oz`9A%0n6pVV)f_ zLXkLJ2>Q_}F1ww8M&sc6L;jI7WZMiPZ5(Q2>kIQ&4h~^Ol+B|R@7-`x@Ji|HKUC-k z(Dr`&xdTJLfuSlPG)aC5=`qh=T*T{d(kEHKPR8(ePyl;87G?}mWO<8?m ztLBT;+#FqxR zu-K53sk>W9<8@s{AGE$f_42#2WC(b^5OBY@keyQ1ciM>WHb^2pHxiqo<+Q5R6{9Q4 zu{P=pPJADmnb$ zpCq>EP)l4w$F>-d_J=qU$W2{E8`q4wq6_G`Tw^p@cGofXGoO^bYG0VT%$`jOSw$-j z|9qq1b23wzvxXItnPpqR+SY~V1e3DN)~tutQj^=adc361797j{QT~vqQ@ z&%o&le6Z;*3wR93j_-t@&q?*MC7ryc9v+b-kbS|UEk_y8oZqf(dpODhb4D-^56Uo|s|EAJdA=bYb#l%i6ZM!g zxBdgp0*`8UhGt^HLXCM!v&O>DNnbPp?Qo^~) z_CV!O*>KYK^P+-s8lD&mq zF5=-nvk9Q$KmQV!M`0^U?GogQT-I*p7AQ!oy^`H* z{tj^7b}$?oHk1UJCep8nD6;3ye1;0#LLq4{#e0I@u&?xQ1x?@}GcHyUlIn=lx}e=V zguCf31rI%kc2SDv$!&jkj1X z7YA&p6b8HzXXv(I7l$M)Qb!FH%)@yH_jBq5 zY|+?gef+|7#U2M8Uv3O#yz?OR&tQREFjOkG!fx_*?sU-l)G8_zFCV;R075kd+s9QN z5q3!8kbM(mla!BUqtd*%ZxJwwjgC_96AUwulv>TK6*=vF@YkKHCif8-XG@Z`dacQI z5}{Y{*Xxvb17gx&zs`1;xUDDaNb>uVh+Im{1Czjp@h}R3iGadNmi0^??fY|Wo}(*q zXcfc`H;i~ci^PF6yX^bj{;PyANl17*wQBsH!hUWt*G}$JR^N_MA0j7j%U$!Oup)N% zE#atK1v31j4|B&=k^w_Kq}LxJ^L5wUH^#ZSxjS^h;2cjU<7H$0KH8)je8-dMJ`zXg zLQ?1>mOPV~q}sGd8YN+4t;Ag?(7spXUi+x?hS&V7AYzZ0xXQw6)z=L%0&=l;*U}A_ zAGMwI!6x5vHFKSXbErWaB1$Dj*QIE3+C`tQti8L=i{pibSXFM-4%uRO7#vVuF@Ymx z3X7$QSeYQXE>4YO&*Ly?5LOeh_B-#Cyl1k#@fj*py6q7vyzr8R`52Z-YflJCMCt|h z%1BppuoruoELgLdNHxqk4b zT|Xvnp@c`5sAMu&p8Y(#FXekYzNuKGRR&9L3(Q5<>i zsMZ|J3R<(`F;X4d4WaBF4OarbzxUNR7u*l8SO{;?wAtTLvbIu~?@oe^tjcBCE|>f< z9Y)1iQ)kj(?p|Cg(ZI8dE2H!byb9fIp^k5057CX&(vffEz=?Olq;;Ga;RYhHQTt2G z?z4g=-$=d?S2X9CwJ1DGNz2K-uLc;iZV}_Q zI>o^Mz2gRcwK9ZLdrpxDQ(o}J+Q#tZzBGNGAhj5`6a9)2?-LG?BVM&ZeAu~k8?mK5 zZ;62aFl@4DDzvrwiAEBMK-=c~)!w>NSsz?vu6qvor26{_c26E|vtf~*2}|T8=LJWz z=}xJ}#oB{<&hkV0l1vg?8w$y5vW_oS_b>YM_14iiw`t2Kf!~?Y{#LsPz^C8eVOjI& z4)^q0)X^v+w|th#c&;;LXVYbw+NO6pcGqzJPL#n$IJj0g>(gU@)>~(-HVNB0OLyJ0 zI@2b?^4kv?7dJoa_vVI$S6f-nUT;G&3Tw5RT~Ox}TtNi!5J5D(`kJwKvuH@1IewOG zFRNBd4Qu0HyPp>v>gJbty?4mY|@!^d*(M)a+v zGq4dKYrLoM3<(vX3TBW-wR?s|tGQRT)gTatZ~PS1EW|_-pCe5lg7&Pr4ap^^5>tN4e7-(6pv$Tt~L2c z458Do$GC1P{=8)t6V@?fT(=P0GyEUW8_ewr??oyX7}zR z7SU5a6xQu*S1NJNrdQ}tFyfCt4AZ^wl9%V)rO*^ZD#F+p^4TZ6Kh~6_OAjl{^KSJE z65v1Ikm8BY+aiLrf4gf%(O&gNk?C_v0}N!FS^$$1>A}m3IKvI3_~ATadWl)8y@hV2 z-Pvj0?{uLLI`>8*B^8H|mz#^T(5-4#4zIzpn~T1_%3yqrhHZ2w_`#S1{DNj~o}#EJ zQ+K$P$a*`&+sRthr9RHJmp*O!=f}|ghN>J(t7xI4HN5lvJ>7MA{o^{f;KG!tOi#t3 zbkw$p6F;Mqb|hT+F4c}VA>8V#y1A$vSyK6td_mvEBjOU91=^}hhne7s3ci+k{#Z49 zD3@!j4HcNED!U9KyT8*RT&+31d$HVDb~YsM7$NH`X$*5}Seb^CBidbN7wI-2Ra-FT zWEZ1-G0y{wmHx;@EEMnT6kWun|!E*Ck5hhWkvRs!8CXtFw zfs|&A+u-$c^JoKRGij=#c^dvmQ#)P)tiT(HipcYuJ{I`N^v|q~P4Qj<)g59{nyCyQ z#rG66fXYnat7ipDoPGIsS6T}Q0|E_+NBzSWnDgu#`FiUM(wn1Z4)qm5lGz=@^ z@|{TX054rc9W1jf2+iI_AVvx&x z*X|vQ;&y+yW^tnJ-^~$PW`_MRI#%L1TfelGCeY)aWqYuMye%@l)WCOI%fLJ7k-Al~ zCADYG{i$(XWN@#>GlF>nzB`T^QX}jNj1otxRuLs~#?QQFoHJr^^Ct?6VJlq-lY8r= z*;~n1$nrVjN0XS@KDwj5B=y@t)E=h`EC#9m?g;)1Z$;s=yx|Tn9y_<)%3LSRnR|YM z?O2bn;IM(?!eO%Hc3G3oXXgQR)^JAz+PC*12@ze*Se7?Wh=t4_=ymMUDC8Bh* z>qw{wU(4bSz=1xEc4IikejET7Gb>df>dI6R-G(uOIVd!+kh%GcoLKkn-(ToOp;9c< zK$BqvXfp8qcUvhyZ~uQUGBCBfNtWA&sOX>`PygS04BVg|!`%aIpEYUkEwX}M+e<1A z>6l38$k+`d4`KcmoHkcEq;&|kDOo(5h8S6jzVW)ak%hTa8Y!$$vF3Vw`d2bNd3|Gj zybc5Brbc{ewkGVnbGR-6{lb8}l5FdEG)KZ`e*9Vgd)lvTYi8tE$|u)RPdh2IW;&l3 zj{U%ijxne$&lGm+uSf!68Dhxhm2$m#JDux0nwXST9%PMndi;d^7XM=Wi85-qM3B4+ zLq5{m{3ox&f&1JgB!~l=V1c6cYu4kccA!$ zp#_`MczjuEs_?@4Y_pK0S?kiWNoLH=4*Gc`^E{(}5T0g%78 z*_EYgjmm~eFu-h#80ZyXne-ZeeWaEDQouIC38rE43DrU2&MMBQbN*U8jh7l{YfI0| zl+OVwN&bw2;Sm!6W>1S6iuAlgBY}7P>3o5{EvW1q81h}c-pE7VB~Y|bl#nYs*yy9A zv65!imY~%Tq7Ydzr_3=s=66AHDthIjR-x>C@^9Ffoq~!QVNA~`o|DSULIBm#>Uy=3DIj>e0riCH7)`%oY2}k#a70PS1bEq?bB72$z9Q@;r_<9{+TX_d zUjUFle~`P<5d{tTKj2Q;uiv~xKHz}VuZrZ&7DyOKGeoK9c-1D)^Ny} zz;6^V?)du81G!SIrvo{0zB;$@zYpZ7mon3q4iEWTpN-V3XlNuSHW4n@p2s1E=qdq|*^tHv+H_gf6t=2!W?E;yNJK2xBG>ryU@ZX$Ba(xKns5=1Ml`ra= zIskWNU7EzXip9%z1qu_&@fw4=0y(6vLDSn&ZCyAUYS}V+R=SDle6~z-h-dKYl60^i zq%BJ3(?ad2s^+qo6ur>*-bn1GhK}oS66ajD=&mn&5x~wRlQ^9r1rqr^gkEJGLvd** zF8>Yc5O@N0$O52_y}`^@SXalbtg9VYb3x%gVN%%{qZ)Sy>(9nIiBE7R5$nIQ6lyk##a~jI{cs78iH*rxykWSzo)NHenQkc<_T)2#5~De> zfPgW`F;m%SluozaG>a-k5a();6^jRNV6@6eyc`-0(MntXH2Xkug5j4d$}@PEwn{S? z0G+i+f{2fJ$`}3xMC+*cSPNmXqF#A_nH-kWkzQ(>^*|;3IgzHAVD)TkG0=ca{YpIq zEtDiq3pjzW`AW>NNOE)vt{kW(14kq6VNb$71K#&p6+T1EbBki92QM4M0$k#FK9nYB zR9KxMWg%wNj*wjPrmH|*j7AEuTaMB;I&$RuXQYZJ=}IA*kYP2;LKWL0L6!v31(gR~ z-RTnr38*se5OqU}Wu@y`%#Wtd1bDm~o@W~4UpEtI-8IXrT*UUwpc_`^2wXN4%7n&4UN??HZN92^NKJihuz zKM*w0(PyCs=-*&qD?p3kzob0<&Wr!O#L(SIG9@ijX$xChi)KZDJ`E}MHLp)j5C5GM zfmNNZ(4F(A$m$>JII^no9xb=>M^mG>ovYKa+fk{N-mwb9O9aHvLSr`0?mH=X@QB(I zH9G6wy=7hs$XbiX67T(pEp>WF2$6uVazx$d!5_JOX;?tjcPwJ3Z+@V)Q64S}&pssE z1Euro+i^An-Qu#K$x&Y{HPL)K*{~Vy==<_=RL|6pS{a1jzrQukUd8y2B-pfRA z77Hdgw-c{gHs?ViJOBD&0!p>??f(8e#v~d4xYdZvUH>wvNvO1;g@|C8ep$cHNwQM# zqnc5`|Hs-}#?-;4ZM#q?Qrz9$-QC??io3f*ad)R!afjl?-QC^Y-J$G7pLu5Ho&D}F znJ@b{Dm1CBO|sDg^4E8wOX- z9rHa&(;_IohR*u%M&Y8`wl<-!Kv>R#E_3c}Ytz`675e)@qXstNHyFY-Wn;f%;UNa}yHMwEYAdH@1dNlM zkt!1*^yktime#n?c&=63dRuur?LVH{r8NeZOG*^x3YJ;zuqdfiI57F>)+6vCHp)IA zZqI5*JcNHL3UZBx+SdIVagT|HlcCX5Q^3}GZ%|$w*ia8A?2FAw6B#U9CbgM5^VKy^ zgxBp+57FZx-+RC6wUsY{@Z{75-^b%=9(}!<;1rLTjWGpYiQXLY$wvhNP)dR89cqfYjWg*B@~II$T_b! z4unt)JEuNBLIxA)yx#q(9213+hs@wk&kT$AjRRDsZow!E>e`MrLfSJ0>sWIB-GRH1 z4(tbX!$X5@g^jsAQlRr{uL*?;4?a_v0kFAj-&8I&o-_0Sm;)~QqIhwMx2D6ej~BU< zJUmdeoM6Ce&bBydA!N|zv44>pBv7b=#7(5;B2L$Ed}!sPU`UMhePNBxBnZN>roaS( zC4IOsJ`c9Yai;%uC5=5IzYKekw;n`Yni5Rvn z-_KBa1;uz7S(+kpctzFkHThJoNJX^Ah`B<7obhGt^MREUk8^LO(Urj%cp}94%x4^? z6--mECb*mlEq112@%-e9nQ!!tVAWCMK74|QpY%CD+j)Szi9evylsb`2E&q7SUhYe> zvMsj{3Q~)NS!PNP*@~W6F7iSzUVGqH5pIPT<@P5hODTS4T+*AH3k0Scy$&X+WM$6N zC(<3!bulNEHxOC)Pt39K7TFif*XU}OK zMFX;VzbBMZeShFj-`do!sD4V8%J3KQg)d!on+9{(`gMld+rk8p0u>Y(rwF}DdX2i7 zw5MJ5%D!I@-Lw>4=&TYcAq4IAop8zFu8}04vDoi*B;ryELKr|20I0@1OhVE|8-&6tJG=RqH zxbnopf(4DdM-0>-kz*lvqE?Uh=Q(M$uli!q2r~8d(R?SO9VzowHCq8U2!orq$HuwF zI4h~`*+S!4i$tO#LSzqPw%7xhjR4XN1lT;N!KN~CEAs_0hn4{!W{Fw_8ym$wF!gj` z1Y#GVo&l#GJskH>l^s+_17>)bv(Y>P=;QDR2w{jGyQ{-K1jqyt$(?a>AYYvd1=~i^ z$Zf(Z&}?`AR!}_lUff$8k)T<9_-}+tu)Laq(Y2*1#;9BHu;tR!LW6}s1-~^Z>>a+3gx|)dC_;wYc2ry8Fj&JVfY6MhYVEwg9>b#ht$!<4?f5b5SD0S~C89 zP@-s?T`qE`Hh7m2WwdxpLKe=51pDADB842Uf!QQ|YOgBq8hxG6Wn8hUwNQRZC~C!z zgr$DPA;D;!7R8I%=ofO`R#tP=C_k+p(Rv;0dmN7PG>$=Qsuc#f&c0WR&RmCc=WBGx8Im>S{3DelV4R>GKo}OLz*I$Z|~i zIFoSz+?YN7t-~uQmMlhVgoXNR*XF5R6(=6c&XFa$HztweOB^5q@xKw5E~n?h`65(~ z%UAJr=@9Axd{^G2lLgx?TA(IQ(&lM%kGA}khK!nig)1!c?cpfHYZ&wPBx^-sA>n|< z{!tScn7Zd2yWUVOxJ+ujAEbt{Q_zhs8hSU}F>zjXhl=NIxyeGQ{LUB2J}alCY2Pn< z60I;i%Yux1Ld(exs`{h|oH4-+q@O4e&&Zz)CKxwezzD$l6*7A5tPpCCS@%vUqS6$K zt%`+yu1C$Ph0QQ=@`;>LEil!;AIu3faidc#BpSmv19Nu5QrqXO1}8)IiNMzy3DlVT z+air7eLOv&*GQB$oICqwTi|&Xj9!aQX)aSrV3U|JO8?Tf=``ryArvi}*kRnF(ynkY z46q};pXLz;r=0TkC#l4{An}AA`7&DISAjyQ`OQb9tS}YX2)Qhx|Gpcas^Nlt34uO?IxFK?_S0gOD4n5*(4HsE9 zNFr=IM6vSB^vnWLO?Tvl_glR{cgw-uF_u91YDw;@OBaX5@hlCpG9$`s+MS^B9jiQh z;l|P=uHjdmNxHdVaf473#xV*M;AvqB;mm!E)X6+={*WJhm9+hC*(YI6Ys@BwWks{l z{}@4$2N=&4Rs&OfqW>%UM;ebr7LWre;vfi226iA4vg^E>GW(+cMY|vbh1z2jnj+Qq zm{ZXFHcy#u;WGxAAaNWEH-Bh_`SCDt;S^%90I7UCPVzW@!7@ z+iLQH!wOB+ykWgZV*n+7T%khnOUuvmM(J^Z&(~>)ajjJgyr-Yt_)a#!?TY5kXZxeF zP98XYPpS){aGfk<;NHwv@5eu1mak)kbwCaH@bspA=j-w|3XBO5wB}pb2myVryKsJ0 zEsGcyuv|4KS_fLQ$5CH6dwPdLe7TDaBoYcM7X{{mh8I^;9-RT3qd@F}1hqM6^pbkkT}6`ptx*h6 z{`cMbli0^Yv-CRuBvrd`64q#IR^ovPkrG)>;g}z8#&$0l?oNWQfeB&{=W9g2MC;cp z8%8l=?tyzG_*55hYg~0fSKdxt^;$HdUX}FT<$-^#sIVrcs4NC~i&R2sh(gO9(LUl9 z)F27{Hq~(uhx~>>w>04c2+U>^zRwH%9!=R8TZ2_R^w#g_JaZyM;#1(h(&EuZ9C|c` zwHMEEM+jL2d|Jp#b?kkX>i!fQD^~}75UD3JV>&GS99x6(zW0IP^R&q3>Vyw?24AA* zJL<&x#O5mUUAJ3%_lUhatXNhFR36PsOY=;OfA;PLh3ijE(C*>6%xz*xmR)}nqnhUD zD|f`Bn|)&FyQi`klw*Z&sHITd1h|=;rTtC~B(1CbJhnV-Dm+nCjQm%`RolW09m#AV z%Oc2+2WhlZ0!-l!1vpvvp1z+dC^EGn^;LoBG0*+te_`rXo?r8NZC^#<`kLpj#j z7NP@xbYn6qH}^utRMK6>)!w|aG>*ebS%_5VKRL*bF(5SDUj#RCsPNfs#<69jiLeO3 z%gi@@Pyd-g8AWy-Az$u6EhggQ1D-mf)-A_-T_&pirKJPpUkl-n&3pKk%fdaNec}Ub z-bMcZX`?J0lP13m^bd>%-Yc1wh}@Q9dx9Kge4fjTrzY$Rp%0$|7NnqW!2FW`vP+EPX6m#<%}Cz zlig?Qspa}mry8(G0tX3smrW_l?~V3GMLjAltlRFDP9-lCz}Ub|V?m&O zXp&Ii>A{0CI; zkCH9Gru_x5X&3mv`eLojZ7l!&C|6DEBRJ@@QAH0{Evp$11Nw)Mof7sz8Ins#&-fQ* z2zx~$J^GX3_E5EV!UYWoff%F$ zLLh%hb%6iIoGSjoobvH<;0umXk>X`T(b7$5WLY|xIA>}&d_kJTXF?~=!hOPqpIjc`|oPEF&hLE&jHCeybm$0qyZ z487DJTyGU)lK?(8RXl)?4YWYKff&Vt0pMeEBhQSTl8yW2o5L9<(b)|>MP6cuDF<<$ z3nL7n#0}^ER2=hN^#9;vI{^6Dq=|kRk!bk}-XX#YV*lV{69V|yV1lXP#@ezWPBG8k zK`a>mzH}b}&PKiW<@V72dWVCcv#%pkF!wnb49SbqTxuO65>z_YoX!W-c$2WJ4ki19 zX}0li#?Wt|vjj`wKa5lGE1y@p*k333)B@&MebFo-kTM&bWe4jn4qpEA)u#?a0HZ>V zYXqzmfN=`)55|z}2V*GQJc67Jtx8btgO6PpeOUDm#%X2cAI52|%SPS^fHCwPz!>_& zIQ=JMX#O9Jp`-b>zZs_wG~0L)uH;3HZEX=%Ky~NLa~~0qfkqh~W0~9(SKL%jF7Im) zcONGP4HY54F~-l@sX9n&buaAd?RlwzOKffiR1Bua$p!9dYdoT}v*W>{hxnDR`XDex zSmSy7JS&_96e=R{^rHV!lt z>HR37uRm-MPd3DkTOwvWS+Q~++N^gr-d$)R0{pU}4cMObKIt8PLlRM*$`wl|%y3LA z<6sEtuA*>}z(=B`MlCCS&1=J5b|q*T=f=+l#0T8~84yq?tqK>ps)~AT71LJ%7mNvc zE!zW3L+kh92TY}+9#=@HS-SV(doWa-l;|5mUT8kh~PTZ`BJ z+RUiX46tV~#8$Xmp|dJNZ+a!}i?cKN?WzIE1K6rI71gJ!t7i3Pfxq|e>8UwK&)Tnd zi+r|#y}S9i4Wk36HTk^<9Yjr@+1K+Ly-Yt9&Ov3^qp!3~3J3h>P%E}7CZ*I#kr6LS zD|p0NHnGa&6`7@u*gu;t-O5?Td!_}he$27Wl~!tA#Bd`3w1?UdUWz-Xmp?2G$Oo(C zmq@;pO)ub6PSS2_8}N|JpkLL7>p^k5rus6p80pwaCqe73GHh~%+~?w&46f6<^T(b* z7Djy*nhYV4{9u^wYiOO1V(dBvLiT|cACMb2d*P93Cgm^#;)5z=hcjJ2P<_HB8Ajs4 zCWQU>5{x=E7x*Vl`YjY}^mxB1_HL=2aK7SBfbQi^>GYK@HC985{N&WFPo9H{8Q%2eT$hjsn2uojWIN z;?>2(;_Re%l;+GV7_fOK`&VK9*u2j@ydJaz>PIi2e*9OM?0@bz{+A4)+P_H_G|kOb z*R8Bc7Qv+d_;?8Z!Kt$WaO%!8@XTiv7E}NDcw8^IbUhnkH}If4yx0i=r0l25tEcoG zkdGXp(>uNlTu8|7%}0(fe`Se8=pT-S@3?JwfvEGUp5~m{6I?ehI0a-!m&9#$ti(>Z!lKPa@o8vW^z!}0|lTXp?NZ!D~S`&xBL=N)1*BjpA(Jr z7m846t$;2}KhJAx13!XWPha>y#NWIj&Ge8lkWa@NM&DVdbg4N#f60$A7 zdX)OKo0C;p#AgqdUo8}=+}=s@!O156;AAHe{|`7hCY}%V+w(nQg;#ih_G7F7jMoDmYhP0MMongp?KI zA81n~3Crt2dIWmWNt*+LMBoolc7`R(tm_w7&j*)>sdFDV04Q5{#sTy@?74Gu=1be` zS8x*whm}E>e2&PY&8QiVb7!&vJbA95`fxZtjp4(xpoW$&M?5-Y-exUvij*<#F8bs!Kr0^Z5Z+RuuXGq4zMh2QUTR-R5zFAF54_NloXZQ-@dkk*_E}) z`4H}#&XAQ^kYl7k0=zt-|3<0{_(Q7Oc&3nZS{o4eZs7#5O@;sR^7ObPW-ISN`VcWd zrO|wDkx}M=U&t$OqL4%)0f$th@-c|)?-t8MG(-!t1C{N#VSmRz({uhZLa zl}aIioWH5==UuMjWh6kKEBP5*hbi|t5+kdg?ZeC?ma^%shXY`VoVKNHyIVHOgmvIj zWO98wt3(`ui%VJhhh?FMQu}xn+IyjB=VIV@P*2Og40p@^<`F32!3Yk)Pq}#K`KX$+ zIY)$9;Bh&P{>ZUF& z%w2Mn5<&7S4fc^85nneIq%xRPU1>IN)k z_$S#J=L9_BpK5ePD-ztn3kQMfZ(3EyI7JEOZ;!p^&{XN_Ja6kA6Kci=JS*0=`HBe} zw7zXVWRb+P7fE5~6Fg+ut*yK<5mwjt#YMoI{*?1!ZtjAjY82MNlJ2Mhw~^girt5%& zBApg+BnH$6DeadQ%mb14Y!piz+T32C%{`+`ORslJ{C_w*{{XLJ!WRCMV!H9i z)&`g_5)5B_9@;;goq+k`5inoGuL%CX<_q4B`C{X*`NHzw=L;Ka_gLbHK0+OCzs$<05&BrSnbPVh)^ z5^26$?FR-;DD;RCI|(3whkS0il#>{=BjCY_ z&?(CV2zY+{CE)QN0|7sFqg$re1f^ z{6)QP6njTw z+cvcL@jU=eg7`O_gnUQ#FE|O~Kj9=KrjR~`fQ2}_{?Xo#x2Wd9CAcYG4e>Zn(sr@D3`5yzuUl7xe0Yg2u z_WuYm1%D%3G&|AxTfp;zdKJ^h^_N89KOm<4Q#V|2n;#Md{?V9!K}sLnTZBfNV(u#=(GB zM+aAwI8;)US~Jp4WJ;R@bH;H_P=DuD-1wTYUi&x1^rh(s26VR(e9II#5|Ge)I(cqr zzh@n7_rD;fDSsfQ)c}a;@=1<2TFuEQ*KWeV^d=lYz%$;hTDCUxA>cWV8kmT(^F0RQoV2xJ)ACG3_S$1;|pM z{G-nTq>^IM6$Vg7+*&+YA4Z-=fRSfFiTOoO9+J->ivDxL@={oYHKShC6}}nIHx>l; zZ}9_L?`2V8t`7bg@-h>3XKylQLNav+)c#3ab_>};@~Y@#Tn;P#62 zKSvDE5!viZKwRsc76^#p=-fKp=ckIa^qW4b7^&qLK>yeze=KhRKo zXEO6lf1A;9VOnomgIrb+k9sczc{yqY`(cJS`nzy<9_E9rL|^bTiTtp2{a&rfefWxBLsbF4!ul6lmd0@zcN^zGlu z5Uji19Zb+8`f}S28+LB{e|gxhLQ+dX9Pl~o#91+o*IiA?Q?{lDE3htqGUSNP%Qw~q zz)h7l6GPiMUpb)miO!s{?L&Y0)JyXdWqDwkW1s&*V*6pLPZ7RX zL!n*Vm;5PoRpRjazGlUyxG?%g63Doh@cmocV=YXGwEnxC0r1>DXHB~xa;CUs7hNI9 zgmA&Zr;&pC@N4lBUw8p1X^oW;#;APw=(sy|`{zMXmh;f$lP0-YJfx z3i8;3b@7+m1L$ev7p20ekl^QO=~$XPXl{m2H7rNYoy)iDL`(Ejc9Ck*HaKf>B7I40BwE{k0K6s6B)c~ zEHFDxhp&kXE%TBnfij-?cVLM?&nD?~_&LW9T>ltBlNN9#5|Kpnf{aunW)88?Dmqs52Dv-3&#Y?M?#fKOqK8AumP_e&Ytw9EBAj;2`KN)r4y2fD|V z_#6>gSFB$*UTI!FFrg@@N^E>!A$DHIw?_q;;_$$`G-an!nKTX=zybV5pR18Dp?WM_ zpQn_T_q0yjtBB{`41IvwK0ztXY5Zw>lbL>w`eOq3 z-bgJuzym5imtp)AwAz!#kD@+q(eNtc1nhMx^D9U)`MKtTuM=o9(k{OiNVG)PC9Bk=7 z&1i9U2wrFnq-nqJ75-R6*=+bh!^$(rd)*!&*h?o^w1@Evf)JHXoHguf0Y)|s@PN9T zT4GPAcIvG2O+n}+K>0a6aZZ_j+YHk%-!4n0uX)7OT)EKXWuchz5xBlymKD^rRrQ<< zn+>H&OFj2@vFfR*dV?PAc4@_+{5rT#IFs4j3w9uWc5SR_zKRBMXVIcd4GZCg$~!ml z<5z*QUOIE$^Z{VYG&0P%>@{{{LLC#1{M~+gB-NE%$>-cU<<@R72Fkg}mf><0!O=pc z@3cYeV`}SYL!)yP2j-iEr=Q1dc0+&!lVM;uD~X4_otlIRmG7k1Ra;C&;t*Riq>+DC zRs~ct>aeFphUkpyy%L7D+5xg#&`<8Do{gQgC&V!OXG0@cKD^9ERXK6UC$4_1pR0)( zF9k6~vsBx<<9w1tVI&@6vug!-z|G9Wn6(rw#W=0d8Fs@#iYS5;P zDW&uYc82LVLlb9(t?M}ZxnbtS>Dg!CR)6va!*C5(g*8dhR{j{#OIy45T)+sJcJ`4q zrRs^6TuA|MS`c24hV0Ex!YF~81G-&d1?s5JTWY52)ObDGOWE-i~(+X3E-2OKKJ^D^_}om~i&Pl)DZBTf<2Xajh= zSW6~vZF2zaWV@Ij&->lu`sqJ`Jm!1i??jOSwW(~n=^Il?5fQR4y2t{1>{$!*~x|MtW7o_n8NF5Da5JF9a6 zE4%BKQ;38a+K=Un56}LV{{;uVopg*x!wSe3Z%2OX%S_yx)^=|T*DT~$tF*6qE7|6! z3oX74%wN2CrjbB&wSy~V!=T?WzX-Z#(do?E+aCbm2)cA*g+jrrL0l_}Vw16ruey;t z2yp`wsWVnOk@#dFO0tjH4Ecj;YdeA>D0C6KF^|WrbKOONP*YCW7Mh9hB*`*sF!q_N zZ>AuOUO?=Ab)L%L=j>xZ$blr1Q}Tt@)6yT*fv`wN|^ z&erOBtL$9UU~Lom<0uk$?@n`&=x zm)c}1=BorIDv+~Ynwk0ik6)fl=di%yhD){SHa=0CiQ1_48Teqzsg!)NsZ%}*j&UV6 z?a?5Y`ZA#ItiM|i9BelWF9O`(;4Q4cfR1@!{?t{z25-zq70z*;IPBvp(%5vsTXE4)MC5m#cUjd`_uZ#ga1Fq+KWg^*RDp*ycUv$~C{jN?qWF~f|r^O5tW%v?Zbm>16nb{10Z)|_A-80@xG>9-+z!7=WJiuRG&~=gPx647dx>esb!yTC7l%##jZ}7*zh%pnZ6FD2kUI!K ziISi*_0mAl=b#2nwIB7&WdB>b?&B$8Jmf~-6wv3Zk^lj*|6la^wuY8}I{YzBjf5F` zXn?mMwUa+(iMcIit$}HkJ_BR~NRCT3m)TEyQC3R-@nTTyyVKHi&B)#CV=VPaf|17g z?r|HMtK51=tDIn5@9thYmmJ>4pUcP=z-8q65YP4b)KG0v{+d-BlBg2yU($kyY^@Jz z0pK#SNt-og&7^;Se2D6xc6TnhcYg+zWw?;e%hJU-7xguxmm)i>r;rCXhNb>H)a*bu zC@6_TB}{g>8AJWKNr|uWB3T*s$7$p&;-!Y!wjo`9WI$>=hr3=3^#M2O#VH%$G*Tm8 z38Be8b7JRZ#$F_08nkd8TTxHhsGRje=iWW&tvFwyc8y1>I#e&sRC*R7IgYNo1TJC_ zM2iJhA~DzB%*rvQpWd2^mJpF)bbD_nMT}TS^oe4kHDEaz;bHbhX(!A$+H5~qOg6f2Ri+u=Q`oAn zVYh$!6V>Zg-sdo{jKsZP{VFS@KBCjo__f4ZKnVK1kg|emNT7Ue>^qxCt|Ft;YGKw3 zkK{$U5P>8-3WWUJp@vyXbdm>3WyU2gvfjFlB%w$I1qyhP#V~qK0cN=2MALY?*)e;> z*tc_t93#9xEGOB&7pZap4k8U9VvFZag>pX*B6Ab2`V_YWqSt@Ti@j^L9TkWqOMB>xBgy~2$7^VL@O&?2D36^8Ys zkf*Wb_3;P_ENqkxC7D%rcG8X5eXXx#No>T-lGc${^P~J_-;kpZ?b9oJi122OoEV3% zeCY_&lk6iC^Hfq8FIeiayManQCypA&IELo}@d__hjw{fTVTfw7w0%_Zl4jkpAyaDV z$(AMV`)Jwe(}g0V?GsHXu(f*2J=XV6V+-4txT4u4I8ZcCzG^d0d|rybr0=QX02BK#7u-%!tC`-B=1$Zpw5fWym6_30 z1XIf}&LW7algeo;{H${r-jAr0eZ*9=#Lgg~?v-s8Gh<+Bj``VrHXo1Tv-hbrnR~Dt?YZq|%fk{O`@2ujq-g#ii!u{x<1V1C^>|Bz|_eQ{C1L zT)K`8Q?ZK2E@aXbyiN%GERM_Rr9z-=221cokRF9Xbm>^tHGEdk1oa!b|C%So=Ow7% zwNoEFXo0FdxZo@)fsO2+#bUMn`T02srOkz`QWL-bycFpw7JS8MT?^zEwJ)B z>hHFeYXCh&@eS8?jt-R=Dl`<4I|1dp6eYq9zNT+S$^hX!i68f-6dY|t>8t7FMFP-Q zu;;bYM*eT4X)i@!@{z1p8^~wVs+-0llyw+^>cz5VlnhC-BXdnw^Bh=X3;{js-rIM$ zY|SHjt?6$rkxK6yFAs17)yOAsT#siha+B^@z`Ty|P1vNm!1K{?_YRNQ0=SH(F8;t> zRR@PjM~BKvVf1tx#0z9#vJr-FvhbUIJ7$W#$9o>ZBt8Smc{n9xV#zs~H;PL&vK3$E zit;9nYSZ^Dt$_#83RI<(;j9V~ZPtxSe;0_ca?Fi7POrDyT9*|G*Nt7voF36*e4 zE7Z4nS zZQmHh2cI_Jbw`&AL33ZLA&MkCK?$8WF66pS}254>E?J&dq;J5`0;Yh^`Q!S)u}`hzK^zq=L3~ZjLf^<#_XDoTwRAcAYfqj3bNQWI^i}q!1Jw1%paR zpy8ZWWKvlcfb<90qTAR-83Q?gnik1pT;?_&X3UEfd{!3CPR;k7%lRBGgd(JeJeJ&W zNSK$uykTD4bK9_x&VfQUw4ZF|4BKUvmngc@z7+g^NWu5z-oXC~m%)s{?17C!w1^yD zFh}>!&ix7OU*F_M8%%KSQ|$yu3>D!2mu;}Mk&PoD#%k;6^j90K@z)hiww(Sae^~Ju zwzGNFPyJFKM>K*EO+y7RyFq7lRG}B+PjRF;I20@Jx7oAzYfoN$8$I`z$6ICK2@h3x z@lBzE*Uw{b2Xc7uBQ6<@XW-F}>>R`wS<*V(WMduy(&$m{`2NI&IXm25<_MOw!p#@# zBYQRNRtre1j-+DaVTp5zqx)4fk{Ql&Zu5`B@-l9SK@51-2s7BwVBfW-KHXg+0hnad z%a<%rs6;0Mh)|(HJQ@Xh2x^U@$-YQAX>h9?#@M}wW4m!{jTzR0>r1xhOK|bz1%#== z#vF2Z(O{qDq>0cqm_q#&;(j8o={wYP`!FkZtXpO8tAqZOMk1Aj9_d87i35-5{H(=t z9*ZvuGBvqR3!^`)tSF2xh#oRhRP`XS+xI%dz2%P$mE7cy?FR>KfEFB`EA&hs+7ZhE zf@jTN)Ozk-F|fWgf5d_*|Vul zR7f=LQq+`IAGS6m@5bi(EL$N|7Z9zAF&OtF*n#{K`Hq6X#KfCe#tv1Wc9nZry2vk~ z`(tR=*HY4l-Z*X0zNjWwJL8rkcKQ8roVO-r5F2scA{JJoR}&Doam?dxx{@OmCLMGh=^pLf<%Tsg{FdM;3G7D$A4UaL4w6is|-zhrmQ}T$KC?~ z$$sXONrHw#=?^L$gI!q}u~5&+mK+>4fZCJivmV0{SpcK2;ir!E@gChzCxA!<24sCF zG#)Z_g24ozZ3v+le!y5r>Sb7M@J8p6?%;a|bG$R^c<2}^cYtLhB!T^QS(sTC(B{#koDp9G${RY+qcreAVl`6A{P0Dfw zRf(0D(mk8m(fY#ol|Kv5I30N%ehR;Vp+>_Hq~bR@_S6pR*AQ@AasxmY%+O`(H+Ib~ zdOejZWep%9{ON)lZ&yfT97HamAa(oBJq(uUDJ{2OZLf+ZIblE;3ark;ToS!%nP5lv z;d2d72PB}uQ5kA&v@&>#s!dUqS!Ze0v!iBR!)BzKQ#X$-*_wvmOL65t3w%}O4CNy9 z0dphgVEbpS-5S3F9k$2e&C6P}gAVoxvOdJt1XO z+o3hr_go(~H=!PyUKQ?X72lu_)P75Xu^iPhOu8~^pJ75R1^txky?n;Pnb|VqQZ;ko zqPKi@i#2Jr5!Byl*`iaH=S=x4i*Uj5l7VCJl(s$m3PaNeG3kIzA{e4?^VPBj=2cawW_Bqw&a9PSTxd=os8&afuUg^C7zj81+#M8L$6sxm>*{UZj5kYDZ0fc! zTXAB`P~F`J0as=%lLg)xy{_rJvh&9-9u+#-_gFfO96V?a8ZCDcuf{EERJ0s{5CuzA zGCDM8*V5nVnp}EO$nTW|e z@jBmn(}FL3rm#Ki^)aEaD-Qj+%>}AaQ$nat`rAP!_vGF@^_Q-^Iwx&hd@os|_zMR^ zXy*VS84JmHn$qy`rvoNqKAJJ{r1chIaE(&&r=Tfmj6&K^*XPLUfm#Hj^$UF)v^l5! z^#T_*JDZ~1dq;l3>fvKT8S@SF^3@j=S4TRlG=v)2i#`;G#8wu}c&0T9%xy|_q>E?^ zxi2r41%YaayU6jfYqA-N@Ng1}Cr;dH++=>-Dtf@j_K>GM2e`j877~cK@ir+Ceg!W; zOlPxLwJ7tW`BiAXYW$Swc~crS63_~kzCW(H?k?sL@Kap9h+QJN)CEnmxH8388rOSA z{!!j>q(st28#yWEj70G!Aw{A{d4*IszG2g!YNclIO9-(EB6x0lqW|Y$$ou@5Y~HV& zr67CmWJRMuW&?zQDvYd)Z%`|=ArTRssx-f$7v~4^zlARrWN_FfF-)Y~Z6O+*oDhfZ z&HWG;r*+|)cifL8I~>(%DvYD8)YToOOi4^wdOqJUmB_!qOQ4^9u;)cJc*pE@xSiIDW9G5Pbu&OUWe`ZSh(pHFf3d&9N{9ty-SH6zx!V#3*0MiqwK_ z6R=NQ>4HJj$OK(@|F4;T&sKLVrI>5C0Z1|v%rSW3TA7ml3Zetaoiy%&Q0JIEa<&Ow zcZWAg_#wI9sewxR5C68%`&hOX*Pd6c0eZoHz{2&v>Iwg?ld*90p8T7Z1z58#Fj`5~ z-~eb@iJODhn&Q(4E#AM~L(V3X4+-I?2V&0cl?rUwDy1|>*t4n%N+-@2OH{??-eD~> zUjmNt7S<=6(>4eZJ#x@Hl}r*~+@uc6p%@N@O)QE|th45hE=?=#<8Wd#L~oJUp#vEa zz-VMpc!)QRt}tHLD-#l{2Q^)_VV59(A{lCxpAuMtcG27M^QgZpx0UM}mQfx8ruIqx3DZHu}ARp%*5ove{DmeX-#T)=UYgG|zet{wly=~NKMe>%ncC_;!7!z6; zRb2}xARt(Py^H6+X`=u7!fc(L?DP#SjsMaAX?fbNu)@E0Wc$wq&tX`c=xfDrLtBmE zb~RL*DOvTlGlRT}b#Z*Uh=fk}aTfcJuy|hP1SM}}N z8_oAC_duPFm;Iu$6!DXj=c=BRW*>L&FrSyL=Y#B64*E&w;2rK=eZ(E{g%0lm0_%Qv zkJ6K}Ig6i|u<=%$bP@>qCQeEAWxA8=w^mZxO^S5^H{K;}vnlJYXC0FG}^&!*1JK^0&JU{!DGi zpnuRj3N5IB{*Avj^0OYq=>bUm0p_r}Q_h|jPPJD*`eApMQBVPX05uJnM(VZ4uxD%U zH5J4zM$_c_d%fP0$0hFq=|QvP5vlls{dlMuu)9!miEU&Gx8dmzN>ggMcN01JCi!54 z=xo|I@}VK7!1lwbK(hhJ@ZP5xnX97DGm~`gqmDIa8onxd=I9cCTKMJ)oL z!7fDOOM9jepDf7P6fjO?{+UWBfHEQ<&IGGUi`cFPs}eVPn@^}@nWC``UE*>l;}AhB zKdO3Y{j@&ADzOZu+-gSm348Cf&oSwYF4@mv1=~;`}WZxdpI7Xg1B7PWV^h=D6Gb<-HS2(<3M4Kz* zH0LziwWXJQ1C^_~yvDTH@XQ){qyzsvSFDHM&&|&}*&ZO^OGi_Lf@6o$&#aN-mE1Xl z%uOsLfNpk@J5{1ts^>@yZh^kw!EQ$Tmwx-vO@JziB)pX zjt$3h1`qXyV|-o^8_n#R-y}$MEZ>@Fq z?t^(&RdZf7XI(WOjC){`rmG`kyb1kQBvGjd%9@g;XZEsKbRDu+3V08?H>#0tL2cML_S(+xFBagGN^L}$2wysgeriEk!lbUWXhk@LJ2kV4 z%F4%4^PyuJ`DX7u(i9dgN|fpT1utLTL+&0h5-XCB&NL)|Qh6Gw8AmogTTbErv* z!LU*v#$R{MK_nnf=Yu2(z0kdfH*`|HUdvE+ER6(Or!qJ7Tpbt6$b-QyqNlbB9U@3Y zr){D(3ymW|Z7UW^^z)#6FVIo2P38KaMX@E70wztgvw@DZUwG4G=VJsWv*SW<4+xR+C-ZG z*+lCB&h*_bslPf0pdRW|>u2DaX@MFDYE#+O_t;FaUBN|LR;4~Sd2(qQSlb$GIj6rs z--d)AX*uSw(Tfp{8Njx*f{EoaXtj*};g!O-7$O}=a&GkDGC820D~Fzwo)X??%XyWi zA+pPk%W{J-VA>zE@p`!)m`K}_$dTTSb7NOxI_a2poDgs6iM}y_uQ!0m#tz9CW1QY+ zpV_VLnGvSkYfx2@0`W-~&8x|7Cdz{ifjfx@a+aR7AAfFWWQhmFM=xd0LUIVL5-5Yb6NN=Cc?P1XQAy#6m>Vp^x zIzY~7Xx?;X^bWXc3|>erh87rJ$hva`h$FHn^}=|17pa}nKlZI}E{8-cLq^_2e*m4$ zZk)UD7FyR|EYKk+f8GYfYUWdDEe`FDH4cg=LC?oirD$Lx?MPM7&LeXyB70+z?!NWT zk11mluVF`4LB8qnf%+~8QEUCMtUC74s4BXmR--l$C?DbhsY#A3{-a$`tcHmCoO~KV zqT6<_<|BhaPUYgd=h-&9Nz(57(q_szyp~#@TWT6%_DwVLRbp>kL78lp)U~HSgjANL zL+B|b2F#bCS!!lb@=@aY_s@Xa?0fXmQs+aq>ThSL``OuZoDu!oQL{YRoe3Sy8 z5fT18NRq;Ja5ZT(ev309eKa5+-so1LJ41T%;f6)B<}Q3!1}7D;LjvC4@bv4(U3PdP8+)#F8b3XK6nMUBiw`}mjTE=KG)IfonxdBM&d!=?;LQ8o zfy~h9MJ@8a^de6finmIIn+C4U5U1E*=|wh50t`O%Y#Dsz)gVPiu^_4=;sqZvK+yAC z?Q#T7h@lqK4&BqZPNq7fi2vxf^i*_U+D~;wps3$;;Yo=A%!a zFuVd|b0-fn#^+SB&nwNse;qpEyuh&04m^(u2D!2a)WPpv-f%*ymXh;OEL4YLwd4rA zoar3IiF>w2r~-q*;eD@_9=fe&80XzA?8wqt4c&El#sQ7I{~!3?T zIi$W3I(pHN{|i3-@}^^yntP6ZcvqoSaN1pR(#Ej}ZiM1bel?EI4{L@xYyxA2+OE^~ z0&4J5jD{+7s9<~Uh7fAsux1+Q^|!iZxSqh~;q`Y!xRA3m93v)T|M9h|nf4h?4s6_w z&_2NFVOV1NyfuJZU3%I*JdvLr;*I&#=#7-~GTF!BK26ej+Cm86s%f_)!=u_)l!UHO zr{|m;D@jKa+Bg<-h2lAWfR6C1e2QO5LtYZ((c26|NPnv^~7;l0@cWE!!BEu&KG0*Uzim zv5i{0V81OiV+wye9_s?Mr*MgKrkn_AuI`tD(+1>J)^dpt3#0JdyM8nju-vczLKU3r zmc7mZDxM+Gf5@)=ZxIh@hbK;0VACTAKYd2@t!3o7CPTg;8D=POGf1y6ZW`P9ZxE7nBApSzYyGyC|$u900WA8`@#3NBCv^|REkR#C7XWzfY+P1_0` zfsc(Wp()wKKhzdUAo4eU>Lkta)v4i)wVqr)(TyXfAhS98R}7&~x_0I3;stpE74sha zbjcMh!R->RUD!KEg<&5!P94Ke*|sMlk7g`PaVkx??uvP3^$>Mh)N!w^4?*J+y>vGm zSwujB-uSZO>hya1x98+>dFZTYU(zE_s>3weN_LUFp!^9h} zC0HE}^`=~qsBM5rM_A_qM-*8#Hx!8{;n=SF?!+fiv)2=mxNPKsQFm|Ny1`$I;nJ4w zXubRR+^;OjnvI(hw7=dQWKK91orc_w>~7N0*wD=8_H1{02Tt0+ZxykP1LF=N!oePt zx?;|kWRZ=8)T>dqNAk1EkPT0H9?0A^Vn@=BJ!%-b1Gm2Pdqxe2j5vYeSBBS*jf;N6P0a_j8>0w&sP1|5q6y-2QPu?Jk{qN;ogfTo^^-W zN0{g3A+pAWFO?chgd&uOk9~&GN5IKQ@&orKE_z_-aEU%+j=V#f?q!gz{m5K~&11$Z zr6H_NQSc9F1YHahfs+lmXmOrEW`|X2{V7^b1Le*iiM@490NAv(iuSObL`lf&S|uTO#?K--iu`!Z8FDbsJqngjq;_)N6${gR#GWFE|So6;1R^ zte-_6(MduX@(F(G5gp4!3BzaBj|K)DR!2A4`#sRiq2!TCU52i>f|`%(Pyq8Ko{;_9 zjV*PW)C+w>_U|hprvMSkP_g-EqBL;0K=GpFE$9%BQ7`;6XKNNkC9!aoIVku-aR>s9 z9#3nIu0+K+T8;Ch8LkwI1D}-(I2qWvsx*vVKpY7zY+7yf4rKWc1s5lGuzCL{bwvM} zZ%dK6N*^fr=nC>T`5Y4HYC`dT5yj+v6c9gu!1j>aR`99078WQLj!oJ}EVjSWcMF=5 z8$dg0r*N)Uh;s@E^K;(Wr_~pNEL{Rwotal+R5ALN5J1k8#YgLUZ`|ICwNFnIygs2O zYz%7dF0iw)1!(&vFHlrbrISK5w^`p&SYng(XbNw#bMb$DoAPzeR$8VT;4cD{c*9^# zXQKO%XstFJ>U`-JFd`w0tNZtSvXZR&4R4-GWSt>%9HCE;j@x2S zR8{GiTVyRkw}m1NJF5)?M*^km-yxabdS&}OmrZr)`2CD=?_iuQut4wW7jbMBM?IH% za?ex`!F5Y$C$<^ChgMDC;7HnF`G+X{=^K5D_AsK?`x z)}n5zrUx*oXZ5s&mXm)uid+u zA26_1d7KAN_#LPqZQ9bZIA}&OxRcI4+VOQJ-MKcXC(vvk+Jjjd*kqv+8T^Gbn=Q}P&Mr9dkjPox&qR`>r zYreCO+MWXSd|l`<&!|W&d@nZ9c@r$35vz^O&X*PS#!Cr0Sf6YTNtq%a>NfVpO+uoj z25#h!wp-=NiniTiwaW6>C<7()OrX zG`Yij!Dt|!_aSuPTm5FYX{=Q!oKz*R-RAKnrmomwbb;UrbE0a4i-qm)R^H~fMaOW8 z7~Mf;>jkGS#1gtJX7uz`%+BA23XLaJ%{v0rHQA}=Chfdi9Y>HdPgS;$;n%R6{=(Wj zq#)x`^RA*7B;hPw&^hd6H%*g?w@}HM-990 zPxAsc8GB~9J8%jSRt@T6`w9@P;o!)SFms>`D1uIez;Bn|1g(@=MP%rFyK#UUk>C%-Z<*oi--?hC z-b!{s&#wOGh-Z9GQcS}2v!{st?773{_&1r1_<4}~C__{(;=W-*MQFetw^h4}Tux=i z3SoslDmSh48QQzHCOtTxmwmRwhdwGIWs5cI2|SW8>~Re%xT zQ^aa&f@rUzl)ksjC@PFK`p9@JhnEgjyZvCxTx0EjA)MhVcFMh8Y{cB7e_rqWya3h( zyy<3Xr(Or!jd{%_^lF~A+SY{3pGXb<%3)J1Dvtqx*0F8TnEhRHjBmjr$#-&mh&|9!O6gK5L)wOcidV{ks_`4pbb>u( zqeyq|7ssF4@JQFC!tFU#amHgv?O|M7kVy3y$sP!6zJ&R>sO9#;<1_+v+F(dhZNtzG zy*X&a+7sH8$v1wD8L=!i$F<`;!Nye|;)3y7)L%6OKpkCF;0mC9Rt?k5VrW0h6U+z+ zN4%5^G3E^>nAQ}!F{SoPCx?Uc^Im=bcOT{N6bJC*4=@7MGtq#R`G2&Q{Xg~0zjW%~ z)RQqAEP5EA*^VBAU7bJyXo_(1R}y}@ykB`D+4dZg>oeC6^MaRfgxX^eHrHJ66CAb; z-Dgcv2UruXnxVC&#|r=g`QGHh-NMn~J5$y*2(PcEZf$Owfg_`2+@NO(j6_VrQUS4r z%F}Q24xLay6|;D2(TzK=#sNYg+B;04AgLlpg+gBa?Ub8)&Er;3(E@IX(eDT7Y0z#G zilt(?K=joVYt9cW+p9>NROkc}M+<8Dqns&x@`%t1*uvC5epegz&11yGG)v7S@MpoZ zkd%4l4ItZzyeyi_6V@C$8hI#%OGitVQ@}|aEYul9MOtB>*FJjIHQB@g76=jOM32Mm zZ*iJNqwq8aEbe%%r-Yr@3)T3}c2?yZJTc&1b@G$>OPya34-Ok9_3_Hbg6VC3Vi9j$ z;+!{n+Gsa0{ZJ=_{l&+Ps2!SWNQdG+}ur#ZD{|Fjhvlm&77>QXdRs#oDH4+ z=gv7e0N}$mCbs{DUD&4!bDmGA!bbo=dDPs)OIrwcksT5(4}R7MUUu`nUuRtwNsGEm zdzE2txE_0cT-9`84YZaP%3kO2*-QX$clo}b4N=sQi}P%9ODF7^LE`1c>huKIc!3g4 z6(g#Uk3|x@--UdesIHDlG^$q{jO?hNUodh?q0X+VF|6Sw+Srd`%&hOznc@9K4Q>9) zIp~DPZ7&O*-L*lFEuE$$8b_*Uhiz*w&hprW3rbG^FDybQ;4X0i%GdMZnSxK z?)Zg#tOviVLZ*0HRYc4l#!T{2aWKC>iP1;F3NQ1=rDGa@#XKkIu!qA=@{YNyp5%ZP zDh>?$Bl~j~09_cTQ(21uF!A|~go-FV4n$D+OZX@y`z4q~>)Pn}go0S0AJWmr^}r8M z7iD++$SuZh^Y&37k9toC|1$B*-6(%I&BUbbsB%s8Z-dpFX0v<>2D18n$BrvD~k{UFBM zCd@=NQnt1$vl)H;2gwyDh=ka>bhRFhO+Qdo<~(=>N2inM(#@mIq##4E<}cI@Cuoo} zf(JMs9%LLwt4vOCsF{Rz<;RQwJ1qZdO<~MQY+Sk{EI}=9CCLN-KJav=cW8C(D#0R_ z3)^0B-@pf7i)`9!s}-r!bPW{f$g8YXV3%h0nAGe18oQsZ=kD8}Wx~SR4sQ{SUo<;& zdqwBE?OID^iIw=n9S_9ObRU!#S8&*-Cu9eNJi0@`>TlTn1)r)Qcxnh$NCFh}AB`WL)tht%7(aXvN7is6r zNQDaC(I()|Ms@gl*pei-LHr+QGzSG)6ICo_mt{TSkF`XPQ$we)xv`_K)7`fpJF%cP zq&I^67vQ)N+`=C}z7d~BAE-t51jnUo_>G}@OPBKzN(t#hl~&w+cyLzK3L0d4>U!OD zQvVVdQ;5$k8@E_-zLc7Pr8{VCm~xY;b%v{bj~+Kq>z#cc0HOu-`8JTIjwa6%~CN72^HI4`i?LtGS@PS zCgnNBl{IHZ{oQuKzoJb-HJYzF{KarB}EiJ#+75{^vwj}JZkY}xI$m`<(9^V+X31BKyj)bei=u&N}bFmC!QWYo9pn=rJ|KGkAv#p&@U6da%5{_`(@ zTa9yB7T~FpC;NYDMmichxR@In|I1e8o;Xj3^0gz2Sb4B-Mp3M_1!l7Nh*^s>WQlD` zX01^6hXJR{Vr+Iu&N zm4#>}W13~@*pYbc%g{+u;C141&w6Imi;r=BJmP%lV3Vf3$;d6=KY#Yp7!hL6`?HiF z8mEm^DP1#ltMT#pEmmeOw+~L1-V>X264O0F<-$N_ztAih@3Y(y0YO4|obCI;NtFk` zapeu@eLi2H2NO%oD2@lgcnqyA9-fdqk{8BHzJ*kMC-lej7C{!__WQ)OOFZD zltc@hAwv!($p)0N2a0N>Sw8U|lq$)yhmq2TAIIRD=l#l1Y$gAdWHHd4FX4hr97$eW zv&*X;uhY!h&p1uqrId&v{ZZ=#pU7wkdF1AMx|4vd!++utJ$S_w#P85Jtv5?+VW8HD zlHE(kVwcf0hUAMEZan%n^#9 zTt3XWW-&9Q$kGs!(TM-F)rt7f5px24i+MeO;uX1+aj++(u(#Wr_; zl*-4IgAc-dWPwdaQ7A!mARIJf5D1&cTA7qND1!eZOqE=cFPP3^wLI0n#41#;VB*&j zZGm&7D2v5|sxni2d2)-P7P>VfNf5>k)b(t5MoZKe$JZBHL2jOh$R9vCE*F3Sk<=Iv zN|{B8q;gPJrgX}{I2nhj>Usdp#D|z&sOsKc@-wn&gIv76ziVB(k49;XqPFd)!s`vMWnw)tc z?7wX#kAnQFCF$%1GB!f>&~d)Y{zsRRZm67`gEdGGT~3L^ciL3YmyA4`Wllcsxb9$H zxtxO%<15xDBBU94j_^H8nA>>58F;o|=2@es9?6TQ7Ft~ia-GQy83Kec{pflD_!EOg z6Q$IY?+u@Xl+fJ)%NDFFprxG(SBNkf37e+vet!xj>dBns3mLyvv=|9IZa<+1%{W{$ zl0c4TfpZBr&%^L@!??4u65c5+&EWex6l=J9_ubx7{}HdYR}^em4aY!qV~)5bUWq!l zXoi&@>n>A~=nClZ605N5aH=e3l^Q^33`Q7PYx4Y=&cSh%^#WJM9XuO?`^Z2RGCS4>7uew@~Sg%#bSi067GKm*L zSGPsyY&mPf)o*px?F8iu)v}Hi1{o@T4;-_|sFo>}-r#;_r}@Jn6T6?&Jb39P^};R` zpo9)gC>X#-bJ8GW8*MC#=2G6l#`;z?}ALf^nu6Gx!EYuHEroK|1Qx`XY{7Sx@EvZp`} z-Z1q_D=1va2cHeaU696!jW%ZPxI`TkN3p>VqNiX30xg}w%B?Eo!7Ed_6c|Zm`3r)m zyKKH4v4+RbXw_lt@q$djtG*Q(bbkHPzIjMy-_g}YbH2125W0#;RNchC!6iB@R``k0{>^)N5pcK=Pj(1wc7fq{ny5j08VXuhVTw|}`UMt1yU7Fo z7{xF??)JW_5*ei$P6>*LHNRRD5uXq6;t=xYYSbcTVz|>aT0oukJ4fgtZevdQx3tZW zWwvF~8L|aHr6fI}k4C0@;K!wNk5FLJ)|PUkg`W9P!vQ<%{_d+e`Na$Sn<#`p>k*wz zTtU!jZuJVM<^j%`U%?gC5Fc(>TzV+k!sR?(yASnch*`%z7LH}0nPV00{toqRyqLVx zHp3{jfI+aNSfY$jM^NZyGZ-m6@RuR#b&7-P7_JCD=$7&(U#evLZowsM>r5r95IYR- zsS5Xe$e}B6gUk^zmF-A_DE8eqjLpHh$SM+&-OvN&>a}7onq(nE`-&l(WD&Wpu8EFpKLPrr1>MY&_A^o)g%eHAKY)aHebC~eCkhKcy`X--Bvg{uVOm% z!w>4drk{AO;0Jt)?_R2Phsk23_@aiVD}_oimIxsSRt|9gR3&ZIp{L^0ADkO*+`O8%(eGY>A|6l*thP zWJII(QRisOq72r^qWy#Sak^tdKM1U(081Vp&n?z)h;YV^GDBtcb#csMU70QvPe(xl z4s~?5UqO|GIwYp5d@#L1Ep)IvdfQM-cDoA9-DUskGrOIxCfFM+tUk%dyDvHu?ND=02gN<$C{V#B-@e>=NAo5}oi z-T}&oxy2Na=yyN4dUdmZny8t$B5Rx27D06PFf^)2c;tKH-ubna=8dlx<#BqB6~^tvpu+L1{PqBgCY? zkxk;a8H7~h%DK8V5j0b8E;J03r`$#jmo_?7K$PKZS`hXH$P# zh6DN-4h57^QmEzb<$<7&0xdCDASGw{nH-8`iO`v0BMc}5?3+5jnq&>a#vDl)bmL7C z0{jL;^G%867!1Zl8Gaz_pPec#dsE;L;$yNaR1?NI0x|LB=Q=#)`K1fI1{7Ct{3QvT z3WHI+$KUTMf*UA*;b-5@HWGzWfL96y)S9Pat!Mrrb;<|r#bZ|YGs@ljAvGNhRaVeb z^P!k=03D=N1GYJ1u!$w=?CwGvGjm{@5a7T~B9w06(J`3}8V4x`9r;)T5Rx$;;RaPA)fObUv(>Q^(H~BdC8ul* z>4e@AVDqVS0_=vXJsP)hJv>$e+{0RsT`19mrl0d$Jj|`go^lJE7r%a~^k)Uutnl`K z{w8)CmVedBO!HOju}mb9!v@q4O8s! zc*IosMxK%=s>&f-tFqieRceKg+4-c>=E8)pD}QXcL}tu1m_$Nj!eW}GXz2?Ri*BEp zPoxecf*u$pL4AqgC>%c`Mz7(Le%ZCW49HcozK-!>t<9T<^dciv1z;J~SRE3p?QYe5 zl2l3&6%{F$<4=a)8#BcbYJwm^3UhBj!QsYCx0=~pWfJjq<(A|_?Ywyub(v&iPYnVp zYqgV0J`cq6YT#ML*c80sEFsn1CdLA7#uEH!!?PUUGxSwJks8GG?d}#)PNgaF*0vrt z*>;QPoG)J8ksO`iN>uVCtH*^DL<~Q~6_mYV8kb^PP#Bw4uW@aXBeq4=_TI;Injz{c z`UE=W)!%k%a)N;qO`IRuA^E>Iiis;!E`mW){K2_=7-gi&?EoG5*%bYlu=W|yn77R4 z5QdTCfN18+Jg#j77q(G19aBE3aY3D|yeC_aXq})9vA_Y|z*b^VykxFpMO(bKSS$g> zBD|_7W%e5`kUUN>HioMHmb<+?0#X@g?9C-tTE0ezIx$4paZ9?0uwjLy6`k*bBJcct zG$y=4d9;XenR)5Bo$KJ!3}Bw3G%^V=HQ&q9wpU_M%$R}z zNj|ZG0wONbxny|mQG!tnxibU(6A9eBR>6^yZa!OjfHAss91JoSR2x2{oJ6W(2tG$v zO+1NSTZ{^5c1iO|98)RV6%pt$Q}Se2j345RJPs9V zJvY&{#7h`(RzFJhr4yPSsn@U4Nn)>(Zz75D$b#6KHX^<6lkD&c*uAbPGkHhR1F9`v| zTVtr`{fgJ|rdt|6+PC|6?Ovy}7Jnhc%SupPFM>KaK&+}yJ=qHmmoFAE=!&^}f3r&6 z&9eI}`%qQ8+Py2^vX`lr_YXz}cOa{G;RIfdj4yGi_akIAFtnK#xyzxZS&77So{Dnk z*n{+5>YSbLZqCGY#hZRl%Ng-HUni8ZrvB*Y*C=o1Dr zs`}ywT5GCfs&HU9F&YnOvjA5F!AxY)OCeKuHwophXW;)-O1J!3WMKgBc@X|To%I=8 z18Chw#*T*n5=`ojfOtxu>so}6e2TyW?5QPeM!vQXM>CAwaw1I!tGb^=6yhKQzNRE= z^;@LG+~{r%B$qWRZ|3mgg`6YTIaxmLUnpPMeukZU0 zQkHQ_(&x`CIyIEA~(nDDv>kWhIWC?1C zUGX_LTro)WIz%Px=rAy?CBS8hYPoPyW)0IBg;voNrq!?;a6$dwE1{Z zi?ys9KiH25w2Pu9kOl~e8PJhA;JGc%hXqkc_3*LR`UenkSesEW#=~R^h9;gw$xG}# zM9OYv!+$f%7Qio-W|89JuxG%X6w#Bcze2cm>{-~@YB^rsk7#2$j&&vVURr*!=O6o?#Uff#2 zP)hjDUz_hx0@H^Cz>G;`C2|K{EkWL!&|ky_a)jdaRF!kz^8W-L80JF1s%Fj3OY`(M zwl3{kgtlv>-)C$Dg@-gPFXk6kOgDnFArh1yB#waA$S%wP z2?k7P#~i-95}B3<+9sJK?G3T!A|B%cSU*!6M@9u6EtDr#xCkC|vSOy*lA$Lkspi8L zFOL4)6Qczxz=AFH=Mu=a@!(Msq7!>Sp)l3$`)e^mrXrgGT}OQMFPFcbU9}@9)aWbS zk1QSt#O(5IU9*M}&C^vN$QYtITrN_!UEUxPg~if`6Vs$xJ|uXo94vzh zd$Jw^rH7EJ<=OONK)|*pf2I$@1kXSy$}7MwPLr&2V7b{GQ~(iR4x=onrePexPWOIH z%PypsI04T7eVNgW*??P6rO*9fPkb`qE!YCj$&YUYAa>{kcG#}!-hI8YQ`>7xEkrU zg~8IO63gI=?X99&wn)Acy{>x!P9xqQDLETxOn*ac66$EQ=pi ztVEBBdk<(cvigtB-ud@EH4skxa;nL2yKrH)K=8!JB8?0?nn6(d(8R#tzKW1BC@=cN zeWL0Wj?SoatR{-tW}II0ohkGnk_O-`0gw~Q!^w;}C^G84sYw{JdM)dHV8iK~<4?dY zQsLKF+WqfiDlMu`>V=NR@|IwM>fR@gVcCaErUD4~?2$!$%?ciQJR#kI&1f%rCya@` zzYwjpx`Cd}rUeu%vDL)jJED+{YenkQotoX`tC~$HyU-XV&6RJ)o(jX8sd6>i`l(~+ zbtzr44mUeaC!6b&xSaSe=m(h}sEZI0i6CSpXdKkrWn%CvxDp;e%H_b$1Z)ubqog)! z#x>j8G;}#I+@og4w&-pPF!E1)h(kRpl0xr2?0hLhi9{2lvY2L8+sN^qDAG0~n_h@% zYr$RonB^(f3@JMXx-IxQ%?_Cqr%lXl7Ugx8Ri#QVnpNv{XERQ)%NdH&>*Yw2n0Wf5 zV~$-s7rCt-PW5ZI9y>#J@-I_12yAK>%+RyH*QEA7X1vD9D0Stz@D`bvO*u1GdIr(I zKpsaiH89joAr#qDOi%OaY-QCrg<4on;-ygvRQkBT!Y^THlafSMkA&TGFuqgQkk)B;-In7g|1R> z^d$Xi=xe2_nHJ+*^Xw?wXmp*hYy}$Pxpd;R>DjSz|HZEfn+vA_vN_WAwY=2j!BS7B4@ylM&Cj>}_(=fau&`8c`7o9N4(XSK39WYGH2rM>tQ zGs}rUfgz4URxG(jm>`9ai$n;p8vDT@CG0J21buC=TiMa{Y!YE$n`n zw)?uyUNVO~A*&V%2G$@|W>1!BpqH#(FaI{6)nXQF;pow(Tt?CIV8T1DkY^eL(?GVu zMM*6Z6%`>8mr%$Om<*1LfL`x&hcba6#|uONeWJIcL;&xN>hn_Ry+Eq61)g-d#qyJ1 zJKEVVaInGnA$Kxd*SX}X5%vN(?LMyj2{}y@JR#k?M&kp*R`KvUqT`5&GkbERbHC^p zkW|O}tx*!p7g?_*atA1iJ?LH0$i^+MGDv{i!B9z7NdSrA;q%0*!{|O!uU-3{R7yYo z3#35eA@DmF{_F5A7j#?PXy{uX7xCFiSQp<4f%5|sd=k$AeZLq+3eq#Ax^Ap#Z}u34 zR#dzLd%^0Iq(n;=7@Aqe&OsnBHH&LFb;RUW2K?c|oEh5bN)D7(B>Ng{4D!$ZMfq0N z>2__K?=s9@%kT|9b=t4#djo`KRiS8U67NixFTfj5Xl?iCe~jPI zVH^DzZx?KB7Q>gP6^G(NRWOhOfh>d21@vc3VkIEWq0RUT>xiLy+a=bt+qEZP?Zhk8 zBbh0BYRobwBPnMt*A`NJ97Cz3JaVKB(fi#rk~6rCe`}dDC_^B%oz-JsZoLr6)aXJH zK921~=uw`0{@XsxU-^dIvym|ckZm>p*pL3d>gKN>T^hhB0;EQE$r5Z@lQ$H-&=-?I z5llu6H|d2UO=v$nJeFuP4K?OG-MZyEz*~0ME~Dx4)U2FU2CrOg27gTFtEzYL27g}9 z+-qtckzowMs#TOLAAO@hl_1JU(n9ciI}iqp-ZAea62?IpG5Mj%QfY)cu{Aum+V>UC6DjTDTE zH9+RhsN2smbgZii1{H^lvpf>NPrF$;r=i{XPx&W*HoWl!kblO+|5W~28R_bpI@mhf z{cBYGZ~ZbrIysNahS(;)OdsLy%6K@LHU5v51qFob=~bBwCv)?)!vso_81CGWdv`9w zj>L&4olS1{uREUf2{uC7olW=GXPSDe5%-O*bG9d$t9aK~nH+ACOOwbfyNoco5OV>d zk+!c*!ey=Ti&6WO31i1K>k_Y{tWH2$W>pIkjgGZ?q7}m!_0znN>oYq*{%rv-;Kq)K zXtaWj-yjAS2{kwGDdN(UEN?Nz$BDfeCHo6|DQ0LO@kkPRUCdDYz%R9x!CfVqSOdSC z_Ho?k&K$-_&i}DwkGqo_LzNyhOxJ7@2UN;%*zEE&KST8%BZA4ivDJtaiIAc`ZY-^b z!N8u&pccfl+HMya1cezU(sE-Cy3isLpC8p5of4~y8_#A?%9wM6;r`S8O7iYI@NV2Q zoxKyM6<#o)Z+4832U|v#(TxCzB$xh4po$2XZdMS?X#~gD`Co}Wb4?m`9f4@eeV~GY zK9w$q%Cg@m-v`!hh8tSIAsbZ+`PGj8z?#o|C3PZT@3mD<4}|RLWmlp}(pQ?lm;6d7 z@(howgiU#Mk7E2Sl6VlM%eZ?MhQ-L&NdO#XBnebd(u28F>Q!FX}dV2zxTK%5MTRtk;pfcrfldUlDpPnA~!jBdYL zZ0^z6V1pU^QVAuzE{Tj1JPcl*nBgpR%*vvfT6>z@u%t>XORPBBXHN(oNR<`R)X`n& zHSprT-XbVj$~FG>0i+!~x?kNOc?z13GXN-9V~S@`Bm#YjlD)ZG&BI-;d8MWaqWS>p zEY*r>+z|fPp-aZ4iR*ru1;`Qpx{6wCD1zFRV)3KG`CkC%W!abg&mc><3?1%Y?kL1; z>vGQqm=>7$`a<$xSw=~cO%C$6vsJ|*K~us?%Sj;Ru~p*y)^wAXJbFtTTifSH?%>+lMR~8M}w* zbAb`xWcak8ymAJd-#8dM{J4avB8}g7G((^yQ-vlKy)yUqA&DW0!g(@GI8@D#NH8bChJ(yy6$ZbPa6*01{BgHq|S{>9mYZQ8oRqF`as{ zI*VQb^+k;ZJrO)`?3L-)6KI40siSz5B6(+P~l&2VZPGOzKj z4iqx)I7XahJlAjy_|!{tI#&)`yUV_jaUG4kf!uAZKc4x7xDFmZs+`AU1t`9 z?kKk1dl_Rta;`kVBT7M*pjWIw0gU;Up3=}fKT>#{D5{yP2_jpX@?0a zNabVXO4s_&NwGpn{UPq=MluL^_HIE~#YJ6?U({LlO6|tAGlhjUf;D(&Xysm+beA5R zK^PC8lisCFOBD+sE{;gjCzpqC0=sx9&jYE#bUv*^gXDYxF&P?d{V_ z-G6u-@7JAn;hknJ)6AePyQ2>XF4N76JE+q^txcm`<=6z7e{jpWw{4%61y$#`WlW|2 zDE<@$o!B&$y+%x&F>p~gs^;XBW5+M}!O5;MP^vK@xSuUSj_PAvK-jo!%6WJU;}+#a zR`#1CmzP*bw}U~%Bc_%lXEX*j|GNvL6IM1=p%UY!!;H_6B2jux>pm~>P6Va4=CY%5 zS;U3Z25$;BAPQ7e)D#@hs^Bl3znQdOPWL~k(NHIHG~7%H<_XbLz|Tlm5KABN0LN~4 z*EIsa2;E@^sbKpf`=VO81+Jc~^P^;ZhFx@o7&E%afBW?u&S!XyAbeh!Z3Dh1vJnrt z=PRNeZ>fVW5ST~{JqUjk>1Kpqv5bSzOe>z$4O?6)mACLAj{CPT`4)g*uh0ekSxT&P zgTH6u4P4fzmF55@kQD4IazdcKEe!eh6>^DXpNb;R{W_(>l}`FPOy8jtbe^$tN6-9-eh9Wb_YmsP_y`tB-V5O!L%8h~FrZ`r<+LIXZpY_NwjJc`YK)()RTivh zWur~>Cwynn)ZGN*ik>>;#}q!IK=}J!uFTBt5HO z`_?O^ktv|fSMKW+x9?K&i{ex>e)a9@?hpt-q;sTaP?ggQmDhiA$9yYA{U zue5z@^_NnhE6PpV$uMNltrc?fuS)9T2BQ*|5{Hi=ho;z+)}~?~=7`0@PMG1EoBRJF zV%o1tYQ6x}Chk8aVp{*NnEIc2?jRiu`0hs*VbMnZ>Rsl1B8*_%Pjih?F1xJxgB2%5 z4u3ZitaHKl*M1J_>Y8G0(~J_yuG-kW4?7N+kF1c}Cw+l}@d*ap(A$^$bJ3noy)ewi zAh9_%c>gpe^4V=uOUI~9P1|!W_~Qd#ck@-Zkwc}RD6^Yg-~xWcNImtof+`2|^XXqr z<#z`=0xr06Z9Zz=@QKmDAp4lP4FNbqRqlYmA&XS5rk;!*(w zk9x3;)Onw_B*z{q_rz_0SuB5~{f*BWy^j#0YUYE2V@_ z7H77ekN=7(9~Q!z9s;bgmjG7T|Ji)}@0V$2tZ(#x;{!GSJ)S%R5KsO{*f(q(00@`< z?|5?E`I5p-(j4rK!vDgTa~tL+qP|2sw!>Uth8-sR@%00J5L{D%ysr!bH|A|bH~2u z(Qp2U|Ds2a_iOEY-qx-zy+##$zP^Q+#DD`g>;4dUPRfjt+Neg`dy23U>_P~N34HUbDq4TQE#S}FpP=x(4^ zJFDP_dTI=|J@9;ydSvnzZIZ*q`~CI%3Q1`7-ZZOD0F*Dg%7cX3P@tGlkh$C?;!;AF z{u)=%b9UpWN5Vh#lD`pPr`SKgQ^H>j?>%4g9@amst^5YEFOII(_3{ALeec45WXZ4n#k(ty? zO*gO0pS!qrNKVxW{qHb;2!kx!0g&fXu4CCWjn~P@0unbvfmKvYbzpUf!!-mo$ zw@3u=%Z{)9Y9?oS45}T)XxaA`^N1EH6T)+k58MxzFjdqjH50Jug%c#MV3odRMi~{5 z8-hVr-6E2ljo*t1HzX{f7R3OL_d_f)!b+I~-Y5X1+3+BEVGMM+E#{&k~Q z9rHNCn%{;SP}C2x@p0Mjds-DxgZkSRm3tAF%;kAellQ49VNbas+EiVd?3@#_Q`<$u z2vG?E)fY^N06dm6tg_r_m3Z`KSJeWr(|V>mkMvP%VkVOit3I{BiiHT}?6i5#?eas^ zU2=VT0}2J)tr>KMZE?Qalv&N(XH3YU;%k6yy=^INeztjX68@!0^qtz#--&B&t^FBV zU{9{1s;s0*yUX^J(i*w5Bcf-0(d4k_DW`t+ptXR;uGRJf#!YEOFWox-X(i{wHB~%Xx&K_d311q?m1ibG%ShjOb zN)btHYFBw%n--l^lQy0J1bg%<7dJbm^_zItQYsT|7qv#N?~8a7d(CmrxS&*uBjn~? z*wEq1BOf#o=BSp2FjwUhFd6KW8ym3``tf%X4+4>pbbZlhgCdX3m9@M9{g|XlJUy>+ zo7=lx*;_qqaXHcK`3K$)=lKKkl zN9LsdYr2%Q5@*7vpo_e!KO4KB^N+8k-514ZqZUPnxDXa}9dG4uvo(g@9@7?SR;ubz z_2Su(pl)FBjye4t#5@)_=%;oxDsDl2Wjj!PBg|$rNb4F;*oMy=HQBF*>=U({l2Ai6 zl(8DtU~sx13db%See0G|DV&ui`7Wt!G6Ig1uxWH#Z2-8Pf}K=Eq8kd^ce*+#Cp0*f z(=w0>%~|jFGu>Ll6gB~%UY5BvA_4+_G=f}|{hjWc0k0Azw6JvNx@vQDZP-I6m;OWO z0!kGAc0^P%)tYbT(ktyJ2U_jcD`@uq<;K07sLz^X=UJ$9Q9w>pAYaDSvG*@z}E z68))RF{wlSLGtU?$NUo)y1fUeX*T@@vws*L>>ZI#ux-S&GGSTXN^=X>g*l(zz{g%` zT)pD#p^Z`aD5Wr`L;Rc*Z_(ipX6TP;{v;k7ffCYpm)NEKj`&iMAy~cT;?eCfh2xj! zoUNOAUQAcaafhDX!9(fCJse|V46)}2FJMC0ct>ypZZSB$O=bd$fn1>=kgE_cgr{Fh zMGOeb12<5t%MYdX#}y=kWDnk6gh|Lm-nUawd{CEAwdNo$VSvoLw%CUzj0rZ(Hlhzb zG8R=Ia1Muxo6;FT+S?4xfDHrhffNsT@y{yg%G%Vs7P^iLrJALAfz0#kH^8Shy#Y~x zD@73VY?l9S8B}PUghybE$|!POU9FGR@}oE^JQVicxQF)>r8I8Pj1Q)rSozK` z!vfny`X+3gFKv7D#*8j*lhgd<5;CY)K*i3Uui$3DT5QFkRW5Pai>pocGAn|p9?X{O zob3W%{uAAD4)c3DiC@Sbo6zn;`b;%jIx6j`s^=IC=q8)uO2kICPMM0+(&rFC z_ITusJo9q%7k#3XF*wLX15QO6XI^WRz8tcAd&?;sx}4J^Ui2%VMn!vRu5L*YLJ{f+ z6cD$i4-<)jmIP(uSw}IT)+Y=D3x^Se!2Qw-jrul|9zz_=1C4 zbUu881mR2}8dEH06IUSUZ?Er+>_|C)k=kw#Om@^S_3n}anVp$JCE;tA6ywnMTqqc* z14QN36;sWiYf4wDI#6=|#&u}+Ym5ppMcuLKpKxTn>5@vR3db4)!7!*ca1iDPV@HlWu+g4zkc5>!Gr z;jij`<2gwumQKMmJL_~xmq$EmE-cikpfFtL8Ig-Yfx^e`1(kD{XPjN26Ip zT3g^0)h$eLbZ!#TAH<22K$=5k8kIy1Trk7gBwKuBl+acrZ+pI%SI{2J-s7fE4jS`1 zTReJ-U9qV|aER9Bu#E)d%)(PSU|b8Nh5Z;gLh4uY$p@fTsM!r^!aUkXomf=D>6|POHVZ1^etWuAFgCTh3pYEsKk12jzw*PhMoqfzNtfka`3Ib3ftiuyxLNgukfE zoH?N#w-x#9vX2vxCrlaiNrJa?tw!;Sdvpz zgU=X;`qXzrW++OVl~!}+YugpNz;wYJIng8@dOz(4A2JkpNc;tzVQ2_hK{=)SfG7`;5c_!p&t zaO6p(R3y1g7{tt1@#t*W@j|^@LJK(xDDVyQ9{1{=B~gHhW2-0TNQNrocZpZpw;Y@# z;*f2U14)x#`DVz)nZWiYw=Gu_RQTI_19x+b_cdbIT-Q%nMO@```id$!RuM)wk1bJ7 z5F_$|vo{xG*{X$9>-T2)-f+3y-3v*L8d{f&oj43iqS1}+Uutu(nvXnE+-^F8s!Ms( zcALNFd6Kw~j+)+I(s$q8wOL2bZ#O_+P42wmvF|*`yk*PL0ZVXJ`*k*5NgKRcfA(TOFNGH0(el<7_UHs`5kz0G-x-X>;ZS|wmmEF*~3M=h0aPC zx5o6IEe9BH4kLXB;XWv9t^(r%(W}4ta$}}$JA;rA}mLnZLvMGA(P z`w=1YHud5BViRW1pjOG+aVcoCOjj_P9BvK4OVdQl!mACMzX=Lt0q?X8&l-x5x^u~B zZhsve!lS*a1_8e*Qz?P*rRFPi&FC*RZmBy%QOuXR$LW!jn$C(>+M!4XR zez@ADN1uu)`K`V;|NLAv+Yc2Hu~#2nkCZX7wM+C-=Amn}r!;>18K1{^+ph2Q#gQ9J zHa4q+f+>9f=7xqa4^rMVl1M!XSrAS>c31OH$uK@u9X1j&EM#k6ZtyowCVg)`H}cK` zlU@7{n?$D4qn9uy(dBcJpBR#<#Gtsh7RR=VNi2~0FLYLMD(YIlZ!!tQ>n?CaQFe5S zP?A3v8g^5dtdYw6m%jenw&h@_F3K4Twnx&Vd9RU#{2%d#L>WqB(^Vgh@)~nBfZ|j2| zbdEe%%#XBBe0+pC%$T`2{i9ZztTudtqP>_uKflgW?&z(uWlXG%)D#GhYF5tc3ey?I z1|5IuO&y(_?6g;|!))X{Ifz0{2315NPiR0d42u!24qKf-y!&A4yoTvNIs_h5`>9!k z&r^si(~|cYkkmHO(#@ATYyr$Zv}6*+gT34AOe1S6kCArRd4k6@MqE z78~%4f&w<^$Tjgs2_W;^I!!tF(PHn#U|C@llqp^=t1T9>@=~-wj2uM!-u8I5`lK@u zhp;1IA;UzZ;zB95YgNN}{+hcq@A20tVA5<@@}v_QX<0R&|3QqvSFC&IyFy3pBTWG2s4#fj9%7|>6anJVv=o)8&=7js< zTo+jyjQhYg%i*&v_1u?cn5@9}%JWicY5htT+nt`%ZLcRL7}?7HFvfB96BiCT4H3en zaAPKxY5cpIl{*?QO&)HhN%Q!maagN3hU0*Tq`?jn9}W`N6Ygpvz4(sV??8&kC)=!)|$1O4GaI=x4gFNJrZ~!C5m% zaXCvF5c9%HDKQ1$A3jKiqA@n3ScDU<7|BFBVUR;~EWZC_Ac6bkAl})I#V@W#@7sbH zl^Z`yXN2zKSL)|;MK^zYh-ENWOb3ZY8v!l_O}PNgiR8e7MK5x3!(DH#11s3=P^pM5 zLpe8ek-TyW>#A7U<07yI$!&`7+IZ7A?MdV+e#P(aw*1nD?4Jr+g@I6nj|J7{g8Hri zM+(P6BB3CP70$S~eNeG$j;4bKb*8AwQkKc&{MQ~WzX*awpir9t`-_*bwyLE$h1bla z&N=!0xd#A5asI=iu}VpUyD}zb+1(G5FYq}-%~M;T zfkV$u9mR=b50wU+Jg^vvJdaU;r>-mU1uw9rT`!+)D%i)&B-8 z)N;Mk0rot{Iq!;qyuQ`Kf9xyfkOv?7U$X)dUP`sGj08d*_H@ScJ4F(4u@@|1t4TbQ97_FZ;v@#xRt} z%DT(ht2Rm?B*aI^3Z1^;rgwQyRB$=JgIU&v z8MDP2u+6A4OdW8dSsGj(D7wHzSK~rcx)MB1Z>xC^`-n^TmKmmsIo=^1r^_} z<)YG$7Y$#)U(*&Kw{+1q?^szCG2zFEd4Ey0VTUlhE$UMESPoWZrA-3&q}chb0Q=H` z#RVeTa`_{A?IONw;Urxb^oa`*bFC$$z2Pp|qNGW576`(uWvz5jgmo7$=COP1Dp)dvY>)N9(G`-b)jWk+bK-7CpJ)plE|*K?-~`#R`+Kc%g_ zo&-sFD1{yAC4x)EjyG6uM9jh6N%Y_#gd;yf*!<iQ@QuI4?%*KTq#7{{QCYEHM{{u4Afz}6$i<0G;pQPo+w9Ve)=Aa?K`ngmp>e3 z1PyO&K}YYrlDI-9_S^&XwpuvgizU7DI527kiBwLspDR)sR-YXy*AMS3Tt#2^eFYgP zt?xX^^upC|3vFv#em3vj?Z5nx)RvRtJr>1?=|bU|#jPR>;v9q|yxwx=9i3E&^@mq> zWQB+!^{+1GGY$WMmEl#ZSmd-n@3&%oS5u1!nA6@>J#J^OC&)7a#>h60m%z{4;?vjf zN2_=@fC%xbiF4BnEmbmYECra*hWlsz#AiaYBcLZFhX9iK@gtRUSXqNQS$`m@TPy=z_6H7jbAPer}o zzMyT{p_6Js+pV;{*lEVj{*io%T|)4;%tgBa1R1!%sDl+5>?p;_4wo zAA;Mmo#uG;b*>KJ&&2$YJOxAEh(T=izPB0;xbCPyp)YmP8%;lzGA~4`xIoXkxg=FR z5NJ5biQaYfYNjj6OVm$`or<1Y*krqG9&w@UXk!h%m2dKD3g&^~hy$@ew9W4EL# zWC7SHK%i341H{6_Q@OhvRx`+7l#f^Bv!~Wep{d1 zY8I7^r-hsozs5e4gLQ1%;jxbKjQ=*0z(r~wRShc|JB~ZjIebm>K#k#PL}~Ni{dc7y zktma?22dJT0Hq=IfAP?2<(xFz8@~S6h4UMaXsTX{(Mmk6@+-+0GODJPFmu|9q}ki+ zguqE&J1CAW4Z|nD&6#Y~MxCC0TejX(Id^~O{GUEbPhEBEIH z_S#J;x9{QgQqGy>D=}>xM$t5ne+W=i;<~87FV(chZrb+Z!}z8*lD#4sNoo)1%A!PYPx}w1_Isu%`=$gXct&wb zi8LZDR_CXo^k6FNod9y3;sgBCy_hUir32zJpjNC#4K_;V1Eu9qaBuk!{Nhr6TCY6p zk%eIJh9r-<9!AW0n;Gr+TOd!~tE?~uDnr@h<083Z5Y~AuOwOUzQ_y3p^2j?mm~x@* zc-&evDM(C`;*0it6G3T&iU)5jSMsF%B!7Wa;XDor0WqA}#TE~RPjNiGu8;qw6aNZk z6Lu_aXaR7R6a+v(eE<2c=Va>WYU&KQviMig50*6`nCH5^n^;YJrd0_a0@uAK(jIRs zyui0jGJ{s+jS0@-_<3uCM+)W-R99AOYrKhj{fawVz?gf^7FPF9#~2w?+&Bz-JN_Ro zAskglowi#y9qoJV`y2f?bL54Z_OZ3Ol9QzJDA+$XJI&!8iO9A)n2dpOF?w~VG_;%aZu+k_5=U|eMLIYNlnfVB~+-F6E zh&OJSKtsUHSX@XlB?G*XWlDzy;kP2M+Qp-rqlUSkCTO4Ju+3GR_{(O0xY#e#J0fHE zPp1ih_>ZcnY+n|cOJ|A`;Voob$VPI8h$cg83Tilz6$^tqBxRjm2&K`BW!;0h$Z!ygfh1Q?bFE>Z$Xo-e-i7veX;j}H9( zR$(v^Ve*tQ$XiOFTVh2MH6_Sg_c733W=-7}fg_bEVj(*JygT4#jIq~{bu2iZ`Z@w) zZ8A=FT}%RWFmEI8aOk?^pU7GfqMPL zM8giHkX(x_b~!p*3|)8?Fy$$4-*TWOimyVJMGNmgK&dx{AJ62cK-p1nzN5*{hTd`< z!nrK{ymak!hLn;@VFSA^@FH?Qz=!qgz*!=E5GPCi+O+|dr^PYC zS6Y)=#K09YzZY@robE^vr;p{v_SPXX92cA^k6|Dv2a|_^{)s722`+)DSOy}|B=dC z;6CX)i-dZLkQYU#TNzX@5;D08cYA<5leSAaTdLdb`%4ojd{5(Qv}omFbfsx9ku^Mh zvsAEZgM&yP>Bw4@>^J*BA~~HHo4JXqHJ=uMwLGgza0bW5%!)irJuqKK6UF^LXvO(^ z!YimUnc-LZ3hiB$Y*8yX2Shx5f~wnj3X!%h9WqEnWr&Z|lV&rH5Aol%MGapm-yo&e`B%aoF_T$Ssav_IO;hLY6b!&B zvp126N~SbPoR!K+pdcwHHJ#~e|bHx9vt9Gmi^$&8dMrYF+j zvX5|SH_e(ewyVem<@8a>4(R?^93?Vylo?dYQ_lENZNj|uTM7E|`${|J#;^}O(ij9j zo+|DEk82ijoQmt<m~+- z!^pROhC5J>o2RhzQ=amwQ~;u}yWox-XOtAFlVu-dZiJ%Vsk z-b4>O^au6nI&DhNmULP>)CZqwFfDomsM|agW_Z)y(+3+1_k}Q|zu2~Ww69cJz1fq> zCtBK-8UGuFJm;G9Wqa5MU#mNJ!_sMU+eQ}wi{l<2OiZ6!{}brq8LQ{Tm(FGTN(zsf z=p^NyVN1%rd&0Zq35I%u>Z{Rm&2C&3Q@G!VF@{-JJ2vE5etRx7jxJRhkGkw?(a=Ky z%X8>J-3&|zcp25$Xf#D90U`l)QRXzP^wlpaCNM99xEOWW4%OK4T?44-AXC3|6q&Oo zvzA!VB=0zWZKXNr5S1L~oRWN|)_i^F6?FF3cwHHDLZgNpu$We=(#J60rKJfKG{Ua2p>#LhO~?_}eAE|L%7pLXkM0TG0&i^tFU7B4 zKBjvU&ZBA}Z>FyN!o*yj22cJXJSh zw<2Y!LTE@GOCjhpb)^pG&uV^-(ym2a<|1z-!}^T*8~gMO#2NcvrC2BHUXwtu#@#j` z^7_$#NQ6@$!qS0MEQY(UuHOph^k)|AZZVFnDjA*;Sk+9gQXbr{X!bxt^GmhfQLt1bB5Ne~R@D44Xgv-MIpe+7KyuNeFPSp&Wg}YD+3+LP;)rj{LsN94c0Z;b=SE-Z z$kiVQZ!nk1#NCuNZPTh*Id2A?tTHk^g<@DG!4w&3dXK0Lv{=f_%k+rDY$;Yl;Ds8% z8eWO@@`6^MZ?HX>fl=!?n*BJFnakL|SR)^b8p#dcm5uHSX- z%Jy1DZ4=(~<~!VuCeJxDvTOL$KEF2ZGU)D<;kv|JkZ8?hQYD!R>JdqU(5VygTI}v@ z=!*64skS_al_qF5NhxSKfkQX@6pZ~;3P5|rAMbSkgdyx4rhz!h4J7&W`3vemD~8e- zj>go;MR?nA-OjHP@fSjOJsVO;*nLs0JHepGVfF|;@3oJOA^gv+9IAXK`z8SUm<3=T z|4&YfmUiYwu4eyrTC7z69{^-L0Dx?a0>eoOTl?Pu$Ti7~=sttpky@Xst=4A~hoj^E zo#U|)7^P*U*o2s=EqnrGY|@e9kPt~H7B1o({g};8(zhFYEK4%DW*teg`29gIDGNhe z*I1If7oKeX$fRttg1P2Pyk|T$#e3 zEDGXQVkJ#fwK6P3Z3p34$g>IL_whic*n}H@ma?l@iqqj6(Ln~p`J{pfpb-H`^WW23f41!YEfjO&r^EefY8BG3Di5-}}ba%S#&CdS(s$FD^>@TqhF{}hFlZJ^jJ8MzhX4$+1b{(i z%_D7SFfkWN4woODhQo#ha&lTf@wRp3w->Jbe_@cxb{l81R)Ck;hj?!hfByCeaq|2J zgFKT{)>T!sb@yJIS6(FX{Bh*h+B`?jAA2N@k)X<&7&!*XjU$^e9X$94iQ2By1$L?z z#W;>JpxS%l`^F>V>}FN8wyRZ4^$lNjM?uE?inw;p@>H9^9p3YO}36NWTp!3ETL+X#6n@9Q>&_e4(i36wa03i z<44J7r+_mg(x4Fs`KYzKFD+_SNilyCwnv(mR5m+D)i$x;b`Eu%Tg>dm zdVkP3S>I`FmZIe6(8G{sFS+dkqs6Osu&ift(a8zz#(!&uyJ};fSc&Q{QVwFOcK0LX z2wx1MlU~qN{~aK65W9K6gyIUn-&NyNT|MiKj`397#4o`!LRhMxz%72nq2#>ds9_r$ z{5xP*u-vLlRku-(;0JN!IuggR57S=Hb*{B;NnfqP3Mq8?ta1w2F{`JP!q+UIUho9c zxu8=1FfcA`*07KPIFFOrq|JMpOe-lbGZB%flgwhOHy7RaT#}JF9z0lN{6|tv8PmwG z#v;Gm34?v$TgWVa%H3=IdEkkH*jy2oB^dpO1Mv5vQ1zp7u^P|F8948Z86DI1t9vc; z!L7pllZwxtt4;|L$L~o4X;@AOQP%U9Pa!P26=_wFj*!nb;;3A8H7b7*k6-)^?Pn{i zMmG`u+vu|GDB`(>dSk0UEtuh7a};STTC7~Yf$PatOTwvcI;lEIL7}+)5JJf*y)c+t zT?$LqUVVX5-MRU1#mayA2Nx=VFRg%y5DS^Jh>P4H%4Y;pbg$@A*{8j0G3 zx_{q4$6g%`B|Ce+_p!&qiwH?%q=MOpl(N z4eIA|8NXq!rJc01bLLt<@$!oRjDlql=jZ2}z5k7ckNJm%SNn&BH#7uwrl(G2Gk_ov zn@SL8*#N(#e7Pp!R5Kl|v4k*2}kuKrqIoMnYlYdZLb1{>n@3=HeBqfjI)7-e3P~2*Ca| z1g7PA@n&J@swDtJfX~2qZXz;IBmh&vI0Zxo_?MN&y_yR$vWFnqTu0qShBTY;Cn{Ft zB>4TUG@R#3CyUFneE-B2r=g&U(hH6k9#^c6V7t?{&2UXi@@xZgmHux09o7yfaw)Xwx)gFeHF1(?jnc%gWq%xh5e=*4ZF90jzs$%KlJG9k z_`;xnQ226@|AxZz=Ke1fe)TUD9(Z}G;6ohWLIKF>r$HH1zXd zGoaW?5L~1$Gn4%dURQU<2btaFXJ4S-$A&;t1nYzSO5}p(Rt+NV8GkLD`=tw6<9%g) zy?ECJ;+I5+Xy)YQC0`fFbSg@DIaS$4vhAAZD0u##cF6IpPW+c>o~<=LO?Bas7MYs* z8ADiG4R74qT{h`I*SI{4=vd6pJxe?@vIO5JE?$R=pTgI44ME|GwI>svqp{_$QNlDw zZAh1G^GE$!UUYs|G**E%8yBf3r6!(QE8$Fs0s93xk|YJ?Gjx)Wco}pzzb;%Z80!j<%HtZ4~WSrWrT5zg-`z7#AO7yy+Q@ zwY=49L|$%VY^n`c{L=0ybc2XA029E=eC-udh#|hQCfG%53RDI&`@;5NSTi?yC7}%$B{t{@=snhF85C^4f2E>^y>au+WZb$L8&n+opf(l%^l_IBjc~K9o;vw z><`aASS7?u&l8AOl9d7Ng<|D@q3~>fqwwxQ7bEY6%`M!GoxZ2^ZDZ08tH*hI>er)7)}11N?qay>6=<_wb%Pph6m`8Y61xk26#N<6xKBW{%Ig0bFn|bf1pyGVh8GA8q5>ejo3IH-Q-S^h9x~k~5fC z?e5ik18MP!@ibN!DW;P4a>^DayrmQh9$JrV1b)1r6b>nmYn;@Cqx zkajtTKVffZIFTIMICx!&SDjQ71?npV*90KoX8{Dfu>HH|5aaaMPb1EL;&3R~j!Zpa zIMz*vf5w5UkaAAlguvYK5_Ft)dMlLZ&dt9Ggoc;)QEEWGWdkY@kmP@2C)=5@>Fe8> zTAEuJ*#pWxj17$~O!f5vG`!P~zhU@FOijSD)U!`_ALam;NP2YdFZ{S)j$ziT;lGMU zqBe$Nm(wm9r~%XA=(}v2YYnjc&CNzLbBE*g&dT%Hj&oufv3LkUPM6OI><&dV{{?Tv zUce3T>$}zaCGG0P{O&-4RDVj>%2;Ag2 zOGCHPJdPD?u3&Rfx_b-Iw2eP81YR}}V~|1ey|9AlY(~XsIWgDFl&~md*!0rDil^@1 zZI;t+h67l>OEELQa`+z9 ze(=3wg2|lA7`Bkfpu>O}$idsS%)@e(U4JCAMOk2)3U8;n7)^QXQavic@Z7#CSRzHJ zetyVbuU{`kJ+@Ub@4JIytArbTTX?dwnrU|iaA&;pN+Tm7CT@ZwZn@uFT z0vT-A#k{6*#U&jn$*lJ4T^+Pa@l)EmV&+*ENFhgAJ%K>;+pYpBSv=j2@C&XZv_Ksg zK6^f-Vpt%HKt-%`u*?uE2;neKfI-@!5_342G^)myfZ}}qUVQkk?=`YAXTXVdJWHgK zt*KEC2<<+S6c1i!19`QxEkQzZz!Yw5VX_3g%k)#==#X@!#)?!gXi5S5-eeAN_>f|p z86Zm4Z@P&bu`+We92;G@r6!@^+;jg}@J`M_tGArm8zTs=i<`97%)Oa+nQedmAs?%*{&h^G zresM-y2;M9D9Pb>eSLth4bc+wCUDl|2|NQD}?iF#Vn8tn$#0>D;|-V77JJcpf@ z?|E5il1za6wnOYc8l14L_2uXr7^y9fH$my#6Kf(O++FQac*+%gx^_4m^aQ=8CkXsd zj5Apo4>jJZ*v#eLH7~OY@Zs)LfBRfX+7?jXZVgd2xHZW{S$g;_9 z{Gn{Sj1Fh#nZgz01UGtukd4<}wWQY=KSjLylkwP^$%d%AJuY5U1Q~6u2|@`SY?E-J zxGH^ni@+w`*tGVC`ymo~I>|4r1@>+}b(~gDE)4dodPC+{%a=q_GRUS925~evb$L>f z)vilH=P|Za<13vCsG#$c(X#@{yz48-kQl{opkjG{35Do6BrEeqO3sd^Ma=6qgDG8P zIJiX#qQ~N}$p+ofx-_a#yqlelDhBnN!;6fVCxS=t=0TAZ&@t-B%3{6AA!6CC?frL3 z*m|)lvOt&@yN`XlGp_}k^?|cGxL#)?AK;;%O?wU6B&k>3-YXAG2-^{LCB}|eVEY5jV*#2@MzdJd8}%N z{ViCuqi&T+VfcB6d7d_0p#3%o)LOl+Nv9$A6bkped&id5jy)1Ivji_LMha+_>r0RM z=zif#oJp|XS!`f>|FoOTC@uaGxa=NP$4Mgl=2OR}*cX#eBa?X9bAcxbR4XqD`~{8a z8e9un_5mE&caN@@1j+f4#q7M9|IK-XU-i$}nzd~%j8112hb4bEu8hQN$LCbACemXJ^lY>+5H6qi_%$G zSpp_;IN&4xe`_KGe9cHf=s-eLfv4=|b*8I;;iv1RyuT5dTB0`S0_Epl?hLO_NI!bB1tfq>$eUf? zihCNY98ziWvuVbqv0*oky>T;_2Igz%l%QC%7SZvYy+1La&Bfo6cZz|=LJOj{r3a6M zJu3>oSr*)sfl1BQ;3&aJPBs8@zccva^X8AR5#{6~$mbiYCXU~R9gqHauz7Ad zh^zQTl;sCDQ8A0xhSI3B1MnUx_&R=O8BZE2QrU9D!ep;_r}kzR1H4DRzn8C>C{Y-A z?*Cf87Bjjzy$>Be-x*ASFs6Xe)Bu8;2-BvTN1Psrh8?3 zvq8PCbphyW!2~Y&XAn-R4o(8&nBC-ud}aZj(B(Z-lG-=$AM}f zq2Nr&b`(sAgq}g#A``?E8#fX@UuGZo|2mHg`4K>pf{@B}iDLk#SD~9;GdZXeX19mS z`dtX%JU+5-*RSKpK_HBoZXxZM9;zm4=^9xw^qR-B0ZPOqdQj8gcOewO=#XWsUvxt9 zx&&L++M5vw@b4ika@GmU!l5j<+As))o*=^7;royin^ez5oKt6KaLgb2*5vfE@?B{< zwU`a31dlhwL*xM^VxU100>}M8OyB8LawSI^L=(>G7&c zGm#*p?{};`9lwTOCU^=z70X~QZ^4hNp5j@dF`*k z-%Jf?C(f;HZ2VCN!gfDBrMh!!-dk(Rt|OWm1IW(KPQJfnXM1YHf&v5G_j4N;l@K=X z|B{`s|H#e(b)MP3WT&my{+!puMOBSo@Eq-t;z#^HvU9|xa@p1@0o1YH2BUJ}_qJQ# zeH(ItkWUm9C>Il94MTKc{B&{QV%tP3g*j6>-YLifd+n!dVOJ|hr|})5=hhnQ=Z8BA za5R`9S?ESfK;EC+FJfPcj^3!ngXV1}Wf&u;pmMB7aYAJ}n&eWd59dy-`DUW(NnTU} zUV1nQ3QdYYsEi7?n5xPKn=>X~`u4~pfb-}cRa^IS-z!XVZl~QJ?KI`5i5FZs{y1KV z3treZZ;q8sj_#E;5mUs3E(_7|I2y2o+~u5Xy$|Y$@hqWv*~JoTE7*QCWrvtq4yTv3@yXiiLAjZW+40*jpcwvf80>S^iM^t4YuBe%o^^Oe~ z=GfHFG^4w(VXqF22IS=Ouq;N{ZTXSy=Si*JH9a-NbZ3w^^y{o#>eS4P+~m+ybGPze zd(k6Hu0xVLiiM1W?%{(!Rg0chY05hXa(wyt5rN}rF5^KbHV(e&H!ek;S|~hAx;TVJ zx7Eu6{L0UvD?46~*PnXl_%#)10Kam)N)nFt_YT!TBr@6gYam${OFB|nZ8Zw{lO-9e zO3)wvf7`LBLqy&B4i5xmW%M7eXxo{(7+Kmo>+2iZIlKQW!ec@A#ObfP`EPnf-&X8uvU0U&JA*2^y4k3_mnkLX%u&)w>EV63 zJRVT63}p!T;(gq&9E`@U};v5}d{83aU?`QV4$-IliXc>)AYn^*P#jXm7?*koc z)!ZZANxADN(L$p`QIn0q>Xx7&7)g*iPH3+}7yZ^`O;LYmXYdmH*NdO8Fh)KLiqwQX~i#O;$(a)Xc*OIFom z89NbW+ujOsFnVM^@4P~FVEP?`uJqqJt+IIpkNbI(=LTVeM?M9C`#(M9VI$e|Q82}h zKJUmgRMnkyrcX5Rz*V=gZ+RPQgB||>8H~oajl_sR3_Yw1IJv<=Bj#~3oj3Op4-hKNztvo2vOooSH1l=JT!Ikf&`)1-$3}3fN)r^6tonH0~__Uh? zGhz+O3dRgeUn1^mnf+N-+?&E!j86B5Q|iaBau7$jQXOn4=TZrDDUlv{75Uk2reF{i zdglpy1^?tzEZs6lmAG2ogm6L4gkRmDin}MbZ%{aW-0oqUv{R3f3pBe*$~ovcgX}cV zB~!|Erg}=3Z0S9mXphVw3ilo5S=`TdbUH>3C+llspWFftMNhbP57|7g-&DVLp2=Ek z-yXkdRM=)5B(eyHu_+`yKI9bm=1q24XE86*_ern@q)o7wm8pP_5UH=X9w$QX*3+Y7 z(CR1Y5*HY7#N_R79K>U9R;>O;mCijm2|g|GV4yMf|1L6m8d;5rO4c}BesyDdTM*}w zO^VVpFp4DB@OC+qzc*02M}a=5pKSW}%l|}`&Dn-|0HcCyUR4>bx|!)dX8RbWll{l$ zB@fm9OP3RrMa?$<6E{EabZ3x&pRUDZDeM*Fh`LYMs5xBMq<-)ox$GCiNDuS(P~&FJZyJVa;Cx2s;kJ2=9q(8uXh}_*OY~Nn_aA#p z(>}#j4>VnyyJ&({gW=E%uf()^K-Q0)U;_MygjJG1mo$moB6n6lM5Edj_AQgTy+Nza zI`yBg2<4Wuf7#-@XY7F@zc6MXlDrRQ)D8w08|f-jRq6ETbC53twlP*F@lcyEX=z2A zwCK3;rP2*UsHwyu`0)gdzp^!hT_Y)GX($^I-JQ)$W`UmapmyI zf_Rb={QR1|Ul4QtE?3F-llrJ9#L&N${f2xXFn0LfY!8f-&3t@Yyah{xYa&3$ZC_UI zMx9Z?g%OD7#O{R5e)}cSo%W2deYlY(hvDQYPY8I)LB_Xap$1I{#a6?A|1_iv*MkjAm8TH3HKT6{?nOYB~PQTM&s5w!NsNyHqV{M9CgSb{Ve7Pmp@nU zd)3-2NiC!nCGI`?ca&}2Q47{1WsqK*3g`TI6+tXxRZ>V5+kH_JxLN5fgJ3(uMRvcVp1xJ592 zdp6uCXaVML>sf3YglO^*U7<_mUEs5l=qAXyBNFGT6?zW~BNlWT_r=j7qZpc+3*Ar< zC)!(<+={;vCnp;4kjj1*v%-}y8{*SK@L~b`&!nz`TLUI$-%}l6Dl@nXQ5*D|n|J5p zbY6l3kv1!3=($C!TkCR%aHB!bGW5mCgZJ^qV;Jc<&%kKU-T_s@d)aaVIIsHZ(^6Zt zcG-v0iZf9lJa=})sn`jAh`8NKd?#sj;GJpbuQvTHXwPrio5w# zzP-X=HUQ)HC|!~_5ydDBYJ*wEwe3d7>%1%$9BZAW+=>WrRL)~0T)SpHO*b=Q<_6Z zoC@RH?p1~%0tmsR;4w6JSJB@AUqKndUNI7$@H(AmYsAh;h#7+02t;;38bN5Gpw`|U zQR|kA6^HX^a6dbBwP5r`@(vbO43b+kvbP(Sddd*jitK$kKMt15Gnghp^U=v1FC3}k z4i?cdJM0MZ%3|!oliM4(Phlr0)sM*9!7Wn+=p-c0_GKQdi{=3cb9SRxkglUPI@{?8 z3nLnCE^rA4F&H174Tgpbir@q|7`RC$kI-y%h40+RWZ9D{r*Ug~`__BUtAp-9Id}H*1`LG)--zFYfN@k=Ov^u^o!Y z@CrpdessBGKP;SV4b$I+5?bKr4n@jNz^G}?>bX2S3OnVJ*q4l)Oo8#=6;rw$RlsMc zpkfI4?BFR~fu&l3GgOGdPX(da0qSk;IOfeNAc%Wl=S%jbEhJx)-;aFD|*qA*~RU|Q>-gwK#ZuV=vH@KUGvM#VXNtI5%7&uc+Q>*ZYQuBW#FDYM#I~AA`2s&Pe~uKJ*$K> zePrER%t?E5=tkiFE2;PLeBbGcmDmI~V@z~M(9l{uFZvH0!NwQ*(vZvHTnOG*ylJw2 zFZv5kFUOS-E}r&mF8K|^?;FJ%ed&I{=o!7pui*Z!WR}{!F)y{nfbY0kyj(tHY`=?H zn$$v8g>zmjq|8qz+IZz5`Ux&4h4(389>PDt%MEx&xLNB;+GO;J4u8}w5!`gadwRI> zcvi$C z+{WcCPo;vFje3iOq{qvUvna+{xu)$o2 z9N-7!O*wYMO=*!)RfB$b{c;`5_w}2Hy9b(pcD>IXfjHn%bFna_aZ^g7z?x|FZ0mhg z?ZkVm53DpJjgROp#a^I%O(wd2^^v-1OMfZ8QsIHd`8O-ih3+1{+OmK6ob=|I5K z)U0ZhEZu+z&3>9^k*Vv%9wH%yhl1>2j6-EE*x()#rty_K-Yov=MU3xAIV+TahGv}V zbiI0=C@hmwS?^WrV3b`wZZJ+;)mi)~6U)1hPsVYlSur_W-qz>OlA6c4yVRD$*unw+ssT*w z;>G@w-z4BLv1c#O+%oXGyuS!|@4|Gf#ZYP6MpuH$J2@`%NYMi8TmlBQdm9HbZjZC7 zLwd_3Z#7$5z7>d#=Ia#LL8Ht_wxIIPl<4#3EMNE@_i<&dv3FszZZz4a!M__26oceW zfKSFt%Eb0B6!Mr*IIP*~x}^I!Cha@r|AOVFxp|mwkfc+ff32RjKuOHi$U`b?8r_dR zoN5hrjqu(+MgaR_X-)zPQ|Q_r-E| zThf-G(ehXqr@-8cCC6zKTzhFh6&kMNA)C7yT^m*%#6gx;uvf9{m#0p>^xTsebKr2A zGB*EJo;#tzwWNfGRlfXXYo$Z!)FiUOZaf5&ow#rj+Q|XxMD6F)X8b>#Z{`M3k$1RX68QH_1u@OgvsE}WNgO4<@_jx6Y>QNzbFKdOXn%d zH8o_esMkDL!)POvr10%!EE`Y?e6i7og^kl4HYl*)#ym|usr=p&{<-YL3ia||XjDTR za9j=JtzILgUQHV2cx_(YxNC4#%Hyf9q4CuYmgBU)tf3yQMsd6OF5chbS(^iWPfJ-> zGgU&)tmzcH{_SYKsot{qVLvNWkQMAoZ0r14kZFRV+X~#&{nhiE9gRjoBr7;cPZdt{ zX_KxUuiR^#o5weRV`;AxN+H{B41&LxI{RYTEaO(+DRs^V= zj?o-qhfJTN!{Br|-k|?}oBmld@ac%2#sk(2`hZj$=l^JF@-LIf%*f&I+yY?B@E^H0 z;gbtie1xA8#AY0nvNQPGkQ{9ZmEUVRmM1}fcQNs@t|Z#2aJySid1ZT=yt2t|Wk&LL zcneB?hrD@s-%T+k3nbNe*tw8M&We^D89FRbqm!WHAtstA+)1Vy5l-fDmw}|Is*0(% zs#7nFXe*nYv$~`G&RLml7@ZSlZC@Njb7WU@iKnG1nBD`Iy4e>3|7Xjfx~=GM+&@El zWjuHY?2!-HG9=8DgGt`hV#)v6GQ`}*n*+OC`P?zP^EYVY<0U-C#3QRLjNjCm?Pl^| zaIas9tM>T)op46oDATOI!j8JbKi}vWWjL%YO=_YE2Bov&AlI986n{JLvkL*5J#ZBS>0f;x3=?AFl873SI%I6Ef zl-5ywEe7EipkAd)hlG4nB3){4I?sS+HT^5u27dQ@4CaoqgWhR*suz%KL!~mucfDZy zzP@%N$=VD^wuS$dY=ey}pa*R@d-*HbMzp6|BL7_3i+)^;Y3Q?HuW&s{(L>MNHsskR zW9oO@KHhty3)>RpC1Yu&|3>;HJXX|~jL#m*sE$5TrLMPV+p!m#SdpdEo=8GGFH{+| zhmr-{K*|OJNxxnrAm^7n7!;#U+|wOwJTVP+jxr36fHo~Bd@Ob#JS0``2_7 zk!3EjhpL1@U$fsR-7jEXnyW+(mp&cbF2ZgaPh=KVwDc^g+e#8xHxQ{1srYmH9`NPe zA^~PtylVQTbO;xKu)^kh-!AVcS#zk#0y;C!riAD5hR;DYuzIi=m;O+CUm%<=XBnD~ zi^BtIk>T@xIwYWRV3UTEdImC$?az_dOR!i_`)VK=i((p04jpdj1!i{rwn)x=zT)vr zbEMxVb(-;CQAa>IY#(r1JM+PbZH{^ZA%VeP{jKmEPqy+g8XR3Fg#SMC+P083UPzaf zMf=<&=9S?V#Gdv34txeQU5eaLL3{e1Y|~~jikd(4ik-@}VR(b%4oDc+j|7L?r|B6N z^c}6%y73tdT9-ucfVvq-Gn&*6Ou6M}aEhj{O~k=pvNX5#0%6L!W|Gw<{Ig{6daqp* zjsv#8{q?*ot_^K7BwfSAP&U70WWrAd20}U*r;HR$5ms}dNK27MoiAuD^d42?dtPQc zDOa=N6}am95Ow)EA-pXbFfYS(#P)yPD{W}em=XFcfXRW;Yq%iaLkF+?-W{ca0H z>7@G{egIO%N#)9zZ6peK@XD|AXljhX2l3`WUW}Ek5a=^21gBq50NHgF1-B6M*+(u84bj;0zq>$tCR$uS|cU~V^+AX*G8@6Q9 zc5p!2(?7nlNHigS=UBBh*#R0dplz2tjgpdOJxg%~oZ?VzXjRyrN6tf*?a`PSB6)b{ zI&T(aj0zg1L#)K@1bclto8TzxMrRFL_K?5upm8p1*n!~LG{Sal0o-jxN0OHJ?tw|G z{yr~UK}j5jL14P<|m{yhn`HXWe! zz5u1?|6eJ+jlMM?srGNZKLzB}5I#Hq1l2UnB~%e0nwpTTxJk1CNj15I3@t3%FdVBA zc!W=`L$OsSDtc00j;2eWM_ygPQExu%s7@a*0S6`2z1@;STe)b6sQA6xz5-$nT$}{D z8nMgGc%61R(QwEK*pvViiJRX%B+P8ZoZ|7%Ubs_ugNiZO5oEyhL-qBbgFr zc4W68wGxA-f6&l(l*r|H*oZ+>_Z5Nkg%(9^f1dyx#wHH>s-Hho4CBNq>+Q31dwF(vs#C+Y?!W@M{8h2MDJ>T)d>xPhct!-3AIB^)?{}T-Xo8v22Rw z$UU3F!9+O=(*X)u9$)c@EE;ezN<5e~^tHE^&MzbWiqk(43dB)CZK$`h&VgkLPXgYQkd-_kB8H$w&>Q9=P|Mt=j zI_U=^2GiNYKWSzivIKK&gM25$ps=p9<$3l-QTp+zi=9cAC38K>3FNLfHEuXj${WX`B=_P!w?(yrdG;?#rjTD67 zZ|oqv?CGGd!lG8C{BhwFKXl;GYP_WG1(wf>l8`dBdSJf~_!sim|NwrBJYwGF>ulv<(9CATrf5B#~ z$(qL)cxETd^Fa17_DwiD$2zC7BF{)mczNZBK5&taHd@_2qo}|gEE+u`(%kFN61S{4 zChow+dvDfrz`CZ^|K-nO*-f^Qs73ToJ`J)dBe$N+hIa|ivZ^8=gF&f6GE(xHr<|o! zTnLb7#xL{}k_?!)9u(m~)}SvvFU{zGd5n9}-@VKJE6=Rf_Sl61{idY{{$m-A7u`4V z%{Cwu3G;A9{)ZziBL^90$`i`~DWp*^^p8eLsz(!B(T6O#YNo@Ospu3BS8)Z&I}{g9 zV_h93syf=qrypia*?B)@AE6AbKSm!hnMwv+A*B-OK1LtFl5tWsre;;x+wZ;dr#-Dt zfgyTA7lURB=R8RDdao+m7Klo+d0Rj(d4AHpJLkfi#G7Wl(~?|xP^*}{H+IQVvT^GK z6@3@x_}-qFtkS~le(YH-HE=p~;oR5uAj96)(`_C^aIzq~omXIn+@w@i7zO5dYic8(W25sBGE z@wQPL8-z-YYWN`~Ml}76%sT_L45{LCoPg))p>)FWNl!Yt#*0Cm$WDT3z$(t&X>SyZ zP^4#Xxg=Rnh9H^uq8TJ8tkTrU!Y`AHqmnw2+x01dcX!GRq(9vD10Id%~fOoBIqNxj{i9 z>V%7^x1Yl;(-;*`uZKRPFR<2tZJo?!Qj>LifDkSpeNn0qDN)|4R4&I(%VnYxDome$M}_ z{RSf4WP7AbgWnCn*N%bvKPR8#NO6Lq!sMdQUpHPSQvi`7*P&gy%bd9NL{Rt7>*Lco zL%{;#XQxkg3E4riz1y+tjHN<6yx2MeLC3x#J&|~BPbtWWs4}<&qdN8eh}Syh2BS9u z4NVg-i&! zsd42(u7oL6++t)r;jfQ$LR01?eJ}^yLBrM$kZ4Evs=}PcpfIn|5j(|x z3U%z>zTzOMkSQ;x&6q#$_m;So_Qp#&S@wXX1^mVJW7#1Dp=oKwtM$S!^pO9Ne?@E6 zKl0DQc+|2@M{LIk$R``OvK?AYu2TU0lnlAUc9ySr(wdvWzh+wkHlfNRXk0yoy({hv zn1}*;s-dKse&br_-_MmEglXe=$%*|tR+P3#LOP~XN&l?IlYxs@i3sE9bZKVVcFIhj zbP%TdQ31@xzBP@7#r+ZgC9S69^jNO)tHcoka$1$$$W!JOOqfv+qm2mS2r=R;euLtq ze`=;BfMszG-Zs?~hs8*%6i4um5LO6@p`r}-&ut>N1`&r6$)iekV8EIMK6yYHW9(`c zz(%i#dX?`7d>)5;qGk)(>*=#_HwwFAbR?uCnW|$}?=cNv-SgL1?*1kKeho~{6YjR4 znQ6^3?+oSX`RMYw(=+qsZ}tBwBKG*($ICZ%*>Z|nz~=jk?6(jKoQ@_c|anR#V{TmTJ2ZX3*h<}y-L6`JMARy{^VL#IB0`Vn7`D3`0poMy}7${Nuh z^{3m!&)NJJ%~D=5TCoxR7tJCzbXfuZ_z*oT*Z+3*QdkunZ;z;NT2O$X+10{sFkqb= zeSpDkK+RZuT~*^=n9d8B_#cLg9x?x|{)&x6Pf@}(!mX%QYy!q|>t0QGRf{S;6M<#U z0HE;=cL7tmFt59p{hMMpB8dQiX35VCqeh>1o_98QKNNqjwf7i1F#OrsT(R-G6$y53 zr56HFfBsZp^mjfGq#|ax!aO)MEh7g3C)#Vv;3%ZwL^QBd71fK4&BzO^96i%XvK;JW zkCZ>^kLL0nFzqQ(&7hjS$vXL)k^^!@km?y!_H+!MoGsAmd0zG;XDF2(^v#<^r?GCQ z&&v9E=bCt_2$2@r=rSHzB|yb6Qx8oZdp}CxX?r}UR#SYj&ia1sXFSD3ckHhTf z5KP2GmuY<(Ri*Y~(Q)Sx7S1={@SACY4gWQ+WN`yAGXDk!qe+@3g0&nRq*j&Ge2BWmHZM_l zCpUeD9apo6iLemrz6F~*HH|YN=|8m;9CvgDz*9FM`|IUYXFn0XAVY2Ff zwX;9>w;6ZSXyLk?meNB+OT#Y{-_JMQp()oyv}$xU2DNSE=X=gOXW0K2GR zGs5+!#z%()4NJGL3P#63S1*fl^ys(o`cubG z-LBPAEa zdC&Uj$A}%6q*on)N(q>Pq>B|_Am0^@j}=5LqYhB9fa_0QMpsD_zzWce;gjzZZPow;_$d3HmahjV@h9@6~elMNP|en9@BS# zt85brG{WXsGR(U|xO%>tTz>4>DG$UWy_5%K*7jNZz;#12O{9a|a!tpX3 z9>A~5k!w&mA+u_n<7#uwIVhzZW38BQiRLXb05v@V1JL_F! zN-o7gECQN*9#)!o0}z~!r2jPepaB7zd|J79ZfK{)QntPQ;8eQ8u4lBa^BtFq{xtc} zW_H1`J@1(gR@6F$klRYd&ej8(d`N`a?lqon>wK55s=bk?e7H=(1VY^!zk)0iuLN7E zn0H}>Kxan&x?-(jtL9#*)!j5lFVUPh84OU83shhSJrvDJeY)8)AA{OwMy2c$uJw4r zJlkzxJ1hh;T>d7%<56Yv$KNsB_=e@^_otT!Ub@!(kH4c^5~iv`4iD(%Nr60Zn$Lmc z>w{sK#i+1M5c!lyxYsDag1{8Zygxq#cgOUxT@*9F=!hl2EI;vQgJo@HMBO{^Qku_D zLy_qgLsd~}df&Eb6n|TzFpRhZ_qim9>z@!s3ehER|E@LU?8`vhRKQM(_`C8kEdtj} zUw=gK1{u}P+f6IF|ze0Pp0hB%hp!CfD(?Q?auko)8NS3?s18$ zoVdP}z-EW<+sOb!o&vUSizoIF*&OoC_4D05l><9BzS2J~J~p4b5F|}yRrGJSUs`Y} zt|5|ByT|5U$F*=cj<*;qxQFx&7&0z{I@`t+g=tp)99~aX`r8jbyBW14Ya`iLAv)*1 z81jZBHDg)Rt0{AdVcQ@Z?aYC1$!P#|I@x83Tmd-qCfE&w$0s@GA38lJjCV4EEFlCZ z#)w4v2%Ff7#iNk)Ubm#PbNmz-!YmivL*n(tla_U-)sTTg$Hz zklZLp7uxIJGaQ@r{#f|3WOr`>IGu%?jTvL;PfuGz5_4?pa0cv!j5o=5bwE#>%3nQg z!J|=(7=K&%X=exyma%0&X&HDPf-&d3S?nO~PXKUwl4rr+aJpvyKX7{S-*CD{Y3^Te z`tM@0apk67l3nOtCSpaD(H2AzVkKe92)!cBFLj`7AYrwW)IC$mV z(R6(pcZT@OwW}4IgRp(P zJyf#7ks6ltNozK_{c9x1-mnvWJGk*5fsdYIK|ApT^t5^3UVZeKMZS!{=C@}07msA^ z>|9;2y8r}U^k-Eq(*!}u2vy1b?5V6yyAZ(6sWbT(oQ@p0{4arz{3Gxv0D)iE;)af5 z2GMW$0kH6s#{=>-RfEZN&+NDcAFnzd`pl;FP~8eWfn z0`PRE;-w_?q!UYJtm(La@N`6ys6TcNXo7~J{FcIhG__$hrRLxN(B9qpq=$jo2>rn@ zWcEpD7rM$B$?Dv^$EYM_02QR`Xcfut0D#j=%HOy;Fea7=@+RBidEIm{wf?~Ae9PL6 zp4Qe?#%i&B&Gl1m!LwkVYJc^#9j4Oobp9FU0X=OgwV2(#?g`aG2$hGw20K@pJHHa3 z4*+`Fz&c94Is}_~e&=z(Ji_`*-S;;^AIgDeBdAZBXZK=zA(uYA43^CNX@c>xwn{_}H^qjd0z|l62UEgCwaR%FK zsx4r(w4FLP!+w3W*CLSQqBLb^aomZzWEJm=x3@1zVp=M%)>M+?Mhrd$$?Wn5+qJSQ zsnH~FNs~VY4N!sf26idC0~IiK03nFW7)Jzm+-h_UP?5gE8H}W-m1r495fE9TC3nh{ zW^i0hH56goH+qg^V887K~f7)dGkEw-!qq(I)&9)@K)U@%hQHm-Ru zFl{0Wh5PoFiyo|7uvoAu!jPXEj$3;=C8M5Re=*s%IL$L!%Go(nnqU9^=uy!3+g5SL zN&O$U-;BiGC3w88kHzZoRVdwNQCcIAy~6vWV4sJYdK0Ox3EijY+_|Ya`4a>!GFQTP z5M}ttAcAU_V(6JKsB4o`w&$jtg=(q4m-ShY(G0ToNl{nETbtk4;CC+ z#DJbYOuQ9qyANCY{!ix3mbVqtsAS;YP)2tr0?ziRUiPl`kjMk}Xe*i%Ksg&Cpq#B{ zt;83tXQJqaI}9UAz{h>cCzt=N zp&K^CNvE^L>4cRb`lyJp;IDc%(GEa88{|Gdv1cxZZgUId5ups@qFF5jM20Ss2eR8w zIvrUBgdcu(%Tqkqvr;nh`d^`siM86jJcA8JbG;)s8!E5RJ;c1zXO;`lgcP7HLImD0 zCYVlsfYfHdw{xq>i}p#8n2yCBI7<3Mg4I)sfS?Go{Yn9)u=IHjw5=r%0&_pmrp)=E zHEY858ciA*koP%WjHTYq^uT`cs=DXwV(8SzC;~U;C~&`m-|*j$#|XgK?6_xZ%;Xk4 z8p4%mCj@$D$1uvh9K&4-b@f6(pTF6An|aS4qnK=emgj||>}DC|k~EAOL#~&-LRkA`as9IeJ8tkk6#YMOk@$&4{FvHlJ~M-)yUymCVTjN zeH*Y$3jb5jHUqxe-GY8I6~By7x*@eV0dzu@pq6sZu0IxpZ&wmiazSJyOF_R(I;dw{RT!IARlr&MzB8!oYT}ZLUN7iPB1brCPL$~8G zae-|ATN2%9SxjGMHgD2Gc5mhjt99^-#u+=J+nlWhtNWed6rF)SrzhFbmY8@;D4(C~ z$w?z~Q9<0Lbp|5%?i4u@iUJ%&& zgH>`_-1y4M!4koac9$a4QACNGm)Ey=5x*juH$}LJHx`UhLh98Rc z)KqGGr+6$&=IHcjrWI++G4Z}HBC-uWvO=loruIm4j-W{$n`|u~*h7Wb@=EgBwVRRi zUDzc{PY0NyTb}9ApSsmxU|w;+xxnjKvB337{fQ30X#!G-p%bT&pICs$#N+S+VMxv5 zp~O1i4)GKVHlYc;zFDJC{2-1-LO@7eifsF?YGltt1aAA=r0;S1`{iCmFsP;VBUY(Y z!G>vT;K%NwN!Ofl%%+_^B^Aux5ilQc-wL+31jyG&kzt2eqpTAYjBpLVaQb<}qLXDH|_cT)U9@wzbAg$#TbifGx0;w)W>#u-bc^3BDXSnv{c zTe>Ap={sId$9ug}5Lw)C26WUAB65N*(Q|tAzKn*4XhPT52C1qxt%OJl7tav)f&{F| zEMi}WsgN&1Is)6Arpa(N4?R>&lSxE0A#d|FM{2?%$Bt*x*AHHV*+nlv>WA$ulEz%1D*GrG`>C~cgO{PYmu$t-V`$$9U2>=s>KQ74 z)?z8hBgCf#XUIyS056v`T@4#OWxEvoJKMe(#mUuLd%navJG9aeL%eGSWN{3&!B4 zL(xfCFh?;_PdrBDc~Ze?57DHOqn^xlgR@51YKm!8iG@i}&FKH4KGGPD|CAY<||>j&OB4t(Bb9nu_&;9R+oY)6fFM;=;@_ zws~8Xb~N>kOLoxk4mA}77i4?Z_6|sOMq(+dy(m$D3L0vmleCr+c$W+;-uQ|v&=kvQ zOK?%vDT3fWeh{sos168;N`tkP}1Pg=`GWY(Br`ugCShMJ1nl6hAlD;970 zepm!sphwq~x0bhoxeTpBycU;RCi^=p=6nhWN*oD3JuHjCpF5PYAA{&~{lX!r%%87t z^cKW;Vnehq)7ks_IT+iWR0_h7Pc{03o6u?y_{#))FwE^Qg33{Ubx!vt$sK}v#M*Ft zJB2|Z)`x*U=xGHE-2SNQTD_LB$*>_x_IFK9<9<c1_Y)E&!iru5Ee25Tfr|K5dhhkSem-8vCeNgv` zMgof{=3X#MN6joorvWlhMdqVZZ&>aCHla2lsQ(-tayCM6J+>a02!#P^AjIIoj20N0 z$Pr=*g3AL)>D44rmm z`ot!t{rlTFMl<0yj+->cK(AzN;fZzYFh6T-rRePwg%IzQLBvkOuL%=5K0V+~2a*=*s!J z-=8fV%W;R1gqnB4PSawIcz>}b>-swF!1R_I8cyVosW>vTnc7R)miueiL_yym0E9%J z_(s`LHXt*<9#zg+pj=B%UhhY@m+UCmn%y~)&?@+n%MF&Dc0@1_b*qX~t!T^0+9o^j zd6FfaWX9wz(xC>D5E3@JnTJ$Iz|4ZAAKll$Uk^{h;K@(C23Vuo`4_Lb>#{z;qukcp z0zEWJ%+q@G{JOc5PzHKdwniMn-0zrGR<+xBtT{kGVX_S#n_*jNXYSu~*JOQ|oSf6U z`!u&ci3kc7BRu9`zq{q(b>sC$J;P!3MBbe8>p|uw)TrIxo?~^>9-h9IN^w2QoG1=K z;wpdFqg>Qm)3$WPevnB#2b{+& zxTf$EtS%8GAw6>W)Vsxl3U&7~+nXE3M=0^*=4Rs5l`dP`dM=JupvK#&Fzd|(r)=mm z%Uoh)VbcR?XAM8#P6nIA?zhq@v{nukxj7|tSEe#BRg-V37p23XuN+@zr=XVUHvdtG zwVtbl+6wrY%gtK%2W`v;yI~0LQ$;cN*_u1t;6?&pXZH7SMZBlf8n`c1O&44cXYPJ* zEv=wt@LR8KJ!eK4v`!NA%VKD&Bev5)jmlvm3*bVw<$?({9SeDdeXy@U;L_5kTC`+) zX|lEq@a?~rPxtL;WK#oAb~VrOb!aHY471(>(L@E%!S+9FGYFj|E?2}50S_h*l9qp0 zOId633d;8?l+(Xc-?Sf3PW_&|#&)QEv;OE`mi0!O`lK=2=W$f9;a^&JDDukn=0HFm zv(>%jSg?5<+1baEV256Bx?0x~?P;&B&G^_@ zYd(KFbi6!hm^A}Qk;=ZS@3XGC@{rMfkawV7I}$m%;}29V;PcG3TE!@fGgpXFee#5Z zB4>q?Ob5$PeZ`Lgzb7K(7Hmn|FT z@mM17NIl3%@?33#M5?slT1ky3d6BeM&N*KE{gP1fhPC#Eah5eriuG-VGJ5Wc~-xUnenVK+;OXb7O)LbmwB+lk=KWbD2vwDytqolpJ|H%p+)3alze(%`wybPUN|%=s_A~Un{G_LsIEE zu~I#3o9E=P%I2k|WNAf)8q3*Fbj{N+hLcG5f4yu?nCoEOBivIYxY1FMXk62%OUfHl zZN7xyF3zpcK02e{nT3uF4eP9U;A@A%su%!=9A%fK+~^C{)P7AzD*hHW4K$EF#9MJ7 zxLAwvYAd3O#fnoJIL$UA$uG1Ew4M2o{yH9;bGGxc%ZVGFknCSkv6)|lpa7*0i^(`& z=o{hb{(1A?c9pR82=GhDU%phh{m)-K=6@U5``Vt4yUYlmIdTL*z%+BrK77?NX}hBW zAxjh57<%ZWM5i;Uj#h?T6DYx#lalqjh1P_+nbSayY%&JlD;7RfXDu43a(vvb-yx`>PCv9si7T})KquAgQX3DwNlz?4yt4pv13GaKH2zz zC6tfmM2X%$zq#4qnGW0^o!lQ~`{zw!%E5f=x2!MBBv3Fq6Wz&caTz(otLP>AZA-`AWC_c zZm(LKSUVTz1(q%I`;I34Tcpsdy)te>J$7yYiRq8}RvC2;eHispe#J(=?XMaV65;GM z$(L`zwzch0prZkqus*NegW+qtTcbVC$Ko5usC9c|JlU2foL(LTLDAXUvGZPrwnKLdjl^=whj@c{?|oKbIvksf z#SlccDwdzY@$jxRC_^TH2;Cimi_0Qx0cHJ=3%oO=}n-SaM_l>3+_|VjM$`EP0q=QkF39q z`JG72G&)Tt;jCEkLAJCoaxA{di?csLyb+tm$Z)A3ibT;=u5JU0&&Q6|KtIwS2=`*t za~Zb4?Wk?k(2jUuZa7dADm{Gs1Lc=Yr6UJTxP-#Oay^oo)e8*M)}uAu4fZI`P(Ah- zy!IGl>7~ec1d!bId~$1`;ubv|Qz$)R;9{Q@Oqb2x)apD%Qj46uQY^_2%)K@uk*L_f zCnjS$@#xE?7mvn#@``dRPWDU15iy+fwB9Rlt;#sH5kPIE+9h2bo6JlP)X(xNOeevu zM|zX-2MoBD9WjEU{%wIh`W(+d6XkPJ*nYMMX=8DH zB7eCz2z9je$A204P>IOT-n)=@!a+@K+C}&8>+NQ!wL}6!5n71b37%0UpA4{XhTGbaZ0ZBqY z&(yZz=#R+lYm=|IWEI_Dm%Y_sIXLzSq3!qvg0~?J&QpbxKO`;5eyfGa;g5a`*@!*l zqHPnBd|dCHcPQkX7gaZ4#?Rf?2bRY>m}hN&fSJ9O3r?8=Cmc8UX}zA_ycp@deyT_eo^BPY@GbK$u_Y2R;zdNS$9Z-%5jSd||M_x_-{N z15;#h%jG4c=CZ1_N85+j~ zjTyEWhGAF-aP<>!U`$U;vplMN56=?Y(Fb8=Stqv$C@~3Gv8BT7ewDP)G!8oxjS*(( zNZVz>;7gCZdQq-r$KDNz4R6ghbd~`F63l?@e~RqGB6P&ylR9$cb7)p)hUs=@f=G&Up$p1|D6?KRF{$zphjAB!mN4N~`Vuek{K zrr?71$tmo4r+5ZdP01B6EwAO4TEUA_$2eu+6j6-q9tc<(;Q5fJ#&Y{|#AQVSZ{(M} zQb*Vtu_S4}1PaO9xGkf;aOaKT(v%!<1F0vE>bXycNZ_r*Y1Pd?RBd>t5Z_iLYo3zb z$StrSkWP?ntTq#j83I@gYGs9!#BsDC`~w45nrL1$%v2!~uz7m%npB1j=j0k!f9~d7 z8S+jGBlJWt{qE=Z1EPVZO(=rQfbS;Iy1BbsclAVrUOzfxX34Hzox62YEDJwM1Gh;> z2ue@UN`M%E1mP#V8$2=S9oZU@YkHpa3#!)+R*JW0JAyly)@aq}*JXNrtgFnBtARYl zQ7x*dgJIWN81L=Qg=gwLo%4z#%lyx+ocS-h_sxvnOji2Rg}mKqSmq#0n)q$_=cI>s21BHyn5Y^UI3egd`s-ugC~aAnn#Up zgs~#BF}5hF?O4}Ud1tdOOpzXPAT|?TV;)|dcV>HkoCh-1#Lhr$Yp-7M1hW*1&Ea}3 z1fHZ<*GCdEj`2#~5C-8#{e3!WCLsk?n=SdC+%Rnt{qy+Yr6pgk5tG`$+{X)s^>M?b zVw(py@A5Vw7SjHCJ!crw3OcYF7DVrm0%Mj`^%9(6=J_v_!*1<>j#{Up3{sjM7 zaKq#&5G+VP=3J!`Mlmt2O^}*5m7SMPKt)uR0%r~`%#7sly9tDaSdgel@`!7;>3}wJ z#A1}u@R+ePlfi>RQss;<&2g0|(LYt7xp&$K$Sxl&_$I3Vn=B7mi5bkgT(TSyb>f5R z1DP)pLkT0dVCBI@#sBZ|Dlu5?3Nc9z3Dn^9o-^+P)q6YVK1BYFyvNz5$xe07+TXd$TPiLQgXN@-&O?gvweueTHx-b<+VF;OJ-X`MV*s1QhI}{ZpesZcsjgmajOIQ%2p@(G$WdHo&_R;&AC_Db2b>P$YXBJw^l+hXCr^D)1C zN%dGO7g_GnyZS=zx+(tDV6fBaZ+pbp4orF#Af;8##%#=yu9n5IolV#;gtEDxE4mu3 z_iC70qf&W(HKuz9{xAiaNqKM8_A5W)G%h_qw_?V^f z(j+QtqIsgtLKs~KxbLH&yk87ob*Ur|XU&@BvrrKpwd_p|$t4>919Vc=krxkA%H(>W zs?j;~)Nv9=xPOSU1{qx`ImV4@5tvQ)UPSKSL4~7yRKO{k ztH2#)^^~SUhGfItC8w{0+W%dMSzw3$L6=sWpVwk37ueozMz;0pSmfr$4e^Md-F5~V z2F9BzB**D&EkrgBV?fF{&nsETu1pUD1r~AHw8I0L&T!)H5zvLf#`xO18f0aOZfVCD zHH}pk6(y2*GaQ4*h&QVvChQqZSieiL)k$;@G~dgc0e?3|4|>LPOLhgY4$ex|v$gci z-40(MTkj5?cn02;`l+?{^PPU<@ElcrvHu5q-W)=l#@mfeR+;dI5kBi;l75xh@|B{i zbg3{K4AAtWm~Z6nh%$rUQNbM!Vpa)5TfgU;6{ts%?jq@N1G{*v@d)qsGD0lh^LTv?4pwNsh5bC%Be!Fq+|KNc2EmGY%25RHu zDk1NaEBnUn4XK%ZwpMZd%Li_%TVyF_4t?4635l*jBe5G8qL-Y)5y>lUx1@Hwoi5vQ zmobTT1nNral+@gE@-SgbX;BEa+jvlZV@KrXKt}Ba1xyhg<%1JXrcc$p74S-@0quwA zSfbS0ue--$yb(pZKp}g%RC0}8!Oi0(FuQTNrO%Q3fxm0Y_GOP zLtTOKP#e1@a#Fj}$tg-Gfe-B%860s+^e<#$z2V__6>V?-KMX=RU?#TsQ*q({3y#>K1b@9Nk~k4kRnTH|?2Vng*0hykDNk22gDkbS9l<)ti?! ziSz;<=XPpYEA=5*rA{3A7M|m^{>G8RkmUp8z&KrJm1nLtuG9g3<+eI`>s@UMm)7!t zfod(klKn~Pvpvzqq<2!6`@qi{2_d*TxCN8u=a+EzjR^E%ww@9{BvPR{GjQ}~?+COj z7uRXYI_;h24?M=@;DNXMD2!ufS9J|fYWuHLnKvuFa8k3|3o4ag9$r0CEq<4V%2e`o zq8t7#?MxUGbQ|5b4g2=cn0NEtYRHv=Q~v)&WTwsxDq{k4%e(^SoEiT&MP`6b2SsN7>q4LVTlQj zyzb4E)9asi_Nztq+=nT)85;w9DCg+?%nnOw!3)c!CAcxX>-II%tg}>R)BftjhUP0( zaGO$_0N>Vo`n$(FAKqNeI6p15%}t6{ARyDbqYk3ds}jm3;LNZx_^V?t{Wim+6&~p{ z7H>JyXG!1temG3*Ai!#`$5vgTi}M)+wlwZ=MkEDR^ntC=aqDmH9W_1MESMRJ)fHq` zY?Mv`wHQ((BuR!N%nNlrxrg>_A4uJ~d6-$Ws56WuW-CCt38X}65#ha;?|gAY9zV{_ zP}9b4@sz+YZO1w#b=opsFo(E{Bkf50(Y%t|OB|tW#jZf-g6U-Gh-9V{>7cLu*yYVf zMGwvJs~g@nMIxt+k0B_`3|F=0g-)ws75D7g%DW7&;3o>PMaF^!XNX@?s4$YJ&KhAY ze{HMssEHcK7H756A+jq&OJU8a1Xrr<-lFgJQx8)Uf+c2q)RUDE&Wd_tMug?JG*4bJ z&eOSHgu#y6w0=~iX<&B2n+&Pwaux;<=W8(h8Pne^_jz&s${WT0?>~KS3KAX2>ejrr z3acMG6(3-58AHq^5=vPiP~F4$nK5jN?L(P4I+$egHWKOm)S9%qR6$ShvUEN>^KGdF z1>RR;CiSaOQYRY`Qs!5!1C6)blYG(IiuJPgHOXr40ZN5E1sE{<5SM;C_GWQ*IR>)_ zWI2uE(_YC8OpPhgr!?ZJWt}6z31ZtbE~zV2BHLmU2Hwqw=bhw&C9f-dOTvTc>c0fp zuNg6mLSFnM^shc2m%kSgY4%xuX+@hiWG*1aCJ5sciF4W-+V>?kOnAE_|FM(chX2V- zC~8be{8&$?$%f)-h9dG;Aq4PfGA2Jaup*!|pQv=#3E#E*?R=8%&T1xOf|mb#5HxXQ zD!@E(Y;7a_rt?LOD4}kWjZuj$D}TvG%v4DTpZ70e&+DIO^8a*s{&fi?Cugoy0LE_! z(Eu+N{cryR0=nrv07L4=hBh`vhQ`)_o?$0*K-;j3KBGRPrGpy_;3Eq|J9ASLeSPQu zkwa|3IJW~#;_%BG!UZBElx`c;<0Xu8860G;IDJKKty#i%)Ni{Td${xATPDsAv=>X& zUf=fS3_Q(O6-|6B8ndWd2FmI4d-*v9*Pnjazr_0ZvtSmu%ahaR7TI+Lkp-G0Qs;1=Via0W~!+ZclG5~8n#vxa4b!Y zMBD6V5;By`Ad(pJx>^jR4|}EfjWU(Yu89s;G=3AR(co;F@G+kaHL>*P>8Rla@nbW* z`#}%iOWacnaimN#XLjQ5PyXP9#AK+)C=*%uq$s>ya$em&PV{5__I6iz!;y{ZkrHf@QI6~<}jvG51c?VLLd@lWM8<5^a+J0 zuWpSUSiwb`Q45NBjR?`=In1aG1I=NG-U84^M>75>l~1Qem29E<>kT zjPQ#7%-L`t1F(dIy^zXX9|CD3Ibgv^i*SA)Ertd=|9B3J*XI+faF-lOwDY}q_^Z-x zOiikRHGWi0h6(;Ae#CWX;RquC*e~t$0oGuJ#fAIB4zr`8*WgISll3|Vgr=INRkK^`Ob!I7}w?* zykP03(7lW(pA7+{@H9mdU6If#hz0$VHwO_lEi2G7L{-21 zGMJ=^;$y1B-#D>^pmhrzJM8yoPV^bhu=FwO#70l0!ELGJjTA!IIFgko^vG? z%H?+DRj=<(^1kzaUXrOl=XzbWGr#Rm!I>FUeg@%U3Zc3U)n;I^84FWvdKm=%3FvPh z9wQL2)V@-38DY+>i_bp&V-LZaT#!x6Owk@e4Szli7P8f}{j_&D~R#*GIJfruLG zTfkt>E0H2{iXvD*CyaX^#?BA)buv17jkt@I7Zdi%bQ{2W^${ zNbI^O{7dC)H0Nuk8+M7RSCz1lhqrFRUYWM}Ta+Q(X)+L-Cn^!#^h~YrT`c+eb4BI} zvbO{8RdoGPnu&7JH@T65u~fCNmQn-~!9_jJiI+fN`g+i>S9@?;q?bY}=*MK5@KE(e z>MB-i&Midg%mtY>r&^)I$O7K^@W++k()K0a)-_)-Ua)>L4 z#&1nHT*){bF6R8MAv?=fI~Ndd$qF(bwB?=ii{|xgJPX!3r4;9mc09MeA`3IjrEBCsN0h2(6M2?52N4QDxG| zm&Rv`V;`h-2sH(#o$p?980i!piLI(VsqB_zS|YGv;^cGFtLfR<0_fm75`Y7_SdBX8 z(iZ?#qe5nZsAZCPzF9y|zfxp=)kPCV}$ z-M&s7oPOS~--(-PV@c>?hvsQpv2o-{Non$I#fs;0VC!cKpGx4avjJ{^!uCwRVU2UD zoq6c;b9FkWlF8|%W5)pzsmCtx*(ngu6o*dNLxaD9W&YGzlZE!6Qb{#o87b{fk|`G) z?H({qos;aKb3aO?AR{|yZ$(=eZ{uL=|8ig7>U@2O)vYo_6tc2@O2xs-$H1QaQWV>) zhSC$%$j+v_B@~~7ND|(lao&ggd3Mu`CqOY9;>#+v`AbctaQ$QkIf|zRR56#tO(2|b z%qvLLNUs(6(QUT{lV9_0aMw)7IyLN}^$YDpD~<0+;oSN=_+#yS z;N3;yLC-kQM_J1z=Fvj^diq%<&EHb}y?o3f(g*zH*3wbIFH36!of-=tSl3AYbDp)apbCTv(C7x8R%zOcxwH*5}y{R1?e{hNHvE~-2bG6e_4%W&wrUsu>@iqK}Ksv`5o|3ACYfq-oO zyU!ai9%yJ{0vHZ-b}@7TyrBPIP-zBpJ$8}dPfi^JupoLu>DWS7iosOFf!1~EC8ZN` z8T`?p+Xij8zqwDbWEU;%6j3}CXRGExbP73?DAst zlL*roa^uIlk)tPSmAaL=;DdB<9tk5Ht(8S~2qv@aGTtdI8nk86rp&ntR?ap$@S0A6 zl{_+fLp9zT%pz@2&plI=QJeMF zXa-}Kqf4ttkh)O0oRN+86hN~S@`N@-^6+7M9OrR}pd|kRctIo3!GZ}r%tRwi#iL)C z2?o8)oEPOM-Yc7g8K}US!An%kdGdPqD(r&i)M&1_?I>;uj%OdekJZOLa(WGB=uKl?IFEW_EBd!=nlnHO2YwmC-_uWX1tTv z_qDzd&d!jz?Z~utO|V%Pl@dgpsYr)BXF@Ote7=j_jan`-23PY`EIXB7*2#4hF|1g9 z4nXoFn}(mngaIYY;Yl9S7~KZ3AU^^UQD)n1GsmSBvK;`gZa4?N(ilJm5KwUj%CpO0 z+{HJEyq|53vq-y`C>SyX69%ej0CkYSX+~}nG{F!}+lj1;LP!)c*u&!cXsj%mod3zOeN$UKHZ+2@t0Q%GpC2;Mn< zifY_q$|K@s#PjGlK0fpTbHz8jbnD41V(vC0fLPua!q(~9c3|EhlaoUH_=T4Ebi_JW zvDNn%u@Y!vWPUzncHx6`z4aKdE|{2G6HhJf`v~gbm+Yz}A{-pF7Cdbh-E6r`a1Djj zhQ~$oCmbx4U zynx4)51AGJWv=m^0t-Bq7X#-myH!)r0xqa+p(9?f>8ip65Pe|!bwh_eGWF(yLsz6> zy+#3>)c#czWGX>FM5pjel9VUkZCE{O@$UG}4+2N{l1{)&9COqrrc{+Izb$mYoStlT z#JU3(sl>6vF?XY0K)S1gUqWd1KRxI-q#LW_JL&@)m~s;N{!kumHa=!Tfn1ssnwKk4 zQ4WvQyEUs4pTg)>fjy&IrjWsuoy{cmS1rZDk+kImdkN{c3<8@ncS^3TIVC5H<|rk? zgl>hY`st1AQ~5Mf47yOxHPkM;FHAEsp0YRuTwyp7dZES78H2*cNg2APbkdXyRCX7w z+Lix66Caw$f|kOy&%6|`YYbNq<-%%@5EpX~T!Uwh%l9U{m9DL9@>br#*KqPSDDh;D zPl^aHufuZ`t}vCG5(+B9AXdEI7GXiy^MgtW~w9W`$K;LFa6dT-Odk4ul;$cZ*q*w*Qg^8}?Z7&d9afrB>+Vx4iIm z8Y?t!h;Mw(^I{h#cZc5Lnk^3dwp`V*`=?#cvMZPF)#?Cu?3dSvmYY+7k&}z+B^T|Q zTRcn*)sw7akLah}lywJQ1#9OYXPm$7*FP70j=XEwbd&>CG6JSlKKJ+^e|>qOyaqP} z@fh&8SbGWhMQNIv{Lu3YR7hR%DO7rxHQ`GYn1hRsC_icBN3QTL`uxR}!{FEl)Zp@n zkqkY<;`OxuIPK@`Xq1=RW4|6ZcIfT<4^CVv7sJ{ZX)fe z&8TBh3ngpZ+yRrOky~vCp>EYuU$!;#V#%0*{s6C``cnI(uzHz7x~F%pQpMqRIN41I z@3Jp6?BYUIofVQw-h$EP!Ff`d87Ce!M;lcl=3$Zf&SNZaLo8)uv z2M#35!ui~1vE7R#M&)MhkCtloaiKRe?!c(Z5_&1Mb|@ul?N16? zS2NWoKnJx9WfTbfo&rF2NVtd1=wwE}9FZ2ebE6O`#levAc++&eCWQL_$T$xp=pZ;v zBnb#d-^0j#jUZ1U+({Ys=aS&>JR36z7BDl#jqehH-GOm)k=BG;>$6F17IO2Nml6%b z^E8IfWZXFK<5X5pE|4*Zo{Z~278C#4!2k7LqWg_aaaqWxMhG_Vl2hr&In%JYfHaqYh_BWEk7#4%Tr(?c10XO=Q1qP zA|_=Y-mHsdBpzb**4^be?kQ}O!xgucvI2YB5Vd;F62VB$=r5ki`e4i#?iu%dYVBVq zKiptJgxL~>j9dW}kHe9urd1@1dAp)rbKvtTy}#n-R$OhnutIXHb4N;nUid?0330t} zukWzvB(F7xln{@XVn**L27L_lMS0A8swx4{3w6dUz5f5oiFvV2<=X%i4H6RwNc;c5 zkLhd*P}%-NK^xKV1eA560AjHK2`x}!(XD!p8kzlPnMTKVe~8Y}_2SHfvxPY- zo{0sW7`JfC7cbs1TT9G>KNIO><8u&KQ-Sp2ufN7wr(7BI05aNIjF?8#&+Bx^yKIS( z$Fu8KM+fw;yV+*69YiR2Xx0|jQ>pE7z_veg-R81bRGnyWF1)efTu zXtucahU^@f7)0tNY9fUq<>RqPj+=1Oj`R%T z8^O}GW`t8Y>5gQoUS+NaT3ynYt<^WSR}7$@kF`ajY$i!!xn|rR3@|cH$!WkWxkuzk z&7os+v8&Wq+*}^9s)L-G4FfYl=d$8l@Na|XK*0HN3S2>_D4A-FkWodf1lH+!99>s9 z4ZHfW3Z0eBBuShcUG=l`k&=I-a?y>!cWVx|#pCa3LrbD|xo#)uhGoC^ScG2b=rAC` zUD`K@rq!|~irPt=A40slL9c@zfsb42^!dTc0jt@KnFBPm+STXQs!|)t=6kZ(4oBmF zUeMn!Tx6oVIb#p!L9;ng|D9n=x!dBr=M_w>$2BTfBtmu3A9D4v>RxF{mE-7ztL*UKnwb5 zohb$_1R8h%_c!n!S^a9!dBmAYO=1T8GgI)(gkrxUlm#t>ceX9(dvIjCA>^Xxcm#nm z!5qXOn22VkpcmlX+qDS()H;+XOM&K89~dKip>yFl zPU#A)P?Ad1`QHoIZ_tGo)P6UGzH}0mE^6T8=dgjcx>;0)&w3(58VYE-`<~f!6vC@Y zy!B=*r>kaO3~<-?3^bENy(meH&VEX0WoT-&mtDc*{Rx~i#)ep+;cW=fr#XpcWFv(X z19+)zA+!?kv1zRiIqpQ>-I+tnmen%*nWnx%_PbT+vnJ4)=$$si#NZ|M}FWfX1ua<15H>#CE`Y&2KeaH>24Hyb_ zx#wpcj|>}?+rsRA{^jGxXG>7BW>&VMFUzC93zVb(*p#JH_5j2>l@f5sjC^H=qAv6fz;D((d;2I_O-dX4K_*_e>q~`YZjkrWHhr&t}fHUbWeTdBin`^=hSJyM10}|`EV@RC~v3VwQ#v(3154x ztO}Q17PF=`%N;~rUimmQf3Dg7+oHh|*`Mli^p{(UPTF$+&b-`wCvwLwv233{yXInM zX8nTmMW@T8kHy4vZsggxgdmY1qe~idcy`h16y5#X9?mUk`|r_$kE4M+jz^z6bB^ZR zxxdRre_Pvkw%9eS96lYJyQN;B<2&Gr7$2LP_23nVioMAlM{sJwg_>q)c@v17SAh~r zYiZ^36Q9DOmU@px=H^3t2VfRa=?8WDxg>68vu=)8*$wH~1RyjlMpRd&cgNo@#aQ)q zH7nV{8E|qj`UMIuf5U5|i+F(Le!vz2y2+@KC8nno5aj)%wHT&-7kO@o{4pQmM4$$8 zbMy^%Sv4IhI1W8@j{3i*7Uw~o%*Jg9Hq?(rJKp?`mLq17?j< zA7&yGN^sD#%+tt!?6txfFa{%C!vh_X0-GQbl%84vB~F#BbzD%ZEi_?85Xmri)a*39 zhcyhb?hYYTSSonaCdicGy7{1Bg(T&?)ToG<`sxW841E*xgA8c9Q+|mTktbh-57!)# zw2a*ss+ypz3Q0YbRP8^4{I9GfFp8rk1YoTPl>ctW(#FybU}63j8LkFH6Tn-qzW=(> zxguDu17h?N3=Y#V7;HuRm5<5ntR=1txUXRj`X1gSl5B9J4<{PFw%eGyoj-3ZKF_Z> zwa#cn&2RH^a&ZW8g7?G1#0@=o_{0E0?{0P>z_J`obQodznO$u7`bjJ1QQ*4sV`$lG zS&!ESmh;Eh>3&JUGVAy^^Bn86Tj5WfYdG4WDVk%e<`9{-)k{trSZPTRX)#to2)2BE z*jAi<;sMrUE{rtH|&lo5S0;n`IYH!sSgeKG>dd}R|N1+cVH z8b!`rMTz(62*T2kXP5%b@h%W-M9RytDT5LVF2N~!Wh%53;Eb#qi`Ym&)dW`15tjSyCZ{Hpq^15=jVDq)$9#v3>!k-< z+`p{(2V-6nxYVVDw~rG9K5rm18ErE$I@=`^Ahvr4-VuBS(uz)KINhLZx3IPE!-Ln#m;qGN@d8c8PTF@*f{D~VsDl?yBa zORbMIcLfC%ij0#Y1BmM$A#AZPNYn8G`xkR}O zS-^wiBg}RFx(CBlSB!8XV%1pJ?{;Zf;VjTJfuFPg57v5;(J4eqo8`s-Rq?n{$J*bU7;0}A3PZmuxLyGC=s_T1*W;Ff!wErDI2tflJ%s1t~G z`EEUh{(d{tZqrICsIY|HalEDn_#K#o|AMWek&rkVQeoZUNcR%$QhdDK?1Cay0TxbD z3keia-W6Ma_p0J{RNfu{S{rR{Dc67P^y)!{ zSsB|C3=7G(C0FI(vlnYrXW;_#ke9=1+ByOTz0I_ zvBBMN=4s%-$eeb78Mri9h(^|UCFDr;rgis@>j2!r`dU|z=F$F6PY_^M_Rg{XIqehm zmR+UoWCg(V%BrZt|1c|c|HG_|{Kr{y5%x3g4@OvsHKbV}>&6uRXW&Ja zg`tEIRv9iio!12dm41i6zfE_*tx$I>5jk@O=Z@Mc(8T`oV2u(L%!5tGH2waC_5w9;HfDFhWStr{DIgF}Gkb z_u*ujwzBD1tiLwmZ?s)u(Hv_)4zbL9ni$$i8k((kcMy1<7$A1y@ZRF}apCZNY3Cs=CCJ{4Ot;#wn}ke8R2vK zE>YR;3GtE|dId`D8c>Kl8Rk3r-cms)rLucn!Yn;dljXs#Bm2W*QZX~(bhzbhEP$g; zP);HgHLBc)X96dG`hp~pHlTIKJ?uSzS z!HB@Pxa$ITShW}!wiGU45Z3ytU3LiAL#IYX+DzZ*mr=!M)@U;Hl{Yf5#Gl48L+&WI zUb{~97oO4aqq!az9-N?Pve+x$(-b389y-otyqp7twY4VM4Jq|$1E-bvcz>bd`~~~Z z+xI`Hsd(##^aQ|6C*b(+wG#gyx9|V35(fzofo^@l2dWsAD5)8Hi!Ir-gImuhfm=sU zr?9gxNtp4eDy29Bk0`W-qV)yghIy3N0HwL8igWqVy&R z)sJ~KQ&jeR^E12qncdDyNljpu3#n%MS)S;aIHnfrBFG1;dp%$Z$glKk-d+r>zOY<_EW~cd#|+j?9!YS*LxSI*R4>bm&psNFmNdFkd=qH{PD8S{& zrfmj$ts|0Fm|%Z}P3U3BwtRkBTOEvkhU!>8AfjWAE(mHJ&emv=S?Xq%Vu0HY`rffy zq%>g44YPZzgV@UdOj}vYzsmyJqnoKE<7b2k?sbp>)88LV0+-|fi2(83f&v)?p9m2% z%FqCse-J?e8#Gx0<3CiP*fVJ)%6)=I27~8ftH9t2%+z7UBVa79pwh@bY9hQ==%U9s zwX@IWm=nYLAdFB2y2K{|C`1X~VMU^G%%EW##Z$#8OO~aFJM6^rQu7KyFt^2 zNaR{E=2VC+;KN%xz3aR;kB}7ly}&AFKjT>dkHDMaL329XMubY6l5Rvl(-+Q461*%; z$<6H*xoD)UNvb(5yqYB1JjjDr6khj%YOo1ThudLDDASiLO#SbsRkcrpXPB%5zSEgt z$s(ev#ts7E8p7!&JX`GNpHO>*KSOsi8dU~zd?8!oI9+=zMz3i8G9kfTw9FOuXxCU~ zY%Z*G5$wK%+Y;Bs%US#XMQ{TyU%FdYosRkn{kQD}Au4Tu6|W8Hdk^a9$6~8wE-a9SVcjDE*WpRie@O}5vXES+mYH#UxGi6W02G{(OpG3#^O5pS$DI=0Anio2ptPX& z;Bt!hY5Vn@RXbYYW2Lw8YgZP|&7|BMf}JJ$sh#`gy~B`~BU*J6P8Ndz11rq~Q?$HV z+BcCdDLaZ((fOA?b9JFWsbnQ%hNxlId+DWq#~F7U#D{@nMN`^1^RLliB^p`lm6GYp zE8D(_tnkzE8rS*|jSKz*-my8WJ>Orb_rL#!1IE5+H82(zTl%t}Csd3QY^`o15M4Yo ztVFe9_&}6H%^|sI?`HwnvIoExD`8ydo)8I-DrbR+o?NJjm>w?IrS$>lESl|s$%}(_ zmgd0{7#;QG)rq#*45q1c9ZZ*#tcRJxY%m$?44L>VN;H9cmS4$Lg5!l^bYD{2Zi*z! z-FN1H*&c{`GM#k+2{eMWqxM>iQ4mp`tZd2G>Mt;ES62Q|1o1RsA>hqz}+{48i0kJduPDP9_z?Mtc3QdgME2idqmR;Hv# z_g&K6)i_0^+Wu3?EIU(^>%HQ4{3;@&l$EwT%K5qw&(R{FAt^VI45F4rhxwxUkB7U72l2W*UQW`K5@?8~--*(1S@FUrz0eI1 z-exK7k#{nmSnn<1zO|bT&0KT>X4BE%9(t+V{p;Y*MI- zZGbgYc`ja~_w0v8aZP$>Ofljs?e23;Ce($Va2>BiQe~6Y+_5qxliKAd7S|g4$cA<7 zeMH?)#qjQ0IF_;39+jMFBTekX|hZf~aqgyl^SFc;hTAwff= z;C0hTA8k*w*hdQinpywyPc@?p7TkQ)zG^TI_XeGv zp(NQhi!XL1QPmQD%fu}JI#@SAlzR}V->?)-QZEQ2tN*h|Hc;47v2%Dwow!X4Gj4OmZXGVE8#Q-40!t8f&MQKi7z`U1(Mf-Qpw^%(fERJ z$qzY$KNBui5W!h5$Vhy%>y_7uh}qg@r@)M1%kg6_pf2n;Ez{Kb;xl-)rLxT$b6beZ zG_#^&MswDa@M9L7LtVA%{)?-%7vli`2Y@ZJ=s-a1|C`w2W@_wW{~vRrBO02{fO$E; zQ+22Tfyq4%S&IdoT;R$1eHiWp*V}4@F*!*~N`~&?gys*+mNu3S zzsHOHtHVoi3RTZgy*}?hpRa_2xwn0{ypLZ+>qzf^T%HdAJ z#MxA;fM9rwR*QNM8@jXq^C|1@kqhMXw*yD>R%mJ> z1|O#?n59;npJx3r3ja|^VaUDNWug(v`aBA?S0&8@hg3woitO$To_E;VF8KX`xBIU5 z_(LKEnwf0&q4=WVjB!(*ROl2xdV9dNWDO!S%y@e1sEfLopJno!% z^=q_};LkZ=XjAS)WMaW4%2cZy#SA4FBZ|3HWn{$k7!wkWicIRf@x*jZgLtCM19^Qk zmFmqr5(Khd-3}b%ZaR{f=DTCGm)34@O)9~2eN;__iQWb3@T=g62qN{CEFpGn z#yB)ik8wTifU!F54f35cVMK@Np1YRq%B19Q3P6E=9hC#@Tja*t;A;rzFk3hsIsXFW zA6+dd&+bt9>D2HMfnn*j!_L!!^rAp&psBY+q7hl5^016W8MJ*+hO8x1Fki(TypB@C(<|$P$RbKgG$VtU>^^zHIYX2 z3|h%v9s!HQ=m~i3IBtI0JXku{HE53UYzKl-+*BOvwt=rliVGU5tMT@24urPk{O$T06ICwKbSU>Vw_^+?y3Iv(VK> zyKWm^vHM^aK0AU6D%kXmru{GBt%*YB+WI`#W<8D)fgZ5f>H9&a0<48QCaRv1+JN1&Ar(awU!|AqvMML4*4Z@F*TL zs?@9~kM^){c|jwW=WH|Hc5qR_56F`^>562uM{fy9??el__ z3?a9K_{B)&AvlK7q3e!2D=mrC1ke*x0O{Z|Hm zoNXZcQ)cU7dr+y3dWD#d|JWmRBoqdl!U!d&m8#fdKZZP2w28sr!qc~E?TO9`ipCp+ z(6w6;MsksD)eZhAS~{E$gI};I}&a(ciPRDs8Q@_4CLmLf+(3k zJR*SoB1F$fEMG21U?F5^Yf~n+r|D6KuGY4|zH9Lnm!3UPGyg%{gyV!{?dxi#&opzO zsnKmr?TpqXeW>!MVr#y1Lsr6;$S~nlq?(o6k@Q8Z1B$mW*?_PgPf$xZ4s*tc^G<+)p#*0*0il^L>P6GWsCdA{W#q4pcXaxOR%mLj`@*vaK)!wwHq1Rj$&{PufyT zd9{@#%?(r;$JMf#d!>*;^Z|+U?Ahz7%u9^+ z+(od9a66RdU18bK`2{%LA<&IP7)y3xcN=np;#bV`88+wfl!FdFJyCJyt50L~!VX91 zJ84n@`qOg3g~W8&rCaI)+mXmN8nZa>Ukg7b{scT9QgC9pyn}kxxjWF~h;7&7KZkxe zV(3erzk4|re%Ex;qwy4tlq~r&E}$;!vifErM(jUNF(vg@{)$O)F1j2?6ddF&Zw*Hck>VHK7$~bZ8Rp zh;ShsCOz!!ycxWnY}`ICP9ZHFYICV#vzUy0B!PnLWQ-}DQDPUr#n%??b{=~=tYsHTQMpG`gp;ZZ zC(P9zSK~E&m(jLJg;e9qVJtMA4N0x6J_IwI?3|FOsDmuKKV>laISbWlmxXxgQ)`$T zRP~qaY4hU}#Rm|P`a{_r&)EqG8}zhJmI_Gn(WsKp+h!&$Y#yvDLBN zv2EM7opfy5ww;dMv2EM7-AQisT6>?p*S`15I`^D0>i?-e)TqiBdFK1PbIxBhi?b^e zlfe);vbatgNTkOVRISJm>em*v_vipvFlbq~Kz#d;LP2mIhI z9n61Hr)I|%Vw@F&OvSm^ZEjNKK+wAy{77>I@4*J64m!C+4ukY>oG&uM*c}dkeFOfl z@AG$;BMveh+X7&-!~)nX?EjW10<3AwO$>}p{y!k=%4eoph>#gV0Vz`2D%fD$DpOY^ z=Sx;}&1?{1UsEqD#!7uEw+Br;_wHBem)o4~zT9tKZ&9ets0R=I^K3OSP%?85`yczv zJeb*Wa&%&L+j0F@z?c?fa4p&rWOEOzT$1JnHqJ>U_pcpX-PrzEy-g21Z&VI>ta%&UfzsWsghS<6ga$9VO_tg;cS*zVgP6`{bQQ@Ps%zb3O)M+MT!=%5QDF?hj3A=y(y5) zR8=*T)RaC5mNEFp!aQN;&Rqm57MVFHE9>S2h9q+sFpCRi4=NBvh=`R4F`>Wjh;fEm zv$x}@=|nD3;OwfOu1~oDU3+Q>{JX{PSFRy1N;u=GSJOaGCEZa|RnR|b@hljhXto3n zsAOg-n_2Ia_U6;e@gozG#Q(4HcppG>y4VzBjX;Tr*)L)B!*duI> zL*PSpAOr{!53YA8rTkdqed>o&+77(L++sv3yVxxWK?f1yCP$ZlVM**V2Nua zyp)sR8C)>F|4ciuv8>_gue4_KL$_O^g}I%eNuskbz#4|BL?W!B)KUOkxG(D;{4E^- zZ;{Q(7r@{8*yL}H%rboj0CvDe>tm&b+q2Vu{Wt(J+=r3&-za5DAY~bQo zgk?+ddUHm-|H&;ah@)AJSQqj1bF<9SsyrhtN~N_Eh7LCRwb;b($pr>(2)QVUAz0Rz z4Dz;eqoP(F{MQ@ZpY1=W^L7DuN67DGw_tqnX~h$&2<XN z+XSJhw#Qgm(JV`>def~(9lvOrU1J&9e2qLK6PFCSev|Uj`;5P2q2{7@L@)lq26p)> zY;nuNkk49D!;j=RZvc5xwa?}MF3@#U({i)9{r;WIkqI~SM4 z7{`I0Hm!nl0RDP4VkK6WV-*~(Kom0fehLSfVgQ3RG)W1%z^E$pcTU_GdS$}`(HJPf zm(@P7ipg}sc@?uvbCr+_MZqBR%)BD856zcXvoQYz(fK07sS4EgTABAsBrLFKl!W%* zze7vf-ISgBYvNl9*`y=nDN4n3)Q(QV(ehqR~stPp$FQcG_lHLzCjvJ|i!u{;FCmk+K3AhDYR zNbLD+pWOSXC%$|PnFdI?P_P|Yx=?fJ@`w83y)-|AFb6)YNcXXGQdRuHjFYrEV!Hd#@#RM&`0$a?XgllwK!C z5cfkyiO}bluU|X$z23_c=SUb;pBj)OiP52cTGs)BiSl9hb#?i8epfRmJ0kS>+C3c1 zWHMfjxi@>C_&HTGJ*(HP)7{BG=>e+ah(qcRsU9RW?EV-UT$zq|8@^ASI{sF#W9D_H zt;gAtpr(YJsi%cXaW0H#&3&Al1 za{6>7V=l~r8iVeE%dF)`83ZZZ+2oT>gb05s!+rsOEo@j?G?We)UX#i$#y2Di$WWKP z-ME;{h)76baq``}$#)dg_VUXZR>qj1EpxEQ0kB z$Y&B8iEw8!?!+C4S#x4&>GLEnp}hRY#IU^}d|7W56yy+)AL_&tQpfr@V$SeGUB4t8 zeVca=SQrA2^@Q~^|0*ZrOF*%g7PiOK=nVyfK}9?n zFvQr0SQib-4}$_QRA3?osKpVTKW?U^esbnMRFj^@@F+s^fA9h6)zaG)RQ|YWcTe>cuC-T*5Ah(%O& zX_LND=nPb$aI4r+Cb-d@BO8_`B?7ko@wLIU<|ik}YeBT^=|=HJM&sF}hv&hF>Er}3 zfX3U#o!7ZT_EdVm$pw(Pgt*k0$TM+fz!LsszVM1sgm70Y7b)NiM7HVX+&W)S&`&k zQ*MF+Ca=?8yu~VIUcl)!OR6EV<)N=ZPjo)DYWJBag&XQ`&!Fd7z+?8cVj$0fb+M%M!3+}a5|0DO*H3p_2Y zlXBZ;f{4^CJQ~%zjoL>f;)4i%Ba2?4;(;>WvX)hy1pcYqm;yMo9Kkk%)+LWOsTOgM zZPtC#QX%X1nl}}41(j12zr$G<^FN1I>;EZBx^Qj#H5$iX zDH5xghUUd6wV>c~DPu)0e(X4*mVlGF_@t55#)=*QL0iic8Wy4p!Avqb(wi9I=ryWC z6WQ}?#qiAKLN?!MiV*=jBiqKVUh};kLj_M;<=~ zp_MO=6+wz23H_J(6G!;c6Qo%Xb0h44YhO@^Snqq{78QkiH_p9-BStDz@6l3GAL2CC z1Vca%gy4m|s-RINysBPJbw$*|T91lc6IceYMN8OnNxyFCCUydRv2G2|O{dGYYo~0@ zErEH_wy%&%>Nw86$_RaV(WQfJZ0V(K1y_;xSyKqDOQDJ6dP0%7(3KolyD$M{x}m zCAW$>v86vZ2xTr>xG$PVYgx?WmTDKRSweJL&f(u^{yZ@2($?YcStv@(A9mo$&3C5A zt%IJia(BaB&6DfShxQ!Kb**2v{r-Aj)}dvXQJHh(C>2{^x`IEc74TlZd}!wfBHefh zmkNSv>hZiJ&`M95|?(DU}pk|xh8?RNu>lbi}wKME|{n6Oy zbj!)LR_X&0hte8WcV{&R2g4vF0DNXHH<++%MhaRDmMQP0~*tS*S8F) z_-6qnQp#Ec=EDnD{=zw|ZM4i#k^mn@b;;dla3#js=lR+b(w&4|Xo+u11y-Gy><8XE zs-prIptcvW9X+?80{*F!V_(D%$mZpKkaI zW2@JKa2Q@{1JHm3MLnB3GJFo{qJh5@F>w1QsV-@l5BSD|W~rU0i8#y7m?bqyF^Hy^ zCK}94lO`oFQ0h^q_tX*OnLTWaLC%^Bp48Oa=lANVU8)H_(WoC}&C>l+)7|6z?VcaJ z%$I!kE_K=9`}^As!BR$Skl@7{p|E!47QS@FGZA~m&xAvL5Wiw97LTVC_il| z0wS2fqlQbbdp*1pvJes~Xt7jwio&BDcR9SX$J-O{_bff;H}Pl2&6>)1*GxHb`REa5 z>?@MwhIj9T7rP=Mc5Qg*?+4aRF04H_HFC?^KsL3s8UWBw*m^leht*mliRQmtK^=-F zj?&8*{iScZ_J_JOdPT?C zlW#Dp9w19aFSO#140tWKq6^$>iU=Z$=~Gd8Pyw$G@M_+4xe9}`%4CxRZ9@*qBqKTa zCUl-VEr;PX$c|#;5f9))vZ`jGNn(; zzmX6zzFG!fQnjIbzh4!*tytI+9*Et2S)}fA>e+JVo|^U#o3>!4tifqvuOBo$PG>(UtTs_hy`d`y@0LveWkc z_V7u-IT)+D!{FqB@GTZ0~(WDo3;-P zckw!1Vv{So44b=Stbe))VJcpaN!z()6}xk66PEDd#lp3ed_&(O2OSM7aNdzhrapea zn?O@_i}Gwyz;&ui=E zkkXq)O90VJ@|~vb{f}GpJ>*>3`Zgb+s#;&go=^+6f+XpdJIDmtuMna|Jb{>>+Ih^c znEu*|k};mr?euK40*dkv)fB4VS$>Dg3k&=)#9mqH@9b&F4-G-%w2atY8AC`&oSYj3p8f z!`=KnwViR09TFVF`xv{xi1v#}#Dhl3pgzGV=?FwIASeQv z@qljv^6j}+GDBdsPH2Uvn89;1UZ0gh{TAr`GxAIu+Fe}=bH2>Al6ku zN}XrwGTdRrWl;_#8=rK}y<%Mnu4*Er{l&@`y(E$$o*OPh#)rGfc7EH%^O<=lkdfFa;tlFTE z^<7m0?+%U9D8?6tI+nkHBss0PV`kH1y%d0&?VJ_wnD1Bs>b;L5mQ*(iK5MNK8L49D{kI~4jy6wxh>j$e$_dKe!Xx!qJtk6id(5z(BOgjMJdLSpq%loR zQF$pRo>N|zQMF0PA7dn2ipXBA_N*%N3YDNl#vj}o9uvhQiwilNFwy-XAuF|fi6qjb zcCj&yP$9l8Zu=`N{)~McnXSBFb=ys>(^x4ZFF$fly)blV`Q7b zvLd5A4}B29;)=v9>$gogp2c|3>I^RMMWEr^yb=vaT{M=0hBxi*;7pM7F?6@vo_QKY z7V!q7LP;XR%vzrsi1+uxvTk2`ZomF~UjVfwv_DYDmm7zlospA8TQ2S#Q+P#Y;io__ zuZt-T&EpK7r)1z$)M8Ye;`wQb<%y+1M-eL9F?iMGDXyNK-JWB(Z1Gk)b{4JFGOd2O z$|3BCBt=@6(+8)you%s9Q#H#g4unYmr@#sy4lW)J9xUi~EIfjkfjwd^L#;m0z7&V~ zcYCaQ1?yR?kigkXpts%M+mYZcyDr`MQ2`&bmmk3Ap#s^uNX;NH_rnxl}QQq~4l%V{PwP2P)hX&gwN0q(O4i@19wZSOebkezY=B;Wfe}Tb%fe1x`~` z-drJSeWFI8B#`C$)ARfm`6HPSR$6Y$&8`J10-ba4>qAl&HNZ{g6q(wzSv;pamx`k- zi-)^5#X}m~9m!thL-7tf$cA!xIozWSD4xODr2n#5RvQ}u!E+wFRS#VW1wrzn z+}=XjF3*NB!GqlFwu|WX2+{4=!H>}MMGqZjP;Uq>fp@irhK~TI^owTg5E`3J(M^<= zUnmqiv$6t8Zenh|HU&^$w=@!imsCSmi=s5#6FbZZH(M%aT(^VmBEx6hrLc_o7AlOn zG9x-gvR|?z*>s;#ar35smJ!>fL$_jZSzbWv0=`kkp-DB}Y)(Z5S3vc<*z~TEN^htu zsaBFiPRj5ibI+HamJEof^N=@CEnf5B;YI3r`Z&(3DE>Ys#eIY&8H%I;ew^>ifGOi4 zUBi}Q+TQTUP=k1kBUJu&RR2Lx=NvpRytAT9_!xv|6)#@E_+xlj01^&0P3bJYWs3Vf zN*GepIx9f6#dx>#U>WOr$-NDHH_6xt;c?B5Dr2Z*a*3(k`)1DW(hUG9X^%G$uOEae zKcZD~M0*v?{&`>;(#Dy6UYe=doszjw>ODH1x7)$;G0Dn5AM)sVj5Pn>p5m=urso_R^lyWJtNz-GV#13N&*kHErS zRJqv>T-{_1D?Bc;-KOABIqOKRXOwC2BlZEAQxnP8u8ipWj1_cu0R5}rF->HRm<0%) zd4S;I``;BjdU_5f|HM8`Vpst3Ru5eN$Xf|#qzJk;MuSC3Wd#uJ%pZ`+8j0`yN8Ad~ zdlXy82u~;@Wz+rq=c>QIg1iPVim%Hj3^}>@ZB@{!?L?DmV3B?lXn z1dJY3!x@!N;G)a(+{Ht?{J|@e4s#Vi=<}c$<1ghUqrhau)PIRcng~+T7xJ6QssQO% zC+6!1TjqEXF&Vl5Iw9?Y_`E60)f@RFaA3VX>#+?RM@ZqCU`Eg`RD2v6l>+AY#_IDD zyo*!yR~b-{L}+6_q|$oPf~s4H@KP{eMt!vWw&^t2n6}IbA%7o#?u@xCN=OQ)y*%BE zq5T$oO;}UUzeRxvv!=Kl;+q3`q2-WvYxI*FFbxv{8i4t||LZtEtT5{bLCP(r2$cac zFd|r%;0=>>YY|cgbzJ)!)m;ZTE{ZZ3tiLn2B}`siNjbIn$lWQVYpuq2l86gU?4M=K zY)7H|qCg`*lVnhwqpqGJ8~nio`bV@CAU~l51BH~k=3Of%eqYs$)b0g&G`T_9p@M4Lp_Ws0#*`r^`&{44b~ zkIl@395}`7Dx6{HVsB^;&|g%g6(#I0HEMan%Ju$QhVByl^AvocXns3%qNTP zN7{;SC-)T|K(MR_q2+V1rRI$0TDv# z_w!(*Rgiy@s71yWg2GHlJOIKcIRRR34i#jd{g?w+|G*YdY?K6d|?`nHGF!tK_MVFg@{8IJO|aMhE(3d#88x>cWKHl*!7o2n0%0Y#m#XE2;n z|L1htozFjljb=`>1x!`y9gQK$IfEdI=1Lx7VEzK*$`T8f%1~G+E9=|8;@Qx*%E6{+ zEU;gjvSZD%M5?BEMUUM2M2a34%e}`MW6q6lQ!1jUpHf2px`yUTHcZTEhzlkdiO{jK zf6sYVQIO*)NY+Bd@%TT4;4x%~I-DftAyH;7$V7uFPNKB9{#=G;XL;nzRv*i0k#xqq z*Bm3l2;na1Wl0IOz*KM|RsmIgkQ2b2cX2TK1unGB5BpK@YYVM7>MQ_bmY#)ExquS+ zH!!@DJA7;P!;W@~LH0(qen~*8Nb#z{;z`Yk+>gt#2;{_d|MJu}%{6Q*)wF_DhVW}V zysh+yQGwFsXm}4-&JTMBr{^-cD;Lku7IKJ`Qmk`IeV$Ul9(0rI1ksNXt|DEd4NqJ% z8bKmhT7vccn75y0nyZ6zcKS=H}q|nV5)9#uxzfM8tgfNXjSJnG|Q~g&7RxM0bciTsgD%rYtn2_ z3-6C7%H4V=U zGQVm>O`@DK;sPNd6RfU17OfOPq>pbZSoa^{{#6bozFc0^1LRQgziXQQr`&V+&*jg5 zkDUu=xENudBSB%Lva>|^ksl2GHyH#-oyWvP1MgA(jh*wfx%@fnJ?K9VrC9uHnC|@g za|#*+sP}1kCV-74A3pg=9F06K+rG>XCkfumhzu|`c)1}JWnXLqWYZ1nPH3On1gH8& zCEP5{AK~i1;GAF@q*w-Lmqr-5CmRH#+2T&|ad82;^Kr;vxhZBq?p$AwiWh$$qF|)VqFB`{w7CMihrxq@wtypt}99c?J_lyoMfHTVh>5e{uA(G-KsT%*gt|`DIXL*@}ZgR1S|q6ErKQK4dZtqy`1^ULfxML9-;u6hEjDWoM&e`UGlh zqvBLdB}yZLU~nUMY+%2`Lc>w1P2N}Gqk$`sfP`BN-#0~u)(am+cC6s51BWmt4GMJZ z?FyC)XLlIJ<%GI!s(RxHUlTRNRT!agGPU7PnhA55d~95*J*rTk)l*5x7n9+jfpCQY ze(fvR7S>Ez2BLjtr`&GK9+ok+#v!a|Juo0=4kwP+cm;w76$7dhWZtA{q*5Rf$(^4x zkcenyh*)8VhEs8}t%5*c=_N>ihSKGu3Qm#TmzL!b8&6h>h;|^Yk!Rh22B`rv&ro+_ z=y&L48%a`I)6YF|Y>SInVO3xX+o)+p9{zWT!_yg{Ucx47NlIP;%ebg%Xzf7H0D&Q7 z{xj!ijjP%?l&W5)!*A_QA<>2K_5Ys8nc(Ap)bx@kk_ro9p{WI^k~sw((f5;6O-rHwh8y{Z&x@5 z@&~LSMWn;f8eP{I;vY+&1(Tu2q!AS|@YWYB<%m)KI#^^Q`LF;uhC6LG%I`%*dAj+{ z`Lz4z_dJi2FQ=sGa{TX8&48>{45%sINd^bR20T39uq*%XX3VGZmYr{CFhz>MzD#A& zu%z7caRmj9RUVu9blTFLb*64+KkEPo0S92R0FWOt{fo)e8Ce%yRBK^&ep+V7u!hBS z1D+tj^L_6VDLvi45ic>dTvj$PP-{AN8jr(+=2n-sPy}{HsOF)aH8=f9!Jb@LH4g^< zCdylhFB!XTuk~r!FCSd!>xY#H%j?u?!b!P)+aUCuX40a+V=ECH-7TJyp5eXnhXc zH5`9BSVwPzOJwC_eukj$d8a*R3q=`(3Qq^M<;BIQcFjw55`goCZ{+w|4%f*eZb zDb^zj??TS?J=8iC50?bO^{W0e>8ehMTq*DowH8p^^A?7QD!m~j7qYlP`_WUF)g)FV zYK-}0YkL+myD zJF~M~;WooDyX*Tac?l2Ja8Ff>>$Cpz$<7q6AOgbk>2B|pZtO$N0Y0QzaXcmH*T&iR z2)zUoGRV%XUAiI{k^bexJ*patjWl;tE8R|eC>L8vJU||OZg?U|WBs=@NKUyFqS3tc zK(4*<53(T0zcX)waIMkbon^hFW~IZl~mw$Ffi*`v$M;hAu=ZVW>C=}3HY0=@md)bQDo8!tKNR`I!NWOZmR z)Wr>T;$hQ&;JeM+0!yWtv%b?M8yKH~+mP2#f>r~#D%yy_rWNgWAb0J++Q#YF;wWX7 zfeOj1-xDBBM`xya44QXLep7Z-kzSQltz4B%{p1HeXc)-&k(pclCvE$JO)dB+$F}-& zZb34CUG1ew>U&3a$>*F2+r?S}7@`sljGL^{LPp=l?nEZV-FKX?n*c=fi;i!aE#|%S zU)XT9>HJoYz6Gbuy$bIiy?rk@8lJIFu|iJ@SS4OAXRYjDInzt!0Ha*A3OW-L`pF_Z zyv^0pG)|Kj4Me)!M+Qix{`>#f`grtHh!S$7@M8Un(A(6_r3^fH=QZyXS-UODfKlk5oAH{WYWzqmBu{> z#|~YKEV)^dPzm+S0jfDnC>-k9jX1>j1O=yuOAbT#H@EQ5W9@-_#z4@7PDv38jupjD z`cWW-t$8ut63lvA|Eg@f961_*0A<*%SU^Cm|BiHXFmTn=vo|vQ$F0_+h7Dl9gZMf1 zx7V6HzJ%_)t(p#*erup25Ar1_>tzljft}sodLUMJHm_4Gu3cvQ^VNF$ zm3O?c@=w0%b->LQcbSu7M$byR0CWNsp_N1Fo^|jCi!q-_v!o*=^W$sCQ%N_a4h7VWm`+OEeU1IMR2VZ1m4~yn?jnv>(UD1T zlwR)MkDoJ1zqi%kI*E19MdUY9Ao{J=^T++i2<|S9V?ll!yhfN?ue^+c>$3(u-RGWs za}!a#`KGlSdi!k`Hdr{sQQK9g4@@Fh&?sCTNC9aY3fdr#GJr2o{h%kTn`m%hIsAO- zA}y~#Jg9JAo{1kMY@fRjSkBC-^f1ju6tlrbW>4J0ZURAK0))N=I9KE>=pm-QAs@X@ zz_etf=p`s$z=&5WTd{-wWC*c9v0^oFz!K?Pv$(V&(kLMiuhY5EdjTtErrSx#Jm-ZV zTcUK;)KWnMn8 zqA0TpfrMzWU{a*N7;B;?GOJP<`Whx93|081+VcP=W+H0Jfy}Bc`#Iq;JSEmtcH9uh zMyt)Bt&#M{n(fd@mL3CQ;~8DKO!cO9(EUQu)DZBiOLQ9YEzTvg?RHn73eeag>TI&e z>gC!Rptl+>a%fAeVuKwc;kxX;Ge!ap4(hNxGJP@~bzv=b7m3)G$;n}=2hu2R7H9lD ztG#~0s0gR3ZQ@DS>YPwIuh~_qTT6L%15z7tRL!C`N1Y8iwaWgr;Z4Ckdr5%Mi|tV_7yRL8 z9>8Zg!g=QnyOILJ|x1nPFfFhJ2@P5ELb2_lL^4Q^he|m2lN7eF<%Q$2vODF~YG)>6+mxHDk+6efQ6)Y*T5iWsl(gX{AJM z#c}??god8CK@dUgz4~F1!Vh>v#S5;Lh!LwFdi(+VOO0?Z5nGADJC(DX_F1X5-4HG%hJ?ziyPSL^Caxk(%Ix+!N$m=gu0-ezVoLUMm)pJkMTGnzG!* z2>}pmV&qLgt>&9afIlxjs zh~$={EvA<2cN04!<71pUSQ7lHyx;=X`bza((8gQoCxSSTI`cpIoNIBNCDYSU?<>I^ zmGKVQ2&R$QzfhaOPyO*E(g{PM#6Gm-wJH`9JbveIHid zlr4A!s>~1#k!DN5I?w9}jI0bY1})5d{wS>8*_n2m?>?3!&?O;<>#9;h)G1v=(5xN~ z;pvhCPcDk#8Its1f;d9Ka~LmZ=lI};vlahp5J=Z~hF{=9+(D%`N5Fvf>Rvvtb(ygf z=-v*I$`$gmUwG8Ywk_q#vz|fF?9_cOb9Mu(+&%-Wwaz8O z?1W^ETyW6Bn%;ZVE7&00Lw5~gpWdqwISF|#aD@=@7)|dJgY<71q*+XTle;%D%;la6 zY+K5ID5~MDEMvy(wttJ2xunEqUDV0Ik&8xD9aow;oWdb+qN+4=^4z;MLh=$dS`}X2 zSa#h;>Tsa&$ID1X3fChRq)-3OvNxyUJT^!f$%IlRBN=`Ee(*iJyXgbEr63|*OL;Zh zU%ITT+|XBp>scba#TGW^t!lSwVY(sTL?d%kI(g|Bx|}K`YxGqYbm?uzGk?kAbHbd1 zwj!j}F(NhXYRrim+>{LFVw0^ z$meyKXs%D@!RbS~K?BJX5ASLG$(eJe7$FQvXuui}c6Wjv$P*- ztG;7Ta%WH~$DK=_DUF$UoawC4bxqm%JLUFq(J-RSRqUulH;HY{T{Ci<+E}i$N+&OkXou6*|Q}WC5 z;Y99rAWX^N`G2It^n&1PvH@BG1>jC%{@>CRf5Tyu(1G-bU_0${NEa%SK2cT_-pEL+ z*3HWDlniUUK8{r4KaV)?FEIu)_CzW7JTY_+20Krnu{=O{jQ8LAx+caJ z4uDAg|A>%j0i+bF&vp$xc%7_f1{_$xBT?^=%tlESq+7F3?Gm0^HJOki3}efxAc7BEYjh)E8 zyy=|%c(O5(jGk9s5c-lTgav2rbo+g%PI2k!2}!3@{S&U^A8G5zhRpRW_?9=_T@%V8 zOl!o3uZPq5o=Xe=!{15zm_Hk#yeeL;`4N&E32YcOmH8#mT|g~&=l)lQELxXL&b&=x zB=umv;Xpnat-*_W&0(tpgIniTT(!?nRv^Gs^%Q+GzD;|FBjBN^{p*HmII6!xajhBS zh`VKwAQW?&;5JjIj}&A;*pQJ-zxKLV-S!*o;GfA`;Mq7wxO5&zeLu2N)#Y?ja(ZAm z#z3F5@^~qGcL8WP6hJSM3>#AjQ9Fjb(RUDOV80>t0cycuFx~7?<{InwqpZm^J`wQ3 z24J2q)j(aRX*k@cdHZ|Us8>O(5pC!+mMdpZ(o7Aw8$FpN{TJ8Y!K1TjSsE^$SH62V zwnz>&i4~Q!400}QSVEmAzbDv#%F;_uXKyW;p1{&)qgkkb{_wL(unQl`h~gvR$CEt0 zz966SXJ!qp8~gtIz)RFEM);Q?uIoQzWD4r#ru^2uZ~{cs>{2&OC}aGxLomoH+k_Hx z3Hy-|1_WglV&8!i{1HnGF;nM(Hw%6A>bMa+zYladFTEhhbbzkx`^mw0^5gMT(|X20 z(mB=?%$?y#1w!#AHxkBzpa7#7ubuM-FxtoKuSHBdW1eLOwRidgAf~!Cu}`Bc1#LKi zCH)YaA6NZ8XVrnVsKqv@TuV4)PA^j$JkQOEY{TZbmlnEBm{iTY#|7;xzXn)0+LqH7=31tv;9u)R{wUqz9Xd6)xZa}q4P~qAs3_R9 zc&#reEs=P*oB6jk%oFp)ADdw(s<0$Qje~Jv;||S)3=SjxuY+vN_gDZd3<7M~C_l^V1~k%1qWJU%lraVGtZ%hXvpP^7$_ zxaKDd3rQUXT2Asn5w6L`k%}sPG@H*V?~8K2Ep`?fIS;{#o&TI|v%mdysEjxa$dP%_ zzhOLY2O%D^&CII%|5uI-9qMn6Oj0G;w{Cg=jkjp2Tx`GLxEL6gR4Q29Ab0U1B=t z&%u|Ye}1<7=4S=#J%7tp(r)*jC$0r3^UDF$A_cKxaz@##A zsObm~S+!C-J^}K&I!+Db&+2z4v1hINT2-l}rruk=hjy#eHNT%SLN}4{>r7&K2D+1L zHRd>wA72zH%-W(R{{E@+KNN+s*|d|h6#Ig7a%L9Dt(n%CpPKp(Q%nN{Rowo-{OggL zy1sv>888o`|J^XL!~cme@gz^q|E(~wr$1na&$I&K`0{eQ|1X1}954uC|2YU$|2YT@ z3_u;}ex$MLL*R=}CyFs|g5OcT-jHypnha9oN3u>;m<0}7;f+dS%utHYOi*nWa4AHR z<`gF4IU`)_9jEhB^rK{( zZS8u@`_d78C)T`FJdw{z0A9NY^rd0~7vdX?U51l9 znr^~&{7F8w3s30E**bQH%w$|s!LTqMGak-l2G&2Yaeis-nhjjiKm<4L>%0Sg2iIBW zf13$5B82pj{W*XcH`Gk8`ih*IH4Ql(FRntdubL324JalINVWtYK;J+l=~HX~<73K) zJuvPdQFx$9Afdt0Q-%c<&>?MujDroLM;rg01%Cqk_#ScSzS2(cR5d^3YrY59a|Q0D zxk7xmW6*TMLDVtP875gFMGZ&xqC6ME4MGM&HsUnn4P>%IB+$f?drr5|0^#cU{IuI2 zsEhxYh%M~Q0WK5z+!ng|{;{9~QHwg;+!wR^%5a=5+%4dn^PsZ+~I z-4Idn`d^0t-Eidh{L~NvYgPrZhv9^D1{pzJ9u*iy0_3BEj#bx_vxuw2-}&z-WUv?4 z;PpC{<-X&ll~Zpa!8__-;Wob=OPR`x?Xt6Z?rcI|#P(?RoLpR={|s>nPmz4a35A zS&X++ZQ}|W+njyVA!opK!7U(Hd_vLmN3Si4%HJXIW>odhA@B<@1oZxM2oV2c2q?B- z{$mK_H5Y!8Ep^8%uzfFewPqDO=V~A7{$fWM@XtFZ!;Rt+{qwz7=wQf#d1)(aTzfK{ z64ghhjsqm!-k?rY<#79KGOPCZhHY5LriADYyCZ?!raE-2O z_C4?n$DH454&^)>c{8;76B5<8`W?e*ZDUEx|^5n)krd@4K@JxC+ubXSVU+(2h|I_G(n_`P}Xal9Fsk%FNU^D`q8^DME zt_F9##&&zLjA9xWV81NIH$y&3w)KlQ+idjK)DJ?l(3Fm_C|_J3Z6+8zo)? zM2WRC^K$-1iBHYKED}VA{}CnL*3W#>C}f1hIwp4g`4a)x^|tIJ1fTd?zAkC`_}rz|CrZKBD^o$vWc~U<)NGKih{#3Ncjp-oSz<$+^rvaa#`^$^<@2$S z;rGaSG{PyT+A4WFUUdOn z91HwAX9GtYCwl-L#>5stS#~h_>1^WY^p8zzmAdEOP3vD$42WUX0`sNjn=Pq+$AFSN z*dG>-(PAi)pS9U8-)=WK)+GSV<*-4_G)>;FyxaS(W^}f>o$igFf1VhiOpp^>@ByIC z&oK4oeJ>nthpdK2%-09&k2BI!S5M3)`O8GJCBlh;q>UL}=%x(5_ z*QwxyMYV}RIjtr3_O6Gj#j4<~8=`QfI&Pv8zHHgQ0fMuAa$t$@f~H+9Je$-d;uJ~o z;?6BIeWdBAl$0PCi?m~1@m8SLKeaxFa@5CZadJ%3$+Nt+{ZXGmliM|K z5@8>Zk{a=bB?9AjCef^-M@K$^3mz_%UQ+9tp;>GgA^6?W*tK)ywf#XgU#sS zxg1FDo4>g|+oQ~>s)OIxFGdI??@(X)R{5dQgio$#y`R;9b3)4@6P+Br;+jrOe79Zs zid!kX00aN}z1FY{xt{}_)5I~LuAJ}{ziKuP(EE8K!?-E!TL8aflvtA;v=wK{^c3{Q067qpWc+rBx-@zP*~{aS->QI8MkyPqzc(eXuf-Wk z2^Xfh+x^hK;(U$d;lKFHD=$#AB5u^I8u%weup)zt_?jQdI9}c-lqb$c?--L(wUh#P z1KOq~1jO1TetcD!3oYvqDsrg|2&rMAP+{-in?DuJb43%MDfx|wa2xJi=>WBX5BJVA-|wxznwR_Wj~^BL5JfJ^ z=tB@(Eb*iTwOY7=O%r#{TWAZ@bw_+n>-11nJAJ!o zmbn^J`J&fK+^9ZM0xbnz5_H0|$C5+tyN$|3@4AzZYGq3f6Qhl05O&9sA&vBDa5^iG zeyN^yN)?vBNin)7Pos8Fy`mOlthH{Xc#nCzPTREH{(!IIRy-f>fIrluIkB3s^ROpA z`7T~Zmt9@GU6KN(BKX)J-2zTphYuOtr&V!($*6k9*evIWlbgnZJ$+x@d{JogguSdx z_H&8B(4%wyNl8_@$+$#{gfL^Sz`vKjl)+KH46kG`{{(L2^X$xkA@@xgGEA&2>Vng$ zI|N8N`W#mU#2{m2P7OX9k0LKydI9Bht4_*e#l$Hig+_6d>WrW@3h0&hc(bD)IAq8> z&Am2?Tz<$MmyXayz|RZP0xLXvt1B+UYho-o2G#nNkfd2D{GnBZEvxfde#k z35z^6>tfG}VLLYC1vS*Ps>O;w7SkE75_k%=T0xLv$6}Kl_~5YeF1mYWCiN+{gFQv= zTX4^bY*!*b-fZMaydl`&o`nc67cVZ{`C58@?TI3lwykR^+*)WNy3rXq7BjC6x-P@7 zOCroKxnK|UJ%2Jdt@h-8l7M~$-Xk~*evGH!?cXl*7qXT!+{4qFUYL!$OKffpzARV< zy#gslB9vhaV@N6x-{EGMEw6u}Hwx$fJWJwuv%-4OG~~K}>GuSSXh!=kp~jJ$jCOu- zUKvhji(J%r_%3xt-74~_1wDoi2W?rD^1MkP+v*i0$ATdILB+-8VWenAgAtoMU=1$ARb zKND$doP*c_G%Qthn_9a0-7@J~L29>B6^hu|l2eX4sBdzYh_%C?^QJkQTt7k3mDk|BjqT1&~x*F-+05bur4VgMPfMK!SK=-itfSNi)+-Wd;$)pM4aR@a-fQ%F zSJ%_KL@f_1wx7?^AjgeAhX#YScbC>&Yl{9+b~#+~Sz1z0w|4cbm4Z%w@^(Kc4WZ97 zbX1;4_No>oifojMvNzbxN;ZnBLZ6zq8n%Wa^dLay_9)M!x%~O3BDEc&CRMc7#u(1L z=KKaSvsB__1l0L%tVlnjK|DO#hz=`w6U*$^Nt9A==FDQ5 z4{ARkDS`e!+wfm+;GCw2&EG1*5Ww>vB?#$B9#35^OTrbz;n}~Z%P-_AmD5)ZS#k-jWMiqt%_rvNE*s^53 z8v3$iC+H`qD>rn09+5E(adcAIs!-DRFlEW(EBsaxS&V8p@?;Z7PF>9-o}R279=siU z8W8BUf8sR6on$cPN@wIm!`L5Ks;1fcFa!}KEECg=K+-u)G47g)-(HA1_!fG8F^e&? zb+*%%hY@+Ymoj<{7T-#;44R6rt<9kC#Q4}YLLIKm&FIJU{5kY0Vj4p8s@6L&s8u%M6W4skb%I)P5j6ec`C7qQ$PX=y62)I z%28q-CSV99ea52Ob+$}lNZdVDq_B>>qT$w!u_La zxv&uFvml?aX@(lh@nS*fLQou!%ayJqQMvr<4xuO#vVX_#tzqw+yewb8HO+z% z-m*e=s)4apj{KtqEDLB|Y_(p-qFPqpsU}^>{c#`FBD|=LnlOUXz{`*FsD#Xr2nO8W zL`V>H3UXg%4hgm0#Ng;{xQ!`W3TgR(LcZ7~!&-+(v#w{-eirlBDN?uPHGK0D^%dk2 z`?_MxLKGfv`gm@zJa08yusfZb3mDxSLBm;-Jlwu0nb1i;;oA!)($x@rfb;FgD`GQ9 zGo{>>?r^ooHswa?kH#>HTe_0l{ynHSc$2S-_2Q>6PPs-z5jI;bWor5$@!NLSl?o&w zQ6mQ?9YO3~2{BXTQH6(AUy{lfsm$IWAgVk&55CH*c_|VPa!J=L(W;nN*_uX~%@5l@ z&06S|1425rJdP|ge=upOwBo2TgN$*^J;mf%R8Bf89EvcfC3N#^3*H>Mb1M8f<@xt7 zzEgbmKS(wIDU_algc|AU1ziL^)BX*5J7TAG{EDR7g!82<=u=D~rvzb_iC);D zNB;Cpvu+zw`Gd%W)iRPN>%@QzvXRu@Wvy^hs~6`_iYxezfZexncQAAr$`@Rf%(zW$ zukWwsQVlm}SHRuJVoPc=WAo&WPsFILpG%CFOpB0w?miMOh|tbIiICK)5)f$?71DOQQK=wp0sxz z?YG;x@zbI0K{Bh65%%Q@TL|xvu#hgDfys00-P3hi-~(5_m->~S)&>cD-x@)L;>M~G zW}EJ@3e7@y{)NpZRHV{F{qr2SWIctwNpV`+rksLob7qokN;QK%YDB6`*4}ptZ4+o_ z8HS0utZ?g~CU>$ymDJG1FNP9|Xpo(E;zeiXF=z}1m!GBFG=mK4N#J}@svD>xoh6Jc z=mprrHS8Gex^~!hE4^Sgq)2%)Vos&11KI4Ec<%$>cni*kKF&BjS@w(XkThA1IBBw_Rt-c zLajEc#Za~Sv)?_oS#l^`h_E_YztikP%@9OO?auk`+>D$J+tV*UH*{*arH`90O`Tbn zzijNX5J?MgIU3Bf)G!nl-~&vp6gHNKS60W5eTa5Hvvg{>es;j1H$+tTX2m^p+?CBg zTg`s1ZIdTnafuyz)$Rq0i^fS4tvrG7#=s=cZ`r`(LWOaFo;JPA1a?9?X3Tgmd9f~j z(b$7Q4AGrqwpwDdx$y=Y?8I1#`0kX|HYFe7Q_h#Wo{;s*ST0XoTD5;>Y%K^+I9D^= zy9mVb(j(ADU3G?`8%Mb_y&tG~xFTw7Ph4B&f39u03g=;kXoTSkFvE30a6s4F56K1C zZf%ZV$E$2DbvAXmo2mz2&72n4uXomAFS3A2$*RZK{7{OKm3NonU9Vw(XiwGE4Y5MJ zr>xc+Q7^ih`Hix{=SImO3$-*g>*Bi;(}mzAUuykxPHx1%7^`l%yVdK)s!nV(@2H!h zd2n?vXDQ%3*K|$nw7us_;dBzG`ce=%3xa!yv4d#L*0)y!oaz6JmY(_@Kv%BOWdNs*{PI zsM2dy7rvf(o{duYemo9ZxG>gGfqJHgz@2-7$uoJS_K9B=s!BbR9%zu%zC%)iW#{kq zQXdSAkA=)1gtir1UY3=1@dGX{()Nna@EOBRomwAAjXvw|OLzz{$Qt+ni^2Km3z=&$ z24ld#;$j)-33k6!=KDobqUG9U&@@35`lQFHXql1skmpsY1l!FI5nzslyfu&r$_Tp* z#PiKt5y+D>&GLprcGCSjuNb{}jn9POAG%T`7x4>rZ7#Jc6R_4c(h7|qHg<Z^fQr zj^5I3*lc&2DGLqvqwBE8A7L-X{xFyi!yn9Z0FP)@vXA|~pH&w@tAPJ;@O|}~`GGOS zmi2?J)l4{$kqQfkha;ScS&N!QGppE(N zXtk3*H7X~}>di}r1g1b9wl}n=g)))cG+_p53pP*pC@fh+FA}fn^nzt9;s#OG&BaTm zAJ$MFw$6m!Zyl(UZ=y4H*u#UtH=G@h|5dm-M9L>J}PDp(4neugufh7*hx(>xZw5Z-Osc?W*1zjnCrzqY{bzr{x7> zJVyu{;5DrOM))mBxpAnaQ_=6zZ3Xc{b7IUhHxOxOF1a^r=xV=GJQKD{=u@%Rc1KE9 zk(*Ng(&hLer;0H1Z6);D2VdOg!^1ZBrU!b?Tze(~x*%*viSS&PNuGOlbz4H}Dh!^@ z3P)0VOK*ErJ#R`t__xv^_3t-=tY2Df-OXtiMQ>Ogx!ynHJNQmO!WhcJb_TL})^GbA z$(pey(eiIWoh5Ksz{28oNwgQV_AMZo3*Hh5kaT#HPp%E$N@r#ZN8xq}T`Kq5<}>&y z(>ILCCc+n>4!nNhF;t&6n0i1;Tm8PG@l8lfI`RgrorJ@|oEMG}=8)!AziG3Vz9r?R zG{H_pDp7k1S^ehPk0~`^1B+nP`MoOSlL+z4J>*=KbO8TBQ^C(pMJ9Gz+&u4!SNK$A z(7vE)t@yFIC{8x8QO)M}ZN4Uo->QP6np`RRZhP_1^POMI+OTQ$#Xd_uNkWrJgVwpC znZKC#87~bv_;ic+2T7GVwt4$S6=gjX$tw-ha71E>$I&8!op366zczgc%lX`P`0V4a z-FtEr1rhe0`#CTC)Qqo$A#Y`iG(QQ!?gTc!OGpg7gJJsYm)5?2{Dl6{7M&V0`D8>1 z$!||0qHy~59d3o+VPoQrqLFcsd$mzyz4_f1A+gjgq2)$&3EvJ8KQ?IL<*{^H5}M?p zio5(?!jD+hMBRrQL7R7uY``%~K7r-UHDW*gSeiTmmFElp|6Ca{wx07z0aPPl2mplh z|9;o9a*j=zvQuG%34QU6Qd}cS;fT9}ydzO%b;1cpJ1)z_2eXf#2piTpc2ajw^l6Bn zxr67molaj^qC5FKvi-^X{`%p?W7EUK!)vqez0Py~bl>Q^adxqHcW~^ucUzV|;rAlA zq2L1M0%XasWNkMfvLst#6}=IDVb|vQ?RBVH?9%DmQCrcSxoltd;pm1`u~I0HLj@QANn zidxJQGBqx!80im|jPgzQvv&QN-O5sr{nO(UpLb~#2bndss&X(Q6MTjO$<&DDw&4sa zFA#0IU;?l7xF#j~6^SktrMw=6cW&JKy9{QSN)w_o8vQU8Eb)F?r>TR!S?vs6+vXr_ z_TV^XD#s{;VP{7K$CCDSR_+Wn-$LcE5{CedkJxc`zCviFvq8t*HMcaqAO3lfCfY6% zrtz*>BGegYF%ZVw0LbHdZ%2(r^>>4$6yo72T#6~CE!9BfP?Hb&%g*Ln3MoFZyFDnb z1V{{bOqdXpw$q7=ZF%cN1d)g?wFfbdVu`caZDv@?vG217znYckb)?zl7;nZmzsjRU zGR#>TM0D(P%cDV)bcF+@$hqPv5AX%-(5R-5KKJ@&Ed_q~F^m_$~|}=_d&&qWzD| zT+Vj30Kvw_)DVDou(LNY{YS0&C-9e}ZwOyLd%y^JnyU z#Km>;vZ#t!nEgNr8NC}!$JpEa;e;_-wN&|&>sqQMq6|Prk-ius3ZEHkX84&g?%-s4 ziII!0b2^U4Bp%$~XUwf3#iRjk1=(1S_^H%z1je5*pkP>d)>({E;>X?}mWv(FBjsGk z!kXN+AU>yyb3=U3=jBcBMG&2Y!FKRB?k5KU8%F@11BgbcAQG#7zgEeu+rx=*Y4djJ zif%A*QI#^)f}~E%@JX5@m9{)&V@E_bAQ&LdL6RdEkBc%4TL`Jk?ZG3Wjk+f;Gx<^+ ziz#F-s$9%xcacLyrNkYD!${yj&Qq*C#eoqt>&&u>O)T^YYSDDAbe0lC110;O1_CrH zTNagC>iZB$6Uhw@Rx=Ov^;lA9we?x-$Q1WEb%fB=GRx9}nBP|4c7$qTiBj@M)kKu_ zUFwg}A%Tn-%&Ye$|A0&_flGJtcrz7&4BSuX0lzJPT0cT1NWcXzuKt`Qr(8JC^E~0t zx{G$y+dP5>i2Mm0GoLx#6ITh~SPjaUS!*!0iqL=(XoAF7DTXjbhOh`!CrC%hOtXLx zjIjsrG9M`|z)USu)b~UcmWz&(q5_K>WW_CmQj}z0Bo)ihkhO-j2UY)wxvp~EKp(&_NmJdkwdN1{&K{b zNg$|xTD|RldknoJVi;^c4Yl%k9QchpAp5P!BJ8sIiwTkD9KV26z1ICW)uE)xIig2b zuvWPXh$|;JIBOQ%qDF44mWdu-tMjUgQX2)gJ07pYnL}s?_{4jIOqLBLBodMeTQ11@ zbN>VKFX$=LbP-rM2@zJe$0)J#0;AGCix_!32ql8LND57aMdno z46psmh7YSkdU`UZT$W5M^aD#ZvrVVv%jp)aTP#-nYrm zOEOJ)w#PYN_m8`9U>@|Q#%zl)ya)cr7cx4?=ei4r$!=7nOl`t6sSjv8qn^q!GD3?(#FS`b&2%?@iSlB|`Rek9vIro#o!HG$f3n}-3P7>>M^pqhIQsIz0fPKZA;*dG$?MGh3uWD(J#xw49J> z@0w~eL`Ja&%mm)ha{%n%7c+01NpCze@(iRyA1?uzkO+Gq7#tqmsQ4SB8Zy4e{gTOosRG$A3V*G0SgW>(JQ zd+_CT&6nhj9X~H-b}_lT9Xy0D{Xe6fjLq6Fq!w=fP#OeLI&)Ntf zOczLyB%Jw?5*^EKfY=FX$w(--IPqf)qON3TmGZDDi~8aqsS-qoUSM7pwIhbvUI%-# zX90T)fmt`MOPyBp#Dw0;IDw4cq0t*UxH2*8+MlquCTr8yw=OdlyT{$&52w1D-sxb$ zrz_(kBqF=grOY_@FTt!#8|YfJ?~nRJ?-AZ&9(tfkqZYM#}^Ul{OI9=Apn~)Ddq_Cb)*aT(xl8hov3w0a^8NgAApXewMCgg6z@f@W=#S_g&#i0yWI= z1K)UOaxSbE%zvo{4-BE|1wnFt=ZJS)E(A9o&O`sXm8P+=4+2_;CbwQk{0&*j_JY6Z z*2UF7yZ=^j29!R&FKU===@zA;L8_sicF0D~;ZjQA6SC^a+H->LNgH0H|L)&B;xfVc zWCnnZ@=y-OSO;hIzP;MhFQQ0)BMP34cr*MyAY1>Z_zwDy&F;;yjsu=iB}?0xM2`8T(<{3kM3qpoR>%!uH3Q-=XlSg|=7uKem=*vgLI(?3M&E%v3fI6)zZrQ0p(;59!*S7TR zl%@Nz5sugSGou~NoZX!h`}#3>U_yzCdzI+;c5g5|k$aYC#*%W*@wOStFC+3b0N46R zp#xAAk|2oY4tjh$FAAs%aWI~P-Hy*CgV*Sk9UDFTEIQOkM|C%%*>KY1!Q|0-pwQb7 zkX0<$lgmQeitN#u=L~$z_x5<98r9h?oF8eyKqGP=CK&A)V}Q!?MTi30XKKJq=iq=* z%632sce>l(Lex-I%adjdV>UO-2v*L{7fdzehcywQ3+)UT*bO1rHQt!2HZ@Ry`{61b z*(yLnjT5M9ECMDNKNVB11Mqmycyf?JST_Q5|6vkty3EyPyDYmqzQK4XY5eiJx&eDF z>y4Vn9sFBgmd#>Vy(?_Ig^|pXApG=I8mXLvp`eSw-UXi_mLISOi-0E2!6A4oz$O6z`x!U8b2fua5# zPrNt&P|w412s~&%u$3J}X()G)_e<48E_vYuPkDI^U)lVwk_@W#m~~*}5ELV>%Z(vs z2SH}*@xxVU==H9>{SHr;|LjGwuT`*xTHIXyUe2}Qiyi;dilTjLtbhF)+njLmsd5tArLgW!}2A!jqC7p!FK&8R65#=JMkLb(qE6a>d9qh=&t6!?0r?t85Oet z_T#PXw*lqEP`E(GlA28|K6xrSXE!Klz}~y7!;e7X=Q^(jJQa#B2$EM-I`c zwkln+w~QyYzv}o`*VGm}7~83({z!SVW@@rPicW$)kgyEpg=kr}ohAiW_qL;7K|c+`HaRzs}59-Bj?Ii^pItKC1KVV z1((_ncc-WW&GW<{Ua%d{I@!AmZn*=+Y`Ds34NbK_y&Pcjrj_LyQNw1sJvq27pVNIW z<$FK!!AwnPt_sB$B^xhoS9SIJS!u|>zzJs$ojR@==b+uGH=AM^ytV(l`1EE;a8`y2 zWfgXueQZt$3UUEEcMEX%EtF?s@m68^%Yz^eUxM+T62@AJwJ)^Np>1oNUj~J!3J0T# zZfbwWp*aF+A&2i5Y6k(!iR%!}UjjWueICBueTuh;Vi83sd&E~KX zaqg#;QNP(5I%Pu3Nn;}03$fuppE3Cn6_&zp39CtkUMS_My4E~{&92bsWe05l!NSi^ z(RmkM0q!6`LmFvfhtOlU;hKN0q@P!}G5l6T#{RLuO9-|;^IPno$cIs*7Y}>+jwg?AqiG$3Ns5bI5EqGX#lY z-};Q&?$bUW@>`XlXX&`$`fa&jVhvX%9W-^7&%5^U~JCq=V29$FT+3qvpY$B_^R2$BIoL zQAiHjNzl^R7+jZeEr^>DMJX%d*Ou2qtjGX#`NK?koo6O`@VCmmvuML+=j;8uVA;0b^I z;7&j+V?=hWIug68nJN$St@d=QF|W!d3|zSL(e|jPrY{4tCJ5nKS&U}VmISVr25jx@ zSE)8;tbP8hn!$TJduU`UBPNrL8_s`_%^QWsy5&meEBkcTF03X$O-D^fE1ZK2qpqLa zTZPR7&RF6H@AZK<6MUpu*i1f1fg2U%*qib=zU_Ak#;CRqksdG)Fq0^ep0^{5k|>K% zMGru;f*Lv7K_VH>X$Iw0C_peV=_P4B;UbCBa`u#CKm>JWx*!rzLK;e?IdS67gPy;T zPBhlL3*u;)$Nrfe;tueI`_0l8emHmFH0Lhjk>QD2qK2-4C39O*4C_hDfW#nJ8hlMm z0fG)yTJx$?R?wr^zVYtv9S{Eo+AME}pgN4fB8%tZy%iq3s{755QEG$At(sHD;{Lxv zLF5*=()8;89ST|$jNn!HjR@(BAz(HX3e7^9(Hi08dq?H6gb*_2b{cYfOXg}eymK6i+MvN5 zWWF8JFqzy{*1wZr_l;p`yCBZnrnYkrg=NXM9vv4A^W}ZgZ z&y^gw&Ae126$^UAQ-N_Y5i~Hul_XDFcsglxOJ z#rpsGG(ivp<;M=$%fC3rp9GHi!Uu`e!UD3?4R@wvW+f+62Xst{{VN;frCQ?O#$NQ! zN3xnRdiXaRghcv1)WfiC>H4W9HSGfA>TfoP8ITS7IiRs-4af#P1F}Jek#9#WfNaoO zV1{sdtq{`RY>+P?8$=soph9g3d)Ax_{eyvLVGklpWlReuWPHe3tcfYwB1y6Yf{X7D~Vq z%}P>Ny^x_v7OZ5FxOU2jq5^f&U+q!Pq>9z_@wa*pUQLGCM*?Scb`2wDL&uAGg0R$J z8pCI)EY(sqJ$P#%AGpO09^5f!nTCU}{THNWj13xEVV5^drKhz=6d2G!d+@mMT_x)MmmLMv_EyW z3EB@o1CQ8s`-L-`M^gm`y9Q$U*Syjmdz)6j87NZ2z;yl4OT@|)9#s8BNh-6t1QqLR z$F8hstWWJ=XBkGX5<1%Zzkq3f$3$bqTYf#@mQfa93;&PsvH#pM{=fH&!y5mLh7)y+ z;QVBXg$V;~`a}a<2FE494Wq2wJ_`gnT--t}!58+j90@vF70 z!Pn6?aSAmkK(`>Tr>9Ru{XyqVcz7*$*34}9$%8t*V(*5qv*dg>C7IHI?#n5w7>61a zcE`0<%Xw{>E+P8$#}My|hVPWl7guHf8mwwWw>EOqp69@VPbYY(zk`E82P`cqp$}3e zpSMl9MzHhfF^JCCt!ND_ioM z&t$c_9eBp=a?V&52Pd@GtzDFwRFZ#7nCG*7OV|-QP{>H4HnZQ`IJ&hVx2{5nD3ERw za%#ci_1&B0v;S4XoO4%mRXIVKD0sO(qpxc4{WWae!ti4NSO{BWB^mz=wB1zeR9k^a@_yec}st!`-Qis<*N7ew$4Yb03?xx9{9L6^|o}DbN ziXuWn8dm~9V3RIU(y1f(c1Dh(3e3nkS5E)l-V&4Q!iU5SW#D+a$Ls z?$qBB=2tFQHtY*Q%0|*!zY9PKa}4tlaz~^HIih|JQQ7=BWq2P(2~ml0%rD(G-04V3 zth8@dROei+J)259%{h9>M>ujj9eG)A_HV!o2rjN=pl;uy^^JH0YE!}{R<#>gP^eQz zLB7xua44fN)Den^m|Hq+=hT-gX+Ru|6P+kIJ zqkS6X)UUb0qb$Gq7FaLy^v0iqYPnr1Sfkj@>dVX%LpIlVe4&E+lEBqD&slzf#zIbB z*({Akme8w$T%fIo`PlBxDb?36Z1j)OybFbC>36SZ$h3JNqS>$g${xO+=RozL@^9{N zLsrgGphyZCYcV4?o$5|T?Ga8%n*6qkdC2;hqKJ2lobC~e@QS&GA|7B>o8sJSr4raV zQo|fE?2^s4O*Z-T%4ClORO%jH0!$C|fv0ZVq)I>%($^h|C9fmQ z%zm!i=!ta;ba|EpU~X*n*FiAEeM6lRiXy5?;i_1FOFM7wv1@rmhv!iyb`AZfhB+DW zEZHIt&g*dQ>#P4d;qn>&!_a;v{w=s*XUBiFjcG||wC^cNOhL}2H@_QSia93DOyik% z_$#9^Hel`3JS3Sd`7d>YPfb*uldjv?I=90awuAL9W7;`CO}aT@A?Anm;?2cgv(YeZ z@S3uIfpe#LSkF$;*EKK{9^CW5mbh=;^|L#CnD?B)O&AwG+*ikZ9U9L4M9ZQt>pbj| zZi`i72p0<0hoG7qKJ`Uk9QwA0HQRwG8qO;H zqzcxn&04h5pZavH=w{blRC;w{#9%8_Rt21_%fG8fd`A)@FB+caIUPdKz>I{<>G6Ad zzI@7Bn_K%hJcYCbEwcu5ZyQ_Jyb0&Z_AP~-Ul<&v$IrXeAg6d~%!_rbL#FaK+N|26 zXRM8T`eVJkmv5_%a2iirIk=>!hFC3F7{Zeu($T8TU26mZs|Bo!iLhE#9AR^!^+g%3fMor2e zNmlSkLbT_fJS!Aa*f6`XLMK%aJ#A-j%q%E& zr}4?nv-2xO4iZBa0f*bTI;p%b=`fQBQqn++qt;VC5_U>F=jJOOokfZWPeKz%yP*3# zAPB^?Bu>b`+p7KF>G4240q3MJKtLma`%$6)i!B%+pX%#d+5uKzJL7+L;3;iedqAV+ z*S3Cth42MTgQ=#U@;=6DrVaISsc4en26-?NWmXN1B?;~*_VbQA38}Q)l|*c}NdT}W z$&E*sw+9bi#T@$y{`Tg_-5to(A&(Hg|L5M;2K$)R`m_Bt_6A=sr+DulpNB78CoNl- zK}VV&CXzA48$IpK39QLXybV`JPHS47H6ij>S=8@xcTOmd&ux^_DYQh9tbUC1xZ6`j z8rimn2OhcR<*wRMP&~&fM#bxFXL;Y8;nb^cEWUncZ^>&2OfPoTHR0`=JGJ`WE%7i)R*zEIu2Nvm(E4Lpq z3l$wY|M=a z3Z9CI9Qb=QpU|NUMi8kV&y%`hoIb&$Z7@l{5u5_2m1DqHWkH`~2}B@pfp{5xYn7bB zWN?Np-Z#}DQk0KTsZngDPtQR05U@B(v{?b!(~^_X)A5$iR0 zIoMPtBGjiTMGeh)3N3YdT%XTpkcZLiShUA{N6YOCPFmMvYD-}mu$!%oPn<;stbS$1 zdRA+58}S6VaC~)9$QjF*XCp3rUM=G$0ZM>A1 z%AI~~8pXlX`bk{RVn&@I>7LxcTI-tP7F`Z=!8wwg-dQhPvQAdi2{TVl4-=CI5q(lM z-bLGE?-4E6HaUiT`2{{&-QoRa(d*>{bZj0Ej+?1-N$aPNv`&@TI4pjUg|$1nM128g z`v2mhG#kWeYKO|5!ZI&qg|`*|;h3c?&LHG!{KG_}Ppa2IHus$|Wd%(XYunmN6&!9c z#g5Y6?0e-bY>x$znq&R7Mz;x3*2wG5zC58T7UP+5Pj2Lt=e@c!A%#6OR{s!3Wb%(( zEs6`*jonOUoMamTQ_-b{Cp+oSnoE~RdwYY&*cG9=KU@q9iTzwG78SeS5P({D48=}~ z)$>xP21uhN8%2x&lvK)g$tWQ-$saY6mFicr8$Il|oy%CSvI|;bgpxe+0@}OQ9a`Q; zL8HTuHog%PAuF@m2d8*@LTdA$FsqbvzNOTs{Iw+Sp|x0#YG=z@*h4Y7p*UR@o{yNw zU~IY~O8H`z1^I+wjYTzB9ZXlusRG@Gwq*W>=gAu(iDK_#LY?dK9ExvN==Jl!hrX@L zX|<0UGV~>i{lwy>cbyk&Ex9PsuQ(5>M5Alx?@YSCWobyw`RaMU!H4^qun-xU95`Aw z0@^m|llv-ll2ezWbOWnT^Bt(dJexYkJ$N6M1QzZnfQ}E+Y2XUM3r3)?~$8vgi*vt2tLLiwXrxTqxe(*8@Q>Yt+mO7NYq8X?)u@&*_>PB< zzNDS+B`&OCr~+9~3S7N>>sF=Tq(C7d@G5~Z9Pc0}M@-%H$?I>_B{A-W1+tTID+IqQ zO<2qJ{)9}K+`(GAu)%xt)EI`uRN!WzJd1Ksv%Yfiz(wA|24f$lXUHw()5ebD($(j> z-kw4AdKPy+Ap~SFP_EU>gn*1-QA|?=;aLOg;WDdOQG%BV zM;dbM`h6T_9V4nd7Nv@H@P)0ruCyB9t&&QbpL%u&-nf0zT|M!Xq3;KxcLwK6^UQl^ zziYSWkjL~?h1aY7At`jEMOJz6DTcb|`Q&mJ+&xSZ<(f+A{XsG^-8|Z12Nv1jY{jI_ zz^Rf{l-DaS7rG}A|etFPblCnDu}mWvpyB7^3psfj#QAkePyk%G=Oq@~?;Kr1y? z@#DL$sU(%JK@xgd$_(&#Mv0$tu}e_>`rUwkrsuP&RrIrphH9g%&||SxAzJX;n!8UW zj^M;`u7*$1Us9OTfZ9o&Zj`!1y^TLE@XbdKZ-+xHvl`Sx&EGk1a1pn#`6LChs9L^d zxPd_#ri6g2z*y%9qEn$y7zyA%FYW0G1L&Twdml#k&-ZV~?-T6k$yL!eGvxSmJD-l5 zRxNQbvyFOF#<2NZ+*`gtDpP*n0-|8wn~Wq(8C$WuX}7nZzrNm-u+c)H*u`5S>)?nL zg%zUQf;FTWvQyOzbQd!zNvX^rC}i?Xcp!tgvg&;W6ac>ia@l+Q1iXJx`=;i04EqWm z-npjbtV~oPSfLhj6>$@+{Y}lZb14Rh9!*xubNs9CCJrK?L zA;C)^z~qDr==CY(qh^9jEZL6AyN7%UQ-B6(kN~HVCNsz4;Phu;!Fl4z3wk$8X?CeI<6Nl5 zKdJ;O(+q)+FJy`98{WG?OXeqCb*n) zWfpPjW8a4RYJw{`3)NOoQ{o5je*NZsN)mGawPtwDJid3T{s1A>z9Vcrr6BP0-Pf?a zy~%Blt$6Cb*R%6jkYRa^{~C0}>Y2N*eLI|&o(Mk2d^Kvyr~Dn1F zw)>XPq0&qrioB)99{?K2!3}&1i}5xV3_S$L!=j<-W&{e;T%q7!_Ji@t{*|FMj>dR- zQk1Iox=7l&=?ewLt!Sjy7DBy3YF-H&`qLIZ?9w$U_T8W`^Ak?Src^F(V}U2dZaXRs z_6&ZHr;#*z*h?2WfL&|a!iOFb`M9&TGaueVLG}a)Mq{ZFr~)`zyFJ3C8g)RGBNXwJ z6c`@t0~zwn6(8Gg^oxi>*lZWx9^xYV^D?*^@OLG&@b$mp6H=j{5lS4{K8Gb45i#Wz zrlDZ>^{M_2_G|xrH@E~Il&fO%nc#YnO>kwr1^A(wcmB=uXfADE$NCyRhxN@9eBpBJ zn#Owd_gF3954^I$SYliS+6Domg567dgV`GV&tP;@(J%!Bj==pNkga(rN1)vY~)+_PvOrRshQcSUf?Uk^Wl!SfA9i z%{%&jKg_{VdB;XWa8o3W{?1c~RS1pHm zo*qFlYkmV#0}{PP9G*K>(-oXmZ8AL<(_quc(F~GHmW`RcPkov%b78NRF~ahu=_e)# zTb`ZMR1ff2#k@zQTXeDKPzA|SZ~{GJsbWR((5zk78J_SLA2{K-5m|w5)_R0< zE#8e&M(d~3lCQS@_OYk$72C|rMe9T*n=dbKZs{FfSyTCXYYu+tL+=H@|Bil|ywH9E zw@C#i4p)GHWEzZ4B#?{1@u{81Y^U)CDxq1U&3d7m#Bc`5 zA?@Kl9BKK0@kk1V=*z{5_@$CGExEL&&5W<%O}f@|M!qIyB$X>-mr7c5AhFc377gVu zcz-<`-ow*|#a|tStW3wymq}H|YUeG?Th26OS)U-dwxnT+T$IVu!Bj&w=M`Dra$H~9 zQ*3aSZMOU&@a4OuKaf4GR1lnp<`KfpZMt^){ZHja$*?M7x~OWb$VBaV?5tQ&p}%tG z&(0>~|Hlpf_pbc74lRBNAgNXZB-Q^cdHXM?kiC%=V3#!c$BwIh@h^Bv&%b)eEG5|x zAeY&YY`TW5*P{aDle2WN?c;E5%HR?HaGP^mE-30D=izL)_j>2i2Wykx#Ea+2=OqrL z1!enryd5tw7APk9bopnKkQX7}pBz-E8%lu=o|8q*R7t z<%IkU)lOmeLNsX}adO_M{~>C@{fnq|3?OQW{1;IRF#|x{W;#??} zp58-lx~7&{dfEUWqCx}@DHDb7-bbNek)49Gu{r(=s`W1s6#&&5D(uB#Ck#Y4WtyVi z={!@oq- zvcDoKcEBg>@8){(!~Q|5e~GBxh^cDn|A?rxo}d^|KL{2CKY)Jqi3V9&^Q{<`+ap{* zUtbM|fBOVJCufg1cY?_*ec2!U{YBuo0!$;=TvKm6Whk`3E_czflGDW{dZppkVlSarWERC&As_-62?T z4Frea!L4w22o~HOg1fuBTaXak9fAi4E+JtBN&iGuUV?U<@(2r31OUrkmv{k$Iw% zRbG~3q%FR%Xtor<$tW15Zl6{FazoC<4UYi4AeO`jjnT2!E?(Qy9$$_tt9^r}nf4Sf z;_%;}VuWgZwW3OQ91#vr zeKC+-`ERjW9xt(4-sGnguf`y22wYh%aWD1yQF^qxCJP^SwRbJ#Wphp~!yeIw0uaKD zOX;7rZK1EMhsqpJ!lE;ipx@JK&^uvpY8(^mXj!&Yj@)(}v1R7fudTfqSbB;*p`w-x zK7mi9)q9FPe#7X&;wWEGCJA}?OAK^>q`B^cifF=APS!Do@CqZy)I&?a0ehbyX~WA0 zS+y(bY!Zl9bgh>7BVO?nQTfGibi};D0k+~=B545#i`iN_$mOu^bPx1gy{U6k$aBA% zjJHj?adn4MtXLn~Os`a=`5Bq*v#5L8i0lkcOk3}DN42bZNO+s_G6`j-QH%=gOw>4! z{FJsEO*xlj-;{`b71o>C(n`(v_xxx<$B^mkUesH~c2#9M#a%TDi&%cDbP}p>o-$B5 zh~l9Gb9Oy@ML=vS$tcan$RXJ-4ATf1`4qAQdQA*rK-l68OV1}qlOd<83AuWD(E>WM zx4Uu*%XuP958MfcQevqQXHmPjcH4EQZcyA(dW0c2jAOwDO1% zTiEtS8Ha2Pq7!ujfrzpEJ92>9sG8wUd$)Bl;Y0kU@i(uN@^bh#eu6)+!wn+74@g8b`0?x}@&EXi&TR#}Ix%z_8& zc;4K^UOZkR4qC7dcW1wr<3TT^&E+X~RB#>{;3T^I$;5L+{P%o_(rYgY*quw1u;>3P zd-rUgQI}gI_+LpIuivB%v{pZ%pw}ITork7A9y64>IH5J99)lpk1c-`Bk{~jXN+B+2 z)kjl(p?gKfu@GsYXK-?4A1<;9?iZn#CpJ-8u2Ew2JFT(d@SZCso&^_3x z_@A47hyP02`2Ra;)02~A*n$-k@@x124Iph^V~#VUj?l$8mX*!Ku_yaLr@R%q?jNFT zZYOUEf&=dvC``i_4TWaS9$&@8pZite_%FT|1X$L z$NvpxtC|&)!KP)*pslL2u@_1WmF-!GK#TRJr*qvS>*!2+DcSBn z1;9bvxA|J(SpHbA#Vf08H74Vp`(!BN^3$36^JPU{okZse>a$Y2C{M=fs+T8JwtZ10 z;MH)|>a;$jBS7zH5AR-CJd7n7y2y(Jf*0Wji~}+vsh$5Tc+vEa;KdJ}-(&xK@FMYS zG?2dA6_Z>b`yp(#kdp_ME9)@2VYXny<=bT`dfr>FaC!({HqvUAsQkEzy!^S=(H2@$ zwlX3Mh%2s|C$Id@Htr77IyCq7#WzonH!o(5UiArQQ512Kt*129+y`i0%?}&tBeJ8R z!&pG};=AA3i%O~odPk$pod_k)KPPXuKbnJy4!nwaRV9t4e#}jsxqLXQsSgs*>SsJoR1`dRT{9SNQd%nY&;9;5~i5o-J-qA8piAmPMEjiCr z1(19~{}$66M1k$7J5bIjw_+L@N@^xR`Z1ed3FrMe5Wj2TyEhr4NS=BaSat766wsOs zL@owZdnZgHdFD-O1CfhY;=y0m3)+8HKXspUNK)G8eePexV?&9wT=>ZqGP7EqSqp0q zds{AnsaacXgpkni{w05RWZ>CM0Q)XWiP1`ZrWG9Gb>Vz| zkcDltG*3YQTpMpr&G>>zxA~FfyAh^Q!obqgTbh3g2H3ibSzG|FDFG~e690SQ=Lj;e zGH}q-GjMP)`1s$wd|tn`LnsH+mS*&SdHH@V;iB^`{BF4M6r9S}g4uE_0o}LRx;pLL zUiA$Raz#tpeD!Ppc(d`PE;vBk{^9A=fRN;U)NpW7e9~*lu4M|0F9EwjGCg73-j`wM zsRYVM-`yHCoj(NYlGbxF#^&(=1 zV2am>zTNf70dHZrRg0#ZpNWJh2JQ;Tult&IWM+s+OtH2v0MXvj$p z{E&e%Ow&nQiPZ_R!Q5OxScw*1rzRo%SMqi7@(0F|hc#Y%qjHX)qCgv9BJak<3gXZ) z-|WEz_@?o$x{9>-z>Gdr7J{ZfjGy8wcCjDMwxS0$AvhI1bzg#7H4SX5^p4jLkR)ic z7Qi(VlodEy7LQ#~Bx*XY`wjCO?E?%AESyHIJ;xjDMV%uB_QvgFo2E@5nbaT`h`hnB+jjcY8 zk7h=Uj;ii)lhd-Qaw9FTdltXLp1!0v=~#55T&fi<9uArsXDa0U-Irfz>^6MP9OK=u zKyj>*tKK~ns`IQ$>zoqI?OY4j@Ce01tMal?I>J`TC9rLqnn1x_IRF&hWiglehbqM2wlvx+=iU z*C!%C6mZr(3ZugZWq_*>roAC!q_P|nq@ryfJB&5i(qF|hCr!$(iz}<4(K6R@ypbe0 zAfK+W#;5(Gg8Uubq>;MaXX|d09I^Pk)%n~=H@_8L7*kZ77egPbkEWZRe&oX!+sVwn zRtOnO{noRv`OI<5#Hq$>Us#brX81g*qFE;Wfzu=XqIYZVxBBSqH~C&rW)A}D(wWZg zFbU0vB`PTmK#Ly}msBQ|jO(9>7+HeFl#oDVxnvX6E6bOtwlq!_&3}yMUvOJ zBZMEnMu=cdRb|kv@XJV&87Dr<;o$K$=M|lOy%;Hz8VNm^m87mEUiTwxM1A;8pSuM z+|Dhv<}cL)(@L!0U0!B0^=7vxnz?>IUV|1$KnrtpI=8wUYLP=X8PLV0P9;ZLZWJr{uzMRPtdzbC-e zcfJ@P9CRY0+nip(C5X)&kqLqcP~F9~O0f%^ACTs|^g2w&W_$GOFE#qg@jjG`$Uc#R zxr^nSD7Mbf7&OH>yiRaKGb_!7v6V5!@{}zi_SD*F&Xqk>sgcXv;6>|#_CVQu74d4z zGJ!6RvJO&*2jJ_o27G-f)E~_pt}$V>D7dD3Teh2?9Gb2=EI4h{g&^*QFb@1Ap7ixU z>3F_z_!6ma3VqCeXXxJ~UX0G{ps*spfC)jhFB|&WZ3#w-v_``Liw5J!M}v=LNS6ND z55BZ2nfhY%K~TB&Qq-Rju+^I44*O5$+Eukf-s=&TI%=1@VbzsRoiX2A&-!_M1T`0? z-b)IX($;|{B66MePDfjKY{fHoAAL(V93kH&7Cv$;;!~fIKLQe!>vm z{RT2sz8^<{^Vf1yK>uF8(XMui%|s~ultZsOqhYy~zO{dqFLgh=qyJXg=8*;`v;Su_ zPrC62$LS?(d%CSM())D$GIYn~;BUJD1C=T>(QTTYiT6iJU1YIX#LtlbHGE%~77ui8B&c9uvj0bZjGms6vB{si$iG}2+_?R` z=H`FyB3JsYfn8+Lu-wXTSI6&k01%(~l%jsxUs@Ayjpxpd`^o(Q9MGD8!~|R&qNIw1 zpS<002PL*BZqMBxo`{ZaZuHAbI942}No}a#9S>O)#`G25{sd8D3}o;p)f(v}PS9p>=vOq9qo-I}UF=0kSh{GQHgQ9+Od0#vD6?HC&?T3W0MEH}qr}+cM`d`n zdkYr9_?6vN>I!c*m3ch>>w?BWp`C^EXH9Mc<-!!%MV9LbT4B47uUbr$Ap_-Qh28}D zm>7yh=)jve3`{VGpUxJO`OaG@jmj){@Dw@zc-c!jiH&us%D%qe3!?1fUeS(b)spU0 zNYhtsJCo;b%xoU0{pCV)m zcnKps!%VvGXv-_g-laMpz}yjJ%%btO;tp9%Q6lO!eV8w4C5H|qsqx$7xI*nQaii#4 zFR41lBOTP>IgKqL4mX(URaU`~<5&Fd+PcVuXu2l4?@DHQ5}~m?sij195h5Vd$ftFm z(HOvSAg472=j}pHaDHAttv(KV_>(Qs%!ia3_HsxOU*6oK1lP17_ZlWNDjtbBa#9WR znO^lSBilwz@}}yR|992NlH!YiHLalZr|PUEgFV!lMSH9>+Eoz+ROb(LaneO_`82QS z^2#CR8G>5Ag5K)YW8ucgH_ml0dr2D&U@s|dH9Xg`Rv*{teC@I^h<*EEOW^B)we87w zhHiYV;hw}e=?t^s%B7M;?K;b|iZz_q6UPd$cL*)6)fz{S5`8to zO5G61vN$TzIk6=3nXCwSGhvy97?AvZaZFrH9^4BFNd2G8L8=!KN@mEsx^{uRJq(>n z>9eeoV-Zr)#ggGHKJSENBC4`8ci_0x%S!AbxlckqY2~_Fj2uuX!rsw4MiG(1tYA>b zs;R4&4Wj!h_uJk9veR1-k#H625~}kzI0_B256w;e$k#WSh7c{?CW4=ecmWexo1&(= zsBgC&$`U2<4XU?@6Bz@g^*Rtf1NO6Sb~PKEiBB*XAtdT6sQJiVn^;F#%uBd;pbSU{ z|BrNu!uE4REkmeO!pk2fwt3|Tl8xn7l}%w~KO^Ub!QC>)cs07y76En-md~hUibeY) zJ=N&m>C!BN-|_p^8Qt)v0lP;Grwyyf4`0g)U;g3y%@a!`r)a|nrAecz?Bic@w{Kt7 z?^$b^lejxUt$T53EdE5So@+RBWvpsz6gu^I4RioBQ`-}pruYx`{q(NO{uy(%4ZWdo z+TbtgWMr_3Lu&~EJ#SO+sVo4xU|j_!SZXT65gh62ZvH9YkZk4|8MLLJ)Uejw9lnTF zl9R@vU678J-CHRyd1RT5SA>7hYwsk(-jGAj{{;2VF`_%4U;_&XQWrpw3jgP0g$pZ}3c6oy z;_Gy|{?T)}br?*^Wh|oG)%H>&59}ztKRu8}jTf43_r)KC?-@-9Q7Zo}MQ`JNOVKSi zpfzxQ(5nRd>{8Ct#vF<94=I}UB1J)ir@-LIJR)W177)1lhZLpKliP>*Ek(J0OVI#) zZZ6`F2`^GK-t{F`=1(aK#LB!#Q3gPY3Z|!XzDUs=gg>Py^*Gmy6kR4E)azHbSO4%L zMN>_wvy7_0zev&Wzon?r#vfAjYIy7Pt++ zYX;9b{itFojfsg-I$8*p0g=rC9f@rf2o{wkk5wgmzss)0>KX>CS%7i(>kxgW@L6Np zi10qGjLd`}hpd4$n{PqqBa{{%)T!P(wd`M9w=l8(EO_ik>ow2t?28oJ;;-WmYWszG z_8AZ#*r2+AP)ZuxPKk2y1-3;zg}(GNZs(##Xx;(8VHOS?7op`RW#_yOgnXw!XsO-B%&ReRUg+69}vxbgEmb0O*(O|#7$W=Jlh2me-~ zvi8Z-+by5nkBw;F>*c+u(0BjODm2PmipP6+`B{?}lA=c&D#v}g1dvV3^ieLZiP z!95&Mp>IqBgS7rop(igY^jGwY3WWz$=w#aKK!%Kt-zrr14E*2{P@x9@RH3{;rp$Zd z7FQN>A=EvImrR+2h;Ud20=eIrG9h^Lazvx-cHPNFvY;%zbIDofh?%C*ScDU%#*SX_ zAMah$C2}$>VC>+;Y{goQt++&tP_#dBl0?p^_KZf9SW}A^JYX}uDV7xVeaV#R4vFh_ zPI6Ej6T`-|AoxMw`P5LKSN7&lAvcf|MS(X^oI`pKXvcU~?$x!41zN6d$G@}~)Wm_kBTX}*;B z5-DQ`u@gg7RAd)d7<>d76-D|*D4D2;#y{_9A2MpOdt^pm;9dD1%ixnC3~Ubv%vl@h-CAGg1H59~CexOC>&%_A7i&tV#qM&_>= z)X88k5gaXwlRb(aJ4Dv!itCSmWxMrNq&PHoj-SpBA|w@F4Z!rg?%VzL%D{jJLJLp3 zqCsRT>f<`KNuX>OX$^e}>!|W~YjJI91Eb*nUsMzXpN6O|vFE<`rPqI`i9<4x>0(tK zvgfj%8^kI`e|)X5U~SwICIr;EcX;jDIVpd0dUGDtV3d*7Q5-3k>X|eAMVU}9a%BuM z>3r4w>+0N1>0)#21NhPNw+xx++s%n5SJqicOfGUA-2B&OVO}exdQ{rm+07Z*bkGtL ziRgN(^(fK8hHWpIG7I~)E|M`orc5Aaf-bup_VO>!N}~f)2o2264`ZzE!CS_gy7q95 zE!+v;o7FGqO;iiEbP^9KpH|yhHI!Su5J^=N7Fo^2M_b`;iC5CO;^i(ng;h^me92{| zz1^LH-aQ=Cp!DVP*?CByiySd1Zj6J)@LVh`PCpfj_UdC3M+9&)a93fqze6yM{zT`S z#Aj+9EhF1*!C@|xPbfRoHHKof`T5Y>xQ`BM41z1Vd*oe`gQQRp*aPdF-8CPF9at8 zLo2{B0kXCFpY-M5J)#vAFR1}o4B(m6Ts+q8JTAYRg4TID^Q9yVK;MUJyeijQZjI~? zZyzUb4}(qfs|!d;1O>b;uj;#UkY9RRx+wf_aX z1R{M4*668!#rMGBoynhj0O-rO_wVBW^6%-E6`QkR3BczH_w&$UugK_8ZA|+pWLE2H=K%DMNwjAFAbT zKxE<{P2e6ikd`k8h!??LOpYN$=n_+5@tz$XIu6-jObuBf_8@d5L&-=TcorzIB@kL; z2sXM~B=vNA?P?l3r|HW*b1dlcNDIk*QHb4%L$Yu53dot^h-qPDv0OO>?wL)0-ZM|^ zAma0Yh}WatmzXN`Dl=PPQ}cVg^@`STdFWvK}ps^uB3sfR?35_WhWW~YdMDg z@GXEXCVn_hY_>@<&T0EL*AN$WKFkv;?#~uEqyyr=TI7(+>t0&qh`KppJk=H;fEGDt z`~8qpwi|l-im_^rZz zeMLT5SJhCd^hC;9mJv7VOY;+*O83-XfPxHd*Lu%tVDgC1Yh=ZY*d^SbJ#OOE&(QL__P z?2D?j%F{W?L-iA>0J`MnJ27Ed`|2_xLp%{L(a_sbaz(G2Y6JmQd2{VTdp3_z;21ow zoA$xmubnZ`Mq$SbPLo%6b1L7&tWA*Mlh8E^;hMAU_r-=n`6A>UT^kq?x43cy-P!WG zYJ4QN&wcxxzZ*qe0|l&{ufyBeJ-8(WMoB9alz@03Zhgni9y0)V5%>SDn`c?5s`I9j z#Dg4hot68+OMGkJuF6ukcra99kq5p^ob?;-uO)TWfnVXxwX!&=TBHWV!pmxzIJ`uW ztRGY9P2|y1=!u|FFgCPUL`}*}ZA(@0e#pV0o!f>r5+hn{2Irv_%Hy+2fARZ3S4JO? ztPbLY#UCuP;d4{D?0c<(qZF+e#x|+{y7PFQm9u7S`J(YdeKaSppDj0jxz&w;-eLEx zjA}pf5z50_H~_l1OQlzk-E1@m{q+7UdE{abPtk9%fdFp5Kh$f%tT+b^S!ofTR@?e& zhfA(Ui1$Ynt#8mrXG@_fd+*Cn)#?v+Xjf3sx?{{zNJKfCrP~p|L6<_ooHVK8nko#= zCJqRk(%vn-e@+NfI?j)_K#?39$^W)SuQc>kB95CgFV;x zlKFAT?f0kqv*CmN_5vrMo0>hMEaLe0buB3n2BmXE{X#cK#8c zsA7HW_DMUe?v!}Ng!!HFQwK>Yz*NL@#^FDZ`D)1D`5BiAUIfaQ;Jt&Ud&s%i(Ly#{ zdmzu4?5<-^V}*8P?wQvTX10HQIC7u@=cA>n;bXMEiBFI76;fsL(D4~!kko)Jr?9@LIs0QMXE#G! zA2-tOE$l)v;$8zZqD4E&HxbajUh|~L33CGvX#Kc8Jje@_N)kp@Nf|e9(Bz>_ zLS^&ySUAkSQLoSqBly}NlCd?Udc>$R8>*JwIwji6#!b|r{A}>3cmliHk`epJ2E7@< zJL*!$cY0ZmwVPA_*>KQLWIsaJyuwu6_53@Lg~VeO0`)hZefLMyYek<8Jc&&b88dw_ zVpJq7*f_}iTjup=cZ7!^n6>Osad6YDV<)WQRSdau*YFfW2etLW&6Qkm=NPjME7ei7}yPi5lSMK2ThVZe0e+zn{DtNaVO$cY=DSrGMvF zXybwE4fzC*Xzx4aDv##JKH%>pZj|u73vO4Elq?)8$Raf*t^@JNvaM;2z}1tZ9ay=3 zjmOjp3{~6jEpzB8Td?ZfaUQs7)&$*ygDU6F1qLIPx9;H`wX>>>J>V{&Wg9>lQ22B1 z*zmGB&W8wOkgrBTR8o0rRHXUbjU7`IG>M&daAR7NoaYSb(S>vf_!ZW{$p`lI;Kx;J z4MnntZi?k~hIF8CodOdq!LQcl%0J2LvC(2_;IJG=<-?~uUXKhit4de1h6xN@if6Kg zK=7RI7h}^U6{O*Z=Kf&+vT#?4^^yKSmA58N$5rD8`EJAKMYD~(Z<7K8kK7WQD2B6D z*jC~w)TKhFh@;&jU+;9jN((3TgFP&`DTcNxHlwA-GEaDyS_;@yA$Lk-#F>y!@iTbw z(P}+Xp;$DnYB+#q@KVA`4hwW@lmh7_qs+LhTw7OlxM7z(JOsLyFLDqv0^sN|gW_Mw? zcfn30I)0~MutdrHdxUq_(awsqEd&kbo%W_29NwEOvrj+AZ>Y+YVLGclkX*cN$JdvG z#|$J7e(FXOPd&Pnc~#Hb5Cu&vo@gWRSs&nSEw~s|r^^XvY&s#E-g@B`^sM)QIt&VQ z(|l`n*O>g!qaHhAT-rK-56N8{nZW+F3!exW3}){flMnf%8ubR-U^<_oiR)c#;o`bTXbzF$KVi}w?&x47oL^WeHi7e3 z7}l7xe8th~u4Mc;7zC@83z`s!JV1B$ElaXoUXR+Ec@FEXjjiY`MCx|X#=K|vF!2uK z3(hJ_1(R@OYFa*;j&H-mSBZC8hMmzPn}}k58;&y$lZe)FSHvrPN5@TfD7We+Ug5>q zTE?PfwmY%(@adCZ6d!)59eh{bRVvE0XRF(3pLjiMY3J*rv(xOB?&egV&B9lpIb4?5 zdaCoO2mGOO!UVYIhRDQ4UGadkzLiRbpVoMfd%dxPiGZq!&4%hCf$4V)^1Y;1eV~@C z!ubR>wKVvQy}fLC%xnw$(D6%GpC7#Eax;p(u$EYedp z(a>`vObeoklpRR80aeOy0|N_8jwIkR*O{K(gJ6TnK)G}PcDsd@?cq$ z5@q`&9d<(Y8reP@DEhWSTztyNzMC+Nqozp9oN#$M6SXZlPlPzlG6aoy#_fx_AI`Y? z?j&RU8h!X-Be7U`y(W?1f=(ctB8aJzcZv4oRk(74MLTaw8Bz2WGb%imyz1k&=RrA! zEpy)Y@@d3mR|<5gODdQ_Ek@V~$IHo*&REJXEr#~%A|YqKi}b8z!@YHNmK=Ra$llVn z+M2!iyAeN{z=8@x_6kNezlRO1pl;z2q~nBZKqty37GO*Kr1~&Gb4T!&Nt|$eJLSAK zXQnDB$veRnzZnzx`Ck%LUzGal$1&?pK;=dQ?i_*tSnd8P)FUV4Y=A;Is0}Z9g90s; zkNi*JrJ0aqmTbgL2=QwDn-6Xf1i~zbAG0#oQsgbHiz1g>37?fMI6g?3{~F2d41UbM zJD$CzV9F@5Vf#6AyZwC8M05yK<9g(mT!N~xXPyg&p9>*?#oFU!uxOzgyozIQCI|+|MxLS`%Uv^<=dn$)>h(9(eKUkcpvycNT>JBp=V)$i_p%Q7`>|K? z!TQDa^3?e|hQ6MX02b1c0FHC5zf2wN6s~2s;cR!I$7Kl%2oSWQk>iDr2z?)Q+_twi zo-`R5-!vFMev%mj*j|8#-tBBSfHhP8a=YP{lBcHGp1v49{IJa;NQ&`ifM6W|M^QMY z@`|W9qZaLfk+zzt3!`(v7CUtSYyK5s70o_oEkB(Ri{qvUZ$6-EFyRsW0XiQNa9?TUjV%4^1f-om}b}C^Lo=uqT;MpI}cBCRrJx zg54wC0A`5rk|4MWpv@@?&<<=mvEr9V=}$u@xl=z7W⋙lj^B#!6;s_8}Wvmh~PC# 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

tIa;t5Klba}A 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%0D#ozJ`evbsI|@+XkmC7pGODsS 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

Mfo3GPeH>A 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 z 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 z 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%0DO4`vvq)%}>PpHy4RVe2v{zeMZ& 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 z zY#(4=v~@N%NSZ|c@N(FHYJC49jm9V8KBb3GlIN3e`ZP_~4Ni;4lC8sFm%|r=Y>vq< z7knxv1M-O-(c}adOXn&*%+Qu0k%<8StNoo2c$t|`J4VPcAMD)_@#`zZ*Xt0jE%8k{ zN-7bi&=KR%WNedcToD_!F13s+|0hD9&i3z+*hXlyU#~i|FrMoaLV|HrBr351ZU}v& zm`_1m@g+j2LC@YPDo`X;D_j%oT(aGUPdR0C1wvsyPrwNQIS+IJs(={jD;**e>Y%4J zNl(w*a?V8f$Y5Uw%_KmbpEi~E8iuUjYzPPlkcik(fgCRlMhz6pl&ttSk0h|XC7QDq z&%{)2lO2UQ&j_&4VQ^2IN3)(Z9#~c;Y4sqN7S0&Vq>_*(D3K!|i)C0Ckw9j1xNDGI zN)KKsu2n zkoyQ0H1YuXWouTnQxmI#X(S6miKKaqA;^|g(V?%@Y7S&WT1aGD$LthpCHBIB!oi2h zx2(wrvvy_pNd-j*)^4h;|0$TI0F(|8BeX-Yh(oeV2rS#AgljT6>BPp0sv3->w787n z6p+64-Zdd6Vs)t6Rxr6yQUP8pQC&bqK&(F(b$4kjEyT~YMSD*#*VUyFWE83#zcf-k zaDSRuyTvFV1OP6zavVLe*tYBSSyNV&DA%}NW+Gk*Xzu^->B_i~+;tiMsaF}lTruk_ zrocD?0K6NW6VB&Po7cVy_ewN_@IaRR@ah3*im*>gPEru&02t>8*W-|Ta>~Cj*CHbA z5NTsMpZCPG8s&SKY)>>%GQa|egMf0$!RWc8$`m{8cXCim^BOEy6aO$8932Zdraj8n zSpUz*BQ)tyn*)%n6(QuG`YU1p5)L@#1`T3pjo>l(RW4M-zy1LvjI&A0GmK6@g|K7wbCt2gm|jw>G5Rba!EUDtar*p*G;{v#hUIdIL;}JiZ=6I=r+Hr z^x8n70#u*>Uc;6ux#%?0(@*;3z6vOPel?0SMAGBnzj7%P?f6~@5EUFPC?_k{Esla$ zWb|I@#s>U&$N!nbgd^**H(QHkE9-qx zwO>C;l=n2U`@-Eb&g{yWBV(~@v+x*TxIls#7 zRlDzeW13jv54{Tqq8nWdlvJzT18@miZAvV^R9>!|nEX9@dV2{~obEI7^7H=L1)6$w z6-lHEk390Xl5b~0ey>irT)2#oC%ewb*viF&sK1NvJg)ws+NAo%B{Ypx z@6nAYpR{;gU9fEP^jUA)?m``co001Rr(&;Rcw8cuh5dZZU?lbu3pSly`&#P83-||x z_CWg@A^+FN5R?=lYKqTiqLMs5G15ppLT)QzZJ@@{19@cnKCG1--J=axwA((JVE^`S zF$*P1S7Fr*^CG3SbJG{v8|Pn1_FpbufIF5l^{EWq(dm!S)1nu{sAuQ zNVcX*tT!?JtV%^6p9fC%Y#Kn_r8Dt_RQg91SHD86GWppo_hMn`!ng+r%3B{bG!elu zkyAMs1&8LnPrXo*4xiMU;w6pE3t}XIanz*+^}lfFb#TXpe9Ey#Ed>?9(b6AYl{`ss z`jA2w&)sUQfPH`E1TW|)B{4Ng%g5IL5LZfF01YBt%T(A!#*aru=P~8)&?CC9 z*l1d!R@FrDJ~v@`j>fK|9@uSj_V=uekT1Ht5rdD#

    Bk&?H`Tnb00Gt%j$Ae`;# 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

    e+- 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 diff --git a/lwip.spec b/lwip.spec deleted file mode 100644 index 65ffa68..0000000 --- a/lwip.spec +++ /dev/null @@ -1,474 +0,0 @@ -%global debug_package %{nil} -%global __os_install_post %{nil} - -Summary: lwip is a small independent implementation of the TCP/IP protocol suite -Name: lwip -Version: 2.1.3 -Release: 102 -License: BSD -URL: http://savannah.nongnu.org/projects/lwip/ -Source0: http://download.savannah.nongnu.org/releases/lwip/%{name}-%{version}.zip - -Patch6001: backport-tcp-fix-sequence-number-comparison.patch -Patch6002: backport-tcp-tighten-up-checks-for-received-SYN.patch - -Patch9000: 0001-add-makefile.patch -Patch9001: 0002-adapt-lstack.patch -Patch9002: 0003-fix-the-occasional-coredump-when-the-lwip-exits.patch -Patch9003: 0004-fix-error-of-deleting-conn-table-in-connect.patch -Patch9004: 0005-syn-rcvd-state-reg-conn-into-conntable.patch -Patch9005: 0006-fix-coredump-in-etharp.patch -Patch9006: 0007-gazelle-fix-epoll_ctl-EPOLLET-mode-error.patch -Patch9007: 0008-gazelle-fix-lwip_accept-memcpy-sockaddr-large.patch -Patch9008: 0009-fix-stack-buffer-overflow-when-memcpy-addr.patch -Patch9009: 0010-fix-the-incomplete-release-of-the-conntable.patch -Patch9010: 0011-remove-gazelle-tcp-conn-func.patch -Patch9011: 0012-fix-incomplete-resource-release-in-lwip-close.patch -Patch9012: 0013-remove-gazelle-syscall-thread.patch -Patch9013: 0014-fix-some-compile-errors.patch -Patch9014: 0015-fix-tcp-port-alloc-issue.patch -Patch9015: 0016-lstack-support-mysql-mode.patch -Patch9016: 0017-support-REUSEPOR-option.patch -Patch9017: 0018-exec-gazelle_init_sock-before-read-event.patch -Patch9018: 0019-gazelle-reduce-copy-in-send.patch -Patch9019: 0020-remove-chose_dlsym_handle-function-set-handle-to-RTL.patch -Patch9020: 0021-refactor-event-if-ring-is-full-the-node-is-added-to-.patch -Patch9021: 0022-notify-app-that-sock-state-changes-to-CLOSE_WAIT.patch -Patch9022: 0023-refactor-event-and-checksum-offload-support.patch -Patch9023: 0024-refactor-pkt-read-send-performance.patch -Patch9024: 0025-Replace-gettid-with-syscall-SYS_gettid.patch -Patch9025: 0026-del-redundant-wait_close-and-move-epoll_events-pos.patch -Patch9026: 0027-modify-EISCONN-condition.patch -Patch9027: 0028-per-thread-reassdata-variables.patch -Patch9028: 0029-fix-EISCONN-err-and-remove-same-customized-modificat.patch -Patch9029: 0030-refactor-tcp-new-port.patch -Patch9030: 0031-refactor-add-event-limit-send-pkts-num.patch -Patch9031: 0032-fix-free-pbuf-miss-data.patch -Patch9032: 0033-alloc-socket-fail-clean-sock.patch -Patch9033: 0034-add-accept4-and-epoll_create1.patch -Patch9034: 0035-add-writev-and-readv.patch -Patch9035: 0036-add-fs-secure-compilation-option.patch -Patch9036: 0037-enable-ARP-QUEUE-to-avoid-sync-packet-dropped.patch -Patch9037: 0038-add-tso.patch -Patch9038: 0039-optimize-app-thread-write-buff-block.patch -Patch9039: 0040-add-huge-snd_buf.patch -Patch9040: 0041-optimite-pcb-list-limit-send-size-and-ack-now.patch -Patch9041: 0042-expand-recv-win.patch -Patch9042: 0043-add-prefetch.patch -Patch9043: 0044-skip-unnecessary-tcp_route.patch -Patch9044: 0045-add-variable-in-struct-sock.patch -Patch9045: 0046-add-dataack-when-recv-too-many-acks-with-data.patch -Patch9046: 0047-reduce-struct-pbuf-size.patch -Patch9047: 0048-listen-pcb-also-use-pcb_if.patch -Patch9048: 0049-expand-recv-mbox-size.patch -Patch9049: 0050-lwip-reuse-ip-port.patch -Patch9050: 0051-lwip-add-need_tso_send.patch -Patch9051: 0052-lwip_fnctl-only-support-F_SETFL-F_GETFL.patch -Patch9052: 0053-cleancode-improve-lwipopts.h-readability.patch -Patch9053: 0054-reduce-cpu-usage-when-send.patch -Patch9054: 0055-add-pbuf-lock-when-aggregate-pbuf.patch -Patch9055: 0056-fix-tso-small-packet-drop-in-kernel-server.patch -Patch9056: 0057-same-node-gazellectl-a.patch -Patch9057: 0058-lwip-send-recv-thread-bind-numa.patch -Patch9058: 0059-fix-last_unsent-last_unacked.patch -Patch9059: 0060-lwip-add-udp-multicast.patch -Patch9060: 0061-fix-pbuf-leak-in-udp-connection.patch -Patch9061: 0062-drop-netbuf-in-recv_udp-to-fix-mem-overflow.patch -Patch9062: 0063-optimize-avoid-too-many-empty-acks-in-tcp_input.patch -Patch9063: 0064-fix-udp-send-recv-in-multiple-queue.patch -Patch9064: 0065-fix-udp-recvmbox-size-not-set.patch -Patch9065: 0066-adapt-to-dpdk-19.11-and-dpdk-21.11.patch -Patch9066: 0067-fix-null-pointer-when-all-zero-address-listen.patch -Patch9067: 0068-enable-UDP-CKSUM-in-lwip.patch -Patch9068: 0069-add-error-check-in-hugepage_init-and-sys_mbox_free.patch -Patch9069: 0070-add-CHECKSUM_UDP-when-not-support-OFFLOAD_UDP_CHECKS.patch -Patch9070: 0071-fix-pbuf-tot_len-incorrect-after-pbuf_split_64k-is-c.patch -Patch9071: 0072-add-O_NONBLOCK-and-FIONBIO-when-not-defined.patch -Patch9072: 0073-lstack_lwip-external-api-start-with-do_lwip_-prefix.patch -Patch9073: 0074-gazelle-offloads-are-registered-to-lwip.patch -Patch9074: 0075-adapt-read-write-for-rtc-mode.patch -Patch9075: 0076-fix-recvmsg-return-EINVAL.patch -Patch9076: 0077-adpat-event-for-rtc-mode.patch -Patch9077: 0078-posix_api-support-select.patch -Patch6003: backport-Add-outgoing-VLAN-PCP-support.patch -Patch6004: backport-fix-compiling-ETHARP_SUPPORT_VLAN.patch -Patch9078: 0079-enable-vlan-define.patch -Patch9079: 0080-enable-ipv6.patch -Patch9080: 0081-ip6-hdr.patch -Patch9081: 0082-add-vlanid-in-netif.patch -Patch9082: 0083-lwipopts-add-lwip-debug-log-macro.patch -Patch9083: 0084-add-tcpslowtmr-log-and-tcpfasttmr-cnt.patch -Patch9084: 0085-add-lwip-log-tcp_rst-tcp_abandon-tcp_abort.patch -Patch9085: 0086-log-add-errevent-log-and-tcp-exception-statistics.patch -Patch9086: 0087-support-vlan-offload.patch -Patch9087: 0088-modify-log-info-err.patch -Patch9088: 0089-add-struct-gz-addr.patch -Patch9089: 0090-frag-fix-coredump-when-get-netif.patch -Patch9090: 0091-add-fd-log-info-and-fix-wrong-port-log-info.patch -Patch9091: 0092-fix-the-coredump-issue-when-UDP-traffic-is-sent.patch -Patch9092: 0093-modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening.patch -Patch9093: 0094-lwip-log-fix-reversed-port-in-tcp_input.patch -Patch9094: 0095-event_callback-del-errevent-log-if-err-is-ERR_OK.patch -Patch9095: 0096-tcp_send_fin-add-the-fin-to-the-last-unsent-segment.patch -Patch9096: 0097-Mod-the-issue-that-2w-connection-unable-to-establish.patch -Patch9097: 0098-remove-duplicate-lwip-log.patch -Patch9098: 0099-fix-rte_ring_create-time-consuming.patch - -BuildRequires: gcc-c++ dos2unix dpdk-devel - -#Requires: - -ExclusiveArch: x86_64 aarch64 loongarch64 sw_64 - -%description -lwip is a small independent implementation of the TCP/IP protocol suite. - -%prep -%setup -n %{name}-%{version} -q -find %{_builddir}/%{name}-%{version} -type f -exec dos2unix -q {} \; -%autopatch -p1 - -%build -#export DPDK_VERSION_1911=1 -cd %{_builddir}/%{name}-%{version}/src -%make_build - -%install -cd %{_builddir}/%{name}-%{version}/src -%make_install INSTALL_LIB=%{buildroot}%{_libdir} - -%files -%defattr(0644,root,root) -%{_includedir}/lwip -%{_libdir}/liblwip.a - -%changelog -* Tue Dec 26 2023 jiangheng - 2.1.3-102 -- fix rte_ring_create/free time-consuming - -* Tue Dec 26 2023 jiangheng - 2.1.3-101 -- remove duplicate lwip log - -* Mon Dec 25 2023 hankangkang - 2.1.3-100 -- Mod the issue that 2w connection unable to establish - -* Sat Dec 23 2023 yangchen - 2.1.3-99 -- tcp_send_fin: add the fin to the last unsent segment - -* Wed Dec 20 2023 yangchen - 2.1.3-98 -- event_callback: del errevent log if err is ERR_OK - -* Fri Dec 15 2023 yangchen - 2.1.3-97 -- lwip log: fix reversed port in tcp_input - -* Thu Dec 14 2023 hankangkang - 2.1.3-96 -- modfiy-accept-null-pointer-when-new-conn-receive-RST-packet-in-listening - -* Sat Dec 9 2023 wuchangye - 2.1.3-95 -- fix the coredump issue when UDP traffic is sent - -* Fri Dec 8 2023 yangchen - 2.1.3-94 -- add fd log info and fix wrong port log info - -* Fri Dec 8 2023 jiangheng - 2.1.3-93 -- ip4 frag: fix coredump when get netif - -* Wed Dec 6 2023 zhengjiebing - 2.1.3-92 -- add struct gz_addr_t - -* Tue Dec 5 2023 hankangkang - 2.1.3-91 -- modify-log-info-err - -* Tue Nov 28 2023 zhengjiebing - 2.1.3-90 -- support vlan offload - -* Tue Nov 28 2023 jiangheng - 2.1.3-89 -- log: add errevent log and tcp exception statistics - -* Tue Nov 28 2023 yangchen - 2.1.3-88 -- add lwip log: tcp_rst & tcp_abandon & tcp_abort - -* Tue Nov 28 2023 hankangkang - 2.1.3-87 -- lwipopts: add tcpslowtmr log and tcpfasttmr cnt - -* Mon Nov 27 2023 yangchen - 2.1.3-86 -- lwipopts: add lwip debug log macro - -* Mon Nov 27 2023 zhengjiebing - 2.1.3-85 -- add vlan_id in netif - -* Fri Nov 24 2023 zhangxingrong - 2.1.3-84 -- modify error date - -* Fri Nov 17 2023 zhengjiebing - 2.1.3-83 -- enable ipv6 in lwip - -* Fri Nov 03 2023 zhujunhao - 2.1.3-82 -- add support vlan - -* Fri Nov 03 2023 yangchen - 2.1.3-81 -- posix_api support select - -* Fri Oct 27 2023 jiangheng - 2.1.3-80 -- adapt read/write for rtc mode -- fix recvmsg return EINVAL -- adapt event for rtc mode - -* Tue Oct 24 2023 jiangheng - 2.1.3-79 -- gazelle offloads are registerd to lwip - -* Sun Oct 08 2023 jiangheng - 2.1.3-78 -- lstack_lwip: external api start with do_lwip_ prefix - -* Sun Oct 08 2023 panchenbo - 2.1.3-77 -- add O_NONBLOCK and FIONBIO when not defined - -* Fri Sep 15 2023 jiangheng - 2.1.3-76 -- fix pbuf->tot_len incorrect after pbuf_split_64k is called - -* Tue Jun 27 2023 kircher - 2.1.3-75 -- add CHECKSUM_UDP when not support OFFLOAD_UDP_CHECKS - -* Sun Jun 25 2023 jiangheng - 2.1.3-74 -- add error check in hugepage_init and sys_mbox_free - -* Wed Jun 21 2023 kircher - 2.1.3-73 -- enable udp cksum in lwip - -* Thu Jun 15 2023 Lemmy Huang - 2.1.3-72 -- fix null pointer when zero port listen - -* Thu Jun 15 2023 Lemmy Huang - 2.1.3-71 -- patch -p1 automaition in lwip.spec - -* Thu Jun 15 2023 Lemmy Huang - 2.1.3-70 -- adapt to dpdk-19.11 and dpdk-21.11 - -* Wed Jun 14 2023 jiangheng - 2.1.3-69 -- fix udp recvmbox size not set - -* Wed Jun 14 2023 jiangheng - 2.1.3-68 -- fix udp send/recv in mutiple queue - -* Wed Jun 07 2023 Lemmy Huang - 2.1.3-67 -- optimize: avoid too many empty acks in tcp_input - -* Tue Jun 06 2023 jiangheng - 2.1.3-66 -- revert cleancode series patches - -* Mon May 29 2023 kircher - 2.1.3-65 -- drop netbuf in recv_udp to fix mem overflow - -* Mon May 29 2023 Lemmy Huang - 2.1.3-64 -- cleancode: refactor memp - -* Mon May 29 2023 Lemmy Huang - 2.1.3-63 -- cleancode: refactor OFFLOAD_CHECKSUM GAZELLE_TCP_DATAACKS_REXMIT GAZELLE_TCP_NEW_PORT - -* Mon May 29 2023 Lemmy Huang - 2.1.3-62 -- fix spec patch9069 - -* Mon May 29 2023 Lemmy Huang - 2.1.3-61 -- cleancode: refactor sys_now and lwip_ioctl - -* Mon May 29 2023 Lemmy Huang - 2.1.3-60 -- cleancode: refactor GAZELLE_TCP_PCB_HASH - -* Mon May 29 2023 Lemmy Huang - 2.1.3-59 -- cleancode: refactor options define - -* Thu May 25 2023 Lemmy Huang - 2.1.3-58 -- cleancode: refactor gazelle_hlist.h - -* Thu May 25 2023 Lemmy Huang - 2.1.3-57 -- cleancode: refactor gazelle_list.h - -* Wed May 24 2023 Lemmy Huang - 2.1.3-56 -- cleancode: refactor gazelle_posix_api.h - -* Tue May 23 2023 Lemmy Huang - 2.1.3-55 -- cleancode: refactor lwipsock.h - -* Tue May 23 2023 Lemmy Huang - 2.1.3-54 -- cleancode: remove perf -- cleancode: rename gazelle files in lwip - -* Tue May 23 2023 Lemmy Huang - 2.1.3-53 -- cleancode: improving makefile readability - -* Tue May 16 2023 kircher - 2.1.3-52 -- fix pbuf leak in udp connection - -* Fri May 12 2023 kircher - 2.1.3-51 -- add udp multicast support in lwip - -* Sat Apr 01 2023 jiangheng - 2.1.3-50 -- fix last_unsent/last_unacked error -- fix send failed due to pcb->nrtx > TCP_MAXRTX - -* Wed Mar 22 2023 kircher - 2.1.3-49 -- lwip send recv thread bind numa - -* Mon Mar 13 2023 jiangheng - 2.1.3-48 -- add same node ring & gazellectl -a - -* Mon Mar 13 2023 jiangheng - 2.1.3-47 -- fix tso small packet drop in kernel server - -* Mon Mar 13 2023 jiangheng - 2.1.3-46 -- use pbuf lock when aggregate pbuf - -* Fri Mar 10 2023 jiangheng - 2.1.3-45 -- reduce cpu usage when send - -* Thu Mar 9 2023 Lemmy Huang - 2.1.3-44 -- cleancode: improve lwipopts.h readability - -* Wed Feb 22 2023 jiangheng - 2.1.3-43 -- lwip_fnctl only suport F_SETFL,F_GETFL, other opt return 0 for compitable - -* Tue Feb 21 2023 majun - 2.1.3-42 -- add lwip need_tso_send - -* Tue Feb 14 2023 majun - 2.1.3-41 -- add lwip reuse ip port - -* Sat Feb 11 2023 majun - 2.1.3-40 -- fix TSO snd_nxt incorrectly update - -* Fri Dec 30 2022 wuchangsheng - 2.1.3-39 -- expand recv mbox size - -* Wed Dec 21 2022 jiangheng - 2.1.3-38 -- move pcb_if to ip_pcb to let listen pcb can use it - -* Wed Dec 21 2022 wuchangsheng - 2.1.3-37 -- reduce struct pbuf size - -* Wed Dec 21 2022 kircher - 2.1.3-36 -- do not update cwnd when send dataack - -* Tue Dec 20 2022 kircher - 2.1.3-35 -- fix the dataack is always lower than 256 - -* Tue Dec 20 2022 kircher - 2.1.3-34 -- add dataack when recv too many acks with data - -* Tue Dec 20 2022 wuchangsheng - 2.1.3-33 -- add variable in struct sock - -* Mon Dec 19 2022 kircher - 2.1.3-32 -- skip unnecessary tcp_route - -* Sun Dec 18 2022 wuchangsheng - 2.1.3-31 -- expand rcv wnd size and add prefetch - -* Tue Dec 13 2022 wuchangsheng - 2.1.3-30 -- optimite pcb unsent and unacked list - fast rexmit all pkts - -* Tue Dec 6 2022 zhujunhao - 2.1.3-29 -- add huge snd_buf - -* Sat Dec 3 2022 wuchangsheng - 2.1.3-28 -- add tso define - -* Thu Dec 01 2022 jiangheng - 2.1.3-27 -- remove lwip-2.1.3.tar.gz - -* Sat Nov 26 2022 jiangheng - 2.1.3-26 -- replace lwip-2.1.3.tar.gz to lwip-2.1.3.zip - -* Wed Nov 23 2022 jiangheng - 2.1.3-25 -- enable ARP QUEUE to avoid packet dropped - -* Sat Oct 22 2022 jiangheng - 2.1.3-24 -- add fs secure compilation option - -* Wed Oct 19 2022 zhujunhao - 2.1.3-23 -- add writev and readv - -* Sat Oct 15 2022 zhujunhao - 2.1.3-22 -- add epoll_create1 and accetp4 - -* Tue Oct 11 2022 wuchangsheng - 2.1.3-21 -- alloc socket fail clean sock - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-20 -- fix miss data due to free pbuf - close debug - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-19 -- refactor add event - limit send pkts num max 10 - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-18 -- fix multithread duplicate port num - support select appropriate port num to rss same as nic - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-17 -- fix EISCONN conditon err - remove same customized modification - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-16 -- per thread reassdata variables - -* Thu Oct 6 2022 wuchangsheng - 2.1.3-15 -- modify EISCONN path condition - add in_send and send_flag value in sock - -* Tue Jul 26 2022 wuchangsheng - 2.1.3-14 -- del redundant wait_close in lwip_sock - move epoll_events into cache aligned area - -* Tue Jul 12 2022 Honggang Li - 2.1.3-13 -- Replace gettid() with syscall() - -* Fri Jul 8 2022 xiusailong - 2.1.3-12 -- sync two patches from 20.03-LTS-SP1 - -* Thu Jul 7 2022 wuchangsheng - 2.1.3-11 -- refactor refactor pkt read send performance - -* Tue Mar 29 2022 jiangheng - 2.1.3-10 -- refactor event -- add HW checksum offload support - -* Tue Mar 15 2022 jiangheng - 2.1.3-9 -- notify app that sock state changes to CLOSE_WAIT - -* Tue Mar 15 2022 jiangheng - 2.1.3-8 -- refactor event,if ring is full, node is added to list - -* Mon Mar 07 2022 jiangheng - 2.1.3-7 -- remove chose_dlsym_handle function as it is redundant - -* Mon Mar 07 2022 wu-changsheng - 2.1.3-6 -- gazelle reduce copy in send - -* Mon Mar 07 2022 jiangheng - 2.1.3-5 -- exec gazelle_sock_init before read event - -* Thu Mar 03 2022 jiangheng - 2.1.3-4 -- support REUSEPOR option -- fix rpc msg too much -- fix recrruing events - -* Thu Feb 24 2022 jiangheng - 2.1.3-3 -- remove kernel socket interface -- support the mode that listen and accept thread be separaten - -* Fri Dec 31 2021 jiangheng - 2.1.3-2 -- adapt to lstack - -* Fri Nov 26 2021 jiangheng - 2.1.3-1 -- update to 2.1.3 - -* Mon Sep 06 2021 jiangheng - 2.1.2-2 -- backport some patches from community - -* Mon Nov 30 2020 peanut_huang - 2.1.2-1 -- remove README - -* Mon Nov 30 2020 peanut_huang - 2.1.2-0 -- Init package diff --git a/pax_global_header b/pax_global_header deleted file mode 100644 index 1bed278..0000000 --- a/pax_global_header +++ /dev/null @@ -1 +0,0 @@ -52 comment=6ca936f6b588cee702c638eee75c2436e6cf75de diff --git a/src/Filelists.cmake b/src/Filelists.cmake index ff91fc1..228e0f0 100644 --- a/src/Filelists.cmake +++ b/src/Filelists.cmake @@ -5,12 +5,16 @@ # # This file is NOT designed (on purpose) to be used as cmake # subdir via add_subdirectory() -# The intention is to provide greater flexibility to users to +# The intention is to provide greater flexibility to users to # create their own targets using the *_SRCS variables. +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + set(LWIP_VERSION_MAJOR "2") -set(LWIP_VERSION_MINOR "1") -set(LWIP_VERSION_REVISION "3") +set(LWIP_VERSION_MINOR "2") +set(LWIP_VERSION_REVISION "1") # LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases # LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions # Numbers 1..31 are reserved for release candidates @@ -24,11 +28,11 @@ elseif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_DEVELOPMENT") set(LWIP_VERSION_STRING "${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.dev" ) -else ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE") +else() set(LWIP_VERSION_STRING "${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.rc${LWIP_VERSION_RC}" ) -endif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE") +endif() # The minimum set of files needed for lwIP. set(lwipcore_SRCS @@ -52,10 +56,9 @@ set(lwipcore_SRCS ${LWIP_DIR}/src/core/tcp_out.c ${LWIP_DIR}/src/core/timeouts.c ${LWIP_DIR}/src/core/udp.c - ${LWIP_DIR}/src/core/net_group.c - ${LWIP_DIR}/src/core/lowpower.c ) set(lwipcore4_SRCS + ${LWIP_DIR}/src/core/ipv4/acd.c ${LWIP_DIR}/src/core/ipv4/autoip.c ${LWIP_DIR}/src/core/ipv4/dhcp.c ${LWIP_DIR}/src/core/ipv4/etharp.c @@ -95,9 +98,12 @@ set(lwipnetif_SRCS ${LWIP_DIR}/src/netif/ethernet.c ${LWIP_DIR}/src/netif/bridgeif.c ${LWIP_DIR}/src/netif/bridgeif_fdb.c - ${LWIP_DIR}/src/netif/slipif.c ) +if (NOT ${LWIP_EXCLUDE_SLIPIF}) + list(APPEND lwipnetif_SRCS ${LWIP_DIR}/src/netif/slipif.c) +endif() + # 6LoWPAN set(lwipsixlowpan_SRCS ${LWIP_DIR}/src/netif/lowpan6_common.c @@ -196,6 +202,8 @@ set(lwipsntp_SRCS # MDNS responder set(lwipmdns_SRCS ${LWIP_DIR}/src/apps/mdns/mdns.c + ${LWIP_DIR}/src/apps/mdns/mdns_out.c + ${LWIP_DIR}/src/apps/mdns/mdns_domain.c ) # NetBIOS name server @@ -205,7 +213,7 @@ set(lwipnetbios_SRCS # TFTP server files set(lwiptftp_SRCS - ${LWIP_DIR}/src/apps/tftp/tftp_server.c + ${LWIP_DIR}/src/apps/tftp/tftp.c ) # MQTT client files @@ -242,7 +250,6 @@ set(lwipallapps_SRCS ${lwipnetbios_SRCS} ${lwiptftp_SRCS} ${lwipmqtt_SRCS} - ${lwipmbedtls_SRCS} ) # Generate lwip/init.h (version info) @@ -257,7 +264,7 @@ configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT}) find_package(Doxygen) if (DOXYGEN_FOUND) - message("Doxygen build started") + message(STATUS "Doxygen build started") add_custom_target(lwipdocs COMMAND ${CMAKE_COMMAND} -E remove_directory ${DOXYGEN_DIR}/${DOXYGEN_OUTPUT_DIR}/html @@ -266,7 +273,7 @@ if (DOXYGEN_FOUND) COMMENT "Generating API documentation with Doxygen" VERBATIM) else (DOXYGEN_FOUND) - message("Doxygen needs to be installed to generate the doxygen documentation") + message(STATUS "Doxygen needs to be installed to generate the doxygen documentation") endif (DOXYGEN_FOUND) # lwIP libraries @@ -279,3 +286,8 @@ add_library(lwipallapps EXCLUDE_FROM_ALL ${lwipallapps_SRCS}) target_compile_options(lwipallapps PRIVATE ${LWIP_COMPILER_FLAGS}) target_compile_definitions(lwipallapps PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) target_include_directories(lwipallapps PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) + +add_library(lwipmbedtls EXCLUDE_FROM_ALL ${lwipmbedtls_SRCS}) +target_compile_options(lwipmbedtls PRIVATE ${LWIP_COMPILER_FLAGS}) +target_compile_definitions(lwipmbedtls PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwipmbedtls PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/src/Filelists.mk b/src/Filelists.mk index d7e69c6..7e076f3 100644 --- a/src/Filelists.mk +++ b/src/Filelists.mk @@ -1,8 +1,8 @@ # # Copyright (c) 2001, 2002 Swedish Institute of Computer Science. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, @@ -11,21 +11,21 @@ # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. +# derived from this software without specific prior written permission. # -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # # This file is part of the lwIP TCP/IP stack. -# +# # Author: Adam Dunkels # @@ -49,11 +49,10 @@ COREFILES=$(LWIPDIR)/core/init.c \ $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c \ $(LWIPDIR)/core/timeouts.c \ - $(LWIPDIR)/core/udp.c \ - $(LWIPDIR)/core/net_group.c \ - $(LWIPDIR)/core/lowpower.c + $(LWIPDIR)/core/udp.c -CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \ +CORE4FILES=$(LWIPDIR)/core/ipv4/acd.c \ + $(LWIPDIR)/core/ipv4/autoip.c \ $(LWIPDIR)/core/ipv4/dhcp.c \ $(LWIPDIR)/core/ipv4/etharp.c \ $(LWIPDIR)/core/ipv4/icmp.c \ @@ -178,13 +177,15 @@ SMTPFILES=$(LWIPDIR)/apps/smtp/smtp.c SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c # MDNSFILES: MDNS responder -MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c +MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c \ + $(LWIPDIR)/apps/mdns/mdns_out.c \ + $(LWIPDIR)/apps/mdns/mdns_domain.c # NETBIOSNSFILES: NetBIOS name server NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c -# TFTPFILES: TFTP server files -TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c +# TFTPFILES: TFTP client/server files +TFTPFILES=$(LWIPDIR)/apps/tftp/tftp.c # MQTTFILES: MQTT client files MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c diff --git a/src/api/api_lib.c b/src/api/api_lib.c index ffa14d6..60678f8 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -323,7 +323,7 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind */ if ((netconn_get_ipv6only(conn) == 0) && - ip_addr_cmp(addr, IP6_ADDR_ANY)) { + ip_addr_eq(addr, IP6_ADDR_ANY)) { addr = IP_ANY_TYPE; } #endif /* LWIP_IPV4 && LWIP_IPV6 */ @@ -1260,13 +1260,13 @@ netconn_join_leave_group_netif(struct netconn *conn, * * @param name a string representation of the DNS host name to query * @param addr a preallocated ip_addr_t where to store the resolved IP address - * @param dns_addrtype IP address type (IPv4 / IPv6) * @return ERR_OK: resolving succeeded * ERR_MEM: memory error, try again later * ERR_ARG: dns client not initialized or invalid hostname * ERR_VAL: dns server response was invalid */ #if LWIP_IPV4 && LWIP_IPV6 +/** @param dns_addrtype IP address type (IPv4 / IPv6) */ err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) #else diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 44910d4..8092be9 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -93,7 +93,7 @@ static void netconn_drain(struct netconn *conn); #endif /* LWIP_TCPIP_CORE_LOCKING */ #if LWIP_NETCONN_FULLDUPLEX -const u8_t netconn_deleted = 0; +static const u8_t netconn_deleted = 0; int lwip_netconn_is_deallocated_msg(void *msg) @@ -106,9 +106,9 @@ lwip_netconn_is_deallocated_msg(void *msg) #endif /* LWIP_NETCONN_FULLDUPLEX */ #if LWIP_TCP -const u8_t netconn_aborted = 0; -const u8_t netconn_reset = 0; -const u8_t netconn_closed = 0; +static const u8_t netconn_aborted = 0; +static const u8_t netconn_reset = 0; +static const u8_t netconn_closed = 0; /** Translate an error to a unique void* passed via an mbox */ static void * @@ -221,6 +221,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct netbuf *buf; struct netconn *conn; u16_t len; + err_t err; #if LWIP_SO_RCVBUF int recv_avail; #endif /* LWIP_SO_RCVBUF */ @@ -269,8 +270,10 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, } len = p->tot_len; - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + err = sys_mbox_trypost(&conn->recvmbox, buf); + if (err != ERR_OK) { netbuf_delete(buf); + LWIP_DEBUGF(API_MSG_DEBUG, ("recv_udp: sys_mbox_trypost failed, err=%d\n", err)); return; } else { #if LWIP_SO_RCVBUF @@ -387,35 +390,6 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) return ERR_OK; } -#if LWIP_LOWPOWER -/* check wether need to poll tcp */ -u8_t -poll_tcp_needed(void *arg, struct tcp_pcb *pcb) -{ - struct netconn *conn = (struct netconn *)arg; - u8_t ret = 0; - - LWIP_UNUSED_ARG(pcb); - if (conn == NULL) { - return 0; - } - if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { - ret = 1; - } - - /* Did a nonblocking write fail before? Then check available write-space. */ - if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) { - /* If the queued byte- or pbuf-count drops below the configured low-water limit, - let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { - ret = 1; - } - } - return ret; -} -#endif /* LWIP_LOWPOWER */ - /** * Sent callback function for TCP netconns. * Signals the conn->sem and calls API_EVENT. @@ -498,7 +472,7 @@ err_tcp(void *arg, err_t err) } /* pass error message to acceptmbox to wake up pending accept */ if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { - /* use trypost to preven deadlock */ + /* use trypost to prevent deadlock */ sys_mbox_trypost(&conn->acceptmbox, mbox_msg); } @@ -521,7 +495,7 @@ err_tcp(void *arg, err_t err) conn->current_msg->err = err; } op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); - LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); + LWIP_ASSERT("invalid op_completed_sem", sys_sem_valid(op_completed_sem)); conn->current_msg = NULL; /* wake up the waiting task */ sys_sem_signal(op_completed_sem); @@ -635,11 +609,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) * @param msg the api_msg describing the connection type */ static void -#ifdef LOSCFG_NET_CONTAINER -pcb_new(struct api_msg *msg, struct net_group *group) -#else pcb_new(struct api_msg *msg) -#endif { enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; @@ -658,9 +628,6 @@ pcb_new(struct api_msg *msg) case NETCONN_RAW: msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); if (msg->conn->pcb.raw != NULL) { -#ifdef LOSCFG_NET_CONTAINER - set_raw_pcb_net_group(msg->conn->pcb.raw, group); -#endif #if LWIP_IPV6 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { @@ -676,9 +643,6 @@ pcb_new(struct api_msg *msg) case NETCONN_UDP: msg->conn->pcb.udp = udp_new_ip_type(iptype); if (msg->conn->pcb.udp != NULL) { -#ifdef LOSCFG_NET_CONTAINER - set_udp_pcb_net_group(msg->conn->pcb.udp, group); -#endif #if LWIP_UDPLITE if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); @@ -695,9 +659,6 @@ pcb_new(struct api_msg *msg) case NETCONN_TCP: msg->conn->pcb.tcp = tcp_new_ip_type(iptype); if (msg->conn->pcb.tcp != NULL) { -#ifdef LOSCFG_NET_CONTAINER - set_tcp_pcb_net_group(msg->conn->pcb.tcp, group); -#endif setup_tcp(msg->conn); } break; @@ -725,11 +686,7 @@ lwip_netconn_do_newconn(void *m) msg->err = ERR_OK; if (msg->conn->pcb.tcp == NULL) { -#ifdef LOSCFG_NET_CONTAINER - pcb_new(msg, get_curr_process_net_group()); -#else pcb_new(msg); -#endif } /* Else? This "new" connection already has a PCB allocated. */ /* Is this an error condition? Should it be deleted? */ @@ -805,10 +762,8 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) sys_mbox_set_invalid(&conn->acceptmbox); #endif conn->state = NETCONN_NONE; -#if LWIP_SOCKET /* initialize socket to -1 since 0 is a valid socket */ - conn->socket = -1; -#endif /* LWIP_SOCKET */ + conn->callback_arg.socket = -1; conn->callback = callback; #if LWIP_TCP conn->current_msg = NULL; @@ -1024,7 +979,7 @@ lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) /* Try to close the connection */ if (shut_close) { #if LWIP_SO_LINGER - /* check linger possibilites before calling tcp_close */ + /* check linger possibilities before calling tcp_close */ err = ERR_OK; /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { @@ -1294,7 +1249,6 @@ lwip_netconn_do_bind(void *m) msg->err = err; TCPIP_APIMSG_ACK(msg); } - /** * Bind a pcb contained in a netconn to an interface * Called from netconn_bind_if. @@ -1308,17 +1262,8 @@ lwip_netconn_do_bind_if(void *m) struct netif *netif; struct api_msg *msg = (struct api_msg *)m; err_t err; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); - if (group != NULL) { - netif = netif_get_by_index(msg->msg.bc.if_idx, group); - } else { - netif = NULL; - } -#else netif = netif_get_by_index(msg->msg.bc.if_idx); -#endif if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { err = ERR_OK; @@ -1528,7 +1473,7 @@ lwip_netconn_do_listen(void *m) /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen */ - if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && + if (ip_addr_eq(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && (netconn_get_ipv6only(msg->conn) == 0)) { /* change PCB type to IPADDR_TYPE_ANY */ IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); @@ -2120,18 +2065,8 @@ lwip_netconn_do_join_leave_group_netif(void *m) { struct api_msg *msg = (struct api_msg *)m; struct netif *netif; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); - if (group != NULL) { - netif = netif_get_by_index(msg->msg.jl.if_idx, group); - } else { - netif = NULL; - } -#else netif = netif_get_by_index(msg->msg.jl.if_idx); -#endif - if (netif == NULL) { msg->err = ERR_IF; goto done; diff --git a/src/api/if_api.c b/src/api/if_api.c index 8e094d0..d274c32 100644 --- a/src/api/if_api.c +++ b/src/api/if_api.c @@ -77,7 +77,7 @@ lwip_if_indextoname(unsigned int ifindex, char *ifname) /** * @ingroup if_api - * Returs the interface index corresponding to name ifname. + * Returns the interface index corresponding to name ifname. * @param ifname Interface name * @return The corresponding index if ifname is the name of an interface; * otherwise, zero. diff --git a/src/api/netbuf.c b/src/api/netbuf.c index 3b910de..8f5be9e 100644 --- a/src/api/netbuf.c +++ b/src/api/netbuf.c @@ -5,8 +5,8 @@ * @defgroup netbuf Network buffers * @ingroup netconn * Network buffer descriptor for @ref netconn. Based on @ref pbuf internally - * to avoid copying data around.\n - * Buffers must not be shared accross multiple threads, all functions except + * to avoid copying data around.
    + * Buffers must not be shared across multiple threads, all functions except * netbuf_new() and netbuf_delete() are not thread-safe. */ diff --git a/src/api/netdb.c b/src/api/netdb.c index bca575d..73028c8 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -40,6 +40,7 @@ #if LWIP_DNS && LWIP_SOCKET #include "lwip/err.h" +#include "lwip/errno.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/ip_addr.h" @@ -61,13 +62,18 @@ struct gethostbyname_r_helper { int h_errno; #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ -/** define "hostent" variables storage: 0 if we use a static (but unprotected) - * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +/** LWIP_DNS_API_HOSTENT_STORAGE: if set to 0 (default), lwip_gethostbyname() + * returns the same global variable for all calls (in all threads). + * When set to 1, your port should provide a function + * struct hostent* sys_thread_hostent( struct hostent* h); + * which have to do a copy of "h" and return a pointer ont the "per-thread" + * copy. + */ #ifndef LWIP_DNS_API_HOSTENT_STORAGE #define LWIP_DNS_API_HOSTENT_STORAGE 0 #endif -/** define "hostent" variables storage */ +/* define "hostent" variables storage */ #if LWIP_DNS_API_HOSTENT_STORAGE #define HOSTENT_STORAGE #else @@ -377,11 +383,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname, /* set up sockaddr */ inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); sa6->sin6_family = AF_INET6; +#if LWIP_SOCKET_HAVE_SA_LEN sa6->sin6_len = sizeof(struct sockaddr_in6); +#endif /* LWIP_SOCKET_HAVE_SA_LEN */ sa6->sin6_port = lwip_htons((u16_t)port_nr); sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); ai->ai_family = AF_INET6; - ai->ai_addrlen = sizeof(struct sockaddr_in6); #endif /* LWIP_IPV6 */ } else { #if LWIP_IPV4 @@ -389,10 +396,11 @@ lwip_getaddrinfo(const char *nodename, const char *servname, /* set up sockaddr */ inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); sa4->sin_family = AF_INET; +#if LWIP_SOCKET_HAVE_SA_LEN sa4->sin_len = sizeof(struct sockaddr_in); +#endif /* LWIP_SOCKET_HAVE_SA_LEN */ sa4->sin_port = lwip_htons((u16_t)port_nr); ai->ai_family = AF_INET; - ai->ai_addrlen = sizeof(struct sockaddr_in); #endif /* LWIP_IPV4 */ } @@ -408,6 +416,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, MEMCPY(ai->ai_canonname, nodename, namelen); ai->ai_canonname[namelen] = 0; } + ai->ai_addrlen = sizeof(struct sockaddr_storage); ai->ai_addr = (struct sockaddr *)sa; *res = ai; diff --git a/src/api/netifapi.c b/src/api/netifapi.c index 8aef568..25957cd 100644 --- a/src/api/netifapi.c +++ b/src/api/netifapi.c @@ -63,11 +63,8 @@ netifapi_do_netif_add(struct tcpip_api_call_data *m) /* cast through void* to silence alignment warnings. * We know it works because the structs have been instantiated as struct netifapi_msg */ struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; -#ifdef LOSCFG_NET_CONTAINER - if (!netif_add( msg->netif, get_curr_process_net_group(), -#else + if (!netif_add( msg->netif, -#endif #if LWIP_IPV4 API_EXPR_REF(msg->msg.add.ipaddr), API_EXPR_REF(msg->msg.add.netmask), @@ -125,11 +122,7 @@ netifapi_do_index_to_name(struct tcpip_api_call_data *m) * We know it works because the structs have been instantiated as struct netifapi_msg */ struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; -#ifdef LOSCFG_NET_CONTAINER - if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name, get_curr_process_net_group())) { -#else if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) { -#endif /* return failure via empty name */ msg->msg.ifs.name[0] = '\0'; } @@ -384,45 +377,4 @@ netifapi_netif_index_to_name(u8_t idx, char *name) return err; } -#if LWIP_LOWPOWER -static err_t -netifapi_do_set_lowpower_mod(struct tcpip_api_call_data *m) -{ - struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; - enum lowpower_mod mod = msg->msg.lp.mod; - set_lowpower_mod(mod); - return ERR_OK; -} - -err_t -netifapi_enable_lowpower(void) -{ - err_t err; - NETIFAPI_VAR_DECLARE(msg); - - NETIFAPI_VAR_ALLOC(msg); - - NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_LOWPOWER_MOD; - - err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call); - NETIFAPI_VAR_FREE(msg); - return err; -} - -err_t -netifapi_disable_lowpower(void) -{ - err_t err; - NETIFAPI_VAR_DECLARE(msg); - - NETIFAPI_VAR_ALLOC(msg); - - NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_NORMAL_MOD; - - err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call); - NETIFAPI_VAR_FREE(msg); - return err; -} -#endif /* LWIP_LOWPOWER */ - #endif /* LWIP_NETIF_API */ diff --git a/src/api/sockets.c b/src/api/sockets.c index d920da1..b97bdd7 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -54,10 +54,6 @@ #include "lwip/netif.h" #include "lwip/priv/tcpip_priv.h" #include "lwip/mld6.h" -#if LWIP_ENABLE_DISTRIBUTED_NET -#include "lwip/distributed_net/distributed_net.h" -#include "lwip/distributed_net/distributed_net_core.h" -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ #if LWIP_CHECKSUM_ON_COPY #include "lwip/inet_chksum.h" #endif @@ -72,10 +68,6 @@ #include LWIP_HOOK_FILENAME #endif -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -#endif - /* If the netconn API is not required publicly, then we include the necessary files here to get the implementation */ #if !LWIP_NETCONN @@ -93,9 +85,53 @@ #define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) +#ifndef LWIP_SOCKET_HAVE_SA_LEN +#define LWIP_SOCKET_HAVE_SA_LEN 0 +#endif /* LWIP_SOCKET_HAVE_SA_LEN */ + +/* Address length safe read and write */ +#if LWIP_SOCKET_HAVE_SA_LEN + +#if LWIP_IPV4 +#define IP4ADDR_SOCKADDR_SET_LEN(sin) \ + (sin)->sin_len = sizeof(struct sockaddr_in) +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define IP6ADDR_SOCKADDR_SET_LEN(sin6) \ + (sin6)->sin6_len = sizeof(struct sockaddr_in6) +#endif /* LWIP_IPV6 */ + +#define IPADDR_SOCKADDR_GET_LEN(addr) \ + (addr)->sa.sa_len + +#else + +#if LWIP_IPV4 +#define IP4ADDR_SOCKADDR_SET_LEN(addr) +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define IP6ADDR_SOCKADDR_SET_LEN(addr) +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 && LWIP_IPV6 +#define IPADDR_SOCKADDR_GET_LEN(addr) \ + ((addr)->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) \ + : ((addr)->sa.sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : 0)) +#elif LWIP_IPV4 +#define IPADDR_SOCKADDR_GET_LEN(addr) sizeof(struct sockaddr_in) +#elif LWIP_IPV6 +#define IPADDR_SOCKADDR_GET_LEN(addr) sizeof(struct sockaddr_in6) +#else +#define IPADDR_SOCKADDR_GET_LEN(addr) sizeof(struct sockaddr) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#endif /* LWIP_SOCKET_HAVE_SA_LEN */ + #if LWIP_IPV4 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ - (sin)->sin_len = sizeof(struct sockaddr_in); \ + IP4ADDR_SOCKADDR_SET_LEN(sin); \ (sin)->sin_family = AF_INET; \ (sin)->sin_port = lwip_htons((port)); \ inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ @@ -107,7 +143,7 @@ #if LWIP_IPV6 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ - (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ + IP6ADDR_SOCKADDR_SET_LEN(sin6); \ (sin6)->sin6_family = AF_INET6; \ (sin6)->sin6_port = lwip_htons((port)); \ (sin6)->sin6_flowinfo = 0; \ @@ -164,7 +200,7 @@ static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t * IS_SOCK_ADDR_TYPE_VALID(name)) #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ SOCK_ADDR_TYPE_MATCH(name, sock)) -#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) +#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % LWIP_MIN(4, MEM_ALIGNMENT)) == 0) #define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) @@ -186,7 +222,7 @@ static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t * #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ if (name == NULL) { \ - sock_set_errno(sock, ENOMEM); \ + set_errno(ENOMEM); \ done_socket(sock); \ return -1; \ } }while(0) @@ -286,11 +322,6 @@ static volatile int select_cb_ctr; static struct lwip_select_cb *select_cb_list; #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -#define sock_set_errno(sk, e) do { \ - const int sockerr = (e); \ - set_errno(sockerr); \ -} while (0) - /* Forward declaration of some functions */ #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); @@ -537,7 +568,6 @@ alloc_socket(struct netconn *newconn, int accepted) * (unless it has been created by accept()). */ sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); sockets[i].errevent = 0; - init_waitqueue_head(&sockets[i].wq); #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ return i + LWIP_SOCKET_OFFSET; } @@ -630,7 +660,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct lwip_sock *sock, *nsock; struct netconn *newconn; - ip_addr_t naddr; + ip_addr_t naddr = {0}; u16_t port = 0; int newsock; err_t err; @@ -648,11 +678,11 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); + set_errno(EOPNOTSUPP); } else if (err == ERR_CLSD) { - sock_set_errno(sock, EINVAL); + set_errno(EINVAL); } else { - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); } done_socket(sock); return -1; @@ -662,32 +692,13 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) newsock = alloc_socket(newconn, 1); if (newsock == -1) { netconn_delete(newconn); - sock_set_errno(sock, ENFILE); + set_errno(ENFILE); done_socket(sock); return -1; } LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; - /* See event_callback: If data comes in right away after an accept, even - * though the server task might not have created a new socket yet. - * In that case, newconn->socket is counted down (newconn->socket--), - * so nsock->rcvevent is >= 1 here! - */ - SYS_ARCH_PROTECT(lev); - recvevent = (s16_t)(-1 - newconn->socket); - newconn->socket = newsock; - SYS_ARCH_UNPROTECT(lev); - - if (newconn->callback) { - LOCK_TCPIP_CORE(); - while (recvevent > 0) { - recvevent--; - newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); - } - UNLOCK_TCPIP_CORE(); - } - /* Note that POSIX only requires us to check addr is non-NULL. addrlen must * not be NULL if addr is valid. */ @@ -698,25 +709,46 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); free_socket(nsock, 1); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; + if (*addrlen > IPADDR_SOCKADDR_GET_LEN(&tempaddr)) { + *addrlen = IPADDR_SOCKADDR_GET_LEN(&tempaddr); } MEMCPY(addr, &tempaddr, *addrlen); + } + + /* See event_callback: If data comes in right away after an accept, even + * though the server task might not have created a new socket yet. + * In that case, newconn->socket is counted down (newconn->socket--), + * so nsock->rcvevent is >= 1 here! + */ + SYS_ARCH_PROTECT(lev); + recvevent = (s16_t)(-1 - newconn->callback_arg.socket); + newconn->callback_arg.socket = newsock; + SYS_ARCH_UNPROTECT(lev); + if (newconn->callback) { + LOCK_TCPIP_CORE(); + while (recvevent > 0) { + recvevent--; + newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); + } + UNLOCK_TCPIP_CORE(); + } + + if ((addr != NULL) && (addrlen != NULL)) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); } else { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d\n", s, newsock)); } - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); done_socket(nsock); return newsock; @@ -737,7 +769,7 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); + set_errno(err_to_errno(ERR_VAL)); done_socket(sock); return -1; } @@ -745,7 +777,7 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) /* check size, family and alignment of 'name' */ LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); LWIP_UNUSED_ARG(namelen); SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); @@ -765,13 +797,13 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; } @@ -779,17 +811,6 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) int lwip_close(int s) { -#if LWIP_ENABLE_DISTRIBUTED_NET - if (!is_distributed_net_enabled()) { - return lwip_close_internal(s); - } - return distributed_net_close(s); -} - -int -lwip_close_internal(int s) -{ -#endif struct lwip_sock *sock; int is_tcp = 0; err_t err; @@ -818,7 +839,7 @@ lwip_close_internal(int s) err = netconn_prepare_delete(sock->conn); if (err != ERR_OK) { - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } @@ -831,17 +852,6 @@ lwip_close_internal(int s) int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) { -#if LWIP_ENABLE_DISTRIBUTED_NET - if (!is_distributed_net_enabled()) { - return lwip_connect_internal(s, name, namelen); - } - return distributed_net_connect(s, name, namelen); -} - -int -lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) -{ -#endif struct lwip_sock *sock; err_t err; @@ -852,7 +862,7 @@ lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); + set_errno(err_to_errno(ERR_VAL)); done_socket(sock); return -1; } @@ -868,7 +878,7 @@ lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) /* check size, family and alignment of 'name' */ LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); @@ -888,13 +898,13 @@ lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; } @@ -928,15 +938,15 @@ lwip_listen(int s, int backlog) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); + set_errno(EOPNOTSUPP); } else { - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); } done_socket(sock); return -1; } - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; } @@ -985,7 +995,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) /* We should really do some error checking here. */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", lwip_strerr(err))); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); if (err == ERR_CLSD) { return 0; } else { @@ -1004,7 +1014,7 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) } else { copylen = (u16_t)recv_left; } - if (recvd + copylen < recvd) { + if (recvd > SSIZE_MAX - copylen) { /* overflow */ copylen = (u16_t)(SSIZE_MAX - recvd); } @@ -1043,7 +1053,7 @@ lwip_recv_tcp_done: /* ensure window update after copying all data */ netconn_tcp_recvd(sock->conn, (size_t)recvd); } - sock_set_errno(sock, 0); + set_errno(0); return recvd; } #endif @@ -1071,11 +1081,10 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, #endif /* LWIP_IPV4 && LWIP_IPV6 */ IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); - DF_NADDR(*fromaddr); - if (*fromlen < saddr.sa.sa_len) { + if (*fromlen < IPADDR_SOCKADDR_GET_LEN(&saddr)) { truncated = 1; - } else if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; + } else if (*fromlen > IPADDR_SOCKADDR_GET_LEN(&saddr)) { + *fromlen = IPADDR_SOCKADDR_GET_LEN(&saddr); } MEMCPY(from, &saddr, *fromlen); return truncated; @@ -1100,11 +1109,11 @@ lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fro /* get remote addr/port from tcp_pcb */ u16_t port; ip_addr_t tmpaddr; - err_t err = netconn_getaddr(sock->conn, &tmpaddr, &port, 0); + netconn_getaddr(sock->conn, &tmpaddr, &port, 0); LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); - if (!err && from && fromlen) { + if (from && fromlen) { return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); } } @@ -1122,7 +1131,7 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 u8_t apiflags; err_t err; u16_t buflen, copylen, copied; - int i; + msg_iovlen_t i; LWIP_UNUSED_ARG(dbg_s); LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); @@ -1230,18 +1239,6 @@ ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (!is_distributed_net_enabled()) { - return lwip_recvfrom_internal(s, mem, len, flags, from, fromlen); - } - return distributed_net_recvfrom(s, mem, len, flags, from, fromlen); -} - -ssize_t -lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ -#endif struct lwip_sock *sock; ssize_t ret; @@ -1276,7 +1273,7 @@ lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", s, lwip_strerr(err))); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } @@ -1286,7 +1283,7 @@ lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, } } - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return ret; } @@ -1324,7 +1321,7 @@ ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags) { struct lwip_sock *sock; - int i; + msg_iovlen_t i; ssize_t buflen; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); @@ -1348,7 +1345,7 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { - sock_set_errno(sock, err_to_errno(ERR_VAL)); + set_errno(err_to_errno(ERR_VAL)); done_socket(sock); return -1; } @@ -1382,13 +1379,13 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) } if (buflen > 0) { /* reset socket error since we have received something */ - sock_set_errno(sock, 0); + set_errno(0); } /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ done_socket(sock); return buflen; #else /* LWIP_TCP */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* LWIP_TCP */ @@ -1402,7 +1399,7 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", s, lwip_strerr(err))); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } @@ -1410,12 +1407,12 @@ lwip_recvmsg(int s, struct msghdr *message, int flags) message->msg_flags |= MSG_TRUNC; } - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return (int)datagram_len; } #else /* LWIP_UDP || LWIP_RAW */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* LWIP_UDP || LWIP_RAW */ @@ -1440,13 +1437,9 @@ lwip_send(int s, const void *data, size_t size, int flags) if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) done_socket(sock); -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - return lwip_sendto_internal(s, data, size, flags, NULL, 0); -#else return lwip_sendto(s, data, size, flags, NULL, 0); -#endif #else /* (LWIP_UDP || LWIP_RAW) */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* (LWIP_UDP || LWIP_RAW) */ @@ -1459,7 +1452,7 @@ lwip_send(int s, const void *data, size_t size, int flags) err = netconn_write_partly(sock->conn, data, size, write_flags, &written); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ return (err == ERR_OK ? (ssize_t)written : -1); @@ -1468,17 +1461,6 @@ lwip_send(int s, const void *data, size_t size, int flags) ssize_t lwip_sendmsg(int s, const struct msghdr *msg, int flags) { -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL && LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG - if (!is_distributed_net_enabled()) { - return lwip_sendmsg_internal(s, msg, flags); - } - return distributed_net_sendmsg(s, msg, flags); -} - -ssize_t -lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) -{ -#endif struct lwip_sock *sock; #if LWIP_TCP u8_t write_flags; @@ -1492,13 +1474,13 @@ lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) } LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), - sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); + set_errno(EMSGSIZE); done_socket(sock); return -1;); LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, - sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); + set_errno(EOPNOTSUPP); done_socket(sock); return -1;); LWIP_UNUSED_ARG(msg->msg_control); LWIP_UNUSED_ARG(msg->msg_controllen); @@ -1512,12 +1494,12 @@ lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) written = 0; err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ return (err == ERR_OK ? (ssize_t)written : -1); #else /* LWIP_TCP */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* LWIP_TCP */ @@ -1526,13 +1508,13 @@ lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) #if LWIP_UDP || LWIP_RAW { struct netbuf chain_buf; - int i; + msg_iovlen_t i; ssize_t size = 0; LWIP_UNUSED_ARG(flags); LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); /* initialize chain buffer with destination */ memset(&chain_buf, 0, sizeof(struct netbuf)); @@ -1623,17 +1605,17 @@ lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) /* deallocated the buffer */ netbuf_free(&chain_buf); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return (err == ERR_OK ? size : -1); sendmsg_emsgsize: - sock_set_errno(sock, EMSGSIZE); + set_errno(EMSGSIZE); netbuf_free(&chain_buf); done_socket(sock); return -1; } #else /* LWIP_UDP || LWIP_RAW */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* LWIP_UDP || LWIP_RAW */ @@ -1643,18 +1625,6 @@ ssize_t lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen) { -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (!is_distributed_net_enabled()) { - return lwip_sendto_internal(s, data, size, flags, to, tolen); - } - return distributed_net_sendto(s, data, size, flags, to, tolen); -} - -ssize_t -lwip_sendto_internal(int s, const void *data, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) -{ -#endif struct lwip_sock *sock; err_t err; u16_t short_size; @@ -1672,7 +1642,7 @@ lwip_sendto_internal(int s, const void *data, size_t size, int flags, return lwip_send(s, data, size, flags); #else /* LWIP_TCP */ LWIP_UNUSED_ARG(flags); - sock_set_errno(sock, err_to_errno(ERR_ARG)); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1; #endif /* LWIP_TCP */ @@ -1680,7 +1650,7 @@ lwip_sendto_internal(int s, const void *data, size_t size, int flags, if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { /* cannot fit into one datagram (at least for us) */ - sock_set_errno(sock, EMSGSIZE); + set_errno(EMSGSIZE); done_socket(sock); return -1; } @@ -1688,7 +1658,7 @@ lwip_sendto_internal(int s, const void *data, size_t size, int flags, LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || (IS_SOCK_ADDR_LEN_VALID(tolen) && ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), - sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;); LWIP_UNUSED_ARG(tolen); /* initialize a buffer */ @@ -1746,7 +1716,7 @@ lwip_sendto_internal(int s, const void *data, size_t size, int flags, /* deallocated the buffer */ netbuf_free(&buf); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return (err == ERR_OK ? short_size : -1); } @@ -1805,7 +1775,7 @@ lwip_socket(int domain, int type, int protocol) set_errno(ENFILE); return -1; } - conn->socket = i; + conn->callback_arg.socket = i; done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); set_errno(0); @@ -2147,7 +2117,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, set_errno(EBADF); } else if (!nready) { /* Still none ready, just wait to be woken */ - if (timeout == 0) { + if (timeout == NULL) { /* Wait forever */ msectimeout = 0; } else { @@ -2561,7 +2531,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) /* Get socket */ if (conn) { - s = conn->socket; + s = conn->callback_arg.socket; if (s < 0) { /* Data comes in right away after an accept, even though * the server task might not have created a new socket yet. @@ -2569,16 +2539,16 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) * will use the data later. Note that only receive events * can happen before the new socket is set up. */ SYS_ARCH_PROTECT(lev); - if (conn->socket < 0) { + if (conn->callback_arg.socket < 0) { if (evt == NETCONN_EVT_RCVPLUS) { /* conn->socket is -1 on initialization lwip_accept adjusts sock->recvevent if conn->socket < -1 */ - conn->socket--; + conn->callback_arg.socket--; } SYS_ARCH_UNPROTECT(lev); return; } - s = conn->socket; + s = conn->callback_arg.socket; SYS_ARCH_UNPROTECT(lev); } @@ -2634,7 +2604,6 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) } else { SYS_ARCH_UNPROTECT(lev); } - poll_check_waiters(s, check_waiters); done_socket(sock); } @@ -2745,12 +2714,12 @@ lwip_shutdown(int s, int how) if (sock->conn != NULL) { if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); + set_errno(EOPNOTSUPP); done_socket(sock); return -1; } } else { - sock_set_errno(sock, ENOTCONN); + set_errno(ENOTCONN); done_socket(sock); return -1; } @@ -2763,13 +2732,13 @@ lwip_shutdown(int s, int how) shut_rx = 1; shut_tx = 1; } else { - sock_set_errno(sock, EINVAL); + set_errno(EINVAL); done_socket(sock); return -1; } err = netconn_shutdown(sock->conn, shut_rx, shut_tx); - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return (err == ERR_OK ? 0 : -1); } @@ -2791,7 +2760,7 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) /* get the IP address and port */ err = netconn_getaddr(sock->conn, &naddr, &port, local); if (err != ERR_OK) { - sock_set_errno(sock, err_to_errno(err)); + set_errno(err_to_errno(err)); done_socket(sock); return -1; } @@ -2811,12 +2780,12 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - if (*namelen > saddr.sa.sa_len) { - *namelen = saddr.sa.sa_len; + if (*namelen > IPADDR_SOCKADDR_GET_LEN(&saddr)) { + *namelen = IPADDR_SOCKADDR_GET_LEN(&saddr); } MEMCPY(name, &saddr, *namelen); - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; } @@ -2848,7 +2817,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } if ((NULL == optval) || (NULL == optlen)) { - sock_set_errno(sock, EFAULT); + set_errno(EFAULT); done_socket(sock); return -1; } @@ -2864,7 +2833,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) #if LWIP_MPU_COMPATIBLE /* MPU_COMPATIBLE copies the optval data, so check for max size here */ if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { - sock_set_errno(sock, ENOBUFS); + set_errno(ENOBUFS); done_socket(sock); return -1; } @@ -2887,7 +2856,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); if (cberr != ERR_OK) { LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); - sock_set_errno(sock, err_to_errno(cberr)); + set_errno(err_to_errno(cberr)); done_socket(sock); return -1; } @@ -2900,12 +2869,12 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); #endif /* LWIP_MPU_COMPATIBLE */ - /* maybe lwip_getsockopt_internal has changed err */ + /* maybe lwip_getsockopt_impl has changed err */ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); #endif /* LWIP_TCPIP_CORE_LOCKING */ - sock_set_errno(sock, err); + set_errno(err); done_socket(sock); return err ? -1 : 0; } @@ -2953,6 +2922,49 @@ lwip_sockopt_to_ipopt(int optname) } } +#if LWIP_IPV6 && LWIP_RAW +static void +lwip_getsockopt_impl_ipv6_checksum(int s, struct lwip_sock* sock, void* optval) +{ + if (sock->conn->pcb.raw->chksum_reqd == 0) { + *(int*)optval = -1; + } + else { + *(int*)optval = sock->conn->pcb.raw->chksum_offset; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", + s, (*(int*)optval))); +} + +static int +lwip_setsockopt_impl_ipv6_checksum(int s, struct lwip_sock* sock, const void* optval, socklen_t optlen) +{ + /* It should not be possible to disable the checksum generation with ICMPv6 + * as per RFC 3542 chapter 3.1 */ + if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { + done_socket(sock); + return EINVAL; + } + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); + if (*(const int*)optval < 0) { + sock->conn->pcb.raw->chksum_reqd = 0; + } + else if (*(const int*)optval & 1) { + /* Per RFC3542, odd offsets are not allowed */ + done_socket(sock); + return EINVAL; + } + else { + sock->conn->pcb.raw->chksum_reqd = 1; + sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", + s, sock->conn->pcb.raw->chksum_reqd)); + return 0; +} +#endif + /** lwip_getsockopt_impl: the actual implementation of getsockopt: * same argument as lwip_getsockopt, either called directly or through callback */ @@ -2967,6 +2979,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt #ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { + done_socket(sock); return err; } #endif @@ -3202,6 +3215,12 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); + lwip_getsockopt_impl_ipv6_checksum(s, sock, optval); + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ case IPV6_V6ONLY: LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); @@ -3252,13 +3271,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt #if LWIP_IPV6 && LWIP_RAW case IPV6_CHECKSUM: LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); - if (sock->conn->pcb.raw->chksum_reqd == 0) { - *(int *)optval = -1; - } else { - *(int *)optval = sock->conn->pcb.raw->chksum_offset; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", - s, (*(int *)optval)) ); + lwip_getsockopt_impl_ipv6_checksum(s, sock, optval); break; #endif /* LWIP_IPV6 && LWIP_RAW */ default: @@ -3294,7 +3307,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } if (NULL == optval) { - sock_set_errno(sock, EFAULT); + set_errno(EFAULT); done_socket(sock); return -1; } @@ -3304,16 +3317,13 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt LOCK_TCPIP_CORE(); err = lwip_setsockopt_impl(s, level, optname, optval, optlen); UNLOCK_TCPIP_CORE(); -#if LWIP_LOWPOWER - tcpip_send_msg_na(LOW_NON_BLOCK); -#endif #else /* LWIP_TCPIP_CORE_LOCKING */ #if LWIP_MPU_COMPATIBLE /* MPU_COMPATIBLE copies the optval data, so check for max size here */ if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { - sock_set_errno(sock, ENOBUFS); + set_errno(ENOBUFS); done_socket(sock); return -1; } @@ -3338,18 +3348,18 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); if (cberr != ERR_OK) { LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); - sock_set_errno(sock, err_to_errno(cberr)); + set_errno(err_to_errno(cberr)); done_socket(sock); return -1; } sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); - /* maybe lwip_getsockopt_internal has changed err */ + /* maybe lwip_setsockopt_impl has changed err */ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); #endif /* LWIP_TCPIP_CORE_LOCKING */ - sock_set_errno(sock, err); + set_errno(err); done_socket(sock); return err ? -1 : 0; } @@ -3391,6 +3401,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ #ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { + done_socket(sock); return err; } #endif @@ -3682,7 +3693,15 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { - case IPV6_V6ONLY: +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + err = lwip_setsockopt_impl_ipv6_checksum(s, sock, optval, optlen); + if (err) { + return err; + } + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ + case IPV6_V6ONLY: LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); if (*(const int *)optval) { netconn_set_ipv6only(sock->conn, 1); @@ -3703,11 +3722,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index((u8_t)imr->ipv6mr_interface, get_net_group_from_ippcb(sock->conn->pcb.ip)); -#else netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); -#endif if (netif == NULL) { err = EADDRNOTAVAIL; break; @@ -3784,26 +3799,10 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ switch (optname) { #if LWIP_IPV6 && LWIP_RAW case IPV6_CHECKSUM: - /* It should not be possible to disable the checksum generation with ICMPv6 - * as per RFC 3542 chapter 3.1 */ - if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { - done_socket(sock); - return EINVAL; - } - - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); - if (*(const int *)optval < 0) { - sock->conn->pcb.raw->chksum_reqd = 0; - } else if (*(const int *)optval & 1) { - /* Per RFC3542, odd offsets are not allowed */ - done_socket(sock); - return EINVAL; - } else { - sock->conn->pcb.raw->chksum_reqd = 1; - sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; + err = lwip_setsockopt_impl_ipv6_checksum(s, sock, optval, optlen); + if (err) { + return err; } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", - s, sock->conn->pcb.raw->chksum_reqd)); break; #endif /* LWIP_IPV6 && LWIP_RAW */ default: @@ -3841,7 +3840,7 @@ lwip_ioctl(int s, long cmd, void *argp) #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE case FIONREAD: if (!argp) { - sock_set_errno(sock, EINVAL); + set_errno(EINVAL); done_socket(sock); return -1; } @@ -3884,7 +3883,7 @@ lwip_ioctl(int s, long cmd, void *argp) *((int *)argp) = recv_avail; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; #else /* LWIP_SO_RCVBUF */ @@ -3899,16 +3898,15 @@ lwip_ioctl(int s, long cmd, void *argp) } netconn_set_nonblocking(sock->conn, val); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); - sock_set_errno(sock, 0); + set_errno(0); done_socket(sock); return 0; default: - IOCTL_CMD_CASE_HANDLER(); break; } /* switch (cmd) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ + set_errno(ENOSYS); /* not yet implemented */ done_socket(sock); return -1; } @@ -3932,7 +3930,7 @@ lwip_fcntl(int s, int cmd, int val) switch (cmd) { case F_GETFL: ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; - sock_set_errno(sock, 0); + set_errno(0); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { #if LWIP_TCPIP_CORE_LOCKING @@ -3973,14 +3971,14 @@ lwip_fcntl(int s, int cmd, int val) /* only O_NONBLOCK, all other bits are zero */ netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); ret = 0; - sock_set_errno(sock, 0); + set_errno(0); } else { - sock_set_errno(sock, ENOSYS); /* not yet implemented */ + set_errno(ENOSYS); /* not yet implemented */ } break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ + set_errno(ENOSYS); /* not yet implemented */ break; } done_socket(sock); @@ -4111,8 +4109,8 @@ lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_ad for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { if ((socket_ipv4_multicast_memberships[i].sock == sock) && - ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && - ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { + ip4_addr_eq(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && + ip4_addr_eq(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { socket_ipv4_multicast_memberships[i].sock = NULL; ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); @@ -4200,7 +4198,7 @@ lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_add for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { if ((socket_ipv6_multicast_memberships[i].sock == sock) && (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && - ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { + ip6_addr_eq(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { socket_ipv6_multicast_memberships[i].sock = NULL; socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 1a7bfc5..0891f9e 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -49,9 +49,6 @@ #include "lwip/pbuf.h" #include "lwip/etharp.h" #include "netif/ethernet.h" -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -#endif #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) @@ -71,12 +68,20 @@ sys_mutex_t lock_tcpip_core; static void tcpip_thread_handle_msg(struct tcpip_msg *msg); #if !LWIP_TIMERS -/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ -#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) + +/** Wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ +static void +tcpip_mbox_fetch(sys_mbox_t* mbox, void** msg) +{ + LWIP_ASSERT_CORE_LOCKED(); + + UNLOCK_TCPIP_CORE(); + sys_mbox_fetch(mbox, msg); + LOCK_TCPIP_CORE(); +} + #else /* !LWIP_TIMERS */ -/* wait for a message, timeouts are processed while waiting */ -#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg) -#if !LWIP_LOWPOWER + /** * Wait (forever) for a message to arrive in an mbox. * While waiting, timeouts are processed. @@ -85,7 +90,7 @@ static void tcpip_thread_handle_msg(struct tcpip_msg *msg); * @param msg the place to store the message */ static void -tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +tcpip_mbox_fetch(sys_mbox_t *mbox, void **msg) { u32_t sleeptime, res; @@ -115,7 +120,6 @@ again: goto again; } } -#endif /* !LWIP_LOWPOWER */ #endif /* !LWIP_TIMERS */ /** @@ -144,7 +148,7 @@ tcpip_thread(void *arg) while (1) { /* MAIN Loop */ LWIP_TCPIP_THREAD_ALIVE(); /* wait for a message, timeouts are processed while waiting */ - TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); + tcpip_mbox_fetch(&tcpip_mbox, (void **)&msg); if (msg == NULL) { LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); LWIP_ASSERT("tcpip_thread: invalid message", 0); @@ -171,6 +175,11 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg) msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); sys_sem_signal(msg->msg.api_call.sem); break; + case TCPIP_MSG_CALLBACK_STATIC_WAIT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK WAIT message %p\n", (void *)msg)); + msg->msg.cb_wait.function(msg->msg.cb_wait.ctx); + sys_sem_signal(msg->msg.cb_wait.sem); + break; #endif /* !LWIP_TCPIP_CORE_LOCKING */ #if !LWIP_TCPIP_CORE_LOCKING_INPUT @@ -206,17 +215,7 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg) LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); msg->msg.cb.function(msg->msg.cb.ctx); break; -#if LWIP_LOWPOWER - /* just wake up thread do nothing */ - case TCPIP_MSG_NA: - if (msg->msg.lowpower.type == LOW_BLOCK) { - LOWPOWER_SIGNAL(msg->msg.lowpower.wait_up); - } else { - memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); - } - sys_timeout_set_wake_time(LOW_TMR_DELAY); - break; -#endif + default: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); LWIP_ASSERT("tcpip_thread: invalid message", 0); @@ -224,58 +223,6 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg) } } -#if LWIP_LOWPOWER -/* send a na msg to wake up tcpip_thread */ -void -tcpip_send_msg_na(enum lowpower_msg_type type) -{ - struct tcpip_msg *msg = NULL; - err_t val; - - /* is not used lowpower mode */ - if ((type != LOW_FORCE_NON_BLOCK) && (get_lowpowper_mod() == LOW_TMR_NORMAL_MOD)) { - return; - } - if (sys_timeout_waiting_long() == 0) { - return; - } - - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_LOWPOWER); - if (msg == NULL) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na alloc faild\n")); - return; - } - - /* just wake up thread if nonblock */ - msg->type = TCPIP_MSG_NA; - msg->msg.lowpower.type = type; - - if (type == LOW_BLOCK) { - LOWPOWER_SEM_NEW(msg->msg.lowpower.wait_up, val); - if (val != ERR_OK) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("alloc sem faild\n")); - memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); - return; - } - } - - if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { - if (type == LOW_BLOCK) { - LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); - } - memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); - LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na post faild\n")); - return; - } - - if (type == LOW_BLOCK) { - LOWPOWER_SEM_WAIT(msg->msg.lowpower.wait_up); - LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); - memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); - } -} -#endif /* LWIP_LOWPOWER */ - #ifdef TCPIP_THREAD_TEST /** Work on queued items in single-threaded test mode */ int @@ -309,9 +256,6 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) #if LWIP_TCPIP_CORE_LOCKING_INPUT err_t ret; LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); -#if LWIP_LOWPOWER - tcpip_send_msg_na(LOW_BLOCK); -#endif LOCK_TCPIP_CORE(); ret = input_fn(p, inp); UNLOCK_TCPIP_CORE(); @@ -493,7 +437,7 @@ tcpip_untimeout(sys_timeout_handler h, void *arg) /** * Sends a message to TCPIP thread to call a function. Caller thread blocks on - * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, + * on a provided semaphore, which is NOT automatically signalled by TCPIP thread, * this has to be done by the user. * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way * with least runtime overhead. @@ -508,9 +452,6 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) { #if LWIP_TCPIP_CORE_LOCKING LWIP_UNUSED_ARG(sem); -#if LWIP_LOWPOWER - tcpip_send_msg_na(LOW_BLOCK); -#endif LOCK_TCPIP_CORE(); fn(apimsg); UNLOCK_TCPIP_CORE(); @@ -547,9 +488,6 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) { #if LWIP_TCPIP_CORE_LOCKING err_t err; -#if LWIP_LOWPOWER - tcpip_send_msg_na(LOW_BLOCK); -#endif LOCK_TCPIP_CORE(); err = fn(call); UNLOCK_TCPIP_CORE(); @@ -595,7 +533,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) * e.g. the message is allocated once and posted several times from an IRQ * using tcpip_callbackmsg_trycallback(). * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context. - * + * * @param function the function to call * @param ctx parameter passed to function * @return a struct pointer to pass to tcpip_callbackmsg_trycallback(). @@ -665,6 +603,49 @@ tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg) return sys_mbox_trypost_fromisr(&tcpip_mbox, msg); } +/** + * Sends a message to TCPIP thread to call a function. Caller thread blocks + * until the function returns. + * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or + * LWIP_NETCONN_SEM_PER_THREAD. + * If not, a semaphore is created and destroyed on every call which is usually + * an expensive/slow operation. + * + * @param function the function to call + * @param ctx parameter passed to f + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_callback_wait(tcpip_callback_fn function, void *ctx) +{ +#if LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); + function(ctx); + UNLOCK_TCPIP_CORE(); + return ERR_OK; +#else /* LWIP_TCPIP_CORE_LOCKING */ + err_t err; + sys_sem_t sem; + struct tcpip_msg msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + err = sys_sem_new(&sem, 0); + if (err != ERR_OK) { + return err; + } + + msg.type = TCPIP_MSG_CALLBACK_STATIC_WAIT; + msg.msg.cb_wait.function = function; + msg.msg.cb_wait.ctx = ctx; + msg.msg.cb_wait.sem = &sem; + sys_mbox_post(&tcpip_mbox, &msg); + sys_arch_sem_wait(&sem, 0); + sys_sem_free(&sem); + return ERR_OK; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} + /** * @ingroup lwip_os * Initialize this module: diff --git a/src/apps/altcp_tls/altcp_tls_mbedtls.c b/src/apps/altcp_tls/altcp_tls_mbedtls.c index bb8e623..9e61912 100644 --- a/src/apps/altcp_tls/altcp_tls_mbedtls.c +++ b/src/apps/altcp_tls/altcp_tls_mbedtls.c @@ -3,6 +3,8 @@ * Application layered TCP/TLS connection API (to be used from TCPIP thread) * * This file provides a TLS layer using mbedTLS + * + * This version is currently compatible with the 2.x.x branch (current LTS). */ /* @@ -46,10 +48,11 @@ * GOOD custom entropy * * Missing things / @todo: - * - some unhandled/untested things migh be caught by LWIP_ASSERTs... + * - some unhandled/untested things might be caught by LWIP_ASSERTs... */ #include "lwip/opt.h" +#include "lwip/sys.h" #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ @@ -70,7 +73,7 @@ #include "mbedtls/certs.h" #include "mbedtls/x509.h" #include "mbedtls/ssl.h" -#include "mbedtls/net.h" +#include "mbedtls/net_sockets.h" #include "mbedtls/error.h" #include "mbedtls/debug.h" #include "mbedtls/platform.h" @@ -88,6 +91,9 @@ #ifndef ALTCP_MBEDTLS_ENTROPY_LEN #define ALTCP_MBEDTLS_ENTROPY_LEN 0 #endif +#ifndef ALTCP_MBEDTLS_RNG_FN +#define ALTCP_MBEDTLS_RNG_FN mbedtls_entropy_func +#endif /* Variable prototype, the actual declaration is at the end of this file since it contains pointers to static functions declared here */ @@ -98,10 +104,10 @@ struct altcp_tls_config { mbedtls_ssl_config conf; mbedtls_x509_crt *cert; mbedtls_pk_context *pkey; - uint8_t cert_count; - uint8_t cert_max; - uint8_t pkey_count; - uint8_t pkey_max; + u8_t cert_count; + u8_t cert_max; + u8_t pkey_count; + u8_t pkey_max; mbedtls_x509_crt *ca; #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_USE_SESSION_CACHE /** Inter-connection cache for fast connection startup */ @@ -127,6 +133,15 @@ static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbed static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size); +static void +altcp_mbedtls_flush_output(altcp_mbedtls_state_t* state) +{ + int flushed = mbedtls_ssl_flush_output(&state->ssl_context); + if (flushed) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_flush_output failed: %d\n", flushed)); + } +} + /* callback functions from inner/lower connection: */ /** Accept callback from lower connection (i.e. TCP) @@ -165,6 +180,7 @@ altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err struct altcp_pcb *conn = (struct altcp_pcb *)arg; LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */ if (conn && conn->state) { + altcp_mbedtls_state_t *state; LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); /* upper connected is called when handshake is done */ if (err != ERR_OK) { @@ -172,7 +188,10 @@ altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err return conn->connected(conn->arg, conn, err); } } - return altcp_mbedtls_lower_recv_process(conn, (altcp_mbedtls_state_t *)conn->state); + state = (altcp_mbedtls_state_t *)conn->state; + /* ensure overhead value is valid before first write */ + state->overhead_bytes_adjust = 0; + return altcp_mbedtls_lower_recv_process(conn, state); } return ERR_VAL; } @@ -240,7 +259,7 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p } else { /* before connection setup is done: call 'err' */ if (conn->err) { - conn->err(conn->arg, ERR_CLSD); + conn->err(conn->arg, ERR_ABRT); } altcp_close(conn); } @@ -354,7 +373,7 @@ altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) /* application may have close the connection */ if (conn->state != state) { /* return error code to ensure altcp_mbedtls_handle_rx_appldata() exits the loop */ - return ERR_CLSD; + return ERR_ARG; } return ERR_OK; } @@ -498,27 +517,37 @@ altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len) } /** Sent callback from lower connection (i.e. TCP) - * This only informs the upper layer to try to send more, not about - * the number of ACKed bytes. + * This only informs the upper layer the number of ACKed bytes. + * This now take care of TLS added bytes so application receive + * correct ACKed bytes. */ static err_t altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len) { struct altcp_pcb *conn = (struct altcp_pcb *)arg; LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */ - LWIP_UNUSED_ARG(len); if (conn) { + int overhead; + u16_t app_len; altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("state", state != NULL); LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); - if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { - /* @todo: do something here? */ - return ERR_OK; + /* calculate TLS overhead part to not send it to application */ + overhead = state->overhead_bytes_adjust + state->ssl_context.out_left; + if ((unsigned)overhead > len) { + overhead = len; } - /* try to send more if we failed before */ - mbedtls_ssl_flush_output(&state->ssl_context); - /* call upper sent with len==0 if the application already sent data */ - if ((state->flags & ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT) && conn->sent) { - return conn->sent(conn->arg, conn, 0); + /* remove ACKed bytes from overhead adjust counter */ + state->overhead_bytes_adjust -= len; + /* try to send more if we failed before (may increase overhead adjust counter) */ + altcp_mbedtls_flush_output(state); + /* remove calculated overhead from ACKed bytes len */ + app_len = len - (u16_t)overhead; + /* update application write counter and inform application */ + if (app_len) { + state->overhead_bytes_adjust += app_len; + if (conn->sent) + return conn->sent(conn->arg, conn, app_len); } } return ERR_OK; @@ -539,7 +568,7 @@ altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn) if (conn->state) { altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; /* try to send more if we failed before */ - mbedtls_ssl_flush_output(&state->ssl_context); + altcp_mbedtls_flush_output(state); if (altcp_mbedtls_handle_rx_appldata(conn, state) == ERR_ABRT) { return ERR_ABRT; } @@ -639,6 +668,44 @@ altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb) return ret; } +void +altcp_tls_init_session(struct altcp_tls_session *session) +{ + if (session) + mbedtls_ssl_session_init(&session->data); +} + +err_t +altcp_tls_get_session(struct altcp_pcb *conn, struct altcp_tls_session *session) +{ + if (session && conn && conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + int ret = mbedtls_ssl_get_session(&state->ssl_context, &session->data); + return ret < 0 ? ERR_VAL : ERR_OK; + } + return ERR_ARG; +} + +err_t +altcp_tls_set_session(struct altcp_pcb *conn, struct altcp_tls_session *session) +{ + if (session && conn && conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + int ret = -1; + if (session->data.start) + ret = mbedtls_ssl_set_session(&state->ssl_context, &session->data); + return ret < 0 ? ERR_VAL : ERR_OK; + } + return ERR_ARG; +} + +void +altcp_tls_free_session(struct altcp_tls_session *session) +{ + if (session) + mbedtls_ssl_session_free(&session->data); +} + void * altcp_tls_context(struct altcp_pcb *conn) { @@ -659,16 +726,59 @@ altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char LWIP_UNUSED_ARG(str); if (level >= ALTCP_MBEDTLS_LIB_DEBUG_LEVEL_MIN) { - LWIP_DEBUGF(ALTCP_MBEDTLS_LIB_DEBUG, ("%s:%04d: %s", file, line, str)); + LWIP_DEBUGF(ALTCP_MBEDTLS_LIB_DEBUG, ("%s:%04d: %s\n", file, line, str)); } } #endif +static err_t +altcp_mbedtls_ref_entropy(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (!altcp_tls_entropy_rng) { + altcp_tls_entropy_rng = (struct altcp_tls_entropy_rng *)altcp_mbedtls_alloc_config(sizeof(struct altcp_tls_entropy_rng)); + if (altcp_tls_entropy_rng) { + int ret; + altcp_tls_entropy_rng->ref = 1; + mbedtls_entropy_init(&altcp_tls_entropy_rng->entropy); + mbedtls_ctr_drbg_init(&altcp_tls_entropy_rng->ctr_drbg); + /* Seed the RNG, only once */ + ret = mbedtls_ctr_drbg_seed(&altcp_tls_entropy_rng->ctr_drbg, + ALTCP_MBEDTLS_RNG_FN, &altcp_tls_entropy_rng->entropy, + ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret)); + mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); + mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); + altcp_mbedtls_free_config(altcp_tls_entropy_rng); + altcp_tls_entropy_rng = NULL; + return ERR_ARG; + } + } else { + return ERR_MEM; + } + } else { + altcp_tls_entropy_rng->ref++; + } + return ERR_OK; +} + +static void +altcp_mbedtls_unref_entropy(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (altcp_tls_entropy_rng && altcp_tls_entropy_rng->ref) { + altcp_tls_entropy_rng->ref--; + } +} + /** Create new TLS configuration * ATTENTION: Server certificate and private key have to be added outside this function! */ static struct altcp_tls_config * -altcp_tls_create_config(int is_server, uint8_t cert_count, uint8_t pkey_count, int have_ca) +altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int have_ca) { size_t sz; int ret; @@ -714,31 +824,9 @@ altcp_tls_create_config(int is_server, uint8_t cert_count, uint8_t pkey_count, i mbedtls_ssl_config_init(&conf->conf); - if (!altcp_tls_entropy_rng) { - altcp_tls_entropy_rng = (struct altcp_tls_entropy_rng *)altcp_mbedtls_alloc_config(sizeof(struct altcp_tls_entropy_rng)); - if (altcp_tls_entropy_rng) { - altcp_tls_entropy_rng->ref = 1; - mbedtls_entropy_init(&altcp_tls_entropy_rng->entropy); - mbedtls_ctr_drbg_init(&altcp_tls_entropy_rng->ctr_drbg); - /* Seed the RNG, only once */ - ret = mbedtls_ctr_drbg_seed(&altcp_tls_entropy_rng->ctr_drbg, - mbedtls_entropy_func, &altcp_tls_entropy_rng->entropy, - ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN); - if (ret != 0) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret)); - mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); - mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); - altcp_mbedtls_free_config(altcp_tls_entropy_rng); - altcp_tls_entropy_rng = NULL; - altcp_mbedtls_free_config(conf); - return NULL; - } - } else { - altcp_mbedtls_free_config(conf); - return NULL; - } - } else { - altcp_tls_entropy_rng->ref++; + if (altcp_mbedtls_ref_entropy() != ERR_OK) { + altcp_mbedtls_free_config(conf); + return NULL; } /* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */ @@ -746,16 +834,11 @@ altcp_tls_create_config(int is_server, uint8_t cert_count, uint8_t pkey_count, i MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d\n", ret)); - if (altcp_tls_entropy_rng->ref == 1) { - mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); - mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); - altcp_mbedtls_free_config(altcp_tls_entropy_rng); - altcp_tls_entropy_rng = NULL; - } + altcp_mbedtls_unref_entropy(); altcp_mbedtls_free_config(conf); return NULL; } - mbedtls_ssl_conf_authmode(&conf->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&conf->conf, ALTCP_MBEDTLS_AUTHMODE); mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &altcp_tls_entropy_rng->ctr_drbg); #if ALTCP_MBEDTLS_LIB_DEBUG != LWIP_DBG_OFF @@ -774,6 +857,7 @@ altcp_tls_create_config(int is_server, uint8_t cert_count, uint8_t pkey_count, i ALTCP_MBEDTLS_SESSION_TICKET_CIPHER, ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS); if (ret) { LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_ticket_setup failed: %d\n", ret)); + altcp_mbedtls_unref_entropy(); altcp_mbedtls_free_config(conf); return NULL; } @@ -785,7 +869,7 @@ altcp_tls_create_config(int is_server, uint8_t cert_count, uint8_t pkey_count, i return conf; } -struct altcp_tls_config *altcp_tls_create_config_server(uint8_t cert_count) +struct altcp_tls_config *altcp_tls_create_config_server(u8_t cert_count) { struct altcp_tls_config *conf = altcp_tls_create_config(1, cert_count, cert_count, 0); if (conf == NULL) { @@ -861,7 +945,7 @@ altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_ if (altcp_tls_config_server_add_privkey_cert(conf, privkey, privkey_len, privkey_pass, privkey_pass_len, cert, cert_len) != ERR_OK) { - altcp_mbedtls_free_config(conf); + altcp_tls_free_config(conf); return NULL; } @@ -884,8 +968,8 @@ altcp_tls_create_config_client_common(const u8_t *ca, size_t ca_len, int is_2way mbedtls_x509_crt_init(conf->ca); ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len); if (ret != 0) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x", ret, -1*ret)); - altcp_mbedtls_free_config(conf); + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); return NULL; } @@ -909,7 +993,7 @@ altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_ struct altcp_tls_config *conf; if (!cert || !privkey) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("altcp_tls_create_config_client_2wayauth: certificate and priv key required")); + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("altcp_tls_create_config_client_2wayauth: certificate and priv key required\n")); return NULL; } @@ -922,29 +1006,44 @@ altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_ mbedtls_x509_crt_init(conf->cert); ret = mbedtls_x509_crt_parse(conf->cert, cert, cert_len); if (ret != 0) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse cert failed: %d 0x%x", ret, -1*ret)); - altcp_mbedtls_free_config(conf->cert); + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse cert failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); return NULL; } mbedtls_pk_init(conf->pkey); ret = mbedtls_pk_parse_key(conf->pkey, privkey, privkey_len, privkey_pass, privkey_pass_len); if (ret != 0) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_key failed: %d 0x%x", ret, -1*ret)); - altcp_mbedtls_free_config(conf); + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_key failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); return NULL; } ret = mbedtls_ssl_conf_own_cert(&conf->conf, conf->cert, conf->pkey); if (ret != 0) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d 0x%x", ret, -1*ret)); - altcp_mbedtls_free_config(conf); + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); return NULL; } return conf; } +int +altcp_tls_configure_alpn_protocols(struct altcp_tls_config *conf, const char **protos) +{ +#if defined(MBEDTLS_SSL_ALPN) + int ret = mbedtls_ssl_conf_alpn_protocols(&conf->conf, protos); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_alpn_protocols failed: %d\n", ret)); + } + + return ret; +#else + return -1; +#endif +} + void altcp_tls_free_config(struct altcp_tls_config *conf) { @@ -957,14 +1056,16 @@ altcp_tls_free_config(struct altcp_tls_config *conf) if (conf->ca) { mbedtls_x509_crt_free(conf->ca); } + mbedtls_ssl_config_free(&conf->conf); altcp_mbedtls_free_config(conf); - if (altcp_tls_entropy_rng && altcp_tls_entropy_rng->ref) - altcp_tls_entropy_rng->ref--; + altcp_mbedtls_unref_entropy(); } void altcp_tls_free_entropy(void) { + LWIP_ASSERT_CORE_LOCKED(); + if (altcp_tls_entropy_rng && altcp_tls_entropy_rng->ref == 0) { mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); @@ -999,7 +1100,7 @@ altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len) } lower_recved = len; if (lower_recved > state->rx_passed_unrecved) { - LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)", + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)\n", len, state->rx_passed_unrecved)); lower_recved = (u16_t)state->rx_passed_unrecved; } @@ -1096,7 +1197,7 @@ altcp_mbedtls_sndbuf(struct altcp_pcb *conn) size_t max_len = 0xFFFF; size_t ret; #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - /* @todo: adjust ssl_added to real value related to negociated cipher */ + /* @todo: adjust ssl_added to real value related to negotiated cipher */ size_t max_frag_len = mbedtls_ssl_get_max_frag_len(&state->ssl_context); max_len = LWIP_MIN(max_frag_len, max_len); #endif @@ -1130,18 +1231,18 @@ altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t state = (altcp_mbedtls_state_t *)conn->state; if (state == NULL) { /* @todo: which error? */ - return ERR_CLSD; + return ERR_ARG; } if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { /* @todo: which error? */ return ERR_VAL; } - /* HACK: if thre is something left to send, try to flush it and only + /* HACK: if there is something left to send, try to flush it and only allow sending more if this succeeded (this is a hack because neither returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */ if (state->ssl_context.out_left) { - mbedtls_ssl_flush_output(&state->ssl_context); + altcp_mbedtls_flush_output(state); if (state->ssl_context.out_left) { return ERR_MEM; } @@ -1151,7 +1252,8 @@ altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t altcp_output(conn->inner_conn); if (ret >= 0) { if (ret == len) { - state->flags |= ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT; + /* update application sent counter */ + state->overhead_bytes_adjust -= ret; return ERR_OK; } else { /* @todo/@fixme: assumption: either everything sent or error */ @@ -1176,6 +1278,7 @@ static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size) { struct altcp_pcb *conn = (struct altcp_pcb *) ctx; + altcp_mbedtls_state_t *state; int written = 0; size_t size_left = size; u8_t apiflags = TCP_WRITE_FLAG_COPY; @@ -1184,6 +1287,8 @@ altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size) if ((conn == NULL) || (conn->inner_conn == NULL)) { return MBEDTLS_ERR_NET_INVALID_CONTEXT; } + state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("state != NULL", state != NULL); while (size_left) { u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF); @@ -1191,6 +1296,7 @@ altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size) if (err == ERR_OK) { written += write_len; size_left -= write_len; + state->overhead_bytes_adjust += write_len; } else if (err == ERR_MEM) { if (written) { return written; diff --git a/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c b/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c index 04d47ae..d2c3d58 100644 --- a/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c +++ b/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c @@ -70,7 +70,7 @@ #if defined(MBEDTLS_PLATFORM_MEMORY) && \ (!defined(MBEDTLS_PLATFORM_FREE_MACRO) || \ - defined(MBEDTLS_PLATFORM_CALLOC_MACRO)) + !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)) #define ALTCP_MBEDTLS_PLATFORM_ALLOC 1 #else #define ALTCP_MBEDTLS_PLATFORM_ALLOC 0 @@ -114,13 +114,13 @@ tls_malloc(size_t c, size_t len) alloc_size = sizeof(altcp_mbedtls_malloc_helper_t) + (c * len); /* check for maximum allocation size, mainly to prevent mem_size_t overflow */ if (alloc_size > MEM_SIZE) { - LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls allocation too big: %c * %d bytes vs MEM_SIZE=%d", + LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls allocation too big: %c * %d bytes vs MEM_SIZE=%d\n", (int)c, (int)len, (int)MEM_SIZE)); return NULL; } hlpr = (altcp_mbedtls_malloc_helper_t *)mem_malloc((mem_size_t)alloc_size); if (hlpr == NULL) { - LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls alloc callback failed for %c * %d bytes", (int)c, (int)len)); + LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls alloc callback failed for %c * %d bytes\n", (int)c, (int)len)); return NULL; } #if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS diff --git a/src/apps/altcp_tls/altcp_tls_mbedtls_structs.h b/src/apps/altcp_tls/altcp_tls_mbedtls_structs.h index 17efaaf..2ad2b60 100644 --- a/src/apps/altcp_tls/altcp_tls_mbedtls_structs.h +++ b/src/apps/altcp_tls/altcp_tls_mbedtls_structs.h @@ -60,7 +60,6 @@ extern "C" { #define ALTCP_MBEDTLS_FLAGS_UPPER_CALLED 0x02 #define ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED 0x04 #define ALTCP_MBEDTLS_FLAGS_RX_CLOSED 0x08 -#define ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT 0x10 typedef struct altcp_mbedtls_state_s { void *conf; @@ -72,6 +71,7 @@ typedef struct altcp_mbedtls_state_s { int rx_passed_unrecved; int bio_bytes_read; int bio_bytes_appl; + int overhead_bytes_adjust; } altcp_mbedtls_state_t; #ifdef __cplusplus diff --git a/src/apps/http/altcp_proxyconnect.c b/src/apps/http/altcp_proxyconnect.c index 9a0b2ba..3d5e7e8 100644 --- a/src/apps/http/altcp_proxyconnect.c +++ b/src/apps/http/altcp_proxyconnect.c @@ -133,7 +133,7 @@ altcp_proxyconnect_send_request(struct altcp_pcb *conn) /* overflow */ return ERR_MEM; } - /* Allocate a bufer for the request string */ + /* Allocate a buffer for the request string */ buffer = (char *)mem_malloc(alloc_len); if (buffer == NULL) { return ERR_MEM; diff --git a/src/apps/http/fs.c b/src/apps/http/fs.c index f15a480..e12e314 100644 --- a/src/apps/http/fs.c +++ b/src/apps/http/fs.c @@ -38,20 +38,6 @@ #include HTTPD_FSDATA_FILE -/*-----------------------------------------------------------------------------------*/ - -#if LWIP_HTTPD_CUSTOM_FILES -int fs_open_custom(struct fs_file *file, const char *name); -void fs_close_custom(struct fs_file *file); -#if LWIP_HTTPD_FS_ASYNC_READ -u8_t fs_canread_custom(struct fs_file *file); -u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); -int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); -#else /* LWIP_HTTPD_FS_ASYNC_READ */ -int fs_read_custom(struct fs_file *file, char *buffer, int count); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -#endif /* LWIP_HTTPD_CUSTOM_FILES */ - /*-----------------------------------------------------------------------------------*/ err_t fs_open(struct fs_file *file, const char *name) @@ -64,10 +50,9 @@ fs_open(struct fs_file *file, const char *name) #if LWIP_HTTPD_CUSTOM_FILES if (fs_open_custom(file, name)) { - file->is_custom_file = 1; + file->flags |= FS_FILE_FLAGS_CUSTOM; return ERR_OK; } - file->is_custom_file = 0; #endif /* LWIP_HTTPD_CUSTOM_FILES */ for (f = FS_ROOT; f != NULL; f = f->next) { @@ -75,12 +60,14 @@ fs_open(struct fs_file *file, const char *name) file->data = (const char *)f->data; file->len = f->len; file->index = f->len; - file->pextension = NULL; file->flags = f->flags; #if HTTPD_PRECALCULATED_CHECKSUM file->chksum_count = f->chksum_count; file->chksum = f->chksum; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ +#if LWIP_HTTPD_FILE_EXTENSION + file->pextension = NULL; +#endif /* LWIP_HTTPD_FILE_EXTENSION */ #if LWIP_HTTPD_FILE_STATE file->state = fs_state_init(file, name); #endif /* #if LWIP_HTTPD_FILE_STATE */ @@ -96,7 +83,7 @@ void fs_close(struct fs_file *file) { #if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file) { + if ((file->flags & FS_FILE_FLAGS_CUSTOM) != 0) { fs_close_custom(file); } #endif /* LWIP_HTTPD_CUSTOM_FILES */ @@ -124,7 +111,7 @@ fs_read(struct fs_file *file, char *buffer, int count) LWIP_UNUSED_ARG(callback_arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file) { + if ((file->flags & FS_FILE_FLAGS_CUSTOM) != 0) { #if LWIP_HTTPD_FS_ASYNC_READ return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg); #else /* LWIP_HTTPD_FS_ASYNC_READ */ diff --git a/src/apps/http/fsdata.c b/src/apps/http/fsdata.c index ab9da7e..50bc87a 100644 --- a/src/apps/http/fsdata.c +++ b/src/apps/http/fsdata.c @@ -334,4 +334,3 @@ FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT, #define FS_ROOT file__index_html #define FS_NUMFILES 3 - diff --git a/src/apps/http/http_client.c b/src/apps/http/http_client.c index 82da60d..32c6f6c 100644 --- a/src/apps/http/http_client.c +++ b/src/apps/http/http_client.c @@ -229,12 +229,15 @@ http_parse_response_status(struct pbuf *p, u16_t *http_version, u16_t *http_stat } else { status_num_len = end1 - space1 - 1; } - memset(status_num, 0, sizeof(status_num)); - if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) { - int status = atoi(status_num); - if ((status > 0) && (status <= 0xFFFF)) { - *http_status = (u16_t)status; - return ERR_OK; + if (status_num_len < sizeof(status_num)) { + if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) { + int status; + status_num[status_num_len] = 0; + status = atoi(status_num); + if ((status > 0) && (status <= 0xFFFF)) { + *http_status = (u16_t)status; + return ERR_OK; + } } } } @@ -261,11 +264,14 @@ http_wait_headers(struct pbuf *p, u32_t *content_length, u16_t *total_header_len if (content_len_line_end != 0xFFFF) { char content_len_num[16]; u16_t content_len_num_len = (u16_t)(content_len_line_end - content_len_hdr - 16); - memset(content_len_num, 0, sizeof(content_len_num)); - if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) { - int len = atoi(content_len_num); - if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) { - *content_length = (u32_t)len; + if (content_len_num_len < sizeof(content_len_num)) { + if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) { + int len; + content_len_num[content_len_num_len] = 0; + len = atoi(content_len_num); + if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) { + *content_length = (u32_t)len; + } } } } @@ -337,8 +343,10 @@ httpc_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t r) } if ((p != NULL) && (req->parse_state == HTTPC_PARSE_RX_DATA)) { req->rx_content_len += p->tot_len; + /* received valid data: reset timeout */ + req->timeout_ticks = HTTPC_POLL_TIMEOUT; if (req->recv_fn != NULL) { - /* directly return here: the connection migth already be aborted from the callback! */ + /* directly return here: the connection might already be aborted from the callback! */ return req->recv_fn(req->callback_arg, pcb, p, r); } else { altcp_recved(pcb, p->tot_len); @@ -487,7 +495,7 @@ static int httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri, int use_host, char *buffer, size_t buffer_size) { - if (settings->use_proxy) { + if (settings && settings->use_proxy) { LWIP_ASSERT("server_name != NULL", server_name != NULL); if (server_port != HTTP_DEFAULT_PORT) { return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name)); @@ -515,6 +523,7 @@ httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_ size_t server_name_len, uri_len; #endif + LWIP_ERROR("httpc connection settings not give", settings != NULL, return ERR_ARG;); LWIP_ASSERT("uri != NULL", uri != NULL); /* get request len */ @@ -559,12 +568,12 @@ httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_ req->uri = req->server_name + server_name_len + 1; memcpy(req->uri, uri, uri_len + 1); #endif - req->pcb = altcp_new(settings->altcp_allocator); + req->pcb = altcp_new(settings ? settings->altcp_allocator : NULL); if(req->pcb == NULL) { httpc_free_state(req); return ERR_MEM; } - req->remote_port = settings->use_proxy ? settings->proxy_port : server_port; + req->remote_port = (settings && settings->use_proxy) ? settings->proxy_port : server_port; altcp_arg(req->pcb, req); altcp_recv(req->pcb, httpc_tcp_recv); altcp_err(req->pcb, httpc_tcp_err); @@ -615,7 +624,7 @@ httpc_init_connection_addr(httpc_state_t **connection, const httpc_connection_t } /** - * @ingroup httpc + * @ingroup httpc * HTTP client API: get a file by passing server IP address * * @param server_addr IP address of the server to connect @@ -624,7 +633,7 @@ httpc_init_connection_addr(httpc_state_t **connection, const httpc_connection_t * @param settings connection settings (callbacks, proxy, etc.) * @param recv_fn the http body (not the headers) are passed to this callback * @param callback_arg argument passed to all the callbacks - * @param connection retreives the connection handle (to match in callbacks) + * @param connection retrieves the connection handle (to match in callbacks) * @return ERR_OK if starting the request succeeds (callback_fn will be called later) * or an error code */ @@ -660,7 +669,7 @@ httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const } /** - * @ingroup httpc + * @ingroup httpc * HTTP client API: get a file by passing server name as string (DNS name or IP address string) * * @param server_name server name as string (DNS name or IP address string) @@ -669,7 +678,7 @@ httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const * @param settings connection settings (callbacks, proxy, etc.) * @param recv_fn the http body (not the headers) are passed to this callback * @param callback_arg argument passed to all the callbacks - * @param connection retreives the connection handle (to match in callbacks) + * @param connection retrieves the connection handle (to match in callbacks) * @return ERR_OK if starting the request succeeds (callback_fn will be called later) * or an error code */ @@ -687,12 +696,12 @@ httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const h return err; } - if (settings->use_proxy) { + if (settings && settings->use_proxy) { err = httpc_get_internal_addr(req, &settings->proxy_addr); } else { err = httpc_get_internal_dns(req, server_name); } - if(err != ERR_OK) { + if (err != ERR_OK) { httpc_free_state(req); return err; } @@ -718,19 +727,24 @@ typedef struct _httpc_filestate static void httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err); -/** Initalize http client state for download to file system */ +/** Initialize http client state for download to file system */ static err_t httpc_fs_init(httpc_filestate_t **filestate_out, const char* local_file_name, const httpc_connection_t *settings, void* callback_arg) { httpc_filestate_t *filestate; size_t file_len, alloc_len; + mem_size_t alloc_mem_size; FILE *f; file_len = strlen(local_file_name); alloc_len = sizeof(httpc_filestate_t) + file_len + 1; - - filestate = (httpc_filestate_t *)mem_malloc((mem_size_t)alloc_len); + alloc_mem_size = (mem_size_t)alloc_len; + if (alloc_mem_size < alloc_len) { + /* overflow */ + return ERR_MEM; + } + filestate = (httpc_filestate_t *)mem_malloc(alloc_mem_size); if (filestate == NULL) { return ERR_MEM; } @@ -802,7 +816,7 @@ httpc_fs_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) } /** - * @ingroup httpc + * @ingroup httpc * HTTP client API: get a file to disk by passing server IP address * * @param server_addr IP address of the server to connect @@ -810,7 +824,7 @@ httpc_fs_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) * @param uri uri to get from the server, remember leading "/"! * @param settings connection settings (callbacks, proxy, etc.) * @param callback_arg argument passed to all the callbacks - * @param connection retreives the connection handle (to match in callbacks) + * @param connection retrieves the connection handle (to match in callbacks) * @return ERR_OK if starting the request succeeds (callback_fn will be called later) * or an error code */ @@ -854,7 +868,7 @@ httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri } /** - * @ingroup httpc + * @ingroup httpc * HTTP client API: get a file to disk by passing server name as string (DNS name or IP address string) * * @param server_name server name as string (DNS name or IP address string) @@ -862,7 +876,7 @@ httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri * @param uri uri to get from the server, remember leading "/"! * @param settings connection settings (callbacks, proxy, etc.) * @param callback_arg argument passed to all the callbacks - * @param connection retreives the connection handle (to match in callbacks) + * @param connection retrieves the connection handle (to match in callbacks) * @return ERR_OK if starting the request succeeds (callback_fn will be called later) * or an error code */ diff --git a/src/apps/http/httpd.c b/src/apps/http/httpd.c index fc27e8e..3e9d234 100644 --- a/src/apps/http/httpd.c +++ b/src/apps/http/httpd.c @@ -233,7 +233,7 @@ struct http_ssi_state { struct http_ssi_tag_description { const char *lead_in; - const char *lead_out; + const char *lead_out; }; #endif /* LWIP_HTTPD_SSI */ @@ -471,6 +471,32 @@ http_state_alloc(void) return ret; } +/** Make sure the post code knows that the connection is closed */ +static void +http_state_close_post(struct http_state* hs) +{ +#if LWIP_HTTPD_SUPPORT_POST + if (hs != NULL) { + if ((hs->post_content_len_left != 0) +#if LWIP_HTTPD_POST_MANUAL_WND + || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0)) +#endif /* LWIP_HTTPD_POST_MANUAL_WND */ + ) { + /* prevent calling httpd_post_finished twice */ + hs->post_content_len_left = 0; +#if LWIP_HTTPD_POST_MANUAL_WND + hs->unrecved_bytes = 0; +#endif /* LWIP_HTTPD_POST_MANUAL_WND */ + /* make sure the post code knows that the connection is closed */ + http_uri_buf[0] = 0; + httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN); + } + } +#else /* LWIP_HTTPD_SUPPORT_POST*/ + LWIP_UNUSED_ARG(hs); +#endif /* LWIP_HTTPD_SUPPORT_POST*/ +} + /** Free a struct http_state. * Also frees the file data if dynamic. */ @@ -505,6 +531,7 @@ http_state_eof(struct http_state *hs) hs->req = NULL; } #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ + http_state_close_post(hs); } /** Free a struct http_state. @@ -598,20 +625,7 @@ http_close_or_abort_conn(struct altcp_pcb *pcb, struct http_state *hs, u8_t abor err_t err; LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void *)pcb)); -#if LWIP_HTTPD_SUPPORT_POST - if (hs != NULL) { - if ((hs->post_content_len_left != 0) -#if LWIP_HTTPD_POST_MANUAL_WND - || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0)) -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - ) { - /* make sure the post code knows that the connection is closed */ - http_uri_buf[0] = 0; - httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN); - } - } -#endif /* LWIP_HTTPD_SUPPORT_POST*/ - + http_state_close_post(hs); altcp_arg(pcb, NULL); altcp_recv(pcb, NULL); @@ -871,14 +885,14 @@ get_http_headers(struct http_state *hs, const char *uri) return; } /* We are dealing with a particular filename. Look for one other - special case. We assume that any filename with "404" in it must be - indicative of a 404 server error whereas all other files require - the 200 OK header. */ - if (strstr(uri, "404")) { + special case. We assume that any filename with "404" in it must be + indicative of a 404 server error whereas all other files require + the 200 OK header. */ + if (memcmp(uri, "/404.", 5) == 0) { hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND]; - } else if (strstr(uri, "400")) { + } else if (memcmp(uri, "/400.", 5) == 0) { hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST]; - } else if (strstr(uri, "501")) { + } else if (memcmp(uri, "/501.", 5) == 0) { hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL]; } else { hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_OK]; @@ -1610,6 +1624,11 @@ http_send(struct altcp_pcb *pcb, struct http_state *hs) } #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ +#if LWIP_HTTPD_SSI + if (hs->ssi && (hs->ssi->tag_state == TAG_SENDING)) { + /* do not check the condition below */ + } else +#endif /* Have we run out of file data to send? If so, we need to read the next * block from the file. */ if (hs->left == 0) { @@ -1621,6 +1640,9 @@ http_send(struct altcp_pcb *pcb, struct http_state *hs) #if LWIP_HTTPD_SSI if (hs->ssi) { data_to_send = http_send_data_ssi(pcb, hs); + if (hs->ssi->tag_state == TAG_SENDING) { + return data_to_send; + } } else #endif /* LWIP_HTTPD_SSI */ { @@ -1810,7 +1832,7 @@ http_post_request(struct pbuf *inp, struct http_state *hs, #define HTTP_HDR_CONTENT_LEN "Content-Length: " #define HTTP_HDR_CONTENT_LEN_LEN 16 #define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10 - char *scontent_len = lwip_strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1)); + char *scontent_len = lwip_strnistr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1)); if (scontent_len != NULL) { char *scontent_len_end = lwip_strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN); if (scontent_len_end != NULL) { @@ -2071,15 +2093,15 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct altcp_pcb *pc } #endif /* LWIP_HTTPD_SUPPORT_V09 */ uri_len = (u16_t)(sp2 - (sp1 + 1)); - if ((sp2 != 0) && (sp2 > sp1)) { + if ((sp2 != NULL) && (sp2 > sp1)) { /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */ if (lwip_strnstr(data, CRLF CRLF, data_len) != NULL) { char *uri = sp1 + 1; #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE /* This is HTTP/1.0 compatible: for strict 1.1, a connection would always be persistent unless "close" was specified. */ - if (!is_09 && (lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) || - lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) { + if (!is_09 && (lwip_strnistr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) || + lwip_strnistr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) { hs->keepalive = 1; } else { hs->keepalive = 0; @@ -2371,7 +2393,7 @@ http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const cha hs->file = file->data; LWIP_ASSERT("File length must be positive!", (file->len >= 0)); #if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file && (file->data == NULL)) { + if (((file->flags & FS_FILE_FLAGS_CUSTOM) != 0) && (file->data == NULL)) { /* custom file, need to read data first (via fs_read_custom) */ hs->left = 0; } else @@ -2393,7 +2415,7 @@ http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const cha search for the end of the header. */ char *file_start = lwip_strnstr(hs->file, CRLF CRLF, hs->left); if (file_start != NULL) { - int diff = file_start + 4 - hs->file; + size_t diff = file_start + 4 - hs->file; hs->file += diff; hs->left -= (u32_t)diff; } @@ -2442,7 +2464,7 @@ http_err(void *arg, err_t err) struct http_state *hs = (struct http_state *)arg; LWIP_UNUSED_ARG(err); - LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err))); + LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s\n", lwip_strerr(err))); if (hs != NULL) { http_state_free(hs); diff --git a/src/apps/http/httpd_structs.h b/src/apps/http/httpd_structs.h index 56b97a3..aa5bce2 100644 --- a/src/apps/http/httpd_structs.h +++ b/src/apps/http/httpd_structs.h @@ -113,11 +113,11 @@ static const tHTTPHeader g_psHTTPHeaders[] = { #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ -#if LWIP_HTTPD_SSI +#if LWIP_HTTPD_SSI && LWIP_HTTPD_SSI_BY_FILE_EXTENSION static const char *const g_pcSSIExtensions[] = { - ".shtml", ".shtm", ".ssi", ".xml", ".json" + LWIP_HTTPD_SSI_EXTENSIONS }; #define NUM_SHTML_EXTENSIONS LWIP_ARRAYSIZE(g_pcSSIExtensions) -#endif /* LWIP_HTTPD_SSI */ +#endif /* LWIP_HTTPD_SSI && LWIP_HTTPD_SSI_BY_FILE_EXTENSION */ #endif /* LWIP_HTTPD_STRUCTS_H */ diff --git a/src/apps/http/makefsdata/makefsdata b/src/apps/http/makefsdata/makefsdata index 37b4203..7f1d4d2 100644 --- a/src/apps/http/makefsdata/makefsdata +++ b/src/apps/http/makefsdata/makefsdata @@ -21,7 +21,7 @@ while($file = ) { print(HEADER "HTTP/1.0 200 OK\r\n"); } print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"); - if($file =~ /\.html$/) { + if($file =~ /\.s?html?$/) { print(HEADER "Content-type: text/html\r\n"); } elsif($file =~ /\.gif$/) { print(HEADER "Content-type: image/gif\r\n"); @@ -90,7 +90,7 @@ for($i = 0; $i < @fvars; $i++) { } print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); - print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) .", FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}};\n\n"); } print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); diff --git a/src/apps/http/makefsdata/makefsdata.c b/src/apps/http/makefsdata/makefsdata.c index 695e94f..62d77a3 100644 --- a/src/apps/http/makefsdata/makefsdata.c +++ b/src/apps/http/makefsdata/makefsdata.c @@ -21,16 +21,25 @@ /** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). * Since nearly all browsers support this, this is a good way to reduce ROM size. - * To compress the files, "miniz.c" must be downloaded seperately. + * To compress the files, "miniz.c" must be downloaded separately OR + * MAKEFS_SUPPORT_DEFLATE_ZLIB must be set and the zlib library and headers + * must be present on the system compiling this program. */ #ifndef MAKEFS_SUPPORT_DEFLATE #define MAKEFS_SUPPORT_DEFLATE 0 -#endif +#ifndef MAKEFS_SUPPORT_DEFLATE_ZLIB +#define MAKEFS_SUPPORT_DEFLATE_ZLIB 0 +#endif /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ +#endif /* MAKEFS_SUPPORT_DEFLATE */ #define COPY_BUFSIZE (1024*1024) /* 1 MByte */ #if MAKEFS_SUPPORT_DEFLATE +#if MAKEFS_SUPPORT_DEFLATE_ZLIB +#include +#else #include "../miniz.c" +#endif /* MAKEFS_SUPPORT_DEFLATE */ typedef unsigned char uint8; typedef unsigned short uint16; @@ -49,12 +58,13 @@ typedef unsigned int uint; static uint8 s_outbuf[OUT_BUF_SIZE]; static uint8 s_checkbuf[OUT_BUF_SIZE]; +#ifndef MAKEFS_SUPPORT_DEFLATE_ZLIB /* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it. */ tdefl_compressor g_deflator; -tinfl_decompressor g_inflator; +#endif /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ -int deflate_level = 10; /* default compression level, can be changed via command line */ +static int deflate_level; /* default compression level, can be changed via command line */ #define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" #else /* MAKEFS_SUPPORT_DEFLATE */ #define USAGE_ARG_DEFLATE "" @@ -63,12 +73,14 @@ int deflate_level = 10; /* default compression level, can be changed via command #ifdef WIN32 #define GETCWD(path, len) GetCurrentDirectoryA(len, path) +#define GETCWD_SUCCEEDED(ret) (ret != 0) #define CHDIR(path) SetCurrentDirectoryA(path) #define CHDIR_SUCCEEDED(ret) (ret == TRUE) -#elif __linux__ +#elif __linux__ || __APPLE__ #define GETCWD(path, len) getcwd(path, len) +#define GETCWD_SUCCEEDED(ret) (ret != NULL) #define CHDIR(path) chdir(path) #define CHDIR_SUCCEEDED(ret) (ret == 0) @@ -81,6 +93,10 @@ int deflate_level = 10; /* default compression level, can be changed via command #define NEWLINE "\r\n" #define NEWLINE_LEN 2 +/* Define this here since we don't include any external C files and ports might override it */ +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) + /* define this to get the header variables we use to build HTTP headers */ #define LWIP_HTTPD_DYNAMIC_HEADERS 1 #define LWIP_HTTPD_SSI 1 @@ -92,8 +108,8 @@ int deflate_level = 10; /* default compression level, can be changed via command #include "../core/def.c" /** (Your server name here) */ -const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; -char serverIDBuffer[1024]; +static const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; +static char serverIDBuffer[1024]; /* change this to suit your MEM_ALIGNMENT */ #define PAYLOAD_ALIGNMENT 4 @@ -128,26 +144,26 @@ static int file_can_be_compressed(const char* filename); /* 5 bytes per char + 3 bytes per line */ static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; -char curSubdir[MAX_PATH_LEN]; -char lastFileVar[MAX_PATH_LEN]; -char hdr_buf[4096]; +static char curSubdir[MAX_PATH_LEN-3]; +static char lastFileVar[MAX_PATH_LEN]; +static char hdr_buf[4096]; -unsigned char processSubs = 1; -unsigned char includeHttpHeader = 1; -unsigned char useHttp11 = 0; -unsigned char supportSsi = 1; -unsigned char precalcChksum = 0; -unsigned char includeLastModified = 0; +static unsigned char processSubs = 1; +static unsigned char includeHttpHeader = 1; +static unsigned char useHttp11 = 0; +static unsigned char supportSsi = 1; +static unsigned char precalcChksum = 0; +static unsigned char includeLastModified = 0; #if MAKEFS_SUPPORT_DEFLATE -unsigned char deflateNonSsiFiles = 0; -size_t deflatedBytesReduced = 0; -size_t overallDataBytes = 0; +static unsigned char deflateNonSsiFiles = 0; +static size_t deflatedBytesReduced = 0; +static size_t overallDataBytes = 0; #endif -const char *exclude_list = NULL; -const char *ncompress_list = NULL; +static const char *exclude_list = NULL; +static const char *ncompress_list = NULL; -struct file_entry *first_file = NULL; -struct file_entry *last_file = NULL; +static struct file_entry *first_file = NULL; +static struct file_entry *last_file = NULL; static char *ssi_file_buffer; static char **ssi_file_lines; @@ -190,7 +206,7 @@ int main(int argc, char *argv[]) memset(path, 0, sizeof(path)); memset(appPath, 0, sizeof(appPath)); - printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); + printf(NEWLINE " makefsdata v" LWIP_VERSION_STRING " - HTML to C source converter" NEWLINE); printf(" by Jim Pettinato - circa 2003 " NEWLINE); printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); @@ -229,19 +245,20 @@ int main(int argc, char *argv[]) printf("Writing to file \"%s\"\n", targetfile); } else if (!strcmp(argv[i], "-m")) { includeLastModified = 1; - } else if (!strcmp(argv[i], "-defl")) { + } else if (strstr(argv[i], "-defl") == argv[i]) { #if MAKEFS_SUPPORT_DEFLATE - char *colon = strstr(argv[i], ":"); - if (colon) { - if (colon[1] != 0) { - int defl_level = atoi(&colon[1]); - if ((defl_level >= 0) && (defl_level <= 10)) { - deflate_level = defl_level; - } else { - printf("ERROR: deflate level must be [0..10]" NEWLINE); - exit(0); - } + const char *colon = &argv[i][5]; + if (*colon == ':') { + int defl_level = atoi(&colon[1]); + if ((colon[1] != 0) && (defl_level >= 0) && (defl_level <= 10)) { + deflate_level = defl_level; + } else { + printf("ERROR: deflate level must be [0..10]" NEWLINE); + exit(0); } + } else { + /* default to highest compression */ + deflate_level = 10; } deflateNonSsiFiles = 1; printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); @@ -253,7 +270,7 @@ int main(int argc, char *argv[]) printf("Excluding files with extensions %s" NEWLINE, exclude_list); } else if (strstr(argv[i], "-xc:") == argv[i]) { ncompress_list = &argv[i][4]; - printf("Skipping compresion for files with extensions %s" NEWLINE, ncompress_list); + printf("Skipping compression for files with extensions %s" NEWLINE, ncompress_list); } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { print_usage(); exit(0); @@ -272,7 +289,10 @@ int main(int argc, char *argv[]) exit(-1); } - GETCWD(appPath, MAX_PATH_LEN); + if(!GETCWD_SUCCEEDED(GETCWD(appPath, MAX_PATH_LEN))) { + printf("Unable to get current dir." NEWLINE); + exit(-1); + } /* if command line param or subdir named 'fs' not found spout usage verbiage */ if (!CHDIR_SUCCEEDED(CHDIR(path))) { /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ @@ -280,7 +300,10 @@ int main(int argc, char *argv[]) print_usage(); exit(-1); } - CHDIR(appPath); + if(!CHDIR_SUCCEEDED(CHDIR(appPath))) { + printf("Invalid path: \"%s\"." NEWLINE, appPath); + exit(-1); + } printf("HTTP %sheader will %s statically included." NEWLINE, (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), @@ -306,7 +329,10 @@ int main(int argc, char *argv[]) exit(-1); } - CHDIR(path); + if(!CHDIR_SUCCEEDED(CHDIR(path))) { + printf("Invalid path: \"%s\"." NEWLINE, path); + exit(-1); + } fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE NEWLINE NEWLINE); @@ -340,7 +366,11 @@ int main(int argc, char *argv[]) fclose(data_file); fclose(struct_file); - CHDIR(appPath); + if(!CHDIR_SUCCEEDED(CHDIR(appPath))) { + printf("Invalid path: \"%s\"." NEWLINE, appPath); + exit(-1); + } + /* append struct_file to data_file */ printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); concat_files("fsdata.tmp", "fshdr.tmp", targetfile); @@ -469,13 +499,19 @@ int process_sub(FILE *data_file, FILE *struct_file) continue; } if (freelen > 0) { - CHDIR(currName); + if(!CHDIR_SUCCEEDED(CHDIR(currName))) { + printf("Invalid path: \"%s\"." NEWLINE, currName); + exit(-1); + } strncat(curSubdir, "/", freelen); strncat(curSubdir, currName, freelen - 1); curSubdir[sizeof(curSubdir) - 1] = 0; printf("processing subdirectory %s/..." NEWLINE, curSubdir); filesProcessed += process_sub(data_file, struct_file); - CHDIR(".."); + if(!CHDIR_SUCCEEDED(CHDIR(".."))) { + printf("Unable to get back to parent dir of: \"%s\"." NEWLINE, currName); + exit(-1); + } curSubdir[sublen] = 0; } else { printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, currName); @@ -562,11 +598,17 @@ static u8_t *get_file_data(const char *filename, int *file_size, int can_be_comp if (can_be_compressed) { if (fsize < OUT_BUF_SIZE) { u8_t *ret_buf; +#ifndef MAKEFS_SUPPORT_DEFLATE_ZLIB tdefl_status status; +#else /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ + int status; +#endif /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ size_t in_bytes = fsize; size_t out_bytes = OUT_BUF_SIZE; const void *next_in = buf; void *next_out = s_outbuf; + memset(s_outbuf, 0, sizeof(s_outbuf)); +#ifndef MAKEFS_SUPPORT_DEFLATE_ZLIB /* create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). */ mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (!deflate_level) { @@ -577,12 +619,18 @@ static u8_t *get_file_data(const char *filename, int *file_size, int can_be_comp printf("tdefl_init() failed!\n"); exit(-1); } - memset(s_outbuf, 0, sizeof(s_outbuf)); status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); if (status != TDEFL_STATUS_DONE) { printf("deflate failed: %d\n", status); exit(-1); } +#else /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ + status = compress2(next_out, &out_bytes, next_in, in_bytes, deflate_level); + if (status != Z_OK) { + printf("deflate failed: %d\n", status); + exit(-1); + } +#endif /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); if (out_bytes < fsize) { ret_buf = (u8_t *)malloc(out_bytes); @@ -590,16 +638,22 @@ static u8_t *get_file_data(const char *filename, int *file_size, int can_be_comp memcpy(ret_buf, s_outbuf, out_bytes); { /* sanity-check compression be inflating and comparing to the original */ - tinfl_status dec_status; - tinfl_decompressor inflator; size_t dec_in_bytes = out_bytes; size_t dec_out_bytes = OUT_BUF_SIZE; next_out = s_checkbuf; + memset(s_checkbuf, 0, sizeof(s_checkbuf)); +#ifndef MAKEFS_SUPPORT_DEFLATE_ZLIB + tinfl_status dec_status; + tinfl_decompressor inflator; tinfl_init(&inflator); - memset(s_checkbuf, 0, sizeof(s_checkbuf)); dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); +#else /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ + int dec_status; + dec_status = uncompress2 (s_checkbuf, &dec_out_bytes, ret_buf, &dec_in_bytes); + LWIP_ASSERT("tinfl_decompress failed", dec_status == Z_OK); +#endif /* MAKEFS_SUPPORT_DEFLATE_ZLIB */ LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); } @@ -614,7 +668,7 @@ static u8_t *get_file_data(const char *filename, int *file_size, int can_be_comp printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); } } else { - printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); + printf(" - uncompressed: (file is larger than deflate buffer)" NEWLINE); } } else { printf(" - cannot be compressed" NEWLINE); @@ -841,6 +895,10 @@ static int is_ssi_file(const char *filename) /* build up the relative path to this file */ size_t sublen = strlen(curSubdir); size_t freelen = sizeof(curSubdir) - sublen - 1; + if (sublen + strlen(filename) + 1 >= sizeof(curSubdir)) { + /* prevent buffer overflow */ + return 0; + } strncat(curSubdir, "/", freelen); strncat(curSubdir, filename, freelen - 1); curSubdir[sizeof(curSubdir) - 1] = 0; @@ -853,6 +911,7 @@ static int is_ssi_file(const char *filename) } curSubdir[sublen] = 0; return ret; +#if LWIP_HTTPD_SSI_BY_FILE_EXTENSION } else { /* check file extension */ size_t loop; @@ -861,6 +920,7 @@ static int is_ssi_file(const char *filename) return 1; } } +#endif /* LWIP_HTTPD_SSI_BY_FILE_EXTENSION */ } } return 0; @@ -920,9 +980,9 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename) int flags_printed; /* create qualified name (@todo: prepend slash or not?) */ - sprintf(qualifiedName, "%s/%s", curSubdir, filename); + snprintf(qualifiedName, sizeof(qualifiedName), "%s/%s", curSubdir, filename); /* create C variable name */ - strcpy(varname, qualifiedName); + strncpy(varname, qualifiedName, sizeof(varname)); /* convert slashes & dots to underscores */ fix_filename_for_c(varname, MAX_PATH_LEN); register_filename(varname); @@ -1042,17 +1102,17 @@ int file_write_http_header(FILE *data_file, const char *filename, int file_size, } fprintf(data_file, NEWLINE "/* HTTP header */"); - if (strstr(filename, "404") == filename) { + if (strstr(filename, "404.") == filename) { response_type = HTTP_HDR_NOT_FOUND; if (useHttp11) { response_type = HTTP_HDR_NOT_FOUND_11; } - } else if (strstr(filename, "400") == filename) { + } else if (strstr(filename, "400.") == filename) { response_type = HTTP_HDR_BAD_REQUEST; if (useHttp11) { response_type = HTTP_HDR_BAD_REQUEST_11; } - } else if (strstr(filename, "501") == filename) { + } else if (strstr(filename, "501.") == filename) { response_type = HTTP_HDR_NOT_IMPL; if (useHttp11) { response_type = HTTP_HDR_NOT_IMPL_11; diff --git a/src/apps/http/makefsdata/readme.txt b/src/apps/http/makefsdata/readme.txt index 3768585..929179a 100644 --- a/src/apps/http/makefsdata/readme.txt +++ b/src/apps/http/makefsdata/readme.txt @@ -11,3 +11,13 @@ Usage: htmlgen [targetdir] [-s] [-i]s if targetdir not specified, makefsdata will attempt to process files in subdirectory 'fs'. + +The C version of this program can optionally store the none-SSI files in +a compressed form in which they are also sent to the web client (which +must support the Deflate content encoding). Files that grow during compression +(due to being not compressible well), will stored umcompressed automatically. +In order to do so, compile the program with MAKEFS_SUPPORT_DEFLATE set to 1. You must +manually download minizip.c for this to work. As an alternative, you can additionally +define MAKEFS_SUPPORT_DEFLATE_ZLIB to use your system's zlib instead. +Compression of .html, .js, .css and .svg files usually yields very good compression +rates and is a great way of reducing your program's size. diff --git a/src/apps/http/makefsdata/tinydir.h b/src/apps/http/makefsdata/tinydir.h index 32ae5e8..0b536fa 100644 --- a/src/apps/http/makefsdata/tinydir.h +++ b/src/apps/http/makefsdata/tinydir.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2013-2017, tinydir authors: +Copyright (c) 2013-2021, tinydir authors: - Cong Xu - Lautis Sun - Baudouin Feildel @@ -45,7 +45,9 @@ extern "C" { #include #include #ifdef _MSC_VER -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include # include # pragma warning(push) @@ -65,32 +67,44 @@ extern "C" { /* Windows UNICODE wide character support */ #if defined _MSC_VER || defined __MINGW32__ -#define _tinydir_char_t TCHAR -#define TINYDIR_STRING(s) _TEXT(s) -#define _tinydir_strlen _tcslen -#define _tinydir_strcpy _tcscpy -#define _tinydir_strcat _tcscat -#define _tinydir_strcmp _tcscmp -#define _tinydir_strrchr _tcsrchr -#define _tinydir_strncmp _tcsncmp +# define _tinydir_char_t TCHAR +# define TINYDIR_STRING(s) _TEXT(s) +# define _tinydir_strlen _tcslen +# define _tinydir_strcpy _tcscpy +# define _tinydir_strcat _tcscat +# define _tinydir_strcmp _tcscmp +# define _tinydir_strrchr _tcsrchr +# define _tinydir_strncmp _tcsncmp #else -#define _tinydir_char_t char -#define TINYDIR_STRING(s) s -#define _tinydir_strlen strlen -#define _tinydir_strcpy strcpy -#define _tinydir_strcat strcat -#define _tinydir_strcmp strcmp -#define _tinydir_strrchr strrchr -#define _tinydir_strncmp strncmp +# define _tinydir_char_t char +# define TINYDIR_STRING(s) s +# define _tinydir_strlen strlen +# define _tinydir_strcpy strcpy +# define _tinydir_strcat strcat +# define _tinydir_strcmp strcmp +# define _tinydir_strrchr strrchr +# define _tinydir_strncmp strncmp #endif #if (defined _MSC_VER || defined __MINGW32__) -#include -#define _TINYDIR_PATH_MAX MAX_PATH +# include +# define _TINYDIR_PATH_MAX MAX_PATH #elif defined __linux__ -#include -#define _TINYDIR_PATH_MAX PATH_MAX -#else +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include +# if defined(BSD) +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +# endif +#endif + +#ifndef _TINYDIR_PATH_MAX #define _TINYDIR_PATH_MAX 4096 #endif @@ -111,8 +125,13 @@ extern "C" { # define _TINYDIR_FUNC static __inline #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # define _TINYDIR_FUNC static __inline__ -#else +#elif defined(__cplusplus) # define _TINYDIR_FUNC static inline +#elif defined(__GNUC__) +/* Suppress unused function warning */ +# define _TINYDIR_FUNC __attribute__((unused)) static +#else +# define _TINYDIR_FUNC static #endif /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ @@ -357,7 +376,7 @@ int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) } tinydir_close(dir); - if (tinydir_open(dir, path) == -1) + if (n_files == 0 || tinydir_open(dir, path) == -1) { return -1; } @@ -484,6 +503,7 @@ int tinydir_next(tinydir_dir *dir) _TINYDIR_FUNC int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) { + const _tinydir_char_t *filename; if (dir == NULL || file == NULL) { errno = EINVAL; @@ -498,45 +518,40 @@ int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) errno = ENOENT; return -1; } - if (_tinydir_strlen(dir->path) + - _tinydir_strlen( + filename = #ifdef _MSC_VER - dir->_f.cFileName + dir->_f.cFileName; #else - dir->_e->d_name + dir->_e->d_name; #endif - ) + 1 + _TINYDIR_PATH_EXTRA >= + if (_tinydir_strlen(dir->path) + + _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) { /* the path for the file will be too long */ errno = ENAMETOOLONG; return -1; } - if (_tinydir_strlen( -#ifdef _MSC_VER - dir->_f.cFileName -#else - dir->_e->d_name -#endif - ) >= _TINYDIR_FILENAME_MAX) + if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) { errno = ENAMETOOLONG; return -1; } _tinydir_strcpy(file->path, dir->path); - _tinydir_strcat(file->path, TINYDIR_STRING("/")); - _tinydir_strcpy(file->name, -#ifdef _MSC_VER - dir->_f.cFileName -#else - dir->_e->d_name -#endif - ); - _tinydir_strcat(file->path, file->name); + if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0) + _tinydir_strcat(file->path, TINYDIR_STRING("/")); + _tinydir_strcpy(file->name, filename); + _tinydir_strcat(file->path, filename); #ifndef _MSC_VER #ifdef __MINGW32__ if (_tstat( +#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \ + || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ + || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + || ((defined __APPLE__) && (defined __MACH__)) \ + || (defined BSD) + if (lstat( #else if (stat( #endif @@ -628,7 +643,7 @@ int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) int result = 0; int found = 0; _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t file_name_buf[_TINYDIR_PATH_MAX]; _tinydir_char_t *dir_name; _tinydir_char_t *base_name; #if (defined _MSC_VER || defined __MINGW32__) @@ -650,34 +665,34 @@ int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) /* Get the parent path */ #if (defined _MSC_VER || defined __MINGW32__) #if ((defined _MSC_VER) && (_MSC_VER >= 1400)) - _tsplitpath_s( - path, - drive_buf, _TINYDIR_DRIVE_MAX, - dir_name_buf, _TINYDIR_FILENAME_MAX, - file_name_buf, _TINYDIR_FILENAME_MAX, - ext_buf, _TINYDIR_FILENAME_MAX); + errno = _tsplitpath_s( + path, + drive_buf, _TINYDIR_DRIVE_MAX, + dir_name_buf, _TINYDIR_FILENAME_MAX, + file_name_buf, _TINYDIR_FILENAME_MAX, + ext_buf, _TINYDIR_FILENAME_MAX); #else - _tsplitpath( - path, - drive_buf, - dir_name_buf, - file_name_buf, - ext_buf); -#endif - -/* _splitpath_s not work fine with only filename and widechar support */ -#ifdef _UNICODE - if (drive_buf[0] == L'\xFEFE') - drive_buf[0] = '\0'; - if (dir_name_buf[0] == L'\xFEFE') - dir_name_buf[0] = '\0'; + _tsplitpath( + path, + drive_buf, + dir_name_buf, + file_name_buf, + ext_buf); #endif if (errno) { - errno = EINVAL; return -1; } + +/* _splitpath_s not work fine with only filename and widechar support */ +#ifdef _UNICODE + if (drive_buf[0] == L'\xFEFE') + drive_buf[0] = '\0'; + if (dir_name_buf[0] == L'\xFEFE') + dir_name_buf[0] = '\0'; +#endif + /* Emulate the behavior of dirname by returning "." for dir name if it's empty */ if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') @@ -694,8 +709,23 @@ int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) _tinydir_strcpy(dir_name_buf, path); dir_name = dirname(dir_name_buf); _tinydir_strcpy(file_name_buf, path); - base_name =basename(file_name_buf); + base_name = basename(file_name_buf); +#endif + + /* Special case: if the path is a root dir, open the parent dir as the file */ +#if (defined _MSC_VER || defined __MINGW32__) + if (_tinydir_strlen(base_name) == 0) +#else + if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0) #endif + { + memset(file, 0, sizeof * file); + file->is_dir = 1; + file->is_reg = 0; + _tinydir_strcpy(file->path, dir_name); + file->extension = file->path + _tinydir_strlen(file->path); + return 0; + } /* Open the parent directory */ if (tinydir_open(&dir, dir_name) == -1) diff --git a/src/apps/lwiperf/lwiperf.c b/src/apps/lwiperf/lwiperf.c index dbec4da..144c8bd 100644 --- a/src/apps/lwiperf/lwiperf.c +++ b/src/apps/lwiperf/lwiperf.c @@ -7,7 +7,7 @@ * @defgroup iperf Iperf server * @ingroup apps * - * This is a simple performance measuring client/server to check your bandwith using + * This is a simple performance measuring client/server to check your bandwidth using * iPerf2 on a PC as server/client. * It is currently a minimal implementation providing a TCP client/server only. * @@ -53,6 +53,7 @@ #include "lwip/tcp.h" #include "lwip/sys.h" +#include "lwip/inet.h" #include @@ -263,7 +264,7 @@ lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_typ /* don't want to wait for free memory here... */ tcp_abort(conn->conn_pcb); } - } else { + } else if (conn->server_pcb != NULL) { /* no conn pcb, this is the listener pcb */ err = tcp_close(conn->server_pcb); LWIP_ASSERT("error", err == ERR_OK); @@ -301,7 +302,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn) /* this session is byte-limited */ u32_t amount_bytes = lwip_htonl(conn->settings.amount); /* @todo: this can send up to 1*MSS more than requested... */ - if (amount_bytes >= conn->bytes_transferred) { + if (conn->bytes_transferred >= amount_bytes) { /* all requested bytes transferred -> close the connection */ lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); return ERR_OK; @@ -565,6 +566,11 @@ lwiperf_tcp_err(void *arg, err_t err) { lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; LWIP_UNUSED_ARG(err); + + /* pcb is already deallocated, prevent double-free */ + conn->conn_pcb = NULL; + conn->server_pcb = NULL; + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); } @@ -602,7 +608,7 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL); if (s->specific_remote) { LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL); - if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) { + if (!ip_addr_eq(&newpcb->remote_ip, &s->remote_addr)) { /* this listener belongs to a client session, and this is not the correct remote */ return ERR_VAL; } diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index aad2728..84f267a 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -5,20 +5,19 @@ * @defgroup mdns MDNS * @ingroup apps * - * RFC 6762 - Multicast DNS\n - * RFC 6763 - DNS-Based Service Discovery\n + * RFC 6762 - Multicast DNS
    + * RFC 6763 - DNS-Based Service Discovery + * + * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MDNS! * * @verbinclude mdns.txt * * Things left to implement: * ------------------------- * - * - Tiebreaking for simultaneous probing * - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off... - * - Checking that source address of unicast requests are on the same network - * - Limiting multicast responses to 1 per second per resource record + * - Sending negative responses NSEC * - Fragmenting replies if required - * - Handling multi-packet known answers * - Individual known answer detection for all local IPv6 addresses * - Dynamic size of outgoing packet */ @@ -52,20 +51,26 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Erik Ekman + * Author: Jasper Verschueren * */ #include "lwip/apps/mdns.h" #include "lwip/apps/mdns_priv.h" +#include "lwip/apps/mdns_domain.h" +#include "lwip/apps/mdns_out.h" #include "lwip/netif.h" #include "lwip/udp.h" #include "lwip/ip_addr.h" #include "lwip/mem.h" +#include "lwip/memp.h" #include "lwip/prot/dns.h" #include "lwip/prot/iana.h" #include "lwip/timeouts.h" +#include "lwip/sys.h" -#include +#include /* memset */ +#include /* snprintf */ #if LWIP_MDNS_RESPONDER @@ -78,6 +83,9 @@ #if (!LWIP_UDP) #error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif +#ifndef LWIP_RAND +#error "If you want to use MDNS, you have to define LWIP_RAND=(random function) in your lwipopts.h" +#endif #if LWIP_IPV4 #include "lwip/igmp.h" @@ -91,14 +99,11 @@ static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT; static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT; #endif -#define MDNS_TTL 255 +#define MDNS_IP_TTL 255 -/* Stored offsets to beginning of domain names - * Used for compression. - */ -#define NUM_DOMAIN_OFFSETS 10 -#define DOMAIN_JUMP_SIZE 2 -#define DOMAIN_JUMP 0xc000 +#if LWIP_MDNS_SEARCH +static struct mdns_request mdns_requests[MDNS_MAX_REQUESTS]; +#endif static u8_t mdns_netif_client_id; static struct udp_pcb *mdns_pcb; @@ -109,37 +114,18 @@ static mdns_name_result_cb_t mdns_name_result_cb; #define NETIF_TO_HOST(netif) (struct mdns_host*)(netif_get_client_data(netif, mdns_netif_client_id)) -#define TOPDOMAIN_LOCAL "local" - -#define REVERSE_PTR_TOPDOMAIN "arpa" -#define REVERSE_PTR_V4_DOMAIN "in-addr" -#define REVERSE_PTR_V6_DOMAIN "ip6" - -#define SRV_PRIORITY 0 -#define SRV_WEIGHT 0 - -/* Payload size allocated for each outgoing UDP packet */ -#define OUTPACKET_SIZE 500 - -/* Lookup from hostname -> IPv4 */ -#define REPLY_HOST_A 0x01 -/* Lookup from IPv4/v6 -> hostname */ -#define REPLY_HOST_PTR_V4 0x02 -/* Lookup from hostname -> IPv6 */ -#define REPLY_HOST_AAAA 0x04 -/* Lookup from hostname -> IPv6 */ -#define REPLY_HOST_PTR_V6 0x08 - -/* Lookup for service types */ -#define REPLY_SERVICE_TYPE_PTR 0x10 -/* Lookup for instances of service */ -#define REPLY_SERVICE_NAME_PTR 0x20 -/* Lookup for location of service instance */ -#define REPLY_SERVICE_SRV 0x40 -/* Lookup for text info on service instance */ -#define REPLY_SERVICE_TXT 0x80 - -#define MDNS_PROBE_DELAY_MS 250 +/** Delayed response defines */ +#define MDNS_RESPONSE_DELAY_MAX 120 +#define MDNS_RESPONSE_DELAY_MIN 20 +#define MDNS_RESPONSE_DELAY (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \ + MDNS_RESPONSE_DELAY_MIN) + MDNS_RESPONSE_DELAY_MIN) +/* Delayed response for truncated question defines */ +#define MDNS_RESPONSE_TC_DELAY_MAX 500 +#define MDNS_RESPONSE_TC_DELAY_MIN 400 +#define MDNS_RESPONSE_TC_DELAY_MS (LWIP_RAND() % (MDNS_RESPONSE_TC_DELAY_MAX - \ + MDNS_RESPONSE_TC_DELAY_MIN) + MDNS_RESPONSE_TC_DELAY_MIN) + +/** Probing & announcing defines */ #define MDNS_PROBE_COUNT 3 #ifdef LWIP_RAND /* first probe timeout SHOULD be random 0-250 ms*/ @@ -148,48 +134,19 @@ static mdns_name_result_cb_t mdns_name_result_cb; #define MDNS_INITIAL_PROBE_DELAY_MS MDNS_PROBE_DELAY_MS #endif -#define MDNS_PROBING_NOT_STARTED 0 -#define MDNS_PROBING_ONGOING 1 -#define MDNS_PROBING_COMPLETE 2 +#define MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS 1000 +#define MDNS_PROBE_TIEBREAK_MAX_ANSWERS 5 -static const char *dnssd_protos[] = { - "_udp", /* DNSSD_PROTO_UDP */ - "_tcp", /* DNSSD_PROTO_TCP */ -}; - -/** Description of a service */ -struct mdns_service { - /** TXT record to answer with */ - struct mdns_domain txtdata; - /** Name of service, like 'myweb' */ - char name[MDNS_LABEL_MAXLEN + 1]; - /** Type of service, like '_http' */ - char service[MDNS_LABEL_MAXLEN + 1]; - /** Callback function and userdata - * to update txtdata buffer */ - service_get_txt_fn_t txt_fn; - void *txt_userdata; - /** TTL in seconds of SRV/TXT replies */ - u32_t dns_ttl; - /** Protocol, TCP or UDP */ - u16_t proto; - /** Port of the service */ - u16_t port; -}; +#define MDNS_LEXICOGRAPHICAL_EQUAL 0 +#define MDNS_LEXICOGRAPHICAL_EARLIER 1 +#define MDNS_LEXICOGRAPHICAL_LATER 2 -/** Description of a host/netif */ -struct mdns_host { - /** Hostname */ - char name[MDNS_LABEL_MAXLEN + 1]; - /** Pointer to services */ - struct mdns_service *services[MDNS_MAX_SERVICES]; - /** TTL in seconds of A/AAAA/PTR replies */ - u32_t dns_ttl; - /** Number of probes sent for the current name */ - u8_t probes_sent; - /** State in probing sequence */ - u8_t probing_state; -}; +/* Delay between successive announcements (RFC6762 section 8.3) + * -> increase by a factor 2 with every response sent. + */ +#define MDNS_ANNOUNCE_DELAY_MS 1000 +/* Minimum 2 announces, may send up to 8 (RFC6762 section 8.3) */ +#define MDNS_ANNOUNCE_COUNT 2 /** Information about received packet */ struct mdns_packet { @@ -198,8 +155,6 @@ struct mdns_packet { u16_t source_port; /** If packet was received unicast */ u16_t recv_unicast; - /** Netif that received the packet */ - struct netif *netif; /** Packet data */ struct pbuf *pbuf; /** Current parsing offset in packet */ @@ -211,60 +166,29 @@ struct mdns_packet { u16_t questions; /** Number of unparsed questions */ u16_t questions_left; - /** Number of answers in packet, - * (sum of normal, authoritative and additional answers) - * read from packet header */ + /** Number of answers in packet */ u16_t answers; /** Number of unparsed answers */ u16_t answers_left; -}; - -/** Information about outgoing packet */ -struct mdns_outpacket { - /** Netif to send the packet on */ - struct netif *netif; - /** Packet data */ - struct pbuf *pbuf; - /** Current write offset in packet */ - u16_t write_offset; - /** Identifier. Used in legacy queries */ - u16_t tx_id; - /** Destination IP/port if sent unicast */ - ip_addr_t dest_addr; - u16_t dest_port; - /** Number of questions written */ - u16_t questions; - /** Number of normal answers written */ - u16_t answers; - /** Number of authoritative answers written */ + /** Number of authoritative answers in packet */ u16_t authoritative; - /** Number of additional answers written */ + /** Number of unparsed authoritative answers */ + u16_t authoritative_left; + /** Number of additional answers in packet */ u16_t additional; - /** Offsets for written domain names in packet. - * Used for compression */ - u16_t domain_offsets[NUM_DOMAIN_OFFSETS]; - /** If all answers in packet should set cache_flush bit */ - u8_t cache_flush; - /** If reply should be sent unicast */ - u8_t unicast_reply; - /** If legacy query. (tx_id needed, and write - * question again in reply before answer) */ - u8_t legacy_query; - /* Reply bitmask for host information */ - u8_t host_replies; - /* Bitmask for which reverse IPv6 hosts to answer */ - u8_t host_reverse_v6_replies; - /* Reply bitmask per service */ - u8_t serv_replies[MDNS_MAX_SERVICES]; + /** Number of unparsed additional answers */ + u16_t additional_left; + /** Chained list of known answer received after a truncated question */ + struct mdns_packet *next_answer; + /** Chained list of truncated question that are waiting */ + struct mdns_packet *next_tc_question; }; -/** Domain, type and class. - * Shared between questions and answers */ -struct mdns_rr_info { - struct mdns_domain domain; - u16_t type; - u16_t klass; -}; +/* list of received questions with TC flags set, waiting for known answers */ +static struct mdns_packet *pending_tc_questions; + +/* pool of received packets */ +LWIP_MEMPOOL_DECLARE(MDNS_PKTS, MDNS_MAX_STORED_PKTS, sizeof (struct mdns_packet), "Stored mDNS packets") struct mdns_question { struct mdns_rr_info info; @@ -272,389 +196,42 @@ struct mdns_question { u16_t unicast; }; -struct mdns_answer { - struct mdns_rr_info info; - /** cache flush command bit */ - u16_t cache_flush; - /* Validity time in seconds */ - u32_t ttl; - /** Length of variable answer */ - u16_t rd_length; - /** Offset of start of variable answer in packet */ - u16_t rd_offset; +struct mdns_answer_list { + u16_t offset[MDNS_PROBE_TIEBREAK_MAX_ANSWERS]; + u16_t size; }; -static err_t mdns_send_outpacket(struct mdns_outpacket *outpkt, u8_t flags); -static void mdns_probe(void* arg); - -static err_t -mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len) -{ - if (len > MDNS_LABEL_MAXLEN) { - return ERR_VAL; - } - if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) { - return ERR_VAL; - } - /* Allow only zero marker on last byte */ - if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) { - return ERR_VAL; - } - domain->name[domain->length] = len; - domain->length++; - return ERR_OK; -} - -/** - * Add a label part to a domain - * @param domain The domain to add a label to - * @param label The label to add, like <hostname>, 'local', 'com' or '' - * @param len The length of the label - * @return ERR_OK on success, an err_t otherwise if label too long - */ -err_t -mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len) -{ - err_t err = mdns_domain_add_label_base(domain, len); - if (err != ERR_OK) { - return err; - } - if (len) { - MEMCPY(&domain->name[domain->length], label, len); - domain->length += len; - } - return ERR_OK; -} - -/** - * Add a label part to a domain (@see mdns_domain_add_label but copy directly from pbuf) - */ -static err_t -mdns_domain_add_label_pbuf(struct mdns_domain *domain, const struct pbuf *p, u16_t offset, u8_t len) -{ - err_t err = mdns_domain_add_label_base(domain, len); - if (err != ERR_OK) { - return err; - } - if (len) { - if (pbuf_copy_partial(p, &domain->name[domain->length], len, offset) != len) { - /* take back the ++ done before */ - domain->length--; - return ERR_ARG; - } - domain->length += len; - } - return ERR_OK; -} - -/** - * Internal readname function with max 6 levels of recursion following jumps - * while decompressing name - */ -static u16_t -mdns_readname_loop(struct pbuf *p, u16_t offset, struct mdns_domain *domain, unsigned depth) -{ - u8_t c; - - do { - if (depth > 5) { - /* Too many jumps */ - return MDNS_READNAME_ERROR; - } - - c = pbuf_get_at(p, offset); - offset++; - - /* is this a compressed label? */ - if ((c & 0xc0) == 0xc0) { - u16_t jumpaddr; - if (offset >= p->tot_len) { - /* Make sure both jump bytes fit in the packet */ - return MDNS_READNAME_ERROR; - } - jumpaddr = (((c & 0x3f) << 8) | (pbuf_get_at(p, offset) & 0xff)); - offset++; - if (jumpaddr >= SIZEOF_DNS_HDR && jumpaddr < p->tot_len) { - u16_t res; - /* Recursive call, maximum depth will be checked */ - res = mdns_readname_loop(p, jumpaddr, domain, depth + 1); - /* Dont return offset since new bytes were not read (jumped to somewhere in packet) */ - if (res == MDNS_READNAME_ERROR) { - return res; - } - } else { - return MDNS_READNAME_ERROR; - } - break; - } - - /* normal label */ - if (c <= MDNS_LABEL_MAXLEN) { - err_t res; - - if (c + domain->length >= MDNS_DOMAIN_MAXLEN) { - return MDNS_READNAME_ERROR; - } - res = mdns_domain_add_label_pbuf(domain, p, offset, c); - if (res != ERR_OK) { - return MDNS_READNAME_ERROR; - } - offset += c; - } else { - /* bad length byte */ - return MDNS_READNAME_ERROR; - } - } while (c != 0); - - return offset; -} - -/** - * Read possibly compressed domain name from packet buffer - * @param p The packet - * @param offset start position of domain name in packet - * @param domain The domain name destination - * @return The new offset after the domain, or MDNS_READNAME_ERROR - * if reading failed - */ -u16_t -mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain) -{ - memset(domain, 0, sizeof(struct mdns_domain)); - return mdns_readname_loop(p, offset, domain, 0); -} - -/** - * Print domain name to debug output - * @param domain The domain name - */ -static void -mdns_domain_debug_print(struct mdns_domain *domain) -{ - u8_t *src = domain->name; - u8_t i; - - while (*src) { - u8_t label_len = *src; - src++; - for (i = 0; i < label_len; i++) { - LWIP_DEBUGF(MDNS_DEBUG, ("%c", src[i])); - } - src += label_len; - LWIP_DEBUGF(MDNS_DEBUG, (".")); - } -} - -/** - * Return 1 if contents of domains match (case-insensitive) - * @param a Domain name to compare 1 - * @param b Domain name to compare 2 - * @return 1 if domains are equal ignoring case, 0 otherwise - */ -int -mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b) -{ - u8_t *ptra, *ptrb; - u8_t len; - int res; - - if (a->length != b->length) { - return 0; - } - - ptra = a->name; - ptrb = b->name; - while (*ptra && *ptrb && ptra < &a->name[a->length]) { - if (*ptra != *ptrb) { - return 0; - } - len = *ptra; - ptra++; - ptrb++; - res = lwip_strnicmp((char *) ptra, (char *) ptrb, len); - if (res != 0) { - return 0; - } - ptra += len; - ptrb += len; - } - if (*ptra != *ptrb && ptra < &a->name[a->length]) { - return 0; - } - return 1; -} - -/** - * Call user supplied function to setup TXT data - * @param service The service to build TXT record for - */ -static void -mdns_prepare_txtdata(struct mdns_service *service) -{ - memset(&service->txtdata, 0, sizeof(struct mdns_domain)); - if (service->txt_fn) { - service->txt_fn(service, service->txt_userdata); - } -} - -#if LWIP_IPV4 -/** - * Build domain for reverse lookup of IPv4 address - * like 12.0.168.192.in-addr.arpa. for 192.168.0.12 - * @param domain Where to write the domain name - * @param addr Pointer to an IPv4 address to encode - * @return ERR_OK if domain was written, an err_t otherwise - */ -static err_t -mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t *addr) -{ - int i; - err_t res; - const u8_t *ptr; - - LWIP_UNUSED_ARG(res); - if (!domain || !addr) { - return ERR_ARG; - } - memset(domain, 0, sizeof(struct mdns_domain)); - ptr = (const u8_t *) addr; - for (i = sizeof(ip4_addr_t) - 1; i >= 0; i--) { - char buf[4]; - u8_t val = ptr[i]; - - lwip_itoa(buf, sizeof(buf), val); - res = mdns_domain_add_label(domain, buf, (u8_t)strlen(buf)); - LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); - } - res = mdns_domain_add_label(domain, REVERSE_PTR_V4_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V4_DOMAIN) - 1)); - LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1)); - LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, NULL, 0); - LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); - - return ERR_OK; -} -#endif - -#if LWIP_IPV6 -/** - * Build domain for reverse lookup of IP address - * like b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. for 2001:db8::567:89ab - * @param domain Where to write the domain name - * @param addr Pointer to an IPv6 address to encode - * @return ERR_OK if domain was written, an err_t otherwise - */ -static err_t -mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr) -{ - int i; - err_t res; - const u8_t *ptr; - LWIP_UNUSED_ARG(res); - if (!domain || !addr) { - return ERR_ARG; - } - memset(domain, 0, sizeof(struct mdns_domain)); - ptr = (const u8_t *) addr; - for (i = sizeof(ip6_addr_p_t) - 1; i >= 0; i--) { - char buf; - u8_t byte = ptr[i]; - int j; - for (j = 0; j < 2; j++) { - if ((byte & 0x0F) < 0xA) { - buf = '0' + (byte & 0x0F); - } else { - buf = 'a' + (byte & 0x0F) - 0xA; - } - res = mdns_domain_add_label(domain, &buf, sizeof(buf)); - LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); - byte >>= 4; - } - } - res = mdns_domain_add_label(domain, REVERSE_PTR_V6_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V6_DOMAIN) - 1)); - LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1)); - LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, NULL, 0); - LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); - - return ERR_OK; -} -#endif - -/* Add .local. to domain */ -static err_t -mdns_add_dotlocal(struct mdns_domain *domain) -{ - err_t res = mdns_domain_add_label(domain, TOPDOMAIN_LOCAL, (u8_t)(sizeof(TOPDOMAIN_LOCAL) - 1)); - LWIP_UNUSED_ARG(res); - LWIP_ERROR("mdns_add_dotlocal: Failed to add label", (res == ERR_OK), return res); - return mdns_domain_add_label(domain, NULL, 0); -} - -/** - * Build the .local. domain name - * @param domain Where to write the domain name - * @param mdns TMDNS netif descriptor. - * @return ERR_OK if domain .local. was written, an err_t otherwise - */ -static err_t -mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns) -{ - err_t res; - LWIP_UNUSED_ARG(res); - memset(domain, 0, sizeof(struct mdns_domain)); - LWIP_ERROR("mdns_build_host_domain: mdns != NULL", (mdns != NULL), return ERR_VAL); - res = mdns_domain_add_label(domain, mdns->name, (u8_t)strlen(mdns->name)); - LWIP_ERROR("mdns_build_host_domain: Failed to add label", (res == ERR_OK), return res); - return mdns_add_dotlocal(domain); -} +static err_t mdns_parse_pkt_questions(struct netif *netif, + struct mdns_packet *pkt, + struct mdns_outmsg *reply); +static void mdns_define_probe_rrs_to_send(struct netif *netif, + struct mdns_outmsg *outmsg); +static void mdns_probe_and_announce(void* arg); +static void mdns_conflict_save_time(struct netif *netif); /** - * Build the lookup-all-services special DNS-SD domain name - * @param domain Where to write the domain name - * @return ERR_OK if domain _services._dns-sd._udp.local. was written, an err_t otherwise + * Construction to make mdns struct accessible from mdns_out.c + * TODO: + * can we add the mdns struct to the netif like we do for dhcp, autoip,...? + * Then this is not needed any more. + * + * @param netif The network interface + * @return mdns struct */ -static err_t -mdns_build_dnssd_domain(struct mdns_domain *domain) -{ - err_t res; - LWIP_UNUSED_ARG(res); - memset(domain, 0, sizeof(struct mdns_domain)); - res = mdns_domain_add_label(domain, "_services", (u8_t)(sizeof("_services") - 1)); - LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, "_dns-sd", (u8_t)(sizeof("_dns-sd") - 1)); - LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)strlen(dnssd_protos[DNSSD_PROTO_UDP])); - LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); - return mdns_add_dotlocal(domain); +struct mdns_host* +netif_mdns_data(struct netif *netif) { + return NETIF_TO_HOST(netif); } /** - * Build domain name for a service - * @param domain Where to write the domain name - * @param service The service struct, containing service name, type and protocol - * @param include_name Whether to include the service name in the domain - * @return ERR_OK if domain was written. If service name is included, - * ...local. will be written, otherwise ..local. - * An err_t is returned on error. + * Construction to access the mdns udp pcb. + * + * @return udp_pcb struct of mdns */ -static err_t -mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name) +struct udp_pcb* +get_mdns_pcb(void) { - err_t res; - LWIP_UNUSED_ARG(res); - memset(domain, 0, sizeof(struct mdns_domain)); - if (include_name) { - res = mdns_domain_add_label(domain, service->name, (u8_t)strlen(service->name)); - LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); - } - res = mdns_domain_add_label(domain, service->service, (u8_t)strlen(service->service)); - LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); - res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)strlen(dnssd_protos[service->proto])); - LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); - return mdns_add_dotlocal(domain); + return mdns_pcb; } /** @@ -772,319 +349,93 @@ check_service(struct mdns_service *service, struct mdns_rr_info *rr) return replies; } +#if LWIP_MDNS_SEARCH /** - * Return bytes needed to write before jump for best result of compressing supplied domain - * against domain in outpacket starting at specified offset. - * If a match is found, offset is updated to where to jump to - * @param pbuf Pointer to pbuf with the partially constructed DNS packet - * @param offset Start position of a domain written earlier. If this location is suitable - * for compression, the pointer is updated to where in the domain to jump to. - * @param domain The domain to write - * @return Number of bytes to write of the new domain before writing a jump to the offset. - * If compression can not be done against this previous domain name, the full new - * domain length is returned. - */ -u16_t -mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain) -{ - struct mdns_domain target; - u16_t target_end; - u8_t target_len; - u8_t writelen = 0; - u8_t *ptr; - if (pbuf == NULL) { - return domain->length; - } - target_end = mdns_readname(pbuf, *offset, &target); - if (target_end == MDNS_READNAME_ERROR) { - return domain->length; - } - target_len = (u8_t)(target_end - *offset); - ptr = domain->name; - while (writelen < domain->length) { - u8_t domainlen = (u8_t)(domain->length - writelen); - u8_t labellen; - if (domainlen <= target.length && domainlen > DOMAIN_JUMP_SIZE) { - /* Compare domains if target is long enough, and we have enough left of the domain */ - u8_t targetpos = (u8_t)(target.length - domainlen); - if ((targetpos + DOMAIN_JUMP_SIZE) >= target_len) { - /* We are checking at or beyond a jump in the original, stop looking */ - break; - } - if (target.length >= domainlen && - memcmp(&domain->name[writelen], &target.name[targetpos], domainlen) == 0) { - *offset += targetpos; - return writelen; - } - } - /* Skip to next label in domain */ - labellen = *ptr; - writelen += 1 + labellen; - ptr += 1 + labellen; - } - /* Nothing found */ - return domain->length; -} - -/** - * Write domain to outpacket. Compression will be attempted, - * unless domain->skip_compression is set. - * @param outpkt The outpacket to write to - * @param domain The domain name to write - * @return ERR_OK on success, an err_t otherwise + * Check if question belong to a specified request + * @param request A ongoing MDNS request + * @param rr Domain/type/class from an answer + * @return Bitmask of which matching replies */ -static err_t -mdns_write_domain(struct mdns_outpacket *outpkt, struct mdns_domain *domain) +static int +check_request(struct mdns_request *request, struct mdns_rr_info *rr) { - int i; err_t res; - u16_t writelen = domain->length; - u16_t jump_offset = 0; - u16_t jump; - - if (!domain->skip_compression) { - for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) { - u16_t offset = outpkt->domain_offsets[i]; - if (offset) { - u16_t len = mdns_compress_domain(outpkt->pbuf, &offset, domain); - if (len < writelen) { - writelen = len; - jump_offset = offset; - } - } - } - } - - if (writelen) { - /* Write uncompressed part of name */ - res = pbuf_take_at(outpkt->pbuf, domain->name, writelen, outpkt->write_offset); - if (res != ERR_OK) { - return res; - } + int replies = 0; + struct mdns_domain mydomain; - /* Store offset of this new domain */ - for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) { - if (outpkt->domain_offsets[i] == 0) { - outpkt->domain_offsets[i] = outpkt->write_offset; - break; - } - } + if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) { + /* Invalid class */ + return 0; + } - outpkt->write_offset += writelen; + res = mdns_build_request_domain(&mydomain, request, 0); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) && + (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) { + /* Request for the instance of my service */ + replies |= REPLY_SERVICE_TYPE_PTR; } - if (jump_offset) { - /* Write jump */ - jump = lwip_htons(DOMAIN_JUMP | jump_offset); - res = pbuf_take_at(outpkt->pbuf, &jump, DOMAIN_JUMP_SIZE, outpkt->write_offset); - if (res != ERR_OK) { - return res; + res = mdns_build_request_domain(&mydomain, request, 1); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) { + /* Request for info about my service */ + if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) { + replies |= REPLY_SERVICE_SRV; + } + if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) { + replies |= REPLY_SERVICE_TXT; } - outpkt->write_offset += DOMAIN_JUMP_SIZE; } - return ERR_OK; + return replies; } +#endif /** - * Write a question to an outpacket - * A question contains domain, type and class. Since an answer also starts with these fields this function is also - * called from mdns_add_answer(). - * @param outpkt The outpacket to write to - * @param domain The domain name the answer is for - * @param type The DNS type of the answer (like 'AAAA', 'SRV') - * @param klass The DNS type of the answer (like 'IN') - * @param unicast If highest bit in class should be set, to instruct the responder to - * reply with a unicast packet + * Helper function for mdns_read_question/mdns_read_answer + * Reads a domain, type and class from the packet + * @param pkt The MDNS packet to read from. The parse_offset field will be + * incremented to point to the next unparsed byte. + * @param info The struct to fill with domain, type and class * @return ERR_OK on success, an err_t otherwise */ static err_t -mdns_add_question(struct mdns_outpacket *outpkt, struct mdns_domain *domain, u16_t type, u16_t klass, u16_t unicast) +mdns_read_rr_info(struct mdns_packet *pkt, struct mdns_rr_info *info) { - u16_t question_len; - u16_t field16; - err_t res; - - if (!outpkt->pbuf) { - /* If no pbuf is active, allocate one */ - outpkt->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM); - if (!outpkt->pbuf) { - return ERR_MEM; - } - outpkt->write_offset = SIZEOF_DNS_HDR; - } - - /* Worst case calculation. Domain string might be compressed */ - question_len = domain->length + sizeof(type) + sizeof(klass); - if (outpkt->write_offset + question_len > outpkt->pbuf->tot_len) { - /* No space */ - return ERR_MEM; - } - - /* Write name */ - res = mdns_write_domain(outpkt, domain); - if (res != ERR_OK) { - return res; + u16_t field16, copied; + pkt->parse_offset = mdns_readname(pkt->pbuf, pkt->parse_offset, &info->domain); + if (pkt->parse_offset == MDNS_READNAME_ERROR) { + return ERR_VAL; } - /* Write type */ - field16 = lwip_htons(type); - res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); - if (res != ERR_OK) { - return res; + copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); + if (copied != sizeof(field16)) { + return ERR_VAL; } - outpkt->write_offset += sizeof(field16); + pkt->parse_offset += copied; + info->type = lwip_ntohs(field16); - /* Write class */ - if (unicast) { - klass |= 0x8000; - } - field16 = lwip_htons(klass); - res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); - if (res != ERR_OK) { - return res; + copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); + if (copied != sizeof(field16)) { + return ERR_VAL; } - outpkt->write_offset += sizeof(field16); + pkt->parse_offset += copied; + info->klass = lwip_ntohs(field16); return ERR_OK; } /** - * Write answer to reply packet. - * buf or answer_domain can be null. The rd_length written will be buf_length + - * size of (compressed) domain. Most uses will need either buf or answer_domain, - * special case is SRV that starts with 3 u16 and then a domain name. - * @param reply The outpacket to write to - * @param domain The domain name the answer is for - * @param type The DNS type of the answer (like 'AAAA', 'SRV') - * @param klass The DNS type of the answer (like 'IN') - * @param cache_flush If highest bit in class should be set, to instruct receiver that - * this reply replaces any earlier answer for this domain/type/class - * @param ttl Validity time in seconds to send out for IP address data in DNS replies - * @param buf Pointer to buffer of answer data - * @param buf_length Length of variable data - * @param answer_domain A domain to write after any buffer data as answer + * Read a question from the packet. + * All questions have to be read before the answers. + * @param pkt The MDNS packet to read from. The questions_left field will be decremented + * and the parse_offset will be updated. + * @param question The struct to fill with question data * @return ERR_OK on success, an err_t otherwise */ static err_t -mdns_add_answer(struct mdns_outpacket *reply, struct mdns_domain *domain, u16_t type, u16_t klass, u16_t cache_flush, - u32_t ttl, const u8_t *buf, size_t buf_length, struct mdns_domain *answer_domain) +mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question) { - u16_t answer_len; - u16_t field16; - u16_t rdlen_offset; - u16_t answer_offset; - u32_t field32; - err_t res; - - if (!reply->pbuf) { - /* If no pbuf is active, allocate one */ - reply->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM); - if (!reply->pbuf) { - return ERR_MEM; - } - reply->write_offset = SIZEOF_DNS_HDR; - } - - /* Worst case calculation. Domain strings might be compressed */ - answer_len = domain->length + sizeof(type) + sizeof(klass) + sizeof(ttl) + sizeof(field16)/*rd_length*/; - if (buf) { - answer_len += (u16_t)buf_length; - } - if (answer_domain) { - answer_len += answer_domain->length; - } - if (reply->write_offset + answer_len > reply->pbuf->tot_len) { - /* No space */ - return ERR_MEM; - } - - /* Answer starts with same data as question, then more fields */ - mdns_add_question(reply, domain, type, klass, cache_flush); - - /* Write TTL */ - field32 = lwip_htonl(ttl); - res = pbuf_take_at(reply->pbuf, &field32, sizeof(field32), reply->write_offset); - if (res != ERR_OK) { - return res; - } - reply->write_offset += sizeof(field32); - - /* Store offsets and skip forward to the data */ - rdlen_offset = reply->write_offset; - reply->write_offset += sizeof(field16); - answer_offset = reply->write_offset; - - if (buf) { - /* Write static data */ - res = pbuf_take_at(reply->pbuf, buf, (u16_t)buf_length, reply->write_offset); - if (res != ERR_OK) { - return res; - } - reply->write_offset += (u16_t)buf_length; - } - - if (answer_domain) { - /* Write name answer (compressed if possible) */ - res = mdns_write_domain(reply, answer_domain); - if (res != ERR_OK) { - return res; - } - } - - /* Write rd_length after when we know the answer size */ - field16 = lwip_htons(reply->write_offset - answer_offset); - res = pbuf_take_at(reply->pbuf, &field16, sizeof(field16), rdlen_offset); - - return res; -} - -/** - * Helper function for mdns_read_question/mdns_read_answer - * Reads a domain, type and class from the packet - * @param pkt The MDNS packet to read from. The parse_offset field will be - * incremented to point to the next unparsed byte. - * @param info The struct to fill with domain, type and class - * @return ERR_OK on success, an err_t otherwise - */ -static err_t -mdns_read_rr_info(struct mdns_packet *pkt, struct mdns_rr_info *info) -{ - u16_t field16, copied; - pkt->parse_offset = mdns_readname(pkt->pbuf, pkt->parse_offset, &info->domain); - if (pkt->parse_offset == MDNS_READNAME_ERROR) { - return ERR_VAL; - } - - copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); - if (copied != sizeof(field16)) { - return ERR_VAL; - } - pkt->parse_offset += copied; - info->type = lwip_ntohs(field16); - - copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); - if (copied != sizeof(field16)) { - return ERR_VAL; - } - pkt->parse_offset += copied; - info->klass = lwip_ntohs(field16); - - return ERR_OK; -} - -/** - * Read a question from the packet. - * All questions have to be read before the answers. - * @param pkt The MDNS packet to read from. The questions_left field will be decremented - * and the parse_offset will be updated. - * @param question The struct to fill with question data - * @return ERR_OK on success, an err_t otherwise - */ -static err_t -mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question) -{ - /* Safety check */ - if (pkt->pbuf->tot_len < pkt->parse_offset) { - return ERR_VAL; + /* Safety check */ + if (pkt->pbuf->tot_len < pkt->parse_offset) { + return ERR_VAL; } if (pkt->questions_left) { @@ -1109,13 +460,14 @@ mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question) /** * Read an answer from the packet * The variable length reply is not copied, its pbuf offset and length is stored instead. - * @param pkt The MDNS packet to read. The answers_left field will be decremented and + * @param pkt The MDNS packet to read. The num_left field will be decremented and * the parse_offset will be updated. - * @param answer The struct to fill with answer data + * @param answer The struct to fill with answer data + * @param num_left number of answers left -> answers, authoritative or additional * @return ERR_OK on success, an err_t otherwise */ static err_t -mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer) +mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer, u16_t *num_left) { /* Read questions first */ if (pkt->questions_left) { @@ -1127,11 +479,11 @@ mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer) return ERR_VAL; } - if (pkt->answers_left) { + if (*num_left) { u16_t copied, field16; u32_t ttl; err_t res; - pkt->answers_left--; + (*num_left)--; memset(answer, 0, sizeof(struct mdns_answer)); res = mdns_read_rr_info(pkt, &answer->info); @@ -1165,416 +517,568 @@ mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer) return ERR_VAL; } -#if LWIP_IPV4 -/** Write an IPv4 address (A) RR to outpacket */ -static err_t -mdns_add_a_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif) +/** + * Send unsolicited answer containing all our known data + * @param netif The network interface to send on + * @param destination The target address to send to (usually multicast address) + */ +static void +mdns_announce(struct netif *netif, const ip_addr_t *destination) { - struct mdns_domain host; - mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with A record\n")); - return mdns_add_answer(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, (const u8_t *) netif_ip4_addr(netif), sizeof(ip4_addr_t), NULL); -} + struct mdns_outmsg announce; + int i; + struct mdns_host *mdns = NETIF_TO_HOST(netif); -/** Write a 4.3.2.1.in-addr.arpa -> hostname.local PTR RR to outpacket */ -static err_t -mdns_add_hostv4_ptr_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif) -{ - struct mdns_domain host, revhost; - mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); - mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(netif)); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v4 PTR record\n")); - return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, NULL, 0, &host); -} + memset(&announce, 0, sizeof(announce)); + announce.cache_flush = 1; +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { + announce.host_replies = REPLY_HOST_A | REPLY_HOST_PTR_V4; + } #endif - #if LWIP_IPV6 -/** Write an IPv6 address (AAAA) RR to outpacket */ -static err_t -mdns_add_aaaa_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif, int addrindex) -{ - struct mdns_domain host; - mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with AAAA record\n")); - return mdns_add_answer(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, (const u8_t *) netif_ip6_addr(netif, addrindex), sizeof(ip6_addr_p_t), NULL); -} + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { + announce.host_replies |= REPLY_HOST_AAAA | REPLY_HOST_PTR_V6; + announce.host_reverse_v6_replies |= (1 << i); + } + } +#endif -/** Write a x.y.z.ip6.arpa -> hostname.local PTR RR to outpacket */ -static err_t -mdns_add_hostv6_ptr_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif, int addrindex) -{ - struct mdns_domain host, revhost; - mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); - mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(netif, addrindex)); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v6 PTR record\n")); - return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, NULL, 0, &host); + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + struct mdns_service *serv = mdns->services[i]; + if (serv) { + announce.serv_replies[i] = REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR | + REPLY_SERVICE_SRV | REPLY_SERVICE_TXT; + } + } + + announce.dest_port = LWIP_IANA_PORT_MDNS; + SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr)); + announce.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; + mdns_send_outpacket(&announce, netif); } -#endif -/** Write an all-services -> servicetype PTR RR to outpacket */ +/** + * Perform lexicographical comparison to define the lexicographical order of the + * records. + * + * @param pkt_a first packet (needed for rr data) + * @param pkt_b second packet (needed for rr data) + * @param ans_a first rr + * @param ans_b second rr + * @param result pointer to save result in -> MDNS_LEXICOGRAPHICAL_EQUAL, + * MDNS_LEXICOGRAPHICAL_LATER or MDNS_LEXICOGRAPHICAL_EARLIER. + * @return err_t ERR_OK if result is good, ERR_VAL if domain decompression failed. + */ static err_t -mdns_add_servicetype_ptr_answer(struct mdns_outpacket *reply, struct mdns_service *service) +mdns_lexicographical_comparison(struct mdns_packet *pkt_a, struct mdns_packet *pkt_b, + struct mdns_answer *ans_a, struct mdns_answer *ans_b, + u8_t *result) { - struct mdns_domain service_type, service_dnssd; - mdns_build_service_domain(&service_type, service, 0); - mdns_build_dnssd_domain(&service_dnssd); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service type PTR record\n")); - return mdns_add_answer(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0, service->dns_ttl, NULL, 0, &service_type); + int len, i; + u8_t a_rd, b_rd; + u16_t res; + struct mdns_domain domain_a, domain_b; + + /* Compare classes */ + if (ans_a->info.klass != ans_b->info.klass) { + if (ans_a->info.klass > ans_b->info.klass) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + /* Compare types */ + if (ans_a->info.type != ans_b->info.type) { + if (ans_a->info.type > ans_b->info.type) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + + /* Compare rr data section + * Name compression: + * We have 4 different RR types in our authoritative section (if IPv4 and IPv6 is enabled): A, + * AAAA, SRV and TXT. Only one of the 4 can be subject to name compression in the rdata, the SRV + * record. As stated in the RFC6762 section 8.2: the names must be uncompressed before comparison. + * We only need to take the SRV record into account. It's the only one that in a comparison with + * compressed data could lead to rdata comparison. Others will already stop after the type + * comparison. So if we get passed the class and type comparison we need to check if the + * comparison contains an SRV record. If so, we need a different comparison method. + */ + + /* The answers do not contain an SRV record */ + if (ans_a->info.type != DNS_RRTYPE_SRV && ans_b->info.type != DNS_RRTYPE_SRV) { + len = LWIP_MIN(ans_a->rd_length, ans_b->rd_length); + for (i = 0; i < len; i++) { + a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i)); + b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i)); + if (a_rd != b_rd) { + if (a_rd > b_rd) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + } + /* If the overlapping data is the same, compare the length */ + if (ans_a->rd_length != ans_b->rd_length) { + if (ans_a->rd_length > ans_b->rd_length) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + } + /* Because the types are guaranteed equal here, we know they are both SRV RRs */ + else { + /* We will first compare the priority, weight and port */ + for (i = 0; i < 6; i++) { + a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i)); + b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i)); + if (a_rd != b_rd) { + if (a_rd > b_rd) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + } + /* Decompress names if compressed and save in domain_a or domain_b */ + res = mdns_readname(pkt_a->pbuf, ans_a->rd_offset + 6, &domain_a); + if (res == MDNS_READNAME_ERROR) { + return ERR_VAL; + } + res = mdns_readname(pkt_b->pbuf, ans_b->rd_offset + 6, &domain_b); + if (res == MDNS_READNAME_ERROR) { + return ERR_VAL; + } + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain a: len = %d, name = ", domain_a.name[0])); + mdns_domain_debug_print(&domain_a); + LWIP_DEBUGF(MDNS_DEBUG, ("\n")); + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain b: len = %d, name = ", domain_b.name[0])); + mdns_domain_debug_print(&domain_b); + LWIP_DEBUGF(MDNS_DEBUG, ("\n")); + /* Compare names pairwise */ + len = LWIP_MIN(domain_a.length, domain_b.length); + for (i = 0; i < len; i++) { + if (domain_a.name[i] != domain_b.name[i]) { + if (domain_a.name[i] > domain_b.name[i]) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + } + /* If the overlapping data is the same, compare the length */ + if (domain_a.length != domain_b.length) { + if (domain_a.length > domain_b.length) { + *result = MDNS_LEXICOGRAPHICAL_LATER; + return ERR_OK; + } + else { + *result = MDNS_LEXICOGRAPHICAL_EARLIER; + return ERR_OK; + } + } + } + /* They are exactly the same */ + *result = MDNS_LEXICOGRAPHICAL_EQUAL; + return ERR_OK; } -/** Write a servicetype -> servicename PTR RR to outpacket */ -static err_t -mdns_add_servicename_ptr_answer(struct mdns_outpacket *reply, struct mdns_service *service) +/** + * Clear authoritative answer list + * + * @param a_list answer list to clear + */ +static void +mdns_init_answer_list(struct mdns_answer_list *a_list) { - struct mdns_domain service_type, service_instance; - mdns_build_service_domain(&service_type, service, 0); - mdns_build_service_domain(&service_instance, service, 1); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service name PTR record\n")); - return mdns_add_answer(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0, service->dns_ttl, NULL, 0, &service_instance); + int i; + a_list->size = 0; + for(i = 0; i < MDNS_PROBE_TIEBREAK_MAX_ANSWERS; i++) { + a_list->offset[i] = 0; + } } -/** Write a SRV RR to outpacket */ +/** + * Pushes the offset of the answer on a lexicographically later sorted list. + * We use a simple insertion sort because most of the time we are only sorting + * two items. The answers are sorted from the smallest to the largest. + * + * @param a_list Answer list to which to add the answer + * @param pkt Packet where answer originated + * @param new_offset Offset of the new answer in the packet + * @param new_answer The new answer + * @return err_t ERR_MEM if list is full + */ static err_t -mdns_add_srv_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct mdns_host *mdns, struct mdns_service *service) +mdns_push_answer_to_sorted_list(struct mdns_answer_list *a_list, + struct mdns_packet *pkt, + u16_t new_offset, + struct mdns_answer *new_answer) { - struct mdns_domain service_instance, srvhost; - u16_t srvdata[3]; - mdns_build_service_domain(&service_instance, service, 1); - mdns_build_host_domain(&srvhost, mdns); - if (reply->legacy_query) { - /* RFC 6762 section 18.14: - * In legacy unicast responses generated to answer legacy queries, - * name compression MUST NOT be performed on SRV records. - */ - srvhost.skip_compression = 1; - } - srvdata[0] = lwip_htons(SRV_PRIORITY); - srvdata[1] = lwip_htons(SRV_WEIGHT); - srvdata[2] = lwip_htons(service->port); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with SRV record\n")); - return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, cache_flush, service->dns_ttl, - (const u8_t *) &srvdata, sizeof(srvdata), &srvhost); + int i; + struct mdns_answer a; + int pos = a_list->size; + err_t res = ERR_OK; + u8_t result; + u16_t num_left = pkt->authoritative; + u16_t parse_offset = pkt->parse_offset; + + /* Check size */ + if ((a_list->size + 1) >= MDNS_PROBE_TIEBREAK_MAX_ANSWERS) { + return ERR_MEM; + } + /* Search location and open a location */ + for (i = 0; i < a_list->size; i++) { + /* Read answers already in the list from pkt */ + pkt->parse_offset = a_list->offset[i]; + res = mdns_read_answer(pkt, &a, &num_left); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n")); + return res; + } + /* Compare them with the new answer to find it's place */ + res = mdns_lexicographical_comparison(pkt, pkt, &a, new_answer, &result); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n")); + return res; + } + if (result == MDNS_LEXICOGRAPHICAL_LATER) { + int j; + pos = i; + for (j = (a_list->size + 1); j>i; j--) { + a_list->offset[j] = a_list->offset[j-1]; + } + break; + } + } + /* Insert new value */ + a_list->offset[pos] = new_offset; + a_list->size++; + /* Reset parse offset for further evaluation */ + pkt->parse_offset = parse_offset; + return res; } -/** Write a TXT RR to outpacket */ -static err_t -mdns_add_txt_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct mdns_service *service) +/** + * Check if the given answer answers the give question + * + * @param q query to find answer for + * @param a answer to given query + * @return 1 it a answers q, 0 if not + */ +static u8_t +mdns_is_answer_to_question(struct mdns_question *q, struct mdns_answer *a) { - struct mdns_domain service_instance; - mdns_build_service_domain(&service_instance, service, 1); - mdns_prepare_txtdata(service); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with TXT record\n")); - return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, cache_flush, service->dns_ttl, - (u8_t *) &service->txtdata.name, service->txtdata.length, NULL); + if (q->info.type == DNS_RRTYPE_ANY || q->info.type == a->info.type) { + /* The types match or question type is any */ + if (mdns_domain_eq(&q->info.domain, &a->info.domain)) { + return 1; + } + } + return 0; } /** - * Setup outpacket as a reply to the incoming packet + * Converts the output packet to the input packet format for probe tiebreaking + * + * @param inpkt destination packet for conversion + * @param outpkt source packet for conversion */ static void -mdns_init_outpacket(struct mdns_outpacket *out, struct mdns_packet *in) +mdns_convert_out_to_in_pkt(struct mdns_packet *inpkt, struct mdns_outpacket *outpkt) { - memset(out, 0, sizeof(struct mdns_outpacket)); - out->cache_flush = 1; - out->netif = in->netif; + inpkt->pbuf = outpkt->pbuf; + inpkt->parse_offset = SIZEOF_DNS_HDR; - /* Copy source IP/port to use when responding unicast, or to choose - * which pcb to use for multicast (IPv4/IPv6) - */ - SMEMCPY(&out->dest_addr, &in->source_addr, sizeof(ip_addr_t)); - out->dest_port = in->source_port; + inpkt->questions = inpkt->questions_left = outpkt->questions; + inpkt->answers = inpkt->answers_left = outpkt->answers; + inpkt->authoritative = inpkt->authoritative_left = outpkt->authoritative; + inpkt->additional = inpkt->additional_left = outpkt->additional; +} - if (in->source_port != LWIP_IANA_PORT_MDNS) { - out->unicast_reply = 1; - out->cache_flush = 0; - if (in->questions == 1) { - out->legacy_query = 1; - out->tx_id = in->tx_id; - } - } +/** + * Debug print to print the answer part that is lexicographically compared + * + * @param pkt Packet where answer originated + * @param a The answer to print + */ +static void +mdns_debug_print_answer(struct mdns_packet *pkt, struct mdns_answer *a) +{ +#ifdef LWIP_DEBUG + /* Arbitrarily chose 200 -> don't want to see more then that. It's only + * for debug so not that important. */ + char string[200]; + int i; + int pos; - if (in->recv_unicast) { - out->unicast_reply = 1; + pos = snprintf(string, sizeof(string), "Type = %2d, class = %1d, rdata = ", a->info.type, a->info.klass); + for (i = 0; ((i < a->rd_length) && ((pos + 4*i) < 195)) ; i++) { + snprintf(&string[pos + 4*i], 5, "%3d ", (u8_t)pbuf_get_at(pkt->pbuf, (u16_t)(a->rd_offset + i))); } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: %s\n", string)); +#else + LWIP_UNUSED_ARG(pkt); + LWIP_UNUSED_ARG(a); +#endif } /** - * Send chosen answers as a reply + * Perform probe tiebreaking according to RFC6762 section 8.2 * - * Add all selected answers (first write will allocate pbuf) - * Add additional answers based on the selected answers - * Send the packet + * @param netif network interface of incoming packet + * @param pkt incoming packet */ -static err_t -mdns_send_outpacket(struct mdns_outpacket *outpkt, u8_t flags) +static void +mdns_handle_probe_tiebreaking(struct netif *netif, struct mdns_packet *pkt) { - struct mdns_service *service; - err_t res = ERR_ARG; - int i; - struct mdns_host *mdns = NETIF_TO_HOST(outpkt->netif); - u16_t answers = 0; + struct mdns_question pkt_q, my_q, q_dummy; + struct mdns_answer pkt_a, my_a; + struct mdns_outmsg myprobe_msg; + struct mdns_outpacket myprobe_outpkt; + struct mdns_packet myprobe_inpkt; + struct mdns_answer_list pkt_a_list, my_a_list; + u16_t save_parse_offset; + u16_t pkt_parse_offset, myprobe_parse_offset, myprobe_questions_left; + err_t res; + u8_t match, result; + int min, i; - /* Write answers to host questions */ -#if LWIP_IPV4 - if (outpkt->host_replies & REPLY_HOST_A) { - res = mdns_add_a_answer(outpkt, outpkt->cache_flush, outpkt->netif); - if (res != ERR_OK) { - goto cleanup; - } - answers++; + /* Generate probe packet to perform comparison. + * This is a lot of calculation at this stage without any pre calculation + * needed. It should be evaluated if this is the best approach. + */ + mdns_define_probe_rrs_to_send(netif, &myprobe_msg); + memset(&myprobe_outpkt, 0, sizeof(myprobe_outpkt)); + memset(&myprobe_inpkt, 0, sizeof(myprobe_inpkt)); + res = mdns_create_outpacket(netif, &myprobe_msg, &myprobe_outpkt); + if (res != ERR_OK) { + goto cleanup; } - if (outpkt->host_replies & REPLY_HOST_PTR_V4) { - res = mdns_add_hostv4_ptr_answer(outpkt, outpkt->cache_flush, outpkt->netif); + mdns_convert_out_to_in_pkt(&myprobe_inpkt, &myprobe_outpkt); + + /* Loop over all our probes to search for matches */ + while (myprobe_inpkt.questions_left) { + /* Read one of our probe questions to check if pkt contains same question */ + res = mdns_read_question(&myprobe_inpkt, &my_q); if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n")); goto cleanup; } - answers++; - } -#endif -#if LWIP_IPV6 - if (outpkt->host_replies & REPLY_HOST_AAAA) { - int addrindex; - for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(outpkt->netif, addrindex))) { - res = mdns_add_aaaa_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); + /* Remember parse offsets so we can restart the search for the next question */ + pkt_parse_offset = pkt->parse_offset; + myprobe_parse_offset = myprobe_inpkt.parse_offset; + /* Remember questions left of our probe packet */ + myprobe_questions_left = myprobe_inpkt.questions_left; + /* Reset match flag */ + match = 0; + /* Search for a matching probe in the incoming packet */ + while (pkt->questions_left) { + /* Read probe questions one by one */ + res = mdns_read_question(pkt, &pkt_q); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n")); + goto cleanup; + } + /* Stop evaluating if the class is not supported */ + if (pkt_q.info.klass != DNS_RRCLASS_IN && pkt_q.info.klass != DNS_RRCLASS_ANY) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: question class not supported, skipping probe packet\n")); + goto cleanup; + } + /* We probe for type any, so we do not have to compare types */ + /* Compare if we are probing for the same domain */ + if (mdns_domain_eq(&pkt_q.info.domain, &my_q.info.domain)) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: We are probing for the same rr\n")); + match = 1; + break; + } + } + /* When matched start evaluating the authoritative section */ + if (match) { + /* Ignore all following questions to be able to get to the authoritative answers */ + while (pkt->questions_left) { + res = mdns_read_question(pkt, &q_dummy); if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n")); goto cleanup; } - answers++; } - } - } - if (outpkt->host_replies & REPLY_HOST_PTR_V6) { - u8_t rev_addrs = outpkt->host_reverse_v6_replies; - int addrindex = 0; - while (rev_addrs) { - if (rev_addrs & 1) { - res = mdns_add_hostv6_ptr_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); + while (myprobe_inpkt.questions_left) { + res = mdns_read_question(&myprobe_inpkt, &q_dummy); if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n")); goto cleanup; } - answers++; } - addrindex++; - rev_addrs >>= 1; - } - } -#endif - /* Write answers to service questions */ - for (i = 0; i < MDNS_MAX_SERVICES; i++) { - service = mdns->services[i]; - if (!service) { - continue; - } - - if (outpkt->serv_replies[i] & REPLY_SERVICE_TYPE_PTR) { - res = mdns_add_servicetype_ptr_answer(outpkt, service); - if (res != ERR_OK) { - goto cleanup; - } - answers++; - } - - if (outpkt->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { - res = mdns_add_servicename_ptr_answer(outpkt, service); - if (res != ERR_OK) { - goto cleanup; - } - answers++; - } - - if (outpkt->serv_replies[i] & REPLY_SERVICE_SRV) { - res = mdns_add_srv_answer(outpkt, outpkt->cache_flush, mdns, service); - if (res != ERR_OK) { - goto cleanup; + /* Extract and sort our authoritative answers that answer our question */ + mdns_init_answer_list(&my_a_list); + while(myprobe_inpkt.authoritative_left) { + save_parse_offset = myprobe_inpkt.parse_offset; + res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n")); + goto cleanup; + } + if (mdns_is_answer_to_question(&my_q, &my_a)) { + /* Add to list */ + res = mdns_push_answer_to_sorted_list(&my_a_list, &myprobe_inpkt, save_parse_offset, &my_a); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n")); + goto cleanup; + } + } } - answers++; - } - - if (outpkt->serv_replies[i] & REPLY_SERVICE_TXT) { - res = mdns_add_txt_answer(outpkt, outpkt->cache_flush, service); - if (res != ERR_OK) { - goto cleanup; + /* Extract and sort the packets authoritative answers that answer the + question */ + mdns_init_answer_list(&pkt_a_list); + while(pkt->authoritative_left) { + save_parse_offset = pkt->parse_offset; + res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n")); + goto cleanup; + } + if (mdns_is_answer_to_question(&my_q, &pkt_a)) { + /* Add to list */ + res = mdns_push_answer_to_sorted_list(&pkt_a_list, pkt, save_parse_offset, &pkt_a); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n")); + goto cleanup; + } + } } - answers++; - } - } - /* if this is a response, the data above is anwers, else this is a probe and the answers above goes into auth section */ - if (flags & DNS_FLAG1_RESPONSE) { - outpkt->answers += answers; - } else { - outpkt->authoritative += answers; - } - - /* All answers written, add additional RRs */ - for (i = 0; i < MDNS_MAX_SERVICES; i++) { - service = mdns->services[i]; - if (!service) { - continue; - } + /* Reinitiate authoritative left */ + myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative; + pkt->authoritative_left = pkt->authoritative; - if (outpkt->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { - /* Our service instance requested, include SRV & TXT - * if they are already not requested. */ - if (!(outpkt->serv_replies[i] & REPLY_SERVICE_SRV)) { - res = mdns_add_srv_answer(outpkt, outpkt->cache_flush, mdns, service); + /* Compare pairwise. + * - lexicographically later? -> we win, ignore the packet. + * - lexicographically earlier? -> we loose, wait one second and retry. + * - lexicographically equal? -> no conflict, check other probes. + */ + min = LWIP_MIN(my_a_list.size, pkt_a_list.size); + for (i = 0; i < min; i++) { + /* Get answer of our own list */ + myprobe_inpkt.parse_offset = my_a_list.offset[i]; + res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left); if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n")); goto cleanup; } - outpkt->additional++; - } - - if (!(outpkt->serv_replies[i] & REPLY_SERVICE_TXT)) { - res = mdns_add_txt_answer(outpkt, outpkt->cache_flush, service); + /* Get answer of the packets list */ + pkt->parse_offset = pkt_a_list.offset[i]; + res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n")); + goto cleanup; + } + /* Print both answers for debugging */ + mdns_debug_print_answer(pkt, &pkt_a); + mdns_debug_print_answer(&myprobe_inpkt, &my_a); + /* Define the winner */ + res = mdns_lexicographical_comparison(&myprobe_inpkt, pkt, &my_a, &pkt_a, &result); if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n")); + goto cleanup; + } + if (result == MDNS_LEXICOGRAPHICAL_LATER) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we are lexicographically later\n")); + goto cleanup; + } + else if (result == MDNS_LEXICOGRAPHICAL_EARLIER) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we are lexicographically earlier. 1s timeout started\n")); + /* Increase the number of conflicts occurred */ + mdns_conflict_save_time(netif); + /* then restart with 1s delay */ + mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS); goto cleanup; } - outpkt->additional++; - } - } - - /* If service instance, SRV, record or an IP address is requested, - * supply all addresses for the host - */ - if ((outpkt->serv_replies[i] & (REPLY_SERVICE_NAME_PTR | REPLY_SERVICE_SRV)) || - (outpkt->host_replies & (REPLY_HOST_A | REPLY_HOST_AAAA))) { -#if LWIP_IPV6 - if (!(outpkt->host_replies & REPLY_HOST_AAAA)) { - int addrindex; - for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(outpkt->netif, addrindex))) { - res = mdns_add_aaaa_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); - if (res != ERR_OK) { - goto cleanup; - } - outpkt->additional++; - } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: lexicographically equal, so no conclusion\n")); } } -#endif -#if LWIP_IPV4 - if (!(outpkt->host_replies & REPLY_HOST_A) && - !ip4_addr_isany_val(*netif_ip4_addr(outpkt->netif))) { - res = mdns_add_a_answer(outpkt, outpkt->cache_flush, outpkt->netif); - if (res != ERR_OK) { + /* All compared RR were equal, otherwise we would not be here + * -> check if one of both have more answers to the question */ + if (my_a_list.size != pkt_a_list.size) { + if (my_a_list.size > pkt_a_list.size) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we have more records answering the probe\n")); + goto cleanup; + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we have less records. 1s timeout started\n")); + /* Increase the number of conflicts occurred */ + mdns_conflict_save_time(netif); + /* then restart with 1s delay */ + mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS); goto cleanup; } - outpkt->additional++; } -#endif - } - } - - if (outpkt->pbuf) { - const ip_addr_t *mcast_destaddr; - struct dns_hdr hdr; - - /* Write header */ - memset(&hdr, 0, sizeof(hdr)); - hdr.flags1 = flags; - hdr.numquestions = lwip_htons(outpkt->questions); - hdr.numanswers = lwip_htons(outpkt->answers); - hdr.numauthrr = lwip_htons(outpkt->authoritative); - hdr.numextrarr = lwip_htons(outpkt->additional); - hdr.id = lwip_htons(outpkt->tx_id); - pbuf_take(outpkt->pbuf, &hdr, sizeof(hdr)); - - /* Shrink packet */ - pbuf_realloc(outpkt->pbuf, outpkt->write_offset); - - if (IP_IS_V6_VAL(outpkt->dest_addr)) { -#if LWIP_IPV6 - mcast_destaddr = &v6group; -#endif - } else { -#if LWIP_IPV4 - mcast_destaddr = &v4group; -#endif - } - /* Send created packet */ - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Sending packet, len=%d, unicast=%d\n", outpkt->write_offset, outpkt->unicast_reply)); - if (outpkt->unicast_reply) { - res = udp_sendto_if(mdns_pcb, outpkt->pbuf, &outpkt->dest_addr, outpkt->dest_port, outpkt->netif); - } else { - res = udp_sendto_if(mdns_pcb, outpkt->pbuf, mcast_destaddr, LWIP_IANA_PORT_MDNS, outpkt->netif); + else { + /* There is no conflict on this probe, both devices have the same data + * in the authoritative section. We should still check the other probes + * for conflicts. */ + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: no conflict, all records answering the probe are equal\n")); + } } + /* Evaluate other probes if any. */ + /* Reinitiate parse offsets */ + pkt->parse_offset = pkt_parse_offset; + myprobe_inpkt.parse_offset = myprobe_parse_offset; + /* Reinitiate questions_left and authoritative_left */ + pkt->questions_left = pkt->questions; + pkt->authoritative_left = pkt->authoritative; + myprobe_inpkt.questions_left = myprobe_questions_left; + myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative; } cleanup: - if (outpkt->pbuf) { - pbuf_free(outpkt->pbuf); - outpkt->pbuf = NULL; + if (myprobe_inpkt.pbuf != NULL) { + pbuf_free(myprobe_inpkt.pbuf); } - return res; } /** - * Send unsolicited answer containing all our known data - * @param netif The network interface to send on - * @param destination The target address to send to (usually multicast address) + * Check the incoming packet and parse all questions + * + * @param netif network interface of incoming packet + * @param pkt incoming packet + * @param reply outgoing message + * @return err_t */ -static void -mdns_announce(struct netif *netif, const ip_addr_t *destination) +static err_t +mdns_parse_pkt_questions(struct netif *netif, struct mdns_packet *pkt, + struct mdns_outmsg *reply) { - struct mdns_outpacket announce; - int i; struct mdns_host *mdns = NETIF_TO_HOST(netif); - - memset(&announce, 0, sizeof(announce)); - announce.netif = netif; - announce.cache_flush = 1; -#if LWIP_IPV4 - if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { - announce.host_replies = REPLY_HOST_A | REPLY_HOST_PTR_V4; - } -#endif -#if LWIP_IPV6 - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { - announce.host_replies |= REPLY_HOST_AAAA | REPLY_HOST_PTR_V6; - announce.host_reverse_v6_replies |= (1 << i); - } - } -#endif - - for (i = 0; i < MDNS_MAX_SERVICES; i++) { - struct mdns_service *serv = mdns->services[i]; - if (serv) { - announce.serv_replies[i] = REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR | - REPLY_SERVICE_SRV | REPLY_SERVICE_TXT; - } - } - - announce.dest_port = LWIP_IANA_PORT_MDNS; - SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr)); - mdns_send_outpacket(&announce, DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE); -} - -/** - * Handle question MDNS packet - * 1. Parse all questions and set bits what answers to send - * 2. Clear pending answers if known answers are supplied - * 3. Put chosen answers in new packet and send as reply - */ -static void -mdns_handle_question(struct mdns_packet *pkt) -{ struct mdns_service *service; - struct mdns_outpacket reply; - int replies = 0; int i; err_t res; - struct mdns_host *mdns = NETIF_TO_HOST(pkt->netif); - - if (mdns->probing_state != MDNS_PROBING_COMPLETE) { - /* Don't answer questions until we've verified our domains via probing */ - /* @todo we should check incoming questions during probing for tiebreaking */ - return; - } - - mdns_init_outpacket(&reply, pkt); while (pkt->questions_left) { struct mdns_question q; @@ -1582,7 +1086,7 @@ mdns_handle_question(struct mdns_packet *pkt) res = mdns_read_question(pkt, &q); if (res != ERR_OK) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping query packet\n")); - return; + return res; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Query for domain ")); @@ -1590,42 +1094,51 @@ mdns_handle_question(struct mdns_packet *pkt) LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", q.info.type, q.info.klass)); if (q.unicast) { - /* Reply unicast if any question is unicast */ - reply.unicast_reply = 1; + /* Reply unicast if it is requested in the question */ + reply->unicast_reply_requested = 1; } - reply.host_replies |= check_host(pkt->netif, &q.info, &reply.host_reverse_v6_replies); - replies |= reply.host_replies; + reply->host_replies |= check_host(netif, &q.info, &reply->host_reverse_v6_replies); for (i = 0; i < MDNS_MAX_SERVICES; i++) { service = mdns->services[i]; if (!service) { continue; } - reply.serv_replies[i] |= check_service(service, &q.info); - replies |= reply.serv_replies[i]; - } - - if (replies && reply.legacy_query) { - /* Add question to reply packet (legacy packet only has 1 question) */ - res = mdns_add_question(&reply, &q.info.domain, q.info.type, q.info.klass, 0); - reply.questions = 1; - if (res != ERR_OK) { - goto cleanup; - } + reply->serv_replies[i] |= check_service(service, &q.info); } } - /* Handle known answers */ + return ERR_OK; +} + +/** + * Check the incoming packet and parse all (known) answers + * + * @param netif network interface of incoming packet + * @param pkt incoming packet + * @param reply outgoing message + * @return err_t + */ +static err_t +mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt, + struct mdns_outmsg *reply) +{ + struct mdns_host *mdns = NETIF_TO_HOST(netif); + struct mdns_service *service; + int i; + err_t res; + while (pkt->answers_left) { struct mdns_answer ans; u8_t rev_v6; int match; + u32_t rr_ttl = MDNS_TTL_120; - res = mdns_read_answer(pkt, &ans); + res = mdns_read_answer(pkt, &ans, &pkt->answers_left); if (res != ERR_OK) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n")); - goto cleanup; + return res; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Known answer for domain ")); @@ -1639,8 +1152,8 @@ mdns_handle_question(struct mdns_packet *pkt) } rev_v6 = 0; - match = reply.host_replies & check_host(pkt->netif, &ans.info, &rev_v6); - if (match && (ans.ttl > (mdns->dns_ttl / 2))) { + match = reply->host_replies & check_host(netif, &ans.info, &rev_v6); + if (match && (ans.ttl > (rr_ttl / 2))) { /* The RR in the known answer matches an RR we are planning to send, * and the TTL is less than half gone. * If the payload matches we should not send that answer. @@ -1655,15 +1168,15 @@ mdns_handle_question(struct mdns_packet *pkt) #if LWIP_IPV4 if (match & REPLY_HOST_PTR_V4) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v4 PTR\n")); - reply.host_replies &= ~REPLY_HOST_PTR_V4; + reply->host_replies &= ~REPLY_HOST_PTR_V4; } #endif #if LWIP_IPV6 if (match & REPLY_HOST_PTR_V6) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v6 PTR\n")); - reply.host_reverse_v6_replies &= ~rev_v6; - if (reply.host_reverse_v6_replies == 0) { - reply.host_replies &= ~REPLY_HOST_PTR_V6; + reply->host_reverse_v6_replies &= ~rev_v6; + if (reply->host_reverse_v6_replies == 0) { + reply->host_replies &= ~REPLY_HOST_PTR_V6; } } #endif @@ -1671,18 +1184,18 @@ mdns_handle_question(struct mdns_packet *pkt) } else if (match & REPLY_HOST_A) { #if LWIP_IPV4 if (ans.rd_length == sizeof(ip4_addr_t) && - pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(pkt->netif), ans.rd_length) == 0) { + pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: A\n")); - reply.host_replies &= ~REPLY_HOST_A; + reply->host_replies &= ~REPLY_HOST_A; } #endif } else if (match & REPLY_HOST_AAAA) { #if LWIP_IPV6 if (ans.rd_length == sizeof(ip6_addr_p_t) && /* TODO this clears all AAAA responses if first addr is set as known */ - pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(pkt->netif, 0), ans.rd_length) == 0) { + pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, 0), ans.rd_length) == 0) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: AAAA\n")); - reply.host_replies &= ~REPLY_HOST_AAAA; + reply->host_replies &= ~REPLY_HOST_AAAA; } #endif } @@ -1693,8 +1206,11 @@ mdns_handle_question(struct mdns_packet *pkt) if (!service) { continue; } - match = reply.serv_replies[i] & check_service(service, &ans.info); - if (match && (ans.ttl > (service->dns_ttl / 2))) { + match = reply->serv_replies[i] & check_service(service, &ans.info); + if (match & REPLY_SERVICE_TYPE_PTR) { + rr_ttl = MDNS_TTL_4500; + } + if (match && (ans.ttl > (rr_ttl / 2))) { /* The RR in the known answer matches an RR we are planning to send, * and the TTL is less than half gone. * If the payload matches we should not send that answer. @@ -1709,14 +1225,14 @@ mdns_handle_question(struct mdns_packet *pkt) res = mdns_build_service_domain(&my_ans, service, 0); if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service type PTR\n")); - reply.serv_replies[i] &= ~REPLY_SERVICE_TYPE_PTR; + reply->serv_replies[i] &= ~REPLY_SERVICE_TYPE_PTR; } } if (match & REPLY_SERVICE_NAME_PTR) { res = mdns_build_service_domain(&my_ans, service, 1); if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service name PTR\n")); - reply.serv_replies[i] &= ~REPLY_SERVICE_NAME_PTR; + reply->serv_replies[i] &= ~REPLY_SERVICE_NAME_PTR; } } } @@ -1751,56 +1267,595 @@ mdns_handle_question(struct mdns_packet *pkt) break; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: SRV\n")); - reply.serv_replies[i] &= ~REPLY_SERVICE_SRV; + reply->serv_replies[i] &= ~REPLY_SERVICE_SRV; } while (0); } else if (match & REPLY_SERVICE_TXT) { mdns_prepare_txtdata(service); if (service->txtdata.length == ans.rd_length && pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: TXT\n")); - reply.serv_replies[i] &= ~REPLY_SERVICE_TXT; + reply->serv_replies[i] &= ~REPLY_SERVICE_TXT; } } } } } - mdns_send_outpacket(&reply, DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE); + return ERR_OK; +} + +/** + * Check the incoming packet and parse all authoritative answers to see if the + * query is a probe query. + * + * @param netif network interface of incoming packet + * @param pkt incoming packet + * @param reply outgoing message + * @return err_t + */ +static err_t +mdns_parse_pkt_authoritative_answers(struct netif *netif, struct mdns_packet *pkt, + struct mdns_outmsg *reply) +{ + struct mdns_host *mdns = NETIF_TO_HOST(netif); + struct mdns_service *service; + int i; + err_t res; + + while (pkt->authoritative_left) { + struct mdns_answer ans; + u8_t rev_v6; + int match; + + res = mdns_read_answer(pkt, &ans, &pkt->authoritative_left); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n")); + return res; + } + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Authoritative answer for domain ")); + mdns_domain_debug_print(&ans.info.domain); + LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass)); + + + if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) { + /* Skip known answers for ANY type & class */ + continue; + } + + rev_v6 = 0; + match = reply->host_replies & check_host(netif, &ans.info, &rev_v6); + if (match) { + reply->probe_query_recv = 1; + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own host info received\n")); + } + + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + service = mdns->services[i]; + if (!service) { + continue; + } + match = reply->serv_replies[i] & check_service(service, &ans.info); + + if (match) { + reply->probe_query_recv = 1; + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own service info received\n")); + } + } + } + + return ERR_OK; +} + +/** + * Add / copy message to delaying message buffer. + * + * @param dest destination msg struct + * @param src source msg struct + */ +static void +mdns_add_msg_to_delayed(struct mdns_outmsg *dest, struct mdns_outmsg *src) +{ + int i; + + dest->host_questions |= src->host_questions; + dest->host_replies |= src->host_replies; + dest->host_reverse_v6_replies |= src->host_reverse_v6_replies; + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + dest->serv_questions[i] |= src->serv_questions[i]; + dest->serv_replies[i] |= src->serv_replies[i]; + } + + dest->flags = src->flags; + dest->cache_flush = src->cache_flush; + dest->tx_id = src->tx_id; + dest->legacy_query = src->legacy_query; +} + +/** + * Handle question MDNS packet + * - Perform probe tiebreaking when in probing state + * - Parse all questions and set bits what answers to send + * - Clear pending answers if known answers are supplied + * - Define which type of answer is requested + * - Send out packet or put it on hold until after random time + * + * @param pkt incoming packet (in stack) + * @param netif network interface of incoming packet + */ +static void +mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) +{ + struct mdns_host *mdns = NETIF_TO_HOST(netif); + struct mdns_outmsg reply; + u8_t rrs_to_send; + u8_t shared_answer = 0; + u8_t delay_response = 1; + u8_t send_unicast = 0; + u8_t listen_to_QU_bit = 0; + int i; + err_t res; + + if ((mdns->state == MDNS_STATE_PROBING) || + (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) { + /* Probe Tiebreaking */ + /* Check if packet is a probe message */ + if ((pkt->questions > 0) && (pkt->answers == 0) && + (pkt->authoritative > 0) && (pkt->additional == 0)) { + /* This should be a probe message -> call probe handler */ + mdns_handle_probe_tiebreaking(netif, pkt); + } + } + + if ((mdns->state != MDNS_STATE_COMPLETE) && + (mdns->state != MDNS_STATE_ANNOUNCING)) { + /* Don't answer questions until we've verified our domains via probing */ + /* @todo we should check incoming questions during probing for tiebreaking */ + return; + } + + memset(&reply, 0, sizeof(struct mdns_outmsg)); + + /* Parse question */ + res = mdns_parse_pkt_questions(netif, pkt, &reply); + if (res != ERR_OK) { + return; + } + /* Parse answers -> count as known answers because it's a question */ + res = mdns_parse_pkt_known_answers(netif, pkt, &reply); + if (res != ERR_OK) { + return; + } + if (pkt->next_answer) { + /* Also parse known-answers from additional packets */ + struct mdns_packet *pkta = pkt->next_answer; + while (pkta) { + res = mdns_parse_pkt_known_answers(netif, pkta, &reply); + if (res != ERR_OK) { + return; + } + pkta = pkta->next_answer; + } + } + /* Parse authoritative answers -> probing */ + /* If it's a probe query, we need to directly answer via unicast. */ + res = mdns_parse_pkt_authoritative_answers(netif, pkt, &reply); + if (res != ERR_OK) { + return; + } + /* Ignore additional answers -> do not have any need for them at the moment */ + if(pkt->additional) { + LWIP_DEBUGF(MDNS_DEBUG, + ("MDNS: Query contains additional answers -> they are discarded\n")); + } + + /* Any replies on question? */ + rrs_to_send = reply.host_replies | reply.host_questions; + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + rrs_to_send |= reply.serv_replies[i] | reply.serv_questions[i]; + } + + if (!rrs_to_send) { + /* This case is most common */ + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Nothing to answer\n")); + return; + } + + reply.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; + + /* Detect if it's a legacy querier asking the question + * How to detect legacy DNS query? (RFC6762 section 6.7) + * - source port != 5353 + * - a legacy query can only contain 1 question + */ + if (pkt->source_port != LWIP_IANA_PORT_MDNS) { + if (pkt->questions == 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: request from legacy querier\n")); + reply.legacy_query = 1; + reply.tx_id = pkt->tx_id; + reply.cache_flush = 0; + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: ignore query if (src UDP port != 5353) && (!= legacy query)\n")); + return; + } + } + else { + reply.cache_flush = 1; + } + + /* Delaying response. (RFC6762 section 6) + * Always delay the response, unicast or multicast, except when: + * - Answering to a single question with a unique answer (not a probe). + * - Answering to a probe query via unicast. + * - Answering to a probe query via multicast if not multicasted within 250ms. + * + * unique answer? -> not if it includes service type or name ptr's + */ + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + shared_answer |= (reply.serv_replies[i] & + (REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR)); + } + if ( ((pkt->questions == 1) && (!shared_answer) && !reply.probe_query_recv) + || (reply.probe_query_recv && reply.unicast_reply_requested)) { + delay_response = 0; + } +#if LWIP_IPV6 + if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv + && !reply.unicast_reply_requested && !mdns->ipv6.multicast_probe_timeout) { + delay_response = 0; + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv + && !reply.unicast_reply_requested && !mdns->ipv4.multicast_probe_timeout) { + delay_response = 0; + } +#endif + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: response %s delayed\n", (delay_response ? "randomly" : "not"))); + + /* Unicast / multicast response: + * Answering to (m)DNS querier via unicast response. + * When: + * a) Unicast reply requested && recently multicasted 1/4ttl (RFC6762 section 5.4) + * b) Direct unicast query to port 5353 (RFC6762 section 5.5) + * c) Reply to Legacy DNS querier (RFC6762 section 6.7) + * d) A probe message is received requesting unicast (RFC6762 section 6) + */ + +#if LWIP_IPV6 + if ((IP_IS_V6_VAL(pkt->source_addr) && mdns->ipv6.multicast_timeout_25TTL)) { + listen_to_QU_bit = 1; + } +#endif +#if LWIP_IPV4 + if ((IP_IS_V4_VAL(pkt->source_addr) && mdns->ipv4.multicast_timeout_25TTL)) { + listen_to_QU_bit = 1; + } +#endif + if ( (reply.unicast_reply_requested && listen_to_QU_bit) + || pkt->recv_unicast + || reply.legacy_query + || (reply.probe_query_recv && reply.unicast_reply_requested)) { + send_unicast = 1; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: send response via %s\n", (send_unicast ? "unicast" : "multicast"))); + + /* Send out or put on waiting list */ + if (delay_response) { + if (send_unicast) { +#if LWIP_IPV6 + /* Add answers to IPv6 waiting list if: + * - it's a IPv6 incoming packet + * - no message is in it yet + */ + if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.unicast_msg_in_use) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv6 waiting list\n")); + SMEMCPY(&mdns->ipv6.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t)); + mdns->ipv6.delayed_msg_unicast.dest_port = pkt->source_port; + + mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_unicast, &reply); + + mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv6, + &mdns->ipv6.unicast_msg_in_use); + } +#endif +#if LWIP_IPV4 + /* Add answers to IPv4 waiting list if: + * - it's a IPv4 incoming packet + * - no message is in it yet + */ + if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.unicast_msg_in_use) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv4 waiting list\n")); + SMEMCPY(&mdns->ipv4.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t)); + mdns->ipv4.delayed_msg_unicast.dest_port = pkt->source_port; + + mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_unicast, &reply); + + mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv4, + &mdns->ipv4.unicast_msg_in_use); + } +#endif + } + else { +#if LWIP_IPV6 + /* Add answers to IPv6 waiting list if: + * - it's a IPv6 incoming packet + * - the 1 second timeout is passed (RFC6762 section 6) + * - and it's not a probe packet + * Or if: + * - it's a IPv6 incoming packet + * - and it's a probe packet + */ + if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout + && !reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv6 waiting list\n")); + + mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply); + + mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv6, + &mdns->ipv6.multicast_msg_waiting); + } + else if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv6 waiting list\n")); + + mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply); + + mdns->ipv6.multicast_msg_waiting = 1; + } +#endif +#if LWIP_IPV4 + /* Add answers to IPv4 waiting list if: + * - it's a IPv4 incoming packet + * - the 1 second timeout is passed (RFC6762 section 6) + * - and it's not a probe packet + * Or if: + * - it's a IPv4 incoming packet + * - and it's a probe packet + */ + if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout + && !reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv4 waiting list\n")); + + mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply); + + mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv4, + &mdns->ipv4.multicast_msg_waiting); + } + else if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv4 waiting list\n")); + + mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply); + + mdns->ipv4.multicast_msg_waiting = 1; + } +#endif + } + } + else { + if (send_unicast) { + /* Copy source IP/port to use when responding unicast */ + SMEMCPY(&reply.dest_addr, &pkt->source_addr, sizeof(ip_addr_t)); + reply.dest_port = pkt->source_port; + /* send answer directly via unicast */ + res = mdns_send_outpacket(&reply, netif); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer could not be send\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer send successfully\n")); + } + return; + } + else { + /* Set IP/port to use when responding multicast */ +#if LWIP_IPV6 + if (IP_IS_V6_VAL(pkt->source_addr)) { + if (mdns->ipv6.multicast_timeout && !reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n")); + return; + } + SMEMCPY(&reply.dest_addr, &v6group, sizeof(ip_addr_t)); + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4_VAL(pkt->source_addr)) { + if (mdns->ipv4.multicast_timeout && !reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n")); + return; + } + SMEMCPY(&reply.dest_addr, &v4group, sizeof(ip_addr_t)); + } +#endif + reply.dest_port = LWIP_IANA_PORT_MDNS; + /* send answer directly via multicast */ + res = mdns_send_outpacket(&reply, netif); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer could not be send\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer send successfully\n")); +#if LWIP_IPV6 + if (IP_IS_V6_VAL(pkt->source_addr)) { + mdns_start_multicast_timeouts_ipv6(netif); + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4_VAL(pkt->source_addr)) { + mdns_start_multicast_timeouts_ipv4(netif); + } +#endif + } + return; + } + } +} + +/** + * Handle truncated question MDNS packet + * - Called by timer + * - Call mdns_handle_question + * - Do cleanup + * + * @param arg incoming packet (in pool) + */ +static void +mdns_handle_tc_question(void *arg) +{ + struct mdns_packet *pkt = (struct mdns_packet *)arg; + struct netif *from = netif_get_by_index(pkt->pbuf->if_idx); + /* timer as elapsed, now handle this question */ + mdns_handle_question(pkt, from); + /* remove from pending list */ + if (pending_tc_questions == pkt) { + pending_tc_questions = pkt->next_tc_question; + } + else { + struct mdns_packet *prev = pending_tc_questions; + while (prev && prev->next_tc_question != pkt) { + prev = prev->next_tc_question; + } + LWIP_ASSERT("pkt not found in pending_tc_questions list", prev != NULL); + prev->next_tc_question = pkt->next_tc_question; + } + /* free linked answers and this question */ + while (pkt->next_answer) { + struct mdns_packet *ans = pkt->next_answer; + pkt->next_answer = ans->next_answer; + pbuf_free(ans->pbuf); + LWIP_MEMPOOL_FREE(MDNS_PKTS, ans); + } + pbuf_free(pkt->pbuf); + LWIP_MEMPOOL_FREE(MDNS_PKTS, pkt); +} + +/** + * Save time when a probe conflict occurs: + * - Check if we exceeded the maximum of 15 conflicts in 10seconds. + * + * @param netif network interface on which the conflict occurred. + */ +static void +mdns_conflict_save_time(struct netif *netif) +{ + struct mdns_host* mdns = NETIF_TO_HOST(netif); + int i; + u32_t diff; + u8_t index2; + + /* Increase the number of conflicts occurred */ + mdns->num_conflicts++; + mdns->conflict_time[mdns->index] = sys_now(); + /* Print timestamp list */ + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: conflict timestamp list, insert index = %d\n", mdns->index)); + for(i = 0; i < MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; i++) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: time no. %d = %"U32_F"\n", i, mdns->conflict_time[i])); + } + /* Check if we had enough conflicts, minimum 15 */ + if (mdns->num_conflicts >= MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT) { + /* Get the index to the oldest timestamp */ + index2 = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; + /* Compare the oldest vs newest time stamp */ + diff = mdns->conflict_time[mdns->index] - mdns->conflict_time[index2]; + /* If they are less then 10 seconds apart, initiate rate limit */ + if (diff < MDNS_PROBE_MAX_CONFLICTS_TIME_WINDOW) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: probe rate limit enabled\n")); + mdns->rate_limit_activated = 1; + } + } + /* Increase index */ + mdns->index = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; +} -cleanup: - if (reply.pbuf) { - /* This should only happen if we fail to alloc/write question for legacy query */ - pbuf_free(reply.pbuf); - reply.pbuf = NULL; +/** + * Handle a probe conflict: + * - Check if we exceeded the maximum of 15 conflicts in 10seconds. + * - Let the user know there is a conflict. + * + * @param netif network interface on which the conflict occurred. + * @param slot service index +1 on which the conflict occurred (0 indicate hostname conflict). + */ +static void +mdns_probe_conflict(struct netif *netif, s8_t slot) +{ + /* Increase the number of conflicts occurred and check rate limiting */ + mdns_conflict_save_time(netif); + + /* Disable currently running probe / announce timer */ + sys_untimeout(mdns_probe_and_announce, netif); + + /* Inform the host on the conflict, if a callback is set */ + if (mdns_name_result_cb != NULL) { + mdns_name_result_cb(netif, MDNS_PROBING_CONFLICT, slot); + } + /* TODO: rename and call restart if no mdns_name_result_cb was set? */ +} + +/** + * Lookup matching request for response MDNS packet + */ +#if LWIP_MDNS_SEARCH +static struct mdns_request * +mdns_lookup_request(struct mdns_rr_info *rr) +{ + int i; + /* search originating request */ + for (i = 0; i < MDNS_MAX_REQUESTS; i++) { + if ((mdns_requests[i].result_fn != NULL) && + (check_request(&mdns_requests[i], rr) != 0)) { + return &mdns_requests[i]; + } } + return NULL; } +#endif /** - * Handle response MDNS packet - * Only prints debug for now. Will need more code to do conflict resolution. + * Handle response MDNS packet: + * - Handle responses on probe query + * - Perform conflict resolution on every packet (RFC6762 section 9) + * + * @param pkt incoming packet + * @param netif network interface on which packet was received */ static void -mdns_handle_response(struct mdns_packet *pkt) +mdns_handle_response(struct mdns_packet *pkt, struct netif *netif) { - struct mdns_host* mdns = NETIF_TO_HOST(pkt->netif); + struct mdns_host* mdns = NETIF_TO_HOST(netif); + u16_t total_answers_left; +#if LWIP_MDNS_SEARCH + struct mdns_request *req = NULL; + s8_t first = 1; +#endif + + /* Ignore responses with a source port different from 5353 + * (LWIP_IANA_PORT_MDNS) -> RFC6762 section 6 */ + if (pkt->source_port != LWIP_IANA_PORT_MDNS) { + return; + } /* Ignore all questions */ while (pkt->questions_left) { struct mdns_question q; err_t res; - res = mdns_read_question(pkt, &q); if (res != ERR_OK) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping response packet\n")); return; } +#if LWIP_MDNS_SEARCH + else { + req = mdns_lookup_request(&q.info); + } +#endif } - - while (pkt->answers_left) { + /* We need to check all resource record sections: answers, authoritative and additional */ + total_answers_left = pkt->answers_left + pkt->authoritative_left + pkt->additional_left; + while (total_answers_left) { struct mdns_answer ans; err_t res; - res = mdns_read_answer(pkt, &ans); + res = mdns_read_answer(pkt, &ans, &total_answers_left); if (res != ERR_OK) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n")); return; @@ -1810,19 +1865,143 @@ mdns_handle_response(struct mdns_packet *pkt) mdns_domain_debug_print(&ans.info.domain); LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass)); - /*"Apparently conflicting Multicast DNS responses received *before* the first probe packet is sent MUST - be silently ignored" so drop answer if we haven't started probing yet*/ - if ((mdns->probing_state == MDNS_PROBING_ONGOING) && (mdns->probes_sent > 0)) { + if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass != DNS_RRCLASS_IN) { + /* Skip answers for ANY type or if class != IN */ + continue; + } + +#if LWIP_MDNS_SEARCH + if (req && req->only_ptr) { + /* Need to recheck that this answer match request that match previous answer */ + if (memcmp (req->service.name, ans.info.domain.name, req->service.length) != 0) + req = NULL; + } + if (!req) { + /* Try hard to search matching request */ + req = mdns_lookup_request(&ans.info); + } + if (req && req->result_fn) { + u16_t offset; + struct pbuf *p; + int flags = (first ? MDNS_SEARCH_RESULT_FIRST : 0) | + (!total_answers_left ? MDNS_SEARCH_RESULT_LAST : 0); + if (req->only_ptr) { + if (ans.info.type != DNS_RRTYPE_PTR) + continue; /* Ignore non matching answer type */ + flags = MDNS_SEARCH_RESULT_FIRST | MDNS_SEARCH_RESULT_LAST; + } + p = pbuf_skip(pkt->pbuf, ans.rd_offset, &offset); + if (p == NULL) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Malformed response packet, aborting\n")); + return; + } + if (ans.info.type == DNS_RRTYPE_PTR || ans.info.type == DNS_RRTYPE_SRV) { + /* Those RR types have compressed domain name. Must uncompress here, + since cannot be done without pbuf. */ + struct { + u16_t values[3]; /* SRV: Prio, Weight, Port */ + struct mdns_domain dom; /* PTR & SRV: Domain (uncompressed) */ + } data; + u16_t off = (ans.info.type == DNS_RRTYPE_SRV ? 6 : 0); + u16_t len = mdns_readname(pkt->pbuf, ans.rd_offset + off, &data.dom); + if (len == MDNS_READNAME_ERROR) { + /* Ensure result_fn is called anyway, just copy failed domain as is */ + data.dom.length = ans.rd_length - off; + memcpy(&data.dom, (const char *)p->payload + offset + off, data.dom.length); + } + /* Adjust len/off according RR type */ + if (ans.info.type == DNS_RRTYPE_SRV) { + memcpy(&data, (const char *)p->payload + offset, 6); + len = data.dom.length + 6; + off = 0; + } else { + len = data.dom.length; + off = 6; + } + req->result_fn(&ans, (const char *)&data + off, len, flags, req->arg); + } else { + /* Direct call result_fn with varpart pointing in pbuf payload */ + req->result_fn(&ans, (const char *)p->payload + offset, ans.rd_length, flags, req->arg); + } + first = 0; + } +#endif + + /* "Conflicting Multicast DNS responses received *before* the first probe + * packet is sent MUST be silently ignored" so drop answer if we haven't + * started probing yet. */ + if ((mdns->state == MDNS_STATE_PROBING) || + (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) { + struct mdns_domain domain; + u8_t i; + + res = mdns_build_host_domain(&domain, mdns); + if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!\n")); + mdns_probe_conflict(netif, 0); + break; + } + + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + struct mdns_service* service = mdns->services[i]; + if (!service) { + continue; + } + res = mdns_build_service_domain(&domain, service, 1); + if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches service domain!\n")); + mdns_probe_conflict(netif, i + 1); + break; + } + } + if (i < MDNS_MAX_SERVICES) + break; + } + /* Perform conflict resolution (RFC6762 section 9): + * We assume a conflict if the hostname or service name matches the answers + * domain. Only if the rdata matches exactly we reset our assumption to no + * conflict. As stated in the RFC: + * What may be considered inconsistent is context sensitive, except that + * resource records with identical rdata are never considered inconsistent, + * even if they originate from different hosts. + */ + else if ((mdns->state == MDNS_STATE_ANNOUNCING) || + (mdns->state == MDNS_STATE_COMPLETE)) { struct mdns_domain domain; u8_t i; u8_t conflict = 0; + /* Evaluate unique hostname records -> A and AAAA */ res = mdns_build_host_domain(&domain, mdns); if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!")); + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches host domain, assuming conflict\n")); + /* This means a conflict has taken place, except when the packet contains + * exactly the same rdata. */ conflict = 1; + /* Evaluate rdata -> to see if it's a copy of our own data */ + if (ans.info.type == DNS_RRTYPE_A) { +#if LWIP_IPV4 + if (ans.rd_length == sizeof(ip4_addr_t) && + pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own IPv4 address record -> no conflict\n")); + conflict = 0; + } +#endif + } + else if (ans.info.type == DNS_RRTYPE_AAAA) { +#if LWIP_IPV6 + if (ans.rd_length == sizeof(ip6_addr_p_t)) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, i), ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own iPv6 address record, num = %d -> no conflict\n",i)); + conflict = 0; + } + } + } +#endif + } } - + /* Evaluate unique service name records -> SRV and TXT */ for (i = 0; i < MDNS_MAX_SERVICES; i++) { struct mdns_service* service = mdns->services[i]; if (!service) { @@ -1830,19 +2009,66 @@ mdns_handle_response(struct mdns_packet *pkt) } res = mdns_build_service_domain(&domain, service, 1); if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches service domain!")); + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches service domain, assuming conflict\n")); + /* This means a conflict has taken place, except when the packet contains + * exactly the same rdata. */ conflict = 1; + /* Evaluate rdata -> to see if it's a copy of our own data */ + if (ans.info.type == DNS_RRTYPE_SRV) { + /* Read and compare to with our SRV record */ + u16_t field16, len, read_pos; + struct mdns_domain srv_ans, my_ans; + read_pos = ans.rd_offset; + do { + /* Check priority field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) { + break; + } + read_pos += len; + /* Check weight field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) { + break; + } + read_pos += len; + /* Check port field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) { + break; + } + read_pos += len; + /* Check host field */ + len = mdns_readname(pkt->pbuf, read_pos, &srv_ans); + mdns_build_host_domain(&my_ans, mdns); + if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&srv_ans, &my_ans)) { + break; + } + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own SRV record -> no conflict\n")); + conflict = 0; + } while (0); + } else if (ans.info.type == DNS_RRTYPE_TXT) { + mdns_prepare_txtdata(service); + if (service->txtdata.length == ans.rd_length && + pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own TXT record -> no conflict\n")); + conflict = 0; + } + } } } - if (conflict != 0) { - sys_untimeout(mdns_probe, pkt->netif); - if (mdns_name_result_cb != NULL) { - mdns_name_result_cb(pkt->netif, MDNS_PROBING_CONFLICT); - } + /* Reset host to probing to reconfirm uniqueness */ + LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: Conflict resolution -> reset to probing state\n")); + mdns_resp_restart(netif); + break; } } } + /* Clear all xxx_left variables because we parsed all answers */ + pkt->answers_left = 0; + pkt->authoritative_left = 0; + pkt->additional_left = 0; } /** @@ -1881,33 +2107,88 @@ mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, memset(&packet, 0, sizeof(packet)); SMEMCPY(&packet.source_addr, addr, sizeof(packet.source_addr)); packet.source_port = port; - packet.netif = recv_netif; packet.pbuf = p; packet.parse_offset = offset; packet.tx_id = lwip_ntohs(hdr.id); packet.questions = packet.questions_left = lwip_ntohs(hdr.numquestions); - packet.answers = packet.answers_left = lwip_ntohs(hdr.numanswers) + lwip_ntohs(hdr.numauthrr) + lwip_ntohs(hdr.numextrarr); - + packet.answers = packet.answers_left = lwip_ntohs(hdr.numanswers); + packet.authoritative = packet.authoritative_left = lwip_ntohs(hdr.numauthrr); + packet.additional = packet.additional_left = lwip_ntohs(hdr.numextrarr); + + /* Source address check (RFC6762 section 11) -> for responses. + * Source address check (RFC6762 section 5.5) -> for queries. + * When the dest addr == multicast addr we know the packet originated on that + * link. If not, we need to check the source address. We only accept queries + * that originated on the link. Others are discarded. + */ #if LWIP_IPV6 if (IP_IS_V6(ip_current_dest_addr())) { /* instead of having one 'v6group' per netif, just compare zoneless here */ - if (!ip_addr_cmp_zoneless(ip_current_dest_addr(), &v6group)) { + if (!ip_addr_zoneless_eq(ip_current_dest_addr(), &v6group)) { packet.recv_unicast = 1; + + if (ip6_addr_ismulticast_global(ip_2_ip6(ip_current_src_addr())) + || ip6_addr_isglobal(ip_2_ip6(ip_current_src_addr()))) { + goto dealloc; + } } } #endif #if LWIP_IPV4 if (!IP_IS_V6(ip_current_dest_addr())) { - if (!ip_addr_cmp(ip_current_dest_addr(), &v4group)) { + if (!ip_addr_eq(ip_current_dest_addr(), &v4group)) { packet.recv_unicast = 1; + + if (!ip4_addr_net_eq(ip_2_ip4(ip_current_src_addr()), + netif_ip4_addr(recv_netif), + netif_ip4_netmask(recv_netif))){ + goto dealloc; + } } } #endif if (hdr.flags1 & DNS_FLAG1_RESPONSE) { - mdns_handle_response(&packet); + mdns_handle_response(&packet, recv_netif); } else { - mdns_handle_question(&packet); + if (packet.questions && hdr.flags1 & DNS_FLAG1_TRUNC) { + /* this is a new truncated question */ + struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS); + if (!pkt) + goto dealloc; /* don't reply truncated question if alloc error */ + SMEMCPY(pkt, &packet, sizeof(packet)); + /* insert this question in pending list */ + pkt->next_tc_question = pending_tc_questions; + pending_tc_questions = pkt; + /* question with truncated flags, need to wait 400-500ms before replying */ + sys_timeout(MDNS_RESPONSE_TC_DELAY_MS, mdns_handle_tc_question, pkt); + /* return without dealloc pbuf */ + return; + } + else if (!packet.questions && packet.answers && pending_tc_questions) { + /* this packet is a known-answer packet for a truncated question previously received */ + struct mdns_packet *q = pending_tc_questions; + while (q) { + if ((packet.source_port == q->source_port) && + ip_addr_eq(&packet.source_addr, &q->source_addr)) + break; + q = q->next_tc_question; + } + if (q) { + /* found question from the same source */ + struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS); + if (!pkt) + goto dealloc; /* don't reply truncated question if alloc error */ + SMEMCPY(pkt, &packet, sizeof(packet)); + /* insert this known-ansert in question */ + pkt->next_answer = q->next_answer; + q->next_answer = pkt; + /* nothing more to do */ + return; + } + } + /* if previous tests fail, handle this question normally */ + mdns_handle_question(&packet, recv_netif); } dealloc: @@ -1939,55 +2220,40 @@ mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, c if (reason & (LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_GATEWAY_CHANGED | LWIP_NSC_IPV4_NETMASK_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED | LWIP_NSC_IPV6_SET | LWIP_NSC_IPV6_ADDR_STATE_CHANGED)) { - mdns_resp_announce(netif); + mdns_resp_restart(netif); } } #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK */ -static err_t -mdns_send_probe(struct netif* netif, const ip_addr_t *destination) +static void +mdns_define_probe_rrs_to_send(struct netif *netif, struct mdns_outmsg *outmsg) { - struct mdns_host* mdns; - struct mdns_outpacket pkt; - struct mdns_domain domain; - u8_t i; - err_t res; - - mdns = NETIF_TO_HOST(netif); + struct mdns_host *mdns = NETIF_TO_HOST(netif); + int i; - memset(&pkt, 0, sizeof(pkt)); - pkt.netif = netif; + memset(outmsg, 0, sizeof(struct mdns_outmsg)); /* Add unicast questions with rtype ANY for all our desired records */ - mdns_build_host_domain(&domain, mdns); - res = mdns_add_question(&pkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, 1); - if (res != ERR_OK) { - goto cleanup; - } - pkt.questions++; + outmsg->host_questions = QUESTION_PROBE_HOST_ANY; + for (i = 0; i < MDNS_MAX_SERVICES; i++) { struct mdns_service* service = mdns->services[i]; if (!service) { continue; } - mdns_build_service_domain(&domain, service, 1); - res = mdns_add_question(&pkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, 1); - if (res != ERR_OK) { - goto cleanup; - } - pkt.questions++; + outmsg->serv_questions[i] = QUESTION_PROBE_SERVICE_NAME_ANY; } /* Add answers to the questions above into the authority section for tiebreaking */ #if LWIP_IPV4 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { - pkt.host_replies = REPLY_HOST_A; + outmsg->host_replies = REPLY_HOST_A; } #endif #if LWIP_IPV6 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { - pkt.host_replies |= REPLY_HOST_AAAA; + outmsg->host_replies |= REPLY_HOST_AAAA; } } #endif @@ -1995,54 +2261,97 @@ mdns_send_probe(struct netif* netif, const ip_addr_t *destination) for (i = 0; i < MDNS_MAX_SERVICES; i++) { struct mdns_service *serv = mdns->services[i]; if (serv) { - pkt.serv_replies[i] = REPLY_SERVICE_SRV | REPLY_SERVICE_TXT; + outmsg->serv_replies[i] = REPLY_SERVICE_SRV; } } +} + +static err_t +mdns_send_probe(struct netif* netif, const ip_addr_t *destination) +{ + struct mdns_outmsg outmsg; - pkt.tx_id = 0; - pkt.dest_port = LWIP_IANA_PORT_MDNS; - SMEMCPY(&pkt.dest_addr, destination, sizeof(pkt.dest_addr)); - res = mdns_send_outpacket(&pkt, 0); + mdns_define_probe_rrs_to_send(netif, &outmsg); -cleanup: - if (pkt.pbuf) { - pbuf_free(pkt.pbuf); - pkt.pbuf = NULL; - } - return res; + outmsg.tx_id = 0; + outmsg.dest_port = LWIP_IANA_PORT_MDNS; + SMEMCPY(&outmsg.dest_addr, destination, sizeof(outmsg.dest_addr)); + return mdns_send_outpacket(&outmsg, netif); } /** - * Timer callback for probing network. + * Timer callback for probing and announcing on the network. */ static void -mdns_probe(void* arg) +mdns_probe_and_announce(void* arg) { struct netif *netif = (struct netif *)arg; struct mdns_host* mdns = NETIF_TO_HOST(netif); + u32_t announce_delay; - if(mdns->probes_sent >= MDNS_PROBE_COUNT) { - /* probing successful, announce the new name */ - mdns->probing_state = MDNS_PROBING_COMPLETE; - mdns_resp_announce(netif); - if (mdns_name_result_cb != NULL) { - mdns_name_result_cb(netif, MDNS_PROBING_SUCCESSFUL); - } - } else { + + switch (mdns->state) { + case MDNS_STATE_OFF: + case MDNS_STATE_PROBE_WAIT: + case MDNS_STATE_PROBING: #if LWIP_IPV4 - /*if ipv4 wait with probing until address is set*/ - if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && - mdns_send_probe(netif, IP4_ADDR_ANY) == ERR_OK) + /*if ipv4 wait with probing until address is set*/ + if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && + mdns_send_probe(netif, &v4group) == ERR_OK) #endif - { + { #if LWIP_IPV6 - if (mdns_send_probe(netif, IP6_ADDR_ANY) == ERR_OK) + if (mdns_send_probe(netif, &v6group) == ERR_OK) #endif - { - mdns->probes_sent++; + { + mdns->state = MDNS_STATE_PROBING; + mdns->sent_num++; + } } - } - sys_timeout(MDNS_PROBE_DELAY_MS, mdns_probe, netif); + + if (mdns->sent_num >= MDNS_PROBE_COUNT) { + mdns->state = MDNS_STATE_ANNOUNCE_WAIT; + mdns->sent_num = 0; + } + + if (mdns->sent_num && mdns->rate_limit_activated == 1) { + /* delay second probe if rate limiting activated */ + sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif); + } + else { + sys_timeout(MDNS_PROBE_DELAY_MS, mdns_probe_and_announce, netif); + } + break; + case MDNS_STATE_ANNOUNCE_WAIT: + case MDNS_STATE_ANNOUNCING: + if (mdns->sent_num == 0) { + /* probing was successful, announce all records */ + mdns->state = MDNS_STATE_ANNOUNCING; + /* Reset rate limit max probe conflict timeout flag */ + mdns->rate_limit_activated = 0; + /* Let the client know probing was successful */ + if (mdns_name_result_cb != NULL) { + mdns_name_result_cb(netif, MDNS_PROBING_SUCCESSFUL, 0); + } + } + + mdns_resp_announce(netif); + mdns->sent_num++; + + if (mdns->sent_num >= MDNS_ANNOUNCE_COUNT) { + /* Announcing and probing complete */ + mdns->state = MDNS_STATE_COMPLETE; + mdns->sent_num = 0; + } + else { + announce_delay = MDNS_ANNOUNCE_DELAY_MS * (1 << (mdns->sent_num - 1)); + sys_timeout(announce_delay, mdns_probe_and_announce, netif); + } + break; + case MDNS_STATE_COMPLETE: + default: + /* Do nothing */ + break; } } @@ -2053,11 +2362,10 @@ mdns_probe(void* arg) * @param hostname Name to use. Queries for <hostname>.local will be answered * with the IP addresses of the netif. The hostname will be copied, the * given pointer can be on the stack. - * @param dns_ttl Validity time in seconds to send out for IP address data in DNS replies * @return ERR_OK if netif was added, an err_t otherwise */ err_t -mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) +mdns_resp_add_netif(struct netif *netif, const char *hostname) { err_t res; struct mdns_host *mdns; @@ -2073,9 +2381,19 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) netif_set_client_data(netif, mdns_netif_client_id, mdns); MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname))); - mdns->dns_ttl = dns_ttl; - mdns->probes_sent = 0; - mdns->probing_state = MDNS_PROBING_NOT_STARTED; + + /* Init delayed message structs with address and port */ +#if LWIP_IPV4 + mdns->ipv4.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS; + SMEMCPY(&mdns->ipv4.delayed_msg_multicast.dest_addr, &v4group, + sizeof(ip_addr_t)); +#endif + +#if LWIP_IPV6 + mdns->ipv6.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS; + SMEMCPY(&mdns->ipv6.delayed_msg_multicast.dest_addr, &v6group, + sizeof(ip_addr_t)); +#endif /* Join multicast groups */ #if LWIP_IPV4 @@ -2119,9 +2437,7 @@ mdns_resp_remove_netif(struct netif *netif) mdns = NETIF_TO_HOST(netif); LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL); - if (mdns->probing_state == MDNS_PROBING_ONGOING) { - sys_untimeout(mdns_probe, netif); - } + sys_untimeout(mdns_probe_and_announce, netif); for (i = 0; i < MDNS_MAX_SERVICES; i++) { struct mdns_service *service = mdns->services[i]; @@ -2168,11 +2484,23 @@ mdns_resp_rename_netif(struct netif *netif, const char *hostname) MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, len)); mdns->name[len] = '\0'; /* null termination in case new name is shorter than previous */ - mdns_resp_restart(netif); + mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS); return ERR_OK; } +/** + * @ingroup mdns + * Checks if an MDNS responder is active for a given network interface. + * @param netif The network interface to test. + * @return nonzero if responder active, zero otherwise. + */ +int +mdns_resp_netif_active(struct netif *netif) +{ + return NETIF_TO_HOST(netif) != NULL; +} + /** * @ingroup mdns * Add a service to the selected network interface. @@ -2182,17 +2510,15 @@ mdns_resp_rename_netif(struct netif *netif, const char *hostname) * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP * for others ("_udp") * @param port The port the service listens to - * @param dns_ttl Validity time in seconds to send out for service data in DNS replies * @param txt_fn Callback to get TXT data. Will be called each time a TXT reply is created to * allow dynamic replies. * @param txt_data Userdata pointer for txt_fn * @return service_id if the service was added to the netif, an err_t otherwise */ s8_t -mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_data) +mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_data) { - s8_t i; - s8_t slot = -1; + u8_t slot; struct mdns_service *srv; struct mdns_host *mdns; @@ -2205,13 +2531,12 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service LWIP_ERROR("mdns_resp_add_service: Service too long", (strlen(service) <= MDNS_LABEL_MAXLEN), return ERR_VAL); LWIP_ERROR("mdns_resp_add_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL); - for (i = 0; i < MDNS_MAX_SERVICES; i++) { - if (mdns->services[i] == NULL) { - slot = i; + for (slot = 0; slot < MDNS_MAX_SERVICES; slot++) { + if (mdns->services[slot] == NULL) { break; } } - LWIP_ERROR("mdns_resp_add_service: Service list full (increase MDNS_MAX_SERVICES)", (slot >= 0), return ERR_MEM); + LWIP_ERROR("mdns_resp_add_service: Service list full (increase MDNS_MAX_SERVICES)", (slot < MDNS_MAX_SERVICES), return ERR_MEM); srv = (struct mdns_service *)mem_calloc(1, sizeof(struct mdns_service)); LWIP_ERROR("mdns_resp_add_service: Alloc failed", (srv != NULL), return ERR_MEM); @@ -2222,7 +2547,6 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service srv->txt_userdata = txt_data; srv->proto = (u16_t)proto; srv->port = port; - srv->dns_ttl = dns_ttl; mdns->services[slot] = srv; @@ -2239,14 +2563,14 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service * @return ERR_OK if the service was removed from the netif, an err_t otherwise */ err_t -mdns_resp_del_service(struct netif *netif, s8_t slot) +mdns_resp_del_service(struct netif *netif, u8_t slot) { struct mdns_host *mdns; struct mdns_service *srv; LWIP_ASSERT("mdns_resp_del_service: netif != NULL", netif); mdns = NETIF_TO_HOST(netif); LWIP_ERROR("mdns_resp_del_service: Not an mdns netif", (mdns != NULL), return ERR_VAL); - LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", (slot >= 0) && (slot < MDNS_MAX_SERVICES), return ERR_VAL); + LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL); LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL); srv = mdns->services[slot]; @@ -2264,7 +2588,7 @@ mdns_resp_del_service(struct netif *netif, s8_t slot) * @return ERR_OK if name could be set on service, an err_t otherwise */ err_t -mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name) +mdns_resp_rename_service(struct netif *netif, u8_t slot, const char *name) { struct mdns_service *srv; struct mdns_host *mdns; @@ -2276,7 +2600,7 @@ mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name) mdns = NETIF_TO_HOST(netif); LWIP_ERROR("mdns_resp_rename_service: Not an mdns netif", (mdns != NULL), return ERR_VAL); LWIP_ERROR("mdns_resp_rename_service: Name too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL); - LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (slot >= 0) && (slot < MDNS_MAX_SERVICES), return ERR_VAL); + LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL); LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL); srv = mdns->services[slot]; @@ -2284,7 +2608,7 @@ mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name) MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, len)); srv->name[len] = '\0'; /* null termination in case new name is shorter than previous */ - mdns_resp_restart(netif); + mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS); return ERR_OK; } @@ -2308,6 +2632,86 @@ mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_ return mdns_domain_add_label(&service->txtdata, txt, txt_len); } +#if LWIP_MDNS_SEARCH +/** + * @ingroup mdns + * Stop a search request. + * @param request_id The search request to stop + */ +void +mdns_search_stop(u8_t request_id) +{ + struct mdns_request *req; + LWIP_ASSERT("mdns_search_stop: bad request_id", request_id < MDNS_MAX_REQUESTS); + req = &mdns_requests[request_id]; + if (req && req->result_fn) { + req->result_fn = NULL; + } +} + +/** + * @ingroup mdns + * Search a specific service on the network. + * @param name The name of the service + * @param service The service type, like "_http" + * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP + * for others ("_udp") + * @param netif The network interface where to send search request + * @param result_fn Callback to send answer received. Will be called for each answer of a + * response frame matching request sent. + * @param arg Userdata pointer for result_fn + * @param request_id Returned request identifier to allow stop it. + * @return ERR_OK if the search request was created and sent, an err_t otherwise + */ +err_t +mdns_search_service(const char *name, const char *service, enum mdns_sd_proto proto, + struct netif *netif, search_result_fn_t result_fn, void *arg, + u8_t *request_id) +{ + u8_t slot; + struct mdns_request *req; + if (name) { + LWIP_ERROR("mdns_search_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL); + } + LWIP_ERROR("mdns_search_service: Service too long", (strlen(service) < MDNS_DOMAIN_MAXLEN), return ERR_VAL); + LWIP_ERROR("mdns_search_service: Bad reqid pointer", request_id, return ERR_VAL); + LWIP_ERROR("mdns_search_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL); + for (slot = 0; slot < MDNS_MAX_REQUESTS; slot++) { + if (mdns_requests[slot].result_fn == NULL) { + break; + } + } + if (slot >= MDNS_MAX_REQUESTS) { + /* Don't assert if no more space in mdns_request table. Just return an error. */ + return ERR_MEM; + } + + req = &mdns_requests[slot]; + memset(req, 0, sizeof(struct mdns_request)); + req->result_fn = result_fn; + req->arg = arg; + req->proto = (u16_t)proto; + req->qtype = DNS_RRTYPE_PTR; + if (proto == DNSSD_PROTO_UDP && strcmp(service, "_services._dns-sd") == 0) { + req->only_ptr = 1; /* don't check other answers */ + } + mdns_domain_add_string(&req->service, service); + if (name) { + MEMCPY(&req->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name))); + } + /* save request id (slot) in pointer provided by caller */ + *request_id = slot; + /* now prepare a MDNS request and send it (on specified interface) */ +#if LWIP_IPV6 + mdns_send_request(req, netif, &v6group); +#endif +#if LWIP_IPV4 + mdns_send_request(req, netif, &v4group); +#endif + return ERR_OK; +} +#endif + /** * @ingroup mdns * Send unsolicited answer containing all our known data @@ -2325,14 +2729,18 @@ mdns_resp_announce(struct netif *netif) return; } - if (mdns->probing_state == MDNS_PROBING_COMPLETE) { + /* Do not announce if the mdns responder is off, waiting to probe, probing or + * waiting to announce. */ + if (mdns->state >= MDNS_STATE_ANNOUNCING) { /* Announce on IPv6 and IPv4 */ #if LWIP_IPV6 - mdns_announce(netif, IP6_ADDR_ANY); + mdns_announce(netif, &v6group); + mdns_start_multicast_timeouts_ipv6(netif); #endif #if LWIP_IPV4 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { - mdns_announce(netif, IP4_ADDR_ANY); + mdns_announce(netif, &v4group); + mdns_start_multicast_timeouts_ipv4(netif); } #endif } /* else: ip address changed while probing was ongoing? @todo reset counter to restart? */ @@ -2348,12 +2756,13 @@ mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb) /** * @ingroup mdns - * Restart mdns responder. Call this when cable is connected after being disconnected or - * administrative interface is set up after being down + * Restart mdns responder after a specified delay. Call this when cable is connected + * after being disconnected or administrative interface is set up after being down * @param netif The network interface to send on + * @param delay The delay to use before sending probe */ void -mdns_resp_restart(struct netif *netif) +mdns_resp_restart_delay(struct netif *netif, uint32_t delay) { struct mdns_host* mdns; LWIP_ASSERT_CORE_LOCKED(); @@ -2363,14 +2772,35 @@ mdns_resp_restart(struct netif *netif) if (mdns == NULL) { return; } + /* Make sure timer is not running */ + sys_untimeout(mdns_probe_and_announce, netif); + + mdns->sent_num = 0; + mdns->state = MDNS_STATE_PROBE_WAIT; - if (mdns->probing_state == MDNS_PROBING_ONGOING) { - sys_untimeout(mdns_probe, netif); + /* RFC6762 section 8.1: If fifteen conflicts occur within any ten-second period, + * then the host MUST wait at least five seconds before each successive + * additional probe attempt. + */ + if (mdns->rate_limit_activated == 1) { + sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif); + } + else { + /* Adjust probe delay according sent probe count. */ + sys_timeout(delay, mdns_probe_and_announce, netif); } - /* @todo if we've failed 15 times within a 10 second period we MUST wait 5 seconds (or wait 5 seconds every time except first)*/ - mdns->probes_sent = 0; - mdns->probing_state = MDNS_PROBING_ONGOING; - sys_timeout(MDNS_INITIAL_PROBE_DELAY_MS, mdns_probe, netif); +} + +/** + * @ingroup mdns + * Restart mdns responder. Call this when cable is connected after being disconnected or + * administrative interface is set up after being down + * @param netif The network interface to send on + */ +void +mdns_resp_restart(struct netif *netif) +{ + mdns_resp_restart_delay(netif, MDNS_INITIAL_PROBE_DELAY_MS); } /** @@ -2383,13 +2813,16 @@ mdns_resp_init(void) err_t res; /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */ - +#if LWIP_MDNS_SEARCH + memset(mdns_requests, 0, sizeof(mdns_requests)); +#endif + LWIP_MEMPOOL_INIT(MDNS_PKTS); mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL); #if LWIP_MULTICAST_TX_OPTIONS - udp_set_multicast_ttl(mdns_pcb, MDNS_TTL); + udp_set_multicast_ttl(mdns_pcb, MDNS_IP_TTL); #else - mdns_pcb->ttl = MDNS_TTL; + mdns_pcb->ttl = MDNS_IP_TTL; #endif res = udp_bind(mdns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS); LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */ @@ -2404,4 +2837,19 @@ mdns_resp_init(void) #endif } +/** + * @ingroup mdns + * Return TXT userdata of a specific service on a network interface. + * @param netif Network interface. + * @param slot Service index. + */ +void *mdns_get_service_txt_userdata(struct netif *netif, s8_t slot) +{ + struct mdns_host *mdns = NETIF_TO_HOST(netif); + struct mdns_service *s; + LWIP_ASSERT("mdns_get_service_txt_userdata: index out of range", slot < MDNS_MAX_SERVICES); + s = mdns->services[slot]; + return s ? s->txt_userdata : NULL; +} + #endif /* LWIP_MDNS_RESPONDER */ diff --git a/src/apps/mdns/mdns_domain.c b/src/apps/mdns/mdns_domain.c new file mode 100644 index 0000000..265b5e6 --- /dev/null +++ b/src/apps/mdns/mdns_domain.c @@ -0,0 +1,635 @@ +/** + * @file + * MDNS responder implementation - domain related functionalities + */ + +/* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Author: Jasper Verschueren + * + */ + +#include "lwip/apps/mdns.h" +#include "lwip/apps/mdns_domain.h" +#include "lwip/apps/mdns_priv.h" +#include "lwip/prot/dns.h" + +#include + +#if LWIP_IPV6 +#include "lwip/prot/ip6.h" +#endif + +#if LWIP_MDNS_RESPONDER + +/* Stored offsets to beginning of domain names + * Used for compression. + */ +#define DOMAIN_JUMP_SIZE 2 +#define DOMAIN_JUMP 0xc000 + +#define TOPDOMAIN_LOCAL "local" + +#define REVERSE_PTR_TOPDOMAIN "arpa" +#define REVERSE_PTR_V4_DOMAIN "in-addr" +#define REVERSE_PTR_V6_DOMAIN "ip6" + +static const char *dnssd_protos[] = { + "_udp", /* DNSSD_PROTO_UDP */ + "_tcp", /* DNSSD_PROTO_TCP */ +}; + +/* forward declarations (function prototypes)*/ +static err_t mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len); +static err_t mdns_domain_add_label_pbuf(struct mdns_domain *domain, + const struct pbuf *p, u16_t offset, + u8_t len); +static u16_t mdns_readname_loop(struct pbuf *p, u16_t offset, + struct mdns_domain *domain, unsigned depth); +static err_t mdns_add_dotlocal(struct mdns_domain *domain); + + +static err_t +mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len) +{ + if (len > MDNS_LABEL_MAXLEN) { + return ERR_VAL; + } + if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + /* Allow only zero marker on last byte */ + if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + domain->name[domain->length] = len; + domain->length++; + return ERR_OK; +} + +/** + * Add a label part to a domain + * @param domain The domain to add a label to + * @param label The label to add, like <hostname>, 'local', 'com' or '' + * @param len The length of the label + * @return ERR_OK on success, an err_t otherwise if label too long + */ +err_t +mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len) +{ + err_t err = mdns_domain_add_label_base(domain, len); + if (err != ERR_OK) { + return err; + } + if (len) { + MEMCPY(&domain->name[domain->length], label, len); + domain->length += len; + } + return ERR_OK; +} + +/** + * Add a label part to a domain (@see mdns_domain_add_label but copy directly from pbuf) + */ +static err_t +mdns_domain_add_label_pbuf(struct mdns_domain *domain, const struct pbuf *p, u16_t offset, u8_t len) +{ + err_t err = mdns_domain_add_label_base(domain, len); + if (err != ERR_OK) { + return err; + } + if (len) { + if (pbuf_copy_partial(p, &domain->name[domain->length], len, offset) != len) { + /* take back the ++ done before */ + domain->length--; + return ERR_ARG; + } + domain->length += len; + } + return ERR_OK; +} + +/** + * Add a partial domain to a domain + * @param domain The domain to add a label to + * @param source The domain to add, like <\\x09_services\\007_dns-sd\\000> + * @return ERR_OK on success, an err_t otherwise if label too long + */ +err_t +mdns_domain_add_domain(struct mdns_domain *domain, struct mdns_domain *source) +{ + u16_t len = source->length; + if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + /* Allow only zero marker on last byte */ + if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + if (len) { + /* Copy partial domain */ + MEMCPY(&domain->name[domain->length], source->name, len); + domain->length += len; + } else { + /* Add zero marker */ + domain->name[domain->length] = 0; + domain->length++; + } + return ERR_OK; +} + +/** + * Add a string domain to a domain + * @param domain The domain to add a label to + * @param source The string to add, like <_services._dns-sd> + * @return ERR_OK on success, an err_t otherwise if label too long + */ +err_t +mdns_domain_add_string(struct mdns_domain *domain, const char *source) +{ + u8_t *len = &domain->name[domain->length]; + u8_t *end = &domain->name[MDNS_DOMAIN_MAXLEN]; + u8_t *start = len + 1; + *len = 0; + while (*source && start < end) { + if (*source == '.') { + len = start++; + *len = 0; + source++; + } else { + *start++ = *source++; + *len = *len + 1; + } + } + if (start == end) { + return ERR_VAL; + } + domain->length = (u16_t)(start - &domain->name[0]); + return ERR_OK; +} + + +/** + * Internal readname function with max 6 levels of recursion following jumps + * while decompressing name + */ +static u16_t +mdns_readname_loop(struct pbuf *p, u16_t offset, struct mdns_domain *domain, unsigned depth) +{ + u8_t c; + + do { + if (depth > 5) { + /* Too many jumps */ + return MDNS_READNAME_ERROR; + } + + c = pbuf_get_at(p, offset); + offset++; + + /* is this a compressed label? */ + if ((c & 0xc0) == 0xc0) { + u16_t jumpaddr; + if (offset >= p->tot_len) { + /* Make sure both jump bytes fit in the packet */ + return MDNS_READNAME_ERROR; + } + jumpaddr = (((c & 0x3f) << 8) | (pbuf_get_at(p, offset) & 0xff)); + offset++; + if (jumpaddr >= SIZEOF_DNS_HDR && jumpaddr < p->tot_len) { + u16_t res; + /* Recursive call, maximum depth will be checked */ + res = mdns_readname_loop(p, jumpaddr, domain, depth + 1); + /* Don't return offset since new bytes were not read (jumped to somewhere in packet) */ + if (res == MDNS_READNAME_ERROR) { + return res; + } + } else { + return MDNS_READNAME_ERROR; + } + break; + } + + /* normal label */ + if (c <= MDNS_LABEL_MAXLEN) { + err_t res; + + if (c + domain->length >= MDNS_DOMAIN_MAXLEN) { + return MDNS_READNAME_ERROR; + } + res = mdns_domain_add_label_pbuf(domain, p, offset, c); + if (res != ERR_OK) { + return MDNS_READNAME_ERROR; + } + offset += c; + } else { + /* bad length byte */ + return MDNS_READNAME_ERROR; + } + } while (c != 0); + + return offset; +} + +/** + * Read possibly compressed domain name from packet buffer + * @param p The packet + * @param offset start position of domain name in packet + * @param domain The domain name destination + * @return The new offset after the domain, or MDNS_READNAME_ERROR + * if reading failed + */ +u16_t +mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain) +{ + memset(domain, 0, sizeof(struct mdns_domain)); + return mdns_readname_loop(p, offset, domain, 0); +} + +/** + * Print domain name to debug output + * @param domain The domain name + */ +void +mdns_domain_debug_print(struct mdns_domain *domain) +{ + u8_t *src = domain->name; + u8_t i; + + while (*src) { + u8_t label_len = *src; + src++; + for (i = 0; i < label_len; i++) { + LWIP_DEBUGF(MDNS_DEBUG, ("%c", src[i])); + } + src += label_len; + LWIP_DEBUGF(MDNS_DEBUG, (".")); + } +} + +/** + * Return 1 if contents of domains match (case-insensitive) + * @param a Domain name to compare 1 + * @param b Domain name to compare 2 + * @return 1 if domains are equal ignoring case, 0 otherwise + */ +int +mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b) +{ + u8_t *ptra, *ptrb; + u8_t len; + int res; + + if (a->length != b->length) { + return 0; + } + + ptra = a->name; + ptrb = b->name; + while (*ptra && *ptrb && ptra < &a->name[a->length]) { + if (*ptra != *ptrb) { + return 0; + } + len = *ptra; + ptra++; + ptrb++; + res = lwip_strnicmp((char *) ptra, (char *) ptrb, len); + if (res != 0) { + return 0; + } + ptra += len; + ptrb += len; + } + if (*ptra != *ptrb && ptra < &a->name[a->length]) { + return 0; + } + return 1; +} + +#if LWIP_IPV4 +/** + * Build domain for reverse lookup of IPv4 address + * like 12.0.168.192.in-addr.arpa. for 192.168.0.12 + * @param domain Where to write the domain name + * @param addr Pointer to an IPv4 address to encode + * @return ERR_OK if domain was written, an err_t otherwise + */ +err_t +mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t *addr) +{ + int i; + err_t res; + const u8_t *ptr; + + LWIP_UNUSED_ARG(res); + if (!domain || !addr) { + return ERR_ARG; + } + memset(domain, 0, sizeof(struct mdns_domain)); + ptr = (const u8_t *) addr; + for (i = sizeof(ip4_addr_t) - 1; i >= 0; i--) { + char buf[4]; + u8_t val = ptr[i]; + + lwip_itoa(buf, sizeof(buf), val); + res = mdns_domain_add_label(domain, buf, (u8_t)strlen(buf)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + } + res = mdns_domain_add_label(domain, REVERSE_PTR_V4_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V4_DOMAIN) - 1)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, NULL, 0); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + + return ERR_OK; +} +#endif + +#if LWIP_IPV6 +/** + * Build domain for reverse lookup of IP address + * like b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. for 2001:db8::567:89ab + * @param domain Where to write the domain name + * @param addr Pointer to an IPv6 address to encode + * @return ERR_OK if domain was written, an err_t otherwise + */ +err_t +mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr) +{ + int i; + err_t res; + const u8_t *ptr; + LWIP_UNUSED_ARG(res); + if (!domain || !addr) { + return ERR_ARG; + } + memset(domain, 0, sizeof(struct mdns_domain)); + ptr = (const u8_t *) addr; + for (i = sizeof(ip6_addr_p_t) - 1; i >= 0; i--) { + char buf; + u8_t byte = ptr[i]; + int j; + for (j = 0; j < 2; j++) { + if ((byte & 0x0F) < 0xA) { + buf = '0' + (byte & 0x0F); + } else { + buf = 'a' + (byte & 0x0F) - 0xA; + } + res = mdns_domain_add_label(domain, &buf, sizeof(buf)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + byte >>= 4; + } + } + res = mdns_domain_add_label(domain, REVERSE_PTR_V6_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V6_DOMAIN) - 1)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, NULL, 0); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + + return ERR_OK; +} +#endif + +/* Add .local. to domain */ +static err_t +mdns_add_dotlocal(struct mdns_domain *domain) +{ + err_t res = mdns_domain_add_label(domain, TOPDOMAIN_LOCAL, (u8_t)(sizeof(TOPDOMAIN_LOCAL) - 1)); + LWIP_UNUSED_ARG(res); + LWIP_ERROR("mdns_add_dotlocal: Failed to add label", (res == ERR_OK), return res); + return mdns_domain_add_label(domain, NULL, 0); +} + +/** + * Build the \.local. domain name + * @param domain Where to write the domain name + * @param mdns TMDNS netif descriptor. + * @return ERR_OK if domain \.local. was written, an err_t otherwise + */ +err_t +mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns) +{ + err_t res; + LWIP_UNUSED_ARG(res); + memset(domain, 0, sizeof(struct mdns_domain)); + LWIP_ERROR("mdns_build_host_domain: mdns != NULL", (mdns != NULL), return ERR_VAL); + res = mdns_domain_add_label(domain, mdns->name, (u8_t)strlen(mdns->name)); + LWIP_ERROR("mdns_build_host_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +/** + * Build the lookup-all-services special DNS-SD domain name + * @param domain Where to write the domain name + * @return ERR_OK if domain _services._dns-sd._udp.local. was written, an err_t otherwise + */ +err_t +mdns_build_dnssd_domain(struct mdns_domain *domain) +{ + err_t res; + LWIP_UNUSED_ARG(res); + memset(domain, 0, sizeof(struct mdns_domain)); + res = mdns_domain_add_label(domain, "_services", (u8_t)(sizeof("_services") - 1)); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, "_dns-sd", (u8_t)(sizeof("_dns-sd") - 1)); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)strlen(dnssd_protos[DNSSD_PROTO_UDP])); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +/** + * Build domain name for a service + * @param domain Where to write the domain name + * @param service The service struct, containing service name, type and protocol + * @param include_name Whether to include the service name in the domain + * @return ERR_OK if domain was written. If service name is included, + * \.\.\.local. will be written, otherwise \.\.local. + * An err_t is returned on error. + */ +err_t +mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name) +{ + err_t res; + LWIP_UNUSED_ARG(res); + memset(domain, 0, sizeof(struct mdns_domain)); + if (include_name) { + res = mdns_domain_add_label(domain, service->name, (u8_t)strlen(service->name)); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + } + res = mdns_domain_add_label(domain, service->service, (u8_t)strlen(service->service)); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)strlen(dnssd_protos[service->proto])); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +#if LWIP_MDNS_SEARCH +/** + * Build domain name for a request + * @param domain Where to write the domain name + * @param request The request struct, containing service name, type and protocol + * @param include_name Whether to include the service name in the domain + * @return ERR_OK if domain was written. If service name is included, + * \.\.\.local. will be written, otherwise \.\.local. + * An err_t is returned on error. + */ +err_t +mdns_build_request_domain(struct mdns_domain *domain, struct mdns_request *request, int include_name) +{ + err_t res; + memset(domain, 0, sizeof(struct mdns_domain)); + if (include_name) { + res = mdns_domain_add_label(domain, request->name, (u8_t)strlen(request->name)); + LWIP_ERROR("mdns_build_request_domain: Failed to add label", (res == ERR_OK), return res); + } + res = mdns_domain_add_domain(domain, &request->service); + LWIP_ERROR("mdns_build_request_domain: Failed to add domain", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, dnssd_protos[request->proto], (u8_t)strlen(dnssd_protos[request->proto])); + LWIP_ERROR("mdns_build_request_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} +#endif + +/** + * Return bytes needed to write before jump for best result of compressing supplied domain + * against domain in outpacket starting at specified offset. + * If a match is found, offset is updated to where to jump to + * @param pbuf Pointer to pbuf with the partially constructed DNS packet + * @param offset Start position of a domain written earlier. If this location is suitable + * for compression, the pointer is updated to where in the domain to jump to. + * @param domain The domain to write + * @return Number of bytes to write of the new domain before writing a jump to the offset. + * If compression can not be done against this previous domain name, the full new + * domain length is returned. + */ +u16_t +mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain) +{ + struct mdns_domain target; + u16_t target_end; + u8_t target_len; + u8_t writelen = 0; + u8_t *ptr; + if (pbuf == NULL) { + return domain->length; + } + target_end = mdns_readname(pbuf, *offset, &target); + if (target_end == MDNS_READNAME_ERROR) { + return domain->length; + } + target_len = (u8_t)(target_end - *offset); + ptr = domain->name; + while (writelen < domain->length) { + u8_t domainlen = (u8_t)(domain->length - writelen); + u8_t labellen; + if (domainlen <= target.length && domainlen > DOMAIN_JUMP_SIZE) { + /* Compare domains if target is long enough, and we have enough left of the domain */ + u8_t targetpos = (u8_t)(target.length - domainlen); + if ((targetpos + DOMAIN_JUMP_SIZE) >= target_len) { + /* We are checking at or beyond a jump in the original, stop looking */ + break; + } + if (target.length >= domainlen && + memcmp(&domain->name[writelen], &target.name[targetpos], domainlen) == 0) { + *offset += targetpos; + return writelen; + } + } + /* Skip to next label in domain */ + labellen = *ptr; + writelen += 1 + labellen; + ptr += 1 + labellen; + } + /* Nothing found */ + return domain->length; +} + +/** + * Write domain to outpacket. Compression will be attempted, + * unless domain->skip_compression is set. + * @param outpkt The outpacket to write to + * @param domain The domain name to write + * @return ERR_OK on success, an err_t otherwise + */ +err_t +mdns_write_domain(struct mdns_outpacket *outpkt, struct mdns_domain *domain) +{ + int i; + err_t res; + u16_t writelen = domain->length; + u16_t jump_offset = 0; + u16_t jump; + + if (!domain->skip_compression) { + for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) { + u16_t offset = outpkt->domain_offsets[i]; + if (offset) { + u16_t len = mdns_compress_domain(outpkt->pbuf, &offset, domain); + if (len < writelen) { + writelen = len; + jump_offset = offset; + } + } + } + } + + if (writelen) { + /* Write uncompressed part of name */ + res = pbuf_take_at(outpkt->pbuf, domain->name, writelen, outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + + /* Store offset of this new domain */ + for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) { + if (outpkt->domain_offsets[i] == 0) { + outpkt->domain_offsets[i] = outpkt->write_offset; + break; + } + } + + outpkt->write_offset += writelen; + } + if (jump_offset) { + /* Write jump */ + jump = lwip_htons(DOMAIN_JUMP | jump_offset); + res = pbuf_take_at(outpkt->pbuf, &jump, DOMAIN_JUMP_SIZE, outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += DOMAIN_JUMP_SIZE; + } + return ERR_OK; +} + +#endif /* LWIP_MDNS_RESPONDER */ diff --git a/src/apps/mdns/mdns_out.c b/src/apps/mdns/mdns_out.c new file mode 100644 index 0000000..5c6d26b --- /dev/null +++ b/src/apps/mdns/mdns_out.c @@ -0,0 +1,1163 @@ +/** + * @file + * MDNS responder implementation - output related functionalities + */ + +/* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Author: Jasper Verschueren + * + */ + +#include "lwip/apps/mdns_out.h" +#include "lwip/apps/mdns_priv.h" +#include "lwip/apps/mdns_domain.h" +#include "lwip/prot/dns.h" +#include "lwip/prot/iana.h" +#include "lwip/udp.h" + +#include + +#if LWIP_IPV6 +#include "lwip/prot/ip6.h" +#endif + + +#if LWIP_MDNS_RESPONDER + +/* Function prototypes */ +static void mdns_clear_outmsg(struct mdns_outmsg *outmsg); + +/** + * Call user supplied function to setup TXT data + * @param service The service to build TXT record for + */ +void +mdns_prepare_txtdata(struct mdns_service *service) +{ + memset(&service->txtdata, 0, sizeof(struct mdns_domain)); + if (service->txt_fn) { + service->txt_fn(service, service->txt_userdata); + } +} + +/** + * Write a question to an outpacket + * A question contains domain, type and class. Since an answer also starts with these fields this function is also + * called from mdns_add_answer(). + * @param outpkt The outpacket to write to + * @param domain The domain name the answer is for + * @param type The DNS type of the answer (like 'AAAA', 'SRV') + * @param klass The DNS type of the answer (like 'IN') + * @param unicast If highest bit in class should be set, to instruct the responder to + * reply with a unicast packet + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_add_question(struct mdns_outpacket *outpkt, struct mdns_domain *domain, + u16_t type, u16_t klass, u16_t unicast) +{ + u16_t question_len; + u16_t field16; + err_t res; + + if (!outpkt->pbuf) { + /* If no pbuf is active, allocate one */ + outpkt->pbuf = pbuf_alloc(PBUF_TRANSPORT, MDNS_OUTPUT_PACKET_SIZE, PBUF_RAM); + if (!outpkt->pbuf) { + return ERR_MEM; + } + outpkt->write_offset = SIZEOF_DNS_HDR; + } + + /* Worst case calculation. Domain string might be compressed */ + question_len = domain->length + sizeof(type) + sizeof(klass); + if (outpkt->write_offset + question_len > outpkt->pbuf->tot_len) { + /* No space */ + return ERR_MEM; + } + + /* Write name */ + res = mdns_write_domain(outpkt, domain); + if (res != ERR_OK) { + return res; + } + + /* Write type */ + field16 = lwip_htons(type); + res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += sizeof(field16); + + /* Write class */ + if (unicast) { + klass |= 0x8000; + } + field16 = lwip_htons(klass); + res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += sizeof(field16); + + return ERR_OK; +} + +/** + * Write answer to reply packet. + * buf or answer_domain can be null. The rd_length written will be buf_length + + * size of (compressed) domain. Most uses will need either buf or answer_domain, + * special case is SRV that starts with 3 u16 and then a domain name. + * @param reply The outpacket to write to + * @param domain The domain name the answer is for + * @param type The DNS type of the answer (like 'AAAA', 'SRV') + * @param klass The DNS type of the answer (like 'IN') + * @param cache_flush If highest bit in class should be set, to instruct receiver that + * this reply replaces any earlier answer for this domain/type/class + * @param ttl Validity time in seconds to send out for IP address data in DNS replies + * @param buf Pointer to buffer of answer data + * @param buf_length Length of variable data + * @param answer_domain A domain to write after any buffer data as answer + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_add_answer(struct mdns_outpacket *reply, struct mdns_domain *domain, + u16_t type, u16_t klass, u16_t cache_flush, u32_t ttl, + const u8_t *buf, size_t buf_length, struct mdns_domain *answer_domain) +{ + u16_t answer_len; + u16_t field16; + u16_t rdlen_offset; + u16_t answer_offset; + u32_t field32; + err_t res; + + if (!reply->pbuf) { + /* If no pbuf is active, allocate one */ + reply->pbuf = pbuf_alloc(PBUF_TRANSPORT, MDNS_OUTPUT_PACKET_SIZE, PBUF_RAM); + if (!reply->pbuf) { + return ERR_MEM; + } + reply->write_offset = SIZEOF_DNS_HDR; + } + + /* Worst case calculation. Domain strings might be compressed */ + answer_len = domain->length + sizeof(type) + sizeof(klass) + sizeof(ttl) + sizeof(field16)/*rd_length*/; + if (buf) { + answer_len += (u16_t)buf_length; + } + if (answer_domain) { + answer_len += answer_domain->length; + } + if (reply->write_offset + answer_len > reply->pbuf->tot_len) { + /* No space */ + return ERR_MEM; + } + + /* Answer starts with same data as question, then more fields */ + mdns_add_question(reply, domain, type, klass, cache_flush); + + /* Write TTL */ + field32 = lwip_htonl(ttl); + res = pbuf_take_at(reply->pbuf, &field32, sizeof(field32), reply->write_offset); + if (res != ERR_OK) { + return res; + } + reply->write_offset += sizeof(field32); + + /* Store offsets and skip forward to the data */ + rdlen_offset = reply->write_offset; + reply->write_offset += sizeof(field16); + answer_offset = reply->write_offset; + + if (buf) { + /* Write static data */ + res = pbuf_take_at(reply->pbuf, buf, (u16_t)buf_length, reply->write_offset); + if (res != ERR_OK) { + return res; + } + reply->write_offset += (u16_t)buf_length; + } + + if (answer_domain) { + /* Write name answer (compressed if possible) */ + res = mdns_write_domain(reply, answer_domain); + if (res != ERR_OK) { + return res; + } + } + + /* Write rd_length after when we know the answer size */ + field16 = lwip_htons(reply->write_offset - answer_offset); + res = pbuf_take_at(reply->pbuf, &field16, sizeof(field16), rdlen_offset); + + return res; +} + +/** Write an ANY host question to outpacket */ +static err_t +mdns_add_any_host_question(struct mdns_outpacket *outpkt, + struct mdns_host *mdns, + u16_t request_unicast_reply) +{ + struct mdns_domain host; + mdns_build_host_domain(&host, mdns); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Adding host question for ANY type\n")); + return mdns_add_question(outpkt, &host, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, + request_unicast_reply); +} + +/** Write an ANY service instance question to outpacket */ +static err_t +mdns_add_any_service_question(struct mdns_outpacket *outpkt, + struct mdns_service *service, + u16_t request_unicast_reply) +{ + struct mdns_domain domain; + mdns_build_service_domain(&domain, service, 1); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Adding service instance question for ANY type\n")); + return mdns_add_question(outpkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, + request_unicast_reply); +} + +#if LWIP_IPV4 +/** Write an IPv4 address (A) RR to outpacket */ +static err_t +mdns_add_a_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct netif *netif) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain host; + mdns_build_host_domain(&host, netif_mdns_data(netif)); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with A record\n")); + return mdns_add_answer(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, msg->cache_flush, + ttl, (const u8_t *) netif_ip4_addr(netif), + sizeof(ip4_addr_t), NULL); +} + +/** Write a 4.3.2.1.in-addr.arpa -> hostname.local PTR RR to outpacket */ +static err_t +mdns_add_hostv4_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct netif *netif) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain host, revhost; + mdns_build_host_domain(&host, netif_mdns_data(netif)); + mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(netif)); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v4 PTR record\n")); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + msg->cache_flush, ttl, NULL, 0, &host); +} +#endif + +#if LWIP_IPV6 +/** Write an IPv6 address (AAAA) RR to outpacket */ +static err_t +mdns_add_aaaa_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct netif *netif, int addrindex) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain host; + mdns_build_host_domain(&host, netif_mdns_data(netif)); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with AAAA record\n")); + return mdns_add_answer(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, msg->cache_flush, + ttl, (const u8_t *) netif_ip6_addr(netif, addrindex), + sizeof(ip6_addr_p_t), NULL); +} + +/** Write a x.y.z.ip6.arpa -> hostname.local PTR RR to outpacket */ +static err_t +mdns_add_hostv6_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct netif *netif, int addrindex) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain host, revhost; + mdns_build_host_domain(&host, netif_mdns_data(netif)); + mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(netif, addrindex)); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v6 PTR record\n")); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + msg->cache_flush, ttl, NULL, 0, &host); +} +#endif + +/** Write an all-services -> servicetype PTR RR to outpacket */ +static err_t +mdns_add_servicetype_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct mdns_service *service) +{ + err_t res; + u32_t ttl = MDNS_TTL_4500; + struct mdns_domain service_type, service_dnssd; + mdns_build_service_domain(&service_type, service, 0); + mdns_build_dnssd_domain(&service_dnssd); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service type PTR record\n")); + return mdns_add_answer(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + 0, ttl, NULL, 0, &service_type); +} + +/** Write a servicetype -> servicename PTR RR to outpacket */ +static err_t +mdns_add_servicename_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct mdns_service *service) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain service_type, service_instance; + mdns_build_service_domain(&service_type, service, 0); + mdns_build_service_domain(&service_instance, service, 1); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service name PTR record\n")); + return mdns_add_answer(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + 0, ttl, NULL, 0, &service_instance); +} + +/** Write a SRV RR to outpacket */ +static err_t +mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct mdns_host *mdns, struct mdns_service *service) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain service_instance, srvhost; + u16_t srvdata[3]; + mdns_build_service_domain(&service_instance, service, 1); + mdns_build_host_domain(&srvhost, mdns); + if (msg->legacy_query) { + /* RFC 6762 section 18.14: + * In legacy unicast responses generated to answer legacy queries, + * name compression MUST NOT be performed on SRV records. + */ + srvhost.skip_compression = 1; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl. + * Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + srvdata[0] = lwip_htons(SRV_PRIORITY); + srvdata[1] = lwip_htons(SRV_WEIGHT); + srvdata[2] = lwip_htons(service->port); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with SRV record\n")); + return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, + msg->cache_flush, ttl, + (const u8_t *) &srvdata, sizeof(srvdata), &srvhost); +} + +/** Write a TXT RR to outpacket */ +static err_t +mdns_add_txt_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, + struct mdns_service *service) +{ + err_t res; + u32_t ttl = MDNS_TTL_120; + struct mdns_domain service_instance; + mdns_build_service_domain(&service_instance, service, 1); + mdns_prepare_txtdata(service); + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; + } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with TXT record\n")); + return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, + msg->cache_flush, ttl, (u8_t *) &service->txtdata.name, + service->txtdata.length, NULL); +} + + +static err_t +mdns_add_probe_questions_to_outpacket(struct mdns_outpacket *outpkt, struct mdns_outmsg *msg, + struct netif *netif) +{ + err_t res; + int i; + struct mdns_host *mdns = netif_mdns_data(netif); + + /* Write host questions (probing or legacy query) */ + if(msg->host_questions & QUESTION_PROBE_HOST_ANY) { + res = mdns_add_any_host_question(outpkt, mdns, 1); + if (res != ERR_OK) { + return res; + } + outpkt->questions++; + } + /* Write service questions (probing or legacy query) */ + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + struct mdns_service* service = mdns->services[i]; + if (!service) { + continue; + } + if(msg->serv_questions[i] & QUESTION_PROBE_SERVICE_NAME_ANY) { + res = mdns_add_any_service_question(outpkt, service, 1); + if (res != ERR_OK) { + return res; + } + outpkt->questions++; + } + } + return ERR_OK; +} + +#if LWIP_MDNS_SEARCH +static err_t +mdns_add_query_question_to_outpacket(struct mdns_outpacket *outpkt, struct mdns_outmsg *msg) +{ + err_t res; + /* Write legacy query question */ + if(msg->query) { + struct mdns_request *req = msg->query; + struct mdns_domain dom; + /* Build question domain */ + mdns_build_request_domain(&dom, req, req->name[0]); + /* Add query question to output packet */ + res = mdns_add_question(outpkt, &dom, req->qtype, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + outpkt->questions++; + } + return ERR_OK; +} +#endif + +/** + * Create packet with chosen answers as a reply + * + * Add all selected answers / questions + * Add additional answers based on the selected answers + */ +err_t +mdns_create_outpacket(struct netif *netif, struct mdns_outmsg *msg, + struct mdns_outpacket *outpkt) +{ + struct mdns_host *mdns = netif_mdns_data(netif); + struct mdns_service *service; + err_t res; + int i; + u16_t answers = 0; + +#if LWIP_MDNS_SEARCH + res = mdns_add_query_question_to_outpacket(outpkt, msg); + if (res != ERR_OK) { + return res; + } +#endif + + res = mdns_add_probe_questions_to_outpacket(outpkt, msg, netif); + if (res != ERR_OK) { + return res; + } + + /* Write answers to host questions */ +#if LWIP_IPV4 + if (msg->host_replies & REPLY_HOST_A) { + res = mdns_add_a_answer(outpkt, msg, netif); + if (res != ERR_OK) { + return res; + } + answers++; + } + if (msg->host_replies & REPLY_HOST_PTR_V4) { + res = mdns_add_hostv4_ptr_answer(outpkt, msg, netif); + if (res != ERR_OK) { + return res; + } + answers++; + } +#endif +#if LWIP_IPV6 + if (msg->host_replies & REPLY_HOST_AAAA) { + int addrindex; + for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addrindex))) { + res = mdns_add_aaaa_answer(outpkt, msg, netif, addrindex); + if (res != ERR_OK) { + return res; + } + answers++; + } + } + } + if (msg->host_replies & REPLY_HOST_PTR_V6) { + u8_t rev_addrs = msg->host_reverse_v6_replies; + int addrindex = 0; + while (rev_addrs) { + if (rev_addrs & 1) { + res = mdns_add_hostv6_ptr_answer(outpkt, msg, netif, addrindex); + if (res != ERR_OK) { + return res; + } + answers++; + } + addrindex++; + rev_addrs >>= 1; + } + } +#endif + + /* Write answers to service questions */ + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + service = mdns->services[i]; + if (!service) { + continue; + } + + if (msg->serv_replies[i] & REPLY_SERVICE_TYPE_PTR) { + res = mdns_add_servicetype_ptr_answer(outpkt, msg, service); + if (res != ERR_OK) { + return res; + } + answers++; + } + + if (msg->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { + res = mdns_add_servicename_ptr_answer(outpkt, msg, service); + if (res != ERR_OK) { + return res; + } + answers++; + } + + if (msg->serv_replies[i] & REPLY_SERVICE_SRV) { + res = mdns_add_srv_answer(outpkt, msg, mdns, service); + if (res != ERR_OK) { + return res; + } + answers++; + } + + if (msg->serv_replies[i] & REPLY_SERVICE_TXT) { + res = mdns_add_txt_answer(outpkt, msg, service); + if (res != ERR_OK) { + return res; + } + answers++; + } + } + + /* if this is a response, the data above is anwers, else this is a probe and + * the answers above goes into auth section */ + if (msg->flags & DNS_FLAG1_RESPONSE) { + outpkt->answers += answers; + } else { + outpkt->authoritative += answers; + } + + /* All answers written, add additional RRs */ + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + service = mdns->services[i]; + if (!service) { + continue; + } + + if (msg->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { + /* Our service instance requested, include SRV & TXT + * if they are already not requested. */ + if (!(msg->serv_replies[i] & REPLY_SERVICE_SRV)) { + res = mdns_add_srv_answer(outpkt, msg, mdns, service); + if (res != ERR_OK) { + return res; + } + outpkt->additional++; + } + + if (!(msg->serv_replies[i] & REPLY_SERVICE_TXT)) { + res = mdns_add_txt_answer(outpkt, msg, service); + if (res != ERR_OK) { + return res; + } + outpkt->additional++; + } + } + + /* If service instance, SRV, record or an IP address is requested, + * supply all addresses for the host + */ + if ((msg->serv_replies[i] & (REPLY_SERVICE_NAME_PTR | REPLY_SERVICE_SRV)) || + (msg->host_replies & (REPLY_HOST_A | REPLY_HOST_AAAA))) { +#if LWIP_IPV6 + if (!(msg->host_replies & REPLY_HOST_AAAA)) { + int addrindex; + for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addrindex))) { + res = mdns_add_aaaa_answer(outpkt, msg, netif, addrindex); + if (res != ERR_OK) { + return res; + } + outpkt->additional++; + } + } + } +#endif +#if LWIP_IPV4 + if (!(msg->host_replies & REPLY_HOST_A) && + !ip4_addr_isany_val(*netif_ip4_addr(netif))) { + res = mdns_add_a_answer(outpkt, msg, netif); + if (res != ERR_OK) { + return res; + } + outpkt->additional++; + } +#endif + } + } + + return res; +} + +/** + * Send chosen answers as a reply + * + * Create the packet + * Send the packet + */ +err_t +mdns_send_outpacket(struct mdns_outmsg *msg, struct netif *netif) +{ + struct mdns_outpacket outpkt; + err_t res; + + memset(&outpkt, 0, sizeof(outpkt)); + + res = mdns_create_outpacket(netif, msg, &outpkt); + if (res != ERR_OK) { + goto cleanup; + } + + if (outpkt.pbuf) { + struct dns_hdr hdr; + + /* Write header */ + memset(&hdr, 0, sizeof(hdr)); + hdr.flags1 = msg->flags; + hdr.numquestions = lwip_htons(outpkt.questions); + hdr.numanswers = lwip_htons(outpkt.answers); + hdr.numauthrr = lwip_htons(outpkt.authoritative); + hdr.numextrarr = lwip_htons(outpkt.additional); + hdr.id = lwip_htons(msg->tx_id); + pbuf_take(outpkt.pbuf, &hdr, sizeof(hdr)); + + /* Shrink packet */ + pbuf_realloc(outpkt.pbuf, outpkt.write_offset); + + /* Send created packet */ + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Sending packet, len=%d\n", + outpkt.write_offset)); + + res = udp_sendto_if(get_mdns_pcb(), outpkt.pbuf, &msg->dest_addr, msg->dest_port, netif); + } + +cleanup: + if (outpkt.pbuf) { + pbuf_free(outpkt.pbuf); + outpkt.pbuf = NULL; + } + return res; +} + +#if LWIP_IPV4 +/** + * Called by timeouts when timer is passed, allows multicast IPv4 traffic again. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_timeout_reset_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout finished - IPv4\n")); + + mdns->ipv4.multicast_timeout = 0; +} + +/** + * Called by timeouts when timer is passed, allows direct multicast IPv4 probe + * response traffic again and sends out probe response if one was pending + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_probe_timeout_reset_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv4\n")); + + mdns->ipv4.multicast_probe_timeout = 0; + + if (mdns->ipv4.multicast_msg_waiting) { + res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv4\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv4\n")); + mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast); + mdns->ipv4.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv4(netif); + } + } +} + +/** + * Called by timeouts when timer is passed, allows to send an answer on a QU + * question via multicast. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_timeout_25ttl_reset_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl finished - IPv4\n")); + + mdns->ipv4.multicast_timeout_25TTL = 0; +} + +/** + * Called by timeouts when timer is passed, sends out delayed multicast IPv4 response. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_send_multicast_msg_delayed_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send failed - IPv4\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv4\n")); + mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast); + mdns->ipv4.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv4(netif); + } +} + +/** + * Called by timeouts when timer is passed, sends out delayed unicast IPv4 response. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_send_unicast_msg_delayed_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_unicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send failed - IPv4\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send successful - IPv4\n")); + mdns_clear_outmsg(&mdns->ipv4.delayed_msg_unicast); + mdns->ipv4.unicast_msg_in_use = 0; + } +} + +/** Start all multicast timeouts for IPv4 + * Timeouts started: + * - do not multicast within one second + * - do not multicast a probe response within 250ms + * - send a multicast answer on a QU question if not send recently. + * + * @param netif network interface to start timeouts on + */ +void +mdns_start_multicast_timeouts_ipv4(struct netif *netif) +{ + struct mdns_host *mdns = netif_mdns_data(netif); + + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4, + &mdns->ipv4.multicast_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv4, + &mdns->ipv4.multicast_probe_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv4\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4, + &mdns->ipv4.multicast_timeout_25TTL); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n")); +} +#endif + +#if LWIP_IPV6 +/** + * Called by timeouts when timer is passed, allows multicast IPv6 traffic again. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_timeout_reset_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout finished - IPv6\n")); + + mdns->ipv6.multicast_timeout = 0; +} + +/** + * Called by timeouts when timer is passed, allows direct multicast IPv6 probe + * response traffic again and sends out probe response if one was pending + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_probe_timeout_reset_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv6\n")); + + mdns->ipv6.multicast_probe_timeout = 0; + + if (mdns->ipv6.multicast_msg_waiting) { + res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv6\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv6\n")); + mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast); + mdns->ipv6.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv6(netif); + } + } +} + +/** + * Called by timeouts when timer is passed, allows to send an answer on a QU + * question via multicast. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_timeout_25ttl_reset_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl finished - IPv6\n")); + + mdns->ipv6.multicast_timeout_25TTL = 0; +} + +/** + * Called by timeouts when timer is passed, sends out delayed multicast IPv6 response. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_send_multicast_msg_delayed_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send failed - IPv6\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv6\n")); + mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast); + mdns->ipv6.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv6(netif); + } +} + +/** + * Called by timeouts when timer is passed, sends out delayed unicast IPv6 response. + * + * @param arg pointer to netif of timeout. + */ +void +mdns_send_unicast_msg_delayed_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_unicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send failed - IPv6\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send successful - IPv6\n")); + mdns_clear_outmsg(&mdns->ipv6.delayed_msg_unicast); + mdns->ipv6.unicast_msg_in_use = 0; + } +} + +/** Start all multicast timeouts for IPv6 + * Timeouts started: + * - do not multicast within one second + * - do not multicast a probe response within 250ms + * - send a multicast answer on a QU question if not send recently. + * + * @param netif network interface to start timeouts on + */ +void +mdns_start_multicast_timeouts_ipv6(struct netif *netif) +{ + struct mdns_host *mdns = netif_mdns_data(netif); + + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6, + &mdns->ipv6.multicast_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv6, + &mdns->ipv6.multicast_probe_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv6\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6, + &mdns->ipv6.multicast_timeout_25TTL); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n")); +} +#endif + +/** + * This function clears the output message without changing the destination + * address or port. This is useful for clearing the delayed msg structs without + * losing the set IP. + * + * @param outmsg pointer to output message to clear. + */ +static void +mdns_clear_outmsg(struct mdns_outmsg *outmsg) +{ + int i; + + outmsg->tx_id = 0; + outmsg->flags = 0; + outmsg->cache_flush = 0; + outmsg->unicast_reply_requested = 0; + outmsg->legacy_query = 0; + outmsg->probe_query_recv = 0; + outmsg->host_questions = 0; + outmsg->host_replies = 0; + outmsg->host_reverse_v6_replies = 0; + + for(i = 0; i < MDNS_MAX_SERVICES; i++) { + outmsg->serv_questions[i] = 0; + outmsg->serv_replies[i] = 0; + } +} + +/** + * Sets a timer that calls the handler when finished. + * Depending on the busy_flag the timer is restarted or started. The flag is + * set before return. Sys_timeout does not give us this functionality. + * + * @param netif Network interface info + * @param msecs Time value to set + * @param handler Callback function to call + * @param busy_flag Pointer to flag that displays if the timer is running or not. + */ +void +mdns_set_timeout(struct netif *netif, u32_t msecs, sys_timeout_handler handler, + u8_t *busy_flag) +{ + if(*busy_flag) { + /* restart timer */ + sys_untimeout(handler, netif); + sys_timeout(msecs, handler, netif); + } + else { + /* start timer */ + sys_timeout(msecs, handler, netif); + } + /* Now we have a timer running */ + *busy_flag = 1; +} + +#ifdef LWIP_MDNS_SEARCH +/** + * Send search request containing all our known data + * @param req The request to send + * @param netif The network interface to send on + * @param destination The target address to send to (usually multicast address) + */ +err_t +mdns_send_request(struct mdns_request *req, struct netif *netif, const ip_addr_t *destination) +{ + struct mdns_outmsg outmsg; + err_t res; + + memset(&outmsg, 0, sizeof(outmsg)); + outmsg.query = req; + outmsg.dest_port = LWIP_IANA_PORT_MDNS; + SMEMCPY(&outmsg.dest_addr, destination, sizeof(outmsg.dest_addr)); + res = mdns_send_outpacket(&outmsg, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast query request send failed\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast query request send successful\n")); + } + return res; +} +#endif + +#endif /* LWIP_MDNS_RESPONDER */ diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 595da77..af4b331 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -318,7 +318,7 @@ mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); - /* Iterate trough queue to find head, and count total timeout time */ + /* Iterate through queue to find head, and count total timeout time */ for (iter = *tail; iter != NULL; iter = iter->next) { time_before += iter->timeout_diff; head = iter; @@ -603,14 +603,13 @@ mqtt_cyclic_timer(void *arg) } /* If time for a keep alive message to be sent, transmission has been idle for keep_alive time */ + client->cyclic_tick++; if ((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= client->keep_alive) { LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_cyclic_timer: Sending keep-alive message to server\n")); if (mqtt_output_check_space(&client->output, 0) != 0) { mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0, 0); client->cyclic_tick = 0; } - } else { - client->cyclic_tick++; } } } else { @@ -653,7 +652,7 @@ pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos * @param result Result code from server */ static void -mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) +mqtt_incoming_suback(struct mqtt_request_t *r, u8_t result) { if (r->cb != NULL) { r->cb(r->arg, result < 3 ? ERR_OK : ERR_ABRT); @@ -669,13 +668,11 @@ mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) * @param remaining_length Remaining length of complete message */ static mqtt_connection_status_t -mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u32_t remaining_length) +mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u32_t remaining_length, + u8_t *var_hdr_payload) { mqtt_connection_status_t res = MQTT_CONNECT_ACCEPTED; - u8_t *var_hdr_payload = client->rx_buffer + fixed_hdr_len; - size_t var_hdr_payload_bufsize = sizeof(client->rx_buffer) - fixed_hdr_len; - /* Control packet type */ u8_t pkt_type = MQTT_CTL_PACKET_TYPE(client->rx_buffer[0]); u16_t pkt_id = 0; @@ -698,7 +695,7 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u client->cyclic_tick = 0; client->conn_state = MQTT_CONNECTED; /* Notify upper layer */ - if (client->connect_cb != 0) { + if (client->connect_cb != NULL) { client->connect_cb(client, client->connect_arg, res); } } @@ -713,8 +710,9 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u u16_t payload_length = length; u8_t qos = MQTT_CTL_PACKET_QOS(client->rx_buffer[0]); - if (client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { - /* Should have topic and pkt id*/ + if (client->msg_idx == (u32_t)(fixed_hdr_len + length)) { + /* First publish message frame. Should have topic and pkt id*/ + size_t var_hdr_payload_bufsize = sizeof(client->rx_buffer) - fixed_hdr_len; u8_t *topic; u16_t after_topic; u8_t bkp; @@ -759,7 +757,7 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u payload_length = length - after_topic; payload_offset = after_topic; - LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_incomming_publish: Received message with QoS %d at topic: %s, payload length %"U32_F"\n", + LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_incoming_publish: Received message with QoS %d at topic: %s, payload length %"U32_F"\n", qos, topic, remaining_length + payload_length)); if (client->pub_cb != NULL) { client->pub_cb(client->inpub_arg, (const char *)topic, remaining_length + payload_length); @@ -779,12 +777,16 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u if (remaining_length == 0 && qos > 0) { /* Send PUBACK for QoS 1 or PUBREC for QoS 2 */ u8_t resp_msg = (qos == 1) ? MQTT_MSG_TYPE_PUBACK : MQTT_MSG_TYPE_PUBREC; - LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_incomming_publish: Sending publish response: %s with pkt_id: %d\n", + LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_incoming_publish: Sending publish response: %s with pkt_id: %d\n", mqtt_msg_type_to_str(resp_msg), client->inpub_pkt_id)); pub_ack_rec_rel_response(client, resp_msg, client->inpub_pkt_id, 0); } } } else { + if (length < 2) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,( "mqtt_message_received: Received short message\n")); + goto out_disconnect; + } /* Get packet identifier */ pkt_id = (u16_t)var_hdr_payload[0] << 8; pkt_id |= (u16_t)var_hdr_payload[1]; @@ -810,7 +812,7 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_len, u16_t length, u LWIP_DEBUGF(MQTT_DEBUG_WARN, ("mqtt_message_received: To small SUBACK packet\n")); goto out_disconnect; } else { - mqtt_incomming_suback(r, var_hdr_payload[2]); + mqtt_incoming_suback(r, var_hdr_payload[2]); } } else if (r->cb != NULL) { r->cb(r->arg, ERR_OK); @@ -871,7 +873,7 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_parse_incoming: Remaining length after fixed header: %"U32_F"\n", msg_rem_len)); if (msg_rem_len == 0) { /* Complete message with no extra headers of payload received */ - mqtt_message_received(client, fixed_hdr_len, 0, 0); + mqtt_message_received(client, fixed_hdr_len, 0, 0, NULL); client->msg_idx = 0; fixed_hdr_len = 0; } else { @@ -884,6 +886,8 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) } else { /* Fixed header has been parsed, parse variable header */ u16_t cpy_len, buffer_space; + u8_t *var_hdr_payload; + mqtt_connection_status_t res; /* Allow to copy the lesser one of available length in input data or bytes remaining in message */ cpy_len = (u16_t)LWIP_MIN((u16_t)(p->tot_len - in_offset), msg_rem_len); @@ -893,7 +897,13 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) if (cpy_len > buffer_space) { cpy_len = buffer_space; } - pbuf_copy_partial(p, client->rx_buffer + fixed_hdr_len, cpy_len, in_offset); + /* Adjust cpy_len to ensure zero-copy operation for remaining parts of current message */ + if (client->msg_idx >= MQTT_VAR_HEADER_BUFFER_LEN) { + if (cpy_len > (p->len - in_offset)) + cpy_len = p->len - in_offset; + } + var_hdr_payload = (u8_t*)pbuf_get_contiguous(p, client->rx_buffer + fixed_hdr_len, + buffer_space, cpy_len, in_offset); /* Advance get and put indexes */ client->msg_idx += cpy_len; @@ -901,18 +911,16 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) msg_rem_len -= cpy_len; LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_parse_incoming: msg_idx: %"U32_F", cpy_len: %"U16_F", remaining %"U32_F"\n", client->msg_idx, cpy_len, msg_rem_len)); - if ((msg_rem_len == 0) || (cpy_len == buffer_space)) { - /* Whole message received or buffer is full */ - mqtt_connection_status_t res = mqtt_message_received(client, fixed_hdr_len, cpy_len, msg_rem_len); - if (res != MQTT_CONNECT_ACCEPTED) { - return res; - } - if (msg_rem_len == 0) { - /* Reset parser state */ - client->msg_idx = 0; - /* msg_tot_len = 0; */ - fixed_hdr_len = 0; - } + /* Whole or partial message received */ + res = mqtt_message_received(client, fixed_hdr_len, cpy_len, msg_rem_len, var_hdr_payload); + if (res != MQTT_CONNECT_ACCEPTED) { + return res; + } + if (msg_rem_len == 0) { + /* Reset parser state */ + client->msg_idx = 0; + /* msg_tot_len = 0; */ + fixed_hdr_len = 0; } } } @@ -1012,7 +1020,7 @@ mqtt_tcp_err_cb(void *arg, err_t err) LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_tcp_err_cb: TCP error callback: error %d, arg: %p\n", err, arg)); LWIP_ASSERT("mqtt_tcp_err_cb: client != NULL", client != NULL); /* Set conn to null before calling close as pcb is already deallocated*/ - client->conn = 0; + client->conn = NULL; mqtt_close(client, MQTT_CONNECT_DISCONNECTED); } @@ -1163,7 +1171,7 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ * @param client MQTT client * @param topic topic to subscribe to * @param qos Quality of service, 0 1 or 2 (only used for subscribe) - * @param cb Callback to call when subscribe/unsubscribe reponse is received + * @param cb Callback to call when subscribe/unsubscribe response is received * @param arg User supplied argument to publish callback * @param sub 1 for subscribe, 0 for unsubscribe * @return ERR_OK if successful, @see err_t enum for other results @@ -1289,6 +1297,9 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, u16_t remaining_length = 2 + 4 + 1 + 1 + 2; u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; u16_t client_user_len = 0, client_pass_len = 0; + mqtt_incoming_data_cb_t data_cb; + mqtt_incoming_publish_cb_t pub_cb; + void *inpub_arg; LWIP_ASSERT_CORE_LOCKED(); LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL); @@ -1301,8 +1312,15 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, return ERR_ISCONN; } - /* Wipe clean */ + /* Wipe clean, but keep callbacks */ + data_cb = client->data_cb; + pub_cb = client->pub_cb; + inpub_arg = client->inpub_arg; memset(client, 0, sizeof(mqtt_client_t)); + client->data_cb = data_cb; + client->pub_cb = pub_cb; + client->inpub_arg = inpub_arg; + client->connect_arg = arg; client->connect_cb = cb; client->keep_alive = client_info->keep_alive; @@ -1319,9 +1337,16 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, LWIP_ERROR("mqtt_client_connect: client_info->will_topic length overflow", len <= 0xFF, return ERR_VAL); LWIP_ERROR("mqtt_client_connect: client_info->will_topic length must be > 0", len > 0, return ERR_VAL); will_topic_len = (u8_t)len; - len = strlen(client_info->will_msg); - LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL); - will_msg_len = (u8_t)len; + if (client_info->will_msg_len == 0) + { + len = strlen(client_info->will_msg); + LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL); + will_msg_len = (u8_t)len; + } + else + { + will_msg_len = client_info->will_msg_len; + } len = remaining_length + 2 + will_topic_len + 2 + will_msg_len; LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); remaining_length = (u16_t)len; diff --git a/src/apps/netbiosns/netbiosns.c b/src/apps/netbiosns/netbiosns.c index 479c375..4b1383e 100644 --- a/src/apps/netbiosns/netbiosns.c +++ b/src/apps/netbiosns/netbiosns.c @@ -391,7 +391,7 @@ netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t resp->resp_hdr.authorityRRs = 0; resp->resp_hdr.additionalRRs = 0; - /* prepare NetBIOS header datas */ + /* prepare NetBIOS header data */ MEMCPY( resp->resp_name.encname, netbios_question_hdr->encname, sizeof(netbios_question_hdr->encname)); resp->resp_name.nametype = netbios_question_hdr->nametype; resp->resp_name.type = netbios_question_hdr->type; diff --git a/src/apps/smtp/smtp.c b/src/apps/smtp/smtp.c index 55303c3..498af7f 100644 --- a/src/apps/smtp/smtp.c +++ b/src/apps/smtp/smtp.c @@ -1,12 +1,12 @@ /** * @file * SMTP client module - * + * * Author: Simon Goldschmidt * * @defgroup smtp SMTP client * @ingroup apps - * + * * This is simple SMTP client for raw API. * It is a minimal implementation of SMTP as specified in RFC 5321. * @@ -29,7 +29,7 @@ * When using from any other thread than the tcpip_thread (for NO_SYS==0), use * smtp_send_mail_int()! - * + * * SMTP_BODYDH usage: @code{.c} int my_smtp_bodydh_fn(void *arg, struct smtp_bodydh *bdh) @@ -42,11 +42,11 @@ ++bdh->state; return BDH_WORKING; } - - smtp_send_mail_bodycback("sender", "recipient", "subject", + + smtp_send_mail_bodycback("sender", "recipient", "subject", my_smtp_bodydh_fn, my_smtp_result_fn, some_argument); @endcode - * + * * @todo: * - attachments (the main difficulty here is streaming base64-encoding to * prevent having to allocate a buffer for the whole encoded file at once) @@ -577,7 +577,7 @@ leave: * @param body email body (must be NULL-terminated) * @param callback_fn callback function * @param callback_arg user argument to callback_fn - * @returns - ERR_OK if structures were allocated and no error occured starting the connection + * @returns - ERR_OK if structures were allocated and no error occurred starting the connection * (this does not mean the email has been successfully sent!) * - another err_t on error. */ @@ -1305,7 +1305,7 @@ smtp_process(void *arg, struct altcp_pcb *pcb, struct pbuf *p) LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code)); if (smtp_is_response_finished(s) != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code)); - /* wait for next packet to complete the respone */ + /* wait for next packet to complete the response */ return; } } else { @@ -1498,7 +1498,6 @@ smtp_send_mail_bodycback(const char *from, const char* to, const char* subject, LWIP_ASSERT("string is too long", len <= 0xffff); s->subject_len = (u16_t)len; s->body = NULL; - LWIP_ASSERT("string is too long", len <= 0xffff); s->callback_fn = callback_fn; s->callback_arg = callback_arg; s->bodydh->callback_fn = bodycback_fn; diff --git a/src/apps/snmp/snmp_core.c b/src/apps/snmp/snmp_core.c index 987f106..fc64c42 100644 --- a/src/apps/snmp/snmp_core.c +++ b/src/apps/snmp/snmp_core.c @@ -36,14 +36,14 @@ /** * @defgroup snmp SNMPv2c/v3 agent * @ingroup apps - * SNMPv2c and SNMPv3 compatible agent\n - * There is also a MIB compiler and a MIB viewer in lwIP contrib repository - * (lwip-contrib/apps/LwipMibCompiler).\n + * SNMPv2c and SNMPv3 compatible agent
    + * There is also a MIB compiler and a MIB viewer in lwIP/contrib subdir + * (lwip/contrib/apps/LwipMibCompiler).
    * The agent implements the most important MIB2 MIBs including IPv6 support * (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version - * without IPv6 statistics (TODO).\n + * without IPv6 statistics (TODO).
    * Rewritten by Martin Hentschel and - * Dirk Ziegelmeier \n + * Dirk Ziegelmeier * * 0 Agent Capabilities * ==================== @@ -69,12 +69,15 @@ * * MIB compiler (code generator): * ------------------------------ - * - Provided in lwIP contrib repository. - * - Written in C#. MIB viewer used Windows Forms. + * - Provided in contrib dir. + * - Written in C#. MIB viewer using Windows Forms. * - Developed on Windows with Visual Studio 2010. * - Can be compiled and used on all platforms with http://www.monodevelop.com/. * - Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4) * (https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate). + * This has been the last known revision of that code before being converted to + * closed source. The new code on github has completely changed, so we can not + * just update :-( * - MIB parser, C file generation framework and LWIP code generation are cleanly * separated, which means the code may be useful as a base for code generation * of other SNMP agents. @@ -111,7 +114,7 @@ * tables is not possible. * * Note lwIP has a very limited notion of IP routing. It currently - * doen't have a route table and doesn't have a notion of the U,G,H flags. + * doesn't have a route table and doesn't have a notion of the U,G,H flags. * Instead lwIP uses the interface list with only one default interface * acting as a single gateway interface (G) for the default route. * @@ -235,7 +238,7 @@ static struct snmp_mib const *const *snmp_mibs = default_mibs; void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL)); LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0)); snmp_mibs = mibs; @@ -258,7 +261,7 @@ snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs) */ void snmp_set_device_enterprise_oid(const struct snmp_obj_id *device_enterprise_oid) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); if (device_enterprise_oid == NULL) { snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; } else { @@ -272,7 +275,7 @@ void snmp_set_device_enterprise_oid(const struct snmp_obj_id *device_enterprise_ */ const struct snmp_obj_id *snmp_get_device_enterprise_oid(void) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); return snmp_device_enterprise_oid; } @@ -581,7 +584,7 @@ snmp_oid_prefix(struct snmp_obj_id *target, const u32_t *oid, u8_t oid_len) /** * Combine two OIDs into struct snmp_obj_id - * @param target Assignmet target + * @param target Assignment target * @param oid1 OID 1 * @param oid1_len OID 1 length * @param oid2 OID 2 @@ -934,7 +937,7 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida /* there is no further (suitable) node inside this MIB, search for the next MIB with following priority 1. search for inner MIB's (whose root is located inside tree of current MIB) - 2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any + 2. search for surrounding MIB's (where the current MIB is the inner MIB) and continue there if any 3. take the next closest MIB (not being related to the current MIB) */ const struct snmp_mib *next_mib; @@ -1053,7 +1056,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi if (oid_offset >= oid_len) { - /* passed oid references a tree node -> return first useable sub node of it */ + /* passed oid references a tree node -> return first usable sub node of it */ subnode_oid = 0; } else { subnode_oid = *(oid + oid_offset) + 1; @@ -1123,7 +1126,7 @@ snmp_next_oid_init(struct snmp_next_oid_state *state, } /** checks if the passed incomplete OID may be a possible candidate for snmp_next_oid_check(); -this methid is intended if the complete OID is not yet known but it is very expensive to build it up, +this method is intended if the complete OID is not yet known but it is very expensive to build it up, so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/ u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len) @@ -1279,9 +1282,9 @@ snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value) * get/test/set methods. * * @param buf points to a buffer where the resulting ASN1 octet string is stored to - * @param buf_len max length of the bufffer + * @param buf_len max length of the buffer * @param bit_value Bit value to encode with Bit0 == LSB - * @param bit_count Number of possible bits for the bit value (according to rfc we have to send all bits independant from their truth value) + * @param bit_count Number of possible bits for the bit value (according to rfc we have to send all bits independent from their truth value) * @return number of bytes used from buffer to store the resulting OctetString */ u8_t diff --git a/src/apps/snmp/snmp_core_priv.h b/src/apps/snmp/snmp_core_priv.h index 9532c05..e432318 100644 --- a/src/apps/snmp/snmp_core_priv.h +++ b/src/apps/snmp/snmp_core_priv.h @@ -44,6 +44,14 @@ extern "C" { #endif +#if !defined LWIP_ASSERT_SNMP_LOCKED +#if SNMP_USE_RAW +#define LWIP_ASSERT_SNMP_LOCKED() LWIP_ASSERT_CORE_LOCKED() +#else +#define LWIP_ASSERT_SNMP_LOCKED() +#endif +#endif + /* (outdated) SNMPv1 error codes * shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request */ diff --git a/src/apps/snmp/snmp_mib2_ip.c b/src/apps/snmp/snmp_mib2_ip.c index 6931049..57cf0f5 100644 --- a/src/apps/snmp/snmp_mib2_ip.c +++ b/src/apps/snmp/snmp_mib2_ip.c @@ -263,7 +263,7 @@ ip_AddrTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_ /* find netif with requested ip */ NETIF_FOREACH(netif) { - if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) { + if (ip4_addr_eq(&ip, netif_ip4_addr(netif))) { /* fill in object properties */ return ip_AddrTable_get_cell_value_core(netif, column, value, value_len); } @@ -417,7 +417,7 @@ ip_RouteTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row ip4_addr_t dst; ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif)); - if (ip4_addr_cmp(&dst, &test_ip)) { + if (ip4_addr_eq(&dst, &test_ip)) { /* fill in object properties */ return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len); } @@ -535,7 +535,7 @@ ip_NetToMediaTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_ struct eth_addr *ethaddr; if (etharp_get_entry(i, &ip, &netif, ðaddr)) { - if ((netif_index == netif_to_num(netif)) && ip4_addr_cmp(&ip_in, ip)) { + if ((netif_index == netif_to_num(netif)) && ip4_addr_eq(&ip_in, ip)) { /* fill in object properties */ return ip_NetToMediaTable_get_cell_value_core(i, column, value, value_len); } diff --git a/src/apps/snmp/snmp_mib2_tcp.c b/src/apps/snmp/snmp_mib2_tcp.c index 8a321f3..a23143e 100644 --- a/src/apps/snmp/snmp_mib2_tcp.c +++ b/src/apps/snmp/snmp_mib2_tcp.c @@ -227,17 +227,17 @@ tcp_ConnTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row while (pcb != NULL) { /* do local IP and local port match? */ if (IP_IS_V4_VAL(pcb->local_ip) && - ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) { + ip4_addr_eq(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) { /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */ if (pcb->state == LISTEN) { - if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) { + if (ip4_addr_eq(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) { /* fill in object properties */ return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); } } else { if (IP_IS_V4_VAL(pcb->remote_ip) && - ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) { + ip4_addr_eq(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) { /* fill in object properties */ return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); } @@ -355,9 +355,9 @@ tcp_ConnectionTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8 pcb = *tcp_pcb_nonlisten_lists[i]; while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + if (ip_addr_eq(&local_ip, &pcb->local_ip) && (local_port == pcb->local_port) && - ip_addr_cmp(&remote_ip, &pcb->remote_ip) && + ip_addr_eq(&remote_ip, &pcb->remote_ip) && (remote_port == pcb->remote_port)) { /* fill in object properties */ return tcp_ConnectionTable_get_cell_value_core(column, pcb, value); @@ -454,7 +454,7 @@ tcp_ListenerTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t /* find tcp_pcb with requested ip and port*/ pcb = tcp_listen_pcbs.listen_pcbs; while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + if (ip_addr_eq(&local_ip, &pcb->local_ip) && (local_port == pcb->local_port)) { /* fill in object properties */ return tcp_ListenerTable_get_cell_value_core(column, value); diff --git a/src/apps/snmp/snmp_mib2_udp.c b/src/apps/snmp/snmp_mib2_udp.c index d0bd5de..2b57277 100644 --- a/src/apps/snmp/snmp_mib2_udp.c +++ b/src/apps/snmp/snmp_mib2_udp.c @@ -147,9 +147,9 @@ udp_endpointTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t /* find udp_pcb with requested ip and port*/ pcb = udp_pcbs; while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + if (ip_addr_eq(&local_ip, &pcb->local_ip) && (local_port == pcb->local_port) && - ip_addr_cmp(&remote_ip, &pcb->remote_ip) && + ip_addr_eq(&remote_ip, &pcb->remote_ip) && (remote_port == pcb->remote_port)) { /* fill in object properties */ return udp_endpointTable_get_cell_value_core(column, value); @@ -263,7 +263,7 @@ udp_Table_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid pcb = udp_pcbs; while (pcb != NULL) { if (IP_IS_V4_VAL(pcb->local_ip)) { - if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) { + if (ip4_addr_eq(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) { /* fill in object properties */ return udp_Table_get_cell_value_core(pcb, column, value, value_len); } diff --git a/src/apps/snmp/snmp_msg.c b/src/apps/snmp/snmp_msg.c index 0b6693a..f8c75bb 100644 --- a/src/apps/snmp/snmp_msg.c +++ b/src/apps/snmp/snmp_msg.c @@ -71,8 +71,11 @@ const char *snmp_community_write = SNMP_COMMUNITY_WRITE; /** SNMP community string for sending traps */ const char *snmp_community_trap = SNMP_COMMUNITY_TRAP; -snmp_write_callback_fct snmp_write_callback = NULL; -void *snmp_write_callback_arg = NULL; +snmp_write_callback_fct snmp_write_callback; +void *snmp_write_callback_arg; + +snmp_inform_callback_fct snmp_inform_callback; +void *snmp_inform_callback_arg; #if LWIP_SNMP_CONFIGURE_VERSIONS @@ -177,7 +180,7 @@ snmp_get_community(void) void snmp_set_community(const char *const community) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); snmp_community = community; } @@ -215,7 +218,7 @@ snmp_get_community_trap(void) void snmp_set_community_write(const char *const community) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); LWIP_ASSERT("community string must not be NULL", community != NULL); LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); snmp_community_write = community; @@ -232,7 +235,7 @@ snmp_set_community_write(const char *const community) void snmp_set_community_trap(const char *const community) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); snmp_community_trap = community; } @@ -244,11 +247,22 @@ snmp_set_community_trap(const char *const community) void snmp_set_write_callback(snmp_write_callback_fct write_callback, void *callback_arg) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); snmp_write_callback = write_callback; snmp_write_callback_arg = callback_arg; } +/** + * @ingroup snmp_core + * Callback fired on every received INFORM confirmation (get-response) + */ +void +snmp_set_inform_callback(snmp_inform_callback_fct inform_callback, void* callback_arg) +{ + snmp_inform_callback = inform_callback; + snmp_inform_callback_arg = callback_arg; +} + /* ----------------------------------------------------------------------- */ /* forward declarations */ /* ----------------------------------------------------------------------- */ @@ -284,6 +298,16 @@ snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t por err = snmp_parse_inbound_frame(&request); if (err == ERR_OK) { + if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_RESP) { + if (request.error_status == SNMP_ERR_NOERROR) { + /* If callback function has been defined call it. */ + if (snmp_inform_callback != NULL) { + snmp_inform_callback(&request, snmp_inform_callback_arg); + } + } + /* stop further handling of GET RESP PDU, we are an agent */ + return; + } err = snmp_prepare_outbound_frame(&request); if (err == ERR_OK) { @@ -304,7 +328,6 @@ snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t por struct snmp_varbind vb; vb.next = NULL; - vb.prev = NULL; vb.type = SNMP_ASN1_TYPE_COUNTER32; vb.value_len = sizeof(u32_t); @@ -623,7 +646,7 @@ snmp_process_getbulk_request(struct snmp_request *request) /* no more varbinds in request */ break; } else { - LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!")); + LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!\n")); request->error_status = SNMP_ERR_GENERROR; request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; } @@ -741,6 +764,7 @@ snmp_process_set_request(struct snmp_request *request) #define PARSE_ASSERT(cond, retValue) \ if (!(cond)) { \ LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ + LWIP_DEBUGF(SNMP_DEBUG, ("\n")); \ snmp_stats.inasnparseerrs++; \ return retValue; \ } @@ -748,6 +772,7 @@ snmp_process_set_request(struct snmp_request *request) #define BUILD_EXEC(code, retValue) \ if ((code) != ERR_OK) { \ LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ + LWIP_DEBUGF(SNMP_DEBUG, ("\n")); \ return retValue; \ } @@ -815,7 +840,7 @@ snmp_parse_inbound_frame(struct snmp_request *request) /* @todo: Differentiate read/write access */ strncpy((char *)request->community, snmp_community, SNMP_MAX_COMMUNITY_STR_LEN); request->community[SNMP_MAX_COMMUNITY_STR_LEN] = 0; /* ensure NULL termination (strncpy does NOT guarantee it!) */ - request->community_strlen = (u16_t)strnlen((char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN); + request->community_strlen = (u16_t)strlen((char *)request->community); /* RFC3414 globalData */ IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); @@ -1032,7 +1057,7 @@ snmp_parse_inbound_frame(struct snmp_request *request) IF_PARSE_EXEC(snmpv3_get_user((char *)request->msg_user_name, &auth, key, NULL, NULL)); IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, auth, hmac)); - if (memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) { + if (lwip_memcmp_consttime(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) { snmp_stats.wrongdigests++; request->msg_flags = SNMP_V3_NOAUTHNOPRIV; request->error_status = SNMP_ERR_AUTHORIZATIONERROR; @@ -1174,9 +1199,13 @@ snmp_parse_inbound_frame(struct snmp_request *request) /* SetRequest PDU */ snmp_stats.insetrequests++; break; + case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP): + /* GetResponse PDU */ + snmp_stats.ingetresponses++; + break; default: /* unsupported input PDU for this agent (no parse error) */ - LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ + LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d\n", tlv.type)); \ return ERR_ARG; } request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; @@ -1751,7 +1780,7 @@ snmp_complete_outbound_frame(struct snmp_request *request) if (request->error_status == SNMP_ERR_TOOBIG) { request->error_index = 0; /* defined by RFC 1157 */ } else if (request->error_index == 0) { - /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ + /* set index to varbind where error occurred (if not already set before, e.g. during GetBulk processing) */ request->error_index = request->inbound_varbind_enumerator.varbind_count; } } else { diff --git a/src/apps/snmp/snmp_netconn.c b/src/apps/snmp/snmp_netconn.c index 8850acb..70f8bfc 100644 --- a/src/apps/snmp/snmp_netconn.c +++ b/src/apps/snmp/snmp_netconn.c @@ -116,7 +116,6 @@ snmp_get_local_ip_for_dst(void *handle, const ip_addr_t *dst, ip_addr_t *result) void snmp_init(void) { - LWIP_ASSERT_CORE_LOCKED(); sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO); } diff --git a/src/apps/snmp/snmp_pbuf_stream.c b/src/apps/snmp/snmp_pbuf_stream.c index 42867fb..a6e319c 100644 --- a/src/apps/snmp/snmp_pbuf_stream.c +++ b/src/apps/snmp/snmp_pbuf_stream.c @@ -135,7 +135,7 @@ snmp_pbuf_stream_writeto(struct snmp_pbuf_stream *pbuf_stream, struct snmp_pbuf_ err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream *pbuf_stream, s32_t offset) { - if ((offset < 0) || (offset > pbuf_stream->length)) { + if (((pbuf_stream->offset + offset) < 0) || (offset > pbuf_stream->length)) { /* we cannot seek backwards or forward behind stream end */ return ERR_ARG; } diff --git a/src/apps/snmp/snmp_snmpv2_usm.c b/src/apps/snmp/snmp_snmpv2_usm.c index 7490c9c..4cc73d3 100644 --- a/src/apps/snmp/snmp_snmpv2_usm.c +++ b/src/apps/snmp/snmp_snmpv2_usm.c @@ -62,7 +62,7 @@ static const struct snmp_obj_id *snmp_auth_algo_to_oid(snmpv3_auth_algo_t algo) if (algo == SNMP_V3_AUTH_ALGO_MD5) { return &usmHMACMD5AuthProtocol; } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { - return &usmHMACMD5AuthProtocol; + return &usmHMACSHAAuthProtocol; } return &usmNoAuthProtocol; diff --git a/src/apps/snmp/snmp_threadsync.c b/src/apps/snmp/snmp_threadsync.c index 56d9886..927c62a 100644 --- a/src/apps/snmp/snmp_threadsync.c +++ b/src/apps/snmp/snmp_threadsync.c @@ -176,7 +176,7 @@ do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *ins struct threadsync_data *call_data = &threadsync_node->instance->data; if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) { - LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID")); + LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID\n")); return SNMP_ERR_NOSUCHINSTANCE; } diff --git a/src/apps/snmp/snmp_traps.c b/src/apps/snmp/snmp_traps.c index 3c9c817..465fb9c 100644 --- a/src/apps/snmp/snmp_traps.c +++ b/src/apps/snmp/snmp_traps.c @@ -1,6 +1,6 @@ /** * @file - * SNMPv1 traps implementation. + * SNMPv1 and SNMPv2 traps implementation. */ /* @@ -51,7 +51,11 @@ #include "snmp_asn1.h" #include "snmp_core_priv.h" -struct snmp_msg_trap { +#define SNMP_IS_INFORM 1 +#define SNMP_IS_TRAP 0 + +struct snmp_msg_trap +{ /* source enterprise ID (sysObjectID) */ const struct snmp_obj_id *enterprise; /* source IP address, raw network order format */ @@ -74,16 +78,30 @@ struct snmp_msg_trap { u16_t seqlen; /* encoding varbinds sequence length */ u16_t vbseqlen; + + /* error status */ + s32_t error_status; + /* error index */ + s32_t error_index; + /* trap or inform? */ + u8_t trap_or_inform; }; static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds); static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len); static err_t snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); static err_t snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds); +static u16_t snmp_trap_header_sum_v1_specific(struct snmp_msg_trap *trap); +static u16_t snmp_trap_header_sum_v2c_specific(struct snmp_msg_trap *trap); +static err_t snmp_trap_header_enc_v1_specific(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); +static err_t snmp_trap_header_enc_v2c_specific(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); +static err_t snmp_prepare_trap_oid(struct snmp_obj_id *dest_snmp_trap_oid, const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap); +static void snmp_prepare_necessary_msg_fields(struct snmp_msg_trap *trap_msg, const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); +static err_t snmp_send_msg(struct snmp_msg_trap *trap_msg, struct snmp_varbind *varbinds, u16_t tot_len, ip_addr_t *dip); #define BUILD_EXEC(code) \ if ((code) != ERR_OK) { \ - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound trap frame!")); \ + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound trap frame!\n")); \ return ERR_ARG; \ } @@ -92,7 +110,12 @@ extern const char *snmp_community_trap; void *snmp_traps_handle; -struct snmp_trap_dst { +/** + * @ingroup snmp_traps + * @struct snmp_trap_dst + */ +struct snmp_trap_dst +{ /* destination IP address in network order */ ip_addr_t dip; /* set to 0 when disabled, >0 when enabled */ @@ -102,16 +125,23 @@ static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; static u8_t snmp_auth_traps_enabled = 0; +/* This is used in functions like snmp_coldstart_trap where user didn't specify which version of trap to use */ +static u8_t snmp_default_trap_version = SNMP_VERSION_1; + +/* This is used in trap messages v2c */ +static s32_t req_id = 1; + /** * @ingroup snmp_traps * Sets enable switch for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param enable switch if 0 destination is disabled >0 enabled. + * */ void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); if (dst_idx < SNMP_TRAP_DESTINATIONS) { trap_dst[dst_idx].enable = enable; } @@ -122,11 +152,12 @@ snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) * Sets IPv4 address for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param dst IPv4 address in host order. + * */ void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst) { - LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT_SNMP_LOCKED(); if (dst_idx < SNMP_TRAP_DESTINATIONS) { ip_addr_set(&trap_dst[dst_idx].dip, dst); } @@ -135,6 +166,9 @@ snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst) /** * @ingroup snmp_traps * Enable/disable authentication traps + * + * @param enable enable SNMP traps + * */ void snmp_set_auth_traps_enabled(u8_t enable) @@ -145,6 +179,8 @@ snmp_set_auth_traps_enabled(u8_t enable) /** * @ingroup snmp_traps * Get authentication traps enabled state + * + * @return TRUE if traps are enabled, FALSE if they aren't */ u8_t snmp_get_auth_traps_enabled(void) @@ -152,11 +188,144 @@ snmp_get_auth_traps_enabled(void) return snmp_auth_traps_enabled; } +/** + * @ingroup snmp_traps + * Choose default SNMP version for sending traps (if not specified, default version is SNMP_VERSION_1) + * SNMP_VERSION_1 0 + * SNMP_VERSION_2c 1 + * SNMP_VERSION_3 3 + * + * @param snmp_version version that will be used for sending traps + * + */ +void +snmp_set_default_trap_version(u8_t snmp_version) +{ + snmp_default_trap_version = snmp_version; +} + +/** + * @ingroup snmp_traps + * Get default SNMP version for sending traps + * + * @return selected default version: + * 0 - SNMP_VERSION_1 + * 1 - SNMP_VERSION_2c + * 3 - SNMP_VERSION_3 + */ +u8_t +snmp_get_default_trap_version(void) +{ + return snmp_default_trap_version; +} + +/** + * @ingroup snmp_traps + * Prepares snmpTrapOID for SNMP v2c + * @param dest_snmp_trap_oid pointer to destination snmpTrapOID + * @param eoid enterprise oid (can be NULL) + * @param generic_trap SNMP v1 generic trap + * @param specific_trap SNMP v1 specific trap + * @return ERR_OK if completed successfully; + * ERR_MEM if there wasn't enough memory allocated for destination; + * ERR_VAL if value for generic trap was incorrect; + */ +static err_t +snmp_prepare_trap_oid(struct snmp_obj_id *dest_snmp_trap_oid, const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap) +{ + err_t err = ERR_OK; + const u32_t snmpTrapOID[] = {1, 3, 6, 1, 6, 3, 1, 1, 5}; /* please see rfc3584 */ + + if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) { + if (eoid == NULL) { + MEMCPY(dest_snmp_trap_oid, snmp_get_device_enterprise_oid(), sizeof(*dest_snmp_trap_oid)); + } else { + MEMCPY(dest_snmp_trap_oid, eoid, sizeof(*dest_snmp_trap_oid)); + } + if (dest_snmp_trap_oid->len + 2 < SNMP_MAX_OBJ_ID_LEN) { + dest_snmp_trap_oid->id[dest_snmp_trap_oid->len++] = 0; + dest_snmp_trap_oid->id[dest_snmp_trap_oid->len++] = specific_trap; + } else { + err = ERR_MEM; + } + } else if ((generic_trap >= SNMP_GENTRAP_COLDSTART) && (generic_trap < SNMP_GENTRAP_ENTERPRISE_SPECIFIC)) { + if (sizeof(dest_snmp_trap_oid->id) >= sizeof(snmpTrapOID)) { + MEMCPY(&dest_snmp_trap_oid->id, snmpTrapOID , sizeof(snmpTrapOID)); + dest_snmp_trap_oid->len = LWIP_ARRAYSIZE(snmpTrapOID); + dest_snmp_trap_oid->id[dest_snmp_trap_oid->len++] = specific_trap + 1; + } else { + err = ERR_MEM; + } + } else { + err = ERR_VAL; + } + return err; +} + +/** + * @ingroup snmp_traps + * Prepare the rest of the necessary fields for trap/notification/inform message. + * @param trap_msg message that should be set + * @param eoid enterprise oid (can be NULL) + * @param generic_trap SNMP v1 generic trap + * @param specific_trap SNMP v1 specific trap + * @param varbinds list of varbinds + */ +static void +snmp_prepare_necessary_msg_fields(struct snmp_msg_trap *trap_msg, const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) +{ + if (trap_msg->snmp_version == SNMP_VERSION_1) { + trap_msg->enterprise = (eoid == NULL) ? snmp_get_device_enterprise_oid() : eoid; + trap_msg->gen_trap = generic_trap; + trap_msg->spc_trap = (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) ? specific_trap : 0; + MIB2_COPY_SYSUPTIME_TO(&trap_msg->ts); + } else if (trap_msg->snmp_version == SNMP_VERSION_2c) { + /* Copy sysUpTime into the first varbind */ + MIB2_COPY_SYSUPTIME_TO((u32_t *)varbinds[0].value); + } +} + +/** + * @ingroup snmp_traps + * Copy trap message structure to pbuf and sends it + * @param trap_msg contains the data that should be sent + * @param varbinds list of varbinds + * @param tot_len total length of encoded data + * @param dip destination IP address + * @return ERR_OK if sending was successful + */ +static err_t +snmp_send_msg(struct snmp_msg_trap *trap_msg, struct snmp_varbind *varbinds, u16_t tot_len, ip_addr_t *dip) +{ + err_t err = ERR_OK; + struct pbuf *p = NULL; + /* allocate pbuf(s) */ + p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM); + if (p != NULL) { + struct snmp_pbuf_stream pbuf_stream; + snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len); + + /* pass 1, encode packet ino the pbuf(s) */ + BUILD_EXEC( snmp_trap_header_enc(trap_msg, &pbuf_stream) ); + BUILD_EXEC( snmp_trap_varbind_enc(trap_msg, &pbuf_stream, varbinds) ); + + snmp_stats.outtraps++; + snmp_stats.outpkts++; + + /** send to the TRAP destination */ + err = snmp_sendto(snmp_traps_handle, p, dip, LWIP_IANA_PORT_SNMP_TRAP); + pbuf_free(p); + } else { + err = ERR_MEM; + } + return err; +} /** * @ingroup snmp_traps - * Sends a generic or enterprise specific trap message. + * Prepare and sends a generic or enterprise specific trap message, notification or inform. * + * @param trap_msg defines msg type * @param eoid points to enterprise object identifier * @param generic_trap is the trap code * @param specific_trap used for enterprise traps when generic_trap == 6 @@ -169,89 +338,144 @@ snmp_get_auth_traps_enabled(void) * and .iso.org.dod.internet.private.enterprises.yourenterprise * (sysObjectID) for specific traps. */ -err_t -snmp_send_trap(const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) +static err_t +snmp_send_trap_or_notification_or_inform_generic(struct snmp_msg_trap *trap_msg, const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) { - struct snmp_msg_trap trap_msg; - struct snmp_trap_dst *td; - struct pbuf *p; - u16_t i, tot_len; + struct snmp_trap_dst *td = NULL; + u16_t i = 0; + u16_t tot_len = 0; err_t err = ERR_OK; + u32_t timestamp = 0; + struct snmp_obj_id snmp_trap_oid = { 0 }; /* used for converting SNMPv1 generic/specific trap parameter to SNMPv2 snmpTrapOID */ + struct snmp_varbind snmp_v2_special_varbinds[] = { + /* First varbind is used to store sysUpTime */ + { + NULL, /* *next */ + { /* oid */ + 8, /* oid len */ + {1, 3, 6, 1, 2, 1, 1, 3} /* oid for sysUpTime */ + }, + SNMP_ASN1_TYPE_TIMETICKS, /* type */ + sizeof(u32_t), /* value_len */ + NULL /* value */ + }, + /* Second varbind is used to store snmpTrapOID */ + { + NULL, /* *next */ + { /* oid */ + 10, /* oid len */ + {1, 3, 6, 1, 6, 3, 1, 1, 4, 1} /* oid for snmpTrapOID */ + }, + SNMP_ASN1_TYPE_OBJECT_ID, /* type */ + 0, /* value_len */ + NULL /* value */ + } + }; + + LWIP_ASSERT_SNMP_LOCKED(); + + snmp_v2_special_varbinds[0].next = &snmp_v2_special_varbinds[1]; + + snmp_v2_special_varbinds[0].value = ×tamp; + + snmp_v2_special_varbinds[1].next = varbinds; + + /* see rfc3584 */ + if (trap_msg->snmp_version == SNMP_VERSION_2c) { + err = snmp_prepare_trap_oid(&snmp_trap_oid, eoid, generic_trap, specific_trap); + if (err == ERR_OK) { + snmp_v2_special_varbinds[1].value_len = snmp_trap_oid.len * sizeof(snmp_trap_oid.id[0]); + snmp_v2_special_varbinds[1].value = snmp_trap_oid.id; + varbinds = snmp_v2_special_varbinds; /* After inserting two varbinds at the beginning of the list, make sure that pointer is pointing to the first element */ + } + } - LWIP_ASSERT_CORE_LOCKED(); - - trap_msg.snmp_version = 0; - - for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) { + for (i = 0, td = &trap_dst[0]; (i < SNMP_TRAP_DESTINATIONS) && (err == ERR_OK); i++, td++) { if ((td->enable != 0) && !ip_addr_isany(&td->dip)) { /* lookup current source address for this dst */ - if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) { - if (eoid == NULL) { - trap_msg.enterprise = snmp_get_device_enterprise_oid(); - } else { - trap_msg.enterprise = eoid; - } - - trap_msg.gen_trap = generic_trap; - if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) { - trap_msg.spc_trap = specific_trap; - } else { - trap_msg.spc_trap = 0; - } - - MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts); + if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg->sip)) { + snmp_prepare_necessary_msg_fields(trap_msg, eoid, generic_trap, specific_trap, varbinds); /* pass 0, calculate length fields */ - tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds); - tot_len = snmp_trap_header_sum(&trap_msg, tot_len); - - /* allocate pbuf(s) */ - p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM); - if (p != NULL) { - struct snmp_pbuf_stream pbuf_stream; - snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len); - - /* pass 1, encode packet into the pbuf(s) */ - snmp_trap_header_enc(&trap_msg, &pbuf_stream); - snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds); - - snmp_stats.outtraps++; - snmp_stats.outpkts++; - - /** send to the TRAP destination */ - snmp_sendto(snmp_traps_handle, p, &td->dip, LWIP_IANA_PORT_SNMP_TRAP); - pbuf_free(p); - } else { - err = ERR_MEM; - } + tot_len = snmp_trap_varbind_sum(trap_msg, varbinds); + tot_len = snmp_trap_header_sum(trap_msg, tot_len); + + /* allocate pbuf, fill it and send it */ + err = snmp_send_msg(trap_msg, varbinds, tot_len, &td->dip); } else { /* routing error */ err = ERR_RTE; } } } + req_id++; return err; } +/** + * @ingroup snmp_traps + * This function is a wrapper function for preparing and sending generic or specific traps. + * + * @param oid points to enterprise object identifier + * @param generic_trap is the trap code + * @param specific_trap used for enterprise traps when generic_trap == 6 + * @param varbinds linked list of varbinds to be sent + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the use of the enterprise identifier field + * is per RFC1215. + * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps + * and .iso.org.dod.internet.private.enterprises.yourenterprise + * (sysObjectID) for specific traps. + */ +err_t +snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) +{ + struct snmp_msg_trap trap_msg = {0}; + trap_msg.snmp_version = snmp_default_trap_version; + trap_msg.trap_or_inform = SNMP_IS_TRAP; + return snmp_send_trap_or_notification_or_inform_generic(&trap_msg, oid, generic_trap, specific_trap, varbinds); +} + /** * @ingroup snmp_traps * Send generic SNMP trap + * @param generic_trap is the trap code + * return ERR_OK when success */ err_t snmp_send_trap_generic(s32_t generic_trap) { - static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } }; - return snmp_send_trap(&oid, generic_trap, 0, NULL); + err_t err = ERR_OK; + struct snmp_msg_trap trap_msg = {0}; + trap_msg.snmp_version = snmp_default_trap_version; + trap_msg.trap_or_inform = SNMP_IS_TRAP; + + if(snmp_default_trap_version == SNMP_VERSION_1) { + static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } }; + err = snmp_send_trap_or_notification_or_inform_generic(&trap_msg, &oid, generic_trap, 0, NULL); + } else if (snmp_default_trap_version == SNMP_VERSION_2c) { + err = snmp_send_trap_or_notification_or_inform_generic(&trap_msg, NULL, generic_trap, 0, NULL); + } else { + err = ERR_VAL; + } + return err; } /** * @ingroup snmp_traps * Send specific SNMP trap with variable bindings + * @param specific_trap used for enterprise traps (generic_trap = 6) + * @param varbinds linked list of varbinds to be sent + * @return ERR_OK when success */ err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds) { - return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds); + struct snmp_msg_trap trap_msg = {0}; + trap_msg.snmp_version = snmp_default_trap_version; + trap_msg.trap_or_inform = SNMP_IS_TRAP; + return snmp_send_trap_or_notification_or_inform_generic(&trap_msg, NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds); } /** @@ -276,6 +500,14 @@ snmp_authfail_trap(void) } } +/** + * @ingroup snmp_traps + * Sums trap varbinds + * + * @param trap Trap message + * @param varbinds linked list of varbinds + * @return the required length for encoding of this part of the trap header + */ static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds) { @@ -303,21 +535,18 @@ snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds) } /** - * Sums trap header field lengths from tail to head and - * returns trap_header_lengths for second encoding pass. + * @ingroup snmp_traps + * Sums trap header fields that are specific for SNMP v1 * * @param trap Trap message - * @param vb_len varbind-list length - * @return the required length for encoding the trap header + * @return the required length for encoding of this part of the trap header */ static u16_t -snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) +snmp_trap_header_sum_v1_specific(struct snmp_msg_trap *trap) { - u16_t tot_len; - u16_t len; - u8_t lenlen; - - tot_len = vb_len; + u16_t tot_len = 0; + u16_t len = 0; + u8_t lenlen = 0; snmp_asn1_enc_u32t_cnt(trap->ts, &len); snmp_asn1_enc_length_cnt(len, &lenlen); @@ -347,6 +576,57 @@ snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; + return tot_len; +} + +/** + * @ingroup snmp_traps + * Sums trap header fields that are specific for SNMP v2c + * + * @param trap Trap message + * @return the required length for encoding of this part of the trap header + */ +static u16_t +snmp_trap_header_sum_v2c_specific(struct snmp_msg_trap *trap) +{ + u16_t tot_len = 0; + u16_t len = 0; + u8_t lenlen = 0; + + snmp_asn1_enc_u32t_cnt(req_id, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + snmp_asn1_enc_u32t_cnt(trap->error_status, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + snmp_asn1_enc_u32t_cnt(trap->error_index, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + return tot_len; +} + +/** + * @ingroup snmp_traps + * Sums trap header field lengths from tail to head and + * returns trap_header_lengths for second encoding pass. + * + * @param trap Trap message + * @param vb_len varbind-list length + * @return the required length for encoding the trap header + */ +static u16_t +snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) +{ + u16_t tot_len = vb_len; + u16_t len = 0; + u8_t lenlen = 0; + + if (trap->snmp_version == SNMP_VERSION_1) { + tot_len += snmp_trap_header_sum_v1_specific(trap); + } else if (trap->snmp_version == SNMP_VERSION_2c) { + tot_len += snmp_trap_header_sum_v2c_specific(trap); + } trap->pdulen = tot_len; snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen); tot_len += 1 + lenlen; @@ -366,6 +646,14 @@ snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) return tot_len; } +/** + * @ingroup snmp_traps + * Encodes varbinds. + * @param trap Trap message + * @param pbuf_stream stream used for storing data inside pbuf + * @param varbinds linked list of varbinds + * @retval err_t ERR_OK if successful, ERR_ARG otherwise + */ static err_t snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds) { @@ -387,32 +675,44 @@ snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_ } /** - * Encodes trap header from head to tail. + * @ingroup snmp_traps + * Encodes trap header PDU part. + * @param trap Trap message + * @param pbuf_stream stream used for storing data inside pbuf + * @retval err_t ERR_OK if successful, ERR_ARG otherwise */ static err_t -snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) +snmp_trap_header_enc_pdu(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) { struct snmp_asn1_tlv tlv; - - /* 'Message' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); - BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - - /* version */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); - BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version) ); - - /* community */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); - BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen) ); - /* 'PDU' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); - BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + if (trap->snmp_version == SNMP_VERSION_1) { + /* TRAP V1 */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + } else if ((trap->snmp_version == SNMP_VERSION_2c) && (trap->trap_or_inform == SNMP_IS_INFORM)) { + /* TRAP v2 - INFORM */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_INFORM_REQ), 0, trap->pdulen); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + } else if (trap->snmp_version == SNMP_VERSION_2c) { + /* TRAP v2 - NOTIFICATION*/ + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_V2_TRAP), 0, trap->pdulen); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + } + + return ERR_OK; +} +/** + * @ingroup snmp_traps + * Encodes trap header part that is SNMP v1 header specific. + * @param trap Trap message + * @param pbuf_stream stream used for storing data inside pbuf + */ +static err_t +snmp_trap_header_enc_v1_specific(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) +{ + struct snmp_asn1_tlv tlv; /* object ID */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0); snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len); @@ -434,7 +734,7 @@ snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_s #endif } - /* trap length */ + /* generic trap */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len); BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); @@ -455,4 +755,124 @@ snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_s return ERR_OK; } +/** + * @ingroup snmp_traps + * Encodes trap header part that is SNMP v2c header specific. + * + * @param trap Trap message + * @param pbuf_stream stream used for storing data inside pbuf + */ +static err_t +snmp_trap_header_enc_v2c_specific(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) +{ + struct snmp_asn1_tlv tlv; + /* request id */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(req_id, &tlv.value_len); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, req_id) ); + + /* error status */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->error_status, &tlv.value_len); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->error_status) ); + + /* error index */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->error_index, &tlv.value_len); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->error_index) ); + + return ERR_OK; +} + +/** + * @ingroup snmp_traps + * Encodes trap header from head to tail. + * + * @param trap Trap message + * @param pbuf_stream stream used for storing data inside pbuf + */ +static err_t +snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) +{ + struct snmp_asn1_tlv tlv; + + /* 'Message' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + + /* version */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version) ); + + /* community */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); + BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen) ); + + /* PDU */ + BUILD_EXEC( snmp_trap_header_enc_pdu(trap, pbuf_stream) ); + if (trap->snmp_version == SNMP_VERSION_1) { + /* object ID, IP addr, generic trap, specific trap, timestamp */ + BUILD_EXEC( snmp_trap_header_enc_v1_specific(trap, pbuf_stream) ); + } else if (SNMP_VERSION_2c == trap->snmp_version) { + /* request id, error status, error index */ + BUILD_EXEC( snmp_trap_header_enc_v2c_specific(trap, pbuf_stream) ); + } + + return ERR_OK; +} + +/** + * @ingroup snmp_traps + * Wrapper function for sending informs + * @param specific_trap will be appended to enterprise oid [see RFC 3584] + * @param varbinds linked list of varbinds (at the beginning of this list function will insert 2 special purpose varbinds [see RFC 3584]) + * @param ptr_request_id [out] variable in which to store request_id needed to verify acknowledgement + * @return ERR_OK if successful + */ +err_t +snmp_send_inform_specific(s32_t specific_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id) +{ + return snmp_send_inform(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds, ptr_request_id); +} + +/** + * @ingroup snmp_traps + * Wrapper function for sending informs + * @param generic_trap is the trap code + * @param varbinds linked list of varbinds (at the beginning of this list function will insert 2 special purpose varbinds [see RFC 3584]) + * @param ptr_request_id [out] variable in which to store request_id needed to verify acknowledgement + * @return ERR_OK if successful + */ +err_t +snmp_send_inform_generic(s32_t generic_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id) +{ + return snmp_send_inform(NULL, generic_trap, 0, varbinds, ptr_request_id); +} + +/** + * @ingroup snmp_traps + * Generic function for sending informs + * @param oid points to object identifier + * @param generic_trap is the trap code + * @param specific_trap used for enterprise traps when generic_trap == 6 + * @param varbinds linked list of varbinds (at the beginning of this list function will insert 2 special purpose varbinds [see RFC 3584]) + * @param ptr_request_id [out] variable in which to store request_id needed to verify acknowledgement + * @return ERR_OK if successful + */ +err_t +snmp_send_inform(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id) +{ + struct snmp_msg_trap trap_msg = {0}; + trap_msg.snmp_version = SNMP_VERSION_2c; + trap_msg.trap_or_inform = SNMP_IS_INFORM; + *ptr_request_id = req_id; + return snmp_send_trap_or_notification_or_inform_generic(&trap_msg, oid, generic_trap, specific_trap, varbinds); +} + #endif /* LWIP_SNMP */ diff --git a/src/apps/sntp/sntp.c b/src/apps/sntp/sntp.c index 23731e5..3637530 100644 --- a/src/apps/sntp/sntp.c +++ b/src/apps/sntp/sntp.c @@ -42,6 +42,8 @@ * This is simple "SNTP" client for the lwIP raw API. * It is a minimal implementation of SNTPv4 as specified in RFC 4330. * + * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use SNTP! + * * For a list of some public NTP servers, see this link: * http://support.ntp.org/bin/view/Servers/NTPPoolServers * @@ -235,6 +237,9 @@ struct sntp_server { /** Reachability shift register as described in RFC 5905 */ u8_t reachability; #endif /* SNTP_MONITOR_SERVER_REACHABILITY */ +#if SNTP_SUPPORT_MULTIPLE_SERVERS + u8_t kod_received; +#endif }; static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; @@ -411,6 +416,10 @@ sntp_try_next_server(void *arg) if (sntp_current_server >= SNTP_MAX_SERVERS) { sntp_current_server = 0; } + if (sntp_servers[sntp_current_server].kod_received) { + /* KOD received, don't use this server */ + continue; + } if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) #if SNTP_SERVER_DNS || (sntp_servers[sntp_current_server].name != NULL) @@ -429,9 +438,18 @@ sntp_try_next_server(void *arg) sntp_current_server = old_server; sntp_retry(NULL); } + +static void +sntp_kod_try_next_server(void *arg) +{ + sntp_servers[sntp_current_server].kod_received = 1; + sntp_try_next_server(arg); +} + #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ /* Always retry on error if only one server is supported */ -#define sntp_try_next_server sntp_retry +#define sntp_try_next_server sntp_retry +#define sntp_kod_try_next_server sntp_retry #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ /** UDP recv callback for the sntp pcb */ @@ -449,7 +467,7 @@ sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, err = ERR_ARG; #if SNTP_CHECK_RESPONSE >= 1 /* check server address and port */ - if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && + if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_eq(addr, &sntp_last_server_address)) && (port == SNTP_PORT)) #else /* SNTP_CHECK_RESPONSE >= 1 */ LWIP_UNUSED_ARG(addr); @@ -528,7 +546,7 @@ sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, /* KOD errors are only processed in case of an explicit poll response */ if (sntp_opmode == SNTP_OPMODE_POLL) { /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ - sntp_try_next_server(NULL); + sntp_kod_try_next_server(NULL); } } else { /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */ @@ -787,6 +805,9 @@ sntp_setserver(u8_t idx, const ip_addr_t *server) if (idx < SNTP_MAX_SERVERS) { if (server != NULL) { sntp_servers[idx].addr = (*server); +#if SNTP_SUPPORT_MULTIPLE_SERVERS + sntp_servers[idx].kod_received = 0; +#endif } else { ip_addr_set_zero(&sntp_servers[idx].addr); } @@ -867,12 +888,34 @@ sntp_getserver(u8_t idx) return IP_ADDR_ANY; } +/** + * @ingroup sntp + * Check if a Kiss-of-Death has been received from this server (only valid for + * SNTP_MAX_SERVERS > 1). + * + * @param idx the index of the NTP server + * @return 1 if a KoD has been received, 0 if not. + */ +u8_t +sntp_getkodreceived(u8_t idx) +{ +#if SNTP_SUPPORT_MULTIPLE_SERVERS + if (idx < SNTP_MAX_SERVERS) { + return sntp_servers[idx].kod_received; + } +#else + LWIP_UNUSED_ARG(idx); +#endif + return 0; +} + #if SNTP_SERVER_DNS /** * Initialize one of the NTP servers by name * * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS - * @param server DNS name of the NTP server to set, to be resolved at contact time + * @param server DNS name of the NTP server to set, to be resolved at contact + * time. Note sntp stores the pointer, it doesn't copy the string. */ void sntp_setservername(u8_t idx, const char *server) @@ -880,6 +923,9 @@ sntp_setservername(u8_t idx, const char *server) LWIP_ASSERT_CORE_LOCKED(); if (idx < SNTP_MAX_SERVERS) { sntp_servers[idx].name = server; +#if SNTP_SUPPORT_MULTIPLE_SERVERS + sntp_servers[idx].kod_received = 0; +#endif } } diff --git a/src/apps/tftp/tftp_server.c b/src/apps/tftp/tftp.c similarity index 67% rename from src/apps/tftp/tftp_server.c rename to src/apps/tftp/tftp.c index e3f1512..aab1d9c 100644 --- a/src/apps/tftp/tftp_server.c +++ b/src/apps/tftp/tftp.c @@ -1,6 +1,6 @@ /** * - * @file tftp_server.c + * @file tftp.c * * @author Logan Gunthorpe * Dirk Ziegelmeier @@ -41,12 +41,14 @@ */ /** - * @defgroup tftp TFTP server + * @defgroup tftp TFTP client/server * @ingroup apps * - * This is simple TFTP server for the lwIP raw API. + * This is simple TFTP client/server for the lwIP raw API. + * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use TFTP! */ +#include "lwip/apps/tftp_client.h" #include "lwip/apps/tftp_server.h" #if LWIP_UDP @@ -88,6 +90,7 @@ struct tftp_state { u16_t blknum; u8_t retries; u8_t mode_write; + u8_t tftp_mode; }; static struct tftp_state tftp_state; @@ -114,64 +117,102 @@ close_handle(void) } } -static void +static struct pbuf* +init_packet(u16_t opcode, u16_t extra, size_t size) +{ + struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + size), PBUF_RAM); + u16_t* payload; + + if (p != NULL) { + payload = (u16_t*) p->payload; + payload[0] = PP_HTONS(opcode); + payload[1] = lwip_htons(extra); + } + + return p; +} + +static err_t +send_request(const ip_addr_t *addr, u16_t port, u16_t opcode, const char* fname, const char* mode) +{ + size_t fname_length = strlen(fname)+1; + size_t mode_length = strlen(mode)+1; + struct pbuf* p = init_packet(opcode, 0, fname_length + mode_length - 2); + char* payload; + err_t ret; + + if (p == NULL) { + return ERR_MEM; + } + + payload = (char*) p->payload; + MEMCPY(payload+2, fname, fname_length); + MEMCPY(payload+2+fname_length, mode, mode_length); + + ret = udp_sendto(tftp_state.upcb, p, addr, port); + pbuf_free(p); + return ret; +} + +static err_t send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str) { - int str_length = strlen(str); + size_t str_length = strlen(str); struct pbuf *p; u16_t *payload; + err_t ret; - p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM); + p = init_packet(TFTP_ERROR, code, str_length + 1); if (p == NULL) { - return; + return ERR_MEM; } payload = (u16_t *) p->payload; - payload[0] = PP_HTONS(TFTP_ERROR); - payload[1] = lwip_htons(code); MEMCPY(&payload[2], str, str_length + 1); - udp_sendto(tftp_state.upcb, p, addr, port); + ret = udp_sendto(tftp_state.upcb, p, addr, port); pbuf_free(p); + return ret; } -static void -send_ack(u16_t blknum) +static err_t +send_ack(const ip_addr_t *addr, u16_t port, u16_t blknum) { struct pbuf *p; - u16_t *payload; + err_t ret; - p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM); + p = init_packet(TFTP_ACK, blknum, 0); if (p == NULL) { - return; + return ERR_MEM; } - payload = (u16_t *) p->payload; - payload[0] = PP_HTONS(TFTP_ACK); - payload[1] = lwip_htons(blknum); - udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port); + ret = udp_sendto(tftp_state.upcb, p, addr, port); pbuf_free(p); + return ret; } -static void -resend_data(void) +static err_t +resend_data(const ip_addr_t *addr, u16_t port) { + err_t ret; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM); if (p == NULL) { - return; + return ERR_MEM; } - if (pbuf_copy(p, tftp_state.last_data) != ERR_OK) { + ret = pbuf_copy(p, tftp_state.last_data); + if (ret != ERR_OK) { pbuf_free(p); - return; + return ret; } - udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port); + ret = udp_sendto(tftp_state.upcb, p, addr, port); pbuf_free(p); + return ret; } static void -send_data(void) +send_data(const ip_addr_t *addr, u16_t port) { u16_t *payload; int ret; @@ -180,28 +221,26 @@ send_data(void) pbuf_free(tftp_state.last_data); } - tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM); + tftp_state.last_data = init_packet(TFTP_DATA, tftp_state.blknum, TFTP_MAX_PAYLOAD_SIZE); if (tftp_state.last_data == NULL) { return; } payload = (u16_t *) tftp_state.last_data->payload; - payload[0] = PP_HTONS(TFTP_DATA); - payload[1] = lwip_htons(tftp_state.blknum); ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE); if (ret < 0) { - send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file."); + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Error occurred while reading the file."); close_handle(); return; } pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret)); - resend_data(); + resend_data(addr, port); } static void -recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +tftp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { u16_t *sbuf = (u16_t *) p->payload; int opcode; @@ -210,7 +249,7 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 LWIP_UNUSED_ARG(upcb); if (((tftp_state.port != 0) && (port != tftp_state.port)) || - (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) { + (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_eq(&tftp_state.addr, addr))) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); pbuf_free(p); return; @@ -235,6 +274,11 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 break; } + if ((tftp_state.tftp_mode & LWIP_TFTP_MODE_SERVER) == 0) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "TFTP server not enabled"); + break; + } + sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); /* find \0 in pbuf -> end of filename string */ @@ -270,10 +314,10 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 if (opcode == PP_HTONS(TFTP_WRQ)) { tftp_state.mode_write = 1; - send_ack(0); + send_ack(addr, port, 0); } else { tftp_state.mode_write = 0; - send_data(); + send_data(addr, port); } break; @@ -302,7 +346,7 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file"); close_handle(); } else { - send_ack(blknum); + send_ack(addr, port, blknum); } if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) { @@ -312,7 +356,7 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 } } else if ((u16_t)(blknum + 1) == tftp_state.blknum) { /* retransmit of previous block, ack again (casting to u16_t to care for overflow) */ - send_ack(blknum); + send_ack(addr, port, blknum); } else { send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number"); } @@ -347,14 +391,20 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16 if (!lastpkt) { tftp_state.blknum++; - send_data(); + send_data(addr, port); } else { close_handle(); } break; } - + case PP_HTONS(TFTP_ERROR): + if (tftp_state.handle != NULL) { + pbuf_remove_header(p, TFTP_HEADER_LENGTH); + tftp_state.ctx->error(tftp_state.handle, sbuf[1], (const char*)p->payload, p->len); + close_handle(); + } + break; default: send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation"); break; @@ -379,7 +429,7 @@ tftp_tmr(void *arg) if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) { if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) { LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n")); - resend_data(); + resend_data(&tftp_state.addr, tftp_state.port); tftp_state.retries++; } else { LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n")); @@ -388,12 +438,13 @@ tftp_tmr(void *arg) } } -/** @ingroup tftp - * Initialize TFTP server. +/** + * Initialize TFTP client/server. + * @param mode TFTP mode (client/server) * @param ctx TFTP callback struct */ err_t -tftp_init(const struct tftp_context *ctx) +tftp_init_common(u8_t mode, const struct tftp_context *ctx) { err_t ret; @@ -415,14 +466,35 @@ tftp_init(const struct tftp_context *ctx) tftp_state.timer = 0; tftp_state.last_data = NULL; tftp_state.upcb = pcb; + tftp_state.tftp_mode = mode; - udp_recv(pcb, recv, NULL); + udp_recv(pcb, tftp_recv, NULL); return ERR_OK; } /** @ingroup tftp - * Deinitialize ("turn off") TFTP server. + * Initialize TFTP server. + * @param ctx TFTP callback struct + */ +err_t +tftp_init_server(const struct tftp_context *ctx) +{ + return tftp_init_common(LWIP_TFTP_MODE_SERVER, ctx); +} + +/** @ingroup tftp + * Initialize TFTP client. + * @param ctx TFTP callback struct + */ +err_t +tftp_init_client(const struct tftp_context *ctx) +{ + return tftp_init_common(LWIP_TFTP_MODE_CLIENT, ctx); +} + +/** @ingroup tftp + * Deinitialize ("turn off") TFTP client/server. */ void tftp_cleanup(void) { @@ -432,4 +504,45 @@ void tftp_cleanup(void) memset(&tftp_state, 0, sizeof(tftp_state)); } +static const char * +mode_to_string(enum tftp_transfer_mode mode) +{ + if (mode == TFTP_MODE_OCTET) { + return "octet"; + } + if (mode == TFTP_MODE_NETASCII) { + return "netascii"; + } + if (mode == TFTP_MODE_BINARY) { + return "binary"; + } + return NULL; +} + +err_t +tftp_get(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode) +{ + LWIP_ERROR("TFTP client is not enabled (tftp_init)", (tftp_state.tftp_mode & LWIP_TFTP_MODE_CLIENT) != 0, return ERR_VAL); + LWIP_ERROR("tftp_get: invalid file name", fname != NULL, return ERR_VAL); + LWIP_ERROR("tftp_get: invalid mode", mode <= TFTP_MODE_BINARY, return ERR_VAL); + + tftp_state.handle = handle; + tftp_state.blknum = 1; + tftp_state.mode_write = 1; /* We want to receive data */ + return send_request(addr, port, TFTP_RRQ, fname, mode_to_string(mode)); +} + +err_t +tftp_put(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode) +{ + LWIP_ERROR("TFTP client is not enabled (tftp_init)", (tftp_state.tftp_mode & LWIP_TFTP_MODE_CLIENT) != 0, return ERR_VAL); + LWIP_ERROR("tftp_put: invalid file name", fname != NULL, return ERR_VAL); + LWIP_ERROR("tftp_put: invalid mode", mode <= TFTP_MODE_BINARY, return ERR_VAL); + + tftp_state.handle = handle; + tftp_state.blknum = 1; + tftp_state.mode_write = 0; /* We want to send data */ + return send_request(addr, port, TFTP_WRQ, fname, mode_to_string(mode)); +} + #endif /* LWIP_UDP */ diff --git a/src/core/altcp.c b/src/core/altcp.c index 4abef7c..9644e82 100644 --- a/src/core/altcp.c +++ b/src/core/altcp.c @@ -40,7 +40,7 @@ * * Replace "struct tcp_pcb" with "struct altcp_pcb" * * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link * against the altcp functions - * * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take + * * @ref altcp_new (and @ref altcp_new_ip_type / @ref altcp_new_ip6) take * an @ref altcp_allocator_t as an argument, whereas the original tcp API * functions take no arguments. * * An @ref altcp_allocator_t allocator is an object that holds a pointer to an @@ -75,7 +75,7 @@ * It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS * adaption). However, the parameters used to create it are defined in @ref * altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers - * and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth + * and @ref altcp_tls_create_config_client / @ref altcp_tls_create_config_client_2wayauth * for clients). * * For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and @@ -158,7 +158,7 @@ altcp_free(struct altcp_pcb *conn) /** * @ingroup altcp - * altcp_new_ip6: @ref altcp_new for IPv6 + * altcp_new_ip6: @ref altcp_new for IPv6 */ struct altcp_pcb * altcp_new_ip6(altcp_allocator_t *allocator) @@ -166,9 +166,9 @@ altcp_new_ip6(altcp_allocator_t *allocator) return altcp_new_ip_type(allocator, IPADDR_TYPE_V6); } -/** +/** * @ingroup altcp - * altcp_new: @ref altcp_new for IPv4 + * altcp_new: @ref altcp_new for IPv4 */ struct altcp_pcb * altcp_new(altcp_allocator_t *allocator) diff --git a/src/core/altcp_alloc.c b/src/core/altcp_alloc.c index cd619bc..06ed90d 100644 --- a/src/core/altcp_alloc.c +++ b/src/core/altcp_alloc.c @@ -1,6 +1,6 @@ /** * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n + * Application layered TCP connection API (to be used from TCPIP thread)
    * This interface mimics the tcp callback API to the application while preventing * direct linking (much like virtual functions). * This way, an application can make use of other application layer protocols diff --git a/src/core/altcp_tcp.c b/src/core/altcp_tcp.c index 1869e2a..4f21b70 100644 --- a/src/core/altcp_tcp.c +++ b/src/core/altcp_tcp.c @@ -1,6 +1,7 @@ /** * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n + * Application layered TCP connection API (to be used from TCPIP thread) + * * This interface mimics the tcp callback API to the application while preventing * direct linking (much like virtual functions). * This way, an application can make use of other application layer protocols @@ -74,7 +75,7 @@ static err_t altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err) { struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; - if (listen_conn && listen_conn->accept) { + if (new_tpcb && listen_conn && listen_conn->accept) { /* create a new altcp_conn to pass to the next 'accept' callback */ struct altcp_pcb *new_conn = altcp_alloc(); if (new_conn == NULL) { diff --git a/src/core/def.c b/src/core/def.c index 9da36fe..11ad31b 100644 --- a/src/core/def.c +++ b/src/core/def.c @@ -118,6 +118,29 @@ lwip_strnstr(const char *buffer, const char *token, size_t n) } #endif +#ifndef lwip_strnistr +/** + * @ingroup sys_nonstandard + * lwIP default implementation for strnistr() non-standard function. + * This can be \#defined to strnistr() depending on your platform port. + */ +char * +lwip_strnistr(const char *buffer, const char *token, size_t n) +{ + const char *p; + size_t tokenlen = strlen(token); + if (tokenlen == 0) { + return LWIP_CONST_CAST(char *, buffer); + } + for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { + if (lwip_strnicmp(p, token, tokenlen) == 0) { + return LWIP_CONST_CAST(char *, p); + } + } + return NULL; +} +#endif + #ifndef lwip_stricmp /** * @ingroup sys_nonstandard @@ -238,3 +261,26 @@ lwip_itoa(char *result, size_t bufsize, int number) memmove(res, tmp, (size_t)((result + bufsize) - tmp)); } #endif + +#ifndef lwip_memcmp_consttime +/** + * @ingroup sys_nonstandard + * The goal of this function is to compare memory with constant runtime in order to prevent + * timing attacks to various parts in the stack. + * To do that, in contrast to memcmp(), it only returns: + * 0: equal + * != 0: not equal + */ +int lwip_memcmp_consttime(const void* s1, const void* s2, size_t len) +{ + size_t i; + const unsigned char* a1 = (const unsigned char*)s1; + const unsigned char* a2 = (const unsigned char*)s2; + unsigned char ret = 0; + + for (i = 0; i < len; i++) { + ret |= a1[i] ^ a2[i]; + } + return ret; +} +#endif diff --git a/src/core/distributed_net/distributed_net.c b/src/core/distributed_net/distributed_net.c deleted file mode 100644 index f66240c..0000000 --- a/src/core/distributed_net/distributed_net.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/distributed_net/distributed_net.h" -#include "lwip/priv/sockets_priv.h" - -static sys_mutex_t g_mutex = {0}; - -static u8_t g_is_distributed_net_enabled = 0; - -static u16_t g_local_tcp_server_port = 0; - -static u16_t g_local_udp_server_port = 0; - -static u8_t g_is_distributed_net_socket[NUM_SOCKETS] = {0}; - -#if LWIP_DISTRIBUTED_NET_TRY_CONNECT -static int try_connect_to_local_tcp_server(u16_t tcp_port) -{ - struct sockaddr_in addr = {0}; - (void)memset_s(&addr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in)); - INIT_SOCK_ADDR(&addr, LOCAL_SERVER_IP, tcp_port); - - int sock = lwip_socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - return -1; - } - - int ret = lwip_connect_internal(sock, (struct sockaddr *)&addr, sizeof(addr)); - (void)lwip_close_internal(sock); - return ret; -} -#endif /* LWIP_DISTRIBUTED_NET_TRY_CONNECT */ - -void set_distributed_net_socket(int sock) -{ - int index = SOCKET_TO_INDEX(sock); - if (index >= 0 && index < NUM_SOCKETS) { - sys_mutex_lock(&g_mutex); - g_is_distributed_net_socket[index] = 1; - sys_mutex_unlock(&g_mutex); - } -} - -void reset_distributed_net_socket(int sock) -{ - int index = SOCKET_TO_INDEX(sock); - if (index >= 0 && index < NUM_SOCKETS) { - sys_mutex_lock(&g_mutex); - g_is_distributed_net_socket[index] = 0; - sys_mutex_unlock(&g_mutex); - } -} - -u16_t get_local_tcp_server_port(void) -{ - sys_mutex_lock(&g_mutex); - u16_t ret = g_local_tcp_server_port; - sys_mutex_unlock(&g_mutex); - return ret; -} - -u16_t get_local_udp_server_port(void) -{ - sys_mutex_lock(&g_mutex); - u16_t ret = g_local_udp_server_port; - sys_mutex_unlock(&g_mutex); - return ret; -} - -u8_t is_distributed_net_enabled(void) -{ - sys_mutex_lock(&g_mutex); - u8_t ret = g_is_distributed_net_enabled; - sys_mutex_unlock(&g_mutex); - return ret; -} - -int enable_distributed_net(u16_t tcp_port, u16_t udp_port) -{ - LWIP_DEBUGF(SOCKETS_DEBUG, ("enable distributed_net")); - if (is_distributed_net_enabled()) { - if (get_local_tcp_server_port() == tcp_port && get_local_udp_server_port() == udp_port) { - return 0; - } - set_errno(EINVAL); - return -1; - } - -#if LWIP_DISTRIBUTED_NET_TRY_CONNECT - if (try_connect_to_local_tcp_server(tcp_port) < 0) { - return -1; - } -#endif /* LWIP_DISTRIBUTED_NET_TRY_CONNECT */ - - sys_mutex_lock(&g_mutex); - g_is_distributed_net_enabled = 1; - g_local_tcp_server_port = tcp_port; - g_local_udp_server_port = udp_port; - sys_mutex_unlock(&g_mutex); - return 0; -} - -int disable_distributed_net(void) -{ - LWIP_DEBUGF(SOCKETS_DEBUG, ("disable distributed_net")); - sys_mutex_lock(&g_mutex); - for (int i = 0; i < NUM_SOCKETS; ++i) { - if (g_is_distributed_net_socket[i]) { - (void)lwip_close_internal(INDEX_TO_SOCKET(i)); - } - } - g_local_tcp_server_port = 0; - g_local_udp_server_port = 0; - g_is_distributed_net_enabled = 0; - (void)memset_s(g_is_distributed_net_socket, sizeof(g_is_distributed_net_socket), 0, - sizeof(g_is_distributed_net_socket)); - sys_mutex_unlock(&g_mutex); - return 0; -} - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ \ No newline at end of file diff --git a/src/core/distributed_net/distributed_net_core.c b/src/core/distributed_net/distributed_net_core.c deleted file mode 100644 index b0ede51..0000000 --- a/src/core/distributed_net/distributed_net_core.c +++ /dev/null @@ -1,260 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" -#include - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/distributed_net/distributed_net_core.h" -#include "lwip/distributed_net/distributed_net_utils.h" -#include "lwip/distributed_net/udp_transmit.h" -#include "lwip/priv/sockets_priv.h" - -int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t addr_len) -{ - CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); - CHECK_PARA(addr != NULL, EINVAL); - CHECK_PARA(addr_len > 0, EINVAL); - - struct sockaddr_in addr_in = {0}; - (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); - (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); - if (is_no_proxy_network_segment(&addr_in)) { - return lwip_connect_internal(sock, addr, addr_len); - } - - (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); - INIT_SOCK_ADDR(&addr_in, LOCAL_SERVER_IP, get_local_tcp_server_port()); -#if (defined(EMUI_WEB_CLIENT)) - DISTRIBUTED_NET_START_TCP_SERVER(); -#endif - if (lwip_connect_internal(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) { - if (errno != EINPROGRESS) { - return -1; - } - } - set_distributed_net_socket(sock); - - (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); - (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); - - tcp_connect_data data = {0}; - (void)memset_s(&data, sizeof(data), 0, sizeof(data)); - (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(addr_in.sin_addr)); - data.dest_port = ntohs(addr_in.sin_port); - - if (lwip_send(sock, &data, sizeof(data), 0) < 0) { - reset_distributed_net_socket(sock); - return -1; - } - return 0; -} - -int distributed_net_close(int sock) -{ - CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); - - reset_distributed_net_socket(sock); - return lwip_close_internal(sock); -} - -#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL -typedef union { - struct sockaddr sa; -#if LWIP_IPV6 - struct sockaddr_in6 sin6; -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - struct sockaddr_in sin; -#endif /* LWIP_IPV4 */ -} aligned_sockaddr; - -ssize_t distributed_net_sendto(int sock, const void *buf, size_t buf_len, int flags, const struct sockaddr *addr, - socklen_t addr_len) -{ - CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); - CHECK_PARA(buf != NULL, EINVAL); - CHECK_PARA(buf_len > 0, EINVAL); - - int type = 0; - socklen_t type_len = sizeof(type); - if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { - return -1; - } - - if (type != SOCK_DGRAM) { - return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len); - } - - struct sockaddr_in addr_in = {0}; - (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); - if (addr != NULL && addr_len != 0) { - (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); - } - - if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) { - set_errno(EPERM); - return -1; - } - - if (is_no_proxy_network_segment(&addr_in)) { - return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len); - } - - if (!IS_DNS_PORT(addr_in)) { - set_errno(EPERM); - return -1; - } - - ssize_t ret = udp_transmit_sendto(sock, buf, buf_len, &addr_in); - return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1; -} - -#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG -ssize_t distributed_net_sendmsg(int sock, const struct msghdr *hdr, int flags) -{ - CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); - CHECK_PARA(hdr != NULL, EINVAL); - CHECK_PARA(hdr->msg_iov != NULL, EINVAL); - CHECK_PARA(hdr->msg_iovlen > 0, EINVAL); - - int type = 0; - socklen_t type_len = sizeof(type); - if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { - return -1; - } - - if (type != SOCK_DGRAM) { - return lwip_sendmsg_internal(sock, hdr, flags); - } - - const struct sockaddr *addr = (const struct sockaddr *)hdr->msg_name; - socklen_t addr_len = hdr->msg_namelen; - - struct sockaddr_in addr_in = {0}; - (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); - if (addr != NULL && addr_len != 0) { - (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); - } - - if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) { - set_errno(EPERM); - return -1; - } - - if (is_no_proxy_network_segment(&addr_in)) { - return lwip_sendmsg_internal(sock, hdr, flags); - } - - if (!IS_DNS_PORT(addr_in)) { - set_errno(EPERM); - return -1; - } - - ssize_t ret = udp_transmit_sendmsg(sock, hdr); - return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1; -} -#endif /* LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG */ - -ssize_t distributed_net_recvfrom(int sock, void *buf, size_t buf_len, int flags, struct sockaddr *from, - socklen_t *from_len) -{ - CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); - CHECK_PARA(buf != NULL, EINVAL); - CHECK_PARA(buf_len > 0, EINVAL); - - int type = 0; - socklen_t type_len = sizeof(type); - if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { - return -1; - } - - if (type != SOCK_DGRAM) { - return lwip_recvfrom_internal(sock, buf, buf_len, flags, from, from_len); - } - - size_t new_buf_len = buf_len + sizeof(udp_data); - void *new_buf = mem_malloc(new_buf_len); - if (new_buf == NULL) { - set_errno(ENOMEM); - return -1; - } - - aligned_sockaddr addr_from = {0}; - socklen_t addr_from_len = sizeof(addr_from); - ssize_t ret = - lwip_recvfrom_internal(sock, new_buf, new_buf_len, flags, (struct sockaddr *)&addr_from, &addr_from_len); - if (ret <= 0) { - mem_free(new_buf); - return ret; - } - - if (!IS_LOCAL_UDP_SERVER_ADDR((struct sockaddr_in *)(&addr_from))) { - (void)memcpy_s(buf, buf_len, new_buf, ret); - if (from != NULL && from_len != NULL) { - if (*from_len > addr_from_len) { - *from_len = addr_from_len; - } - (void)memcpy_s(from, *from_len, &addr_from, *from_len); - mem_free(new_buf); - return ret; - } - } - - if (ret <= sizeof(udp_data)) { - mem_free(new_buf); - set_errno(EINVAL); - return -1; - } - - udp_data *data = (udp_data *)new_buf; - (void)memcpy_s(buf, buf_len, data->payload, ret - sizeof(udp_data)); - if (from != NULL && from_len != NULL) { - (void)memcpy_s(from, *from_len, &addr_from, MIN(addr_from_len, *from_len)); - if (*from_len >= sizeof(struct sockaddr_in) - SIN_ZERO_LEN) { - struct sockaddr_in *temp_addr = (struct sockaddr_in *)from; - INIT_SOCK_ADDR(temp_addr, data->dest_addr, data->dest_port); - if (*from_len > sizeof(struct sockaddr_in)) { - *from_len = sizeof(struct sockaddr_in); - } - } - } - - mem_free(new_buf); - return ret - (ssize_t)sizeof(udp_data); -} -#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ diff --git a/src/core/distributed_net/distributed_net_utils.c b/src/core/distributed_net/distributed_net_utils.c deleted file mode 100644 index 7ca803b..0000000 --- a/src/core/distributed_net/distributed_net_utils.c +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/distributed_net/distributed_net_utils.h" - -typedef struct no_proxy_network_segment { - const char *ip; - const in_addr_t mask_len; -} no_proxy_network_segment; - -static const no_proxy_network_segment g_special_network_segment[] = { - {"127.0.0.0", 8}, - {"192.0.0.0", 29}, - {"192.0.2.0", 24}, - {"192.168.0.0", 16}, - {"192.18.0.0", 15}, - {"192.51.100.0", 24}, - {"0.0.0.0", 8}, - {"100.64.0.0", 10}, - {"169.254.0.0", 16}, - {"172.16.0.0", 12}, - {"203.0.113.0", 24}, - {"224.0.0.0", 4}, - {"240.0.0.0", 4}, - {"10.0.0.0", 8}, - {"255.255.255.255", 32}, -}; - -static in_addr_t mask_len_to_mask(u32_t mask_len) -{ - if (mask_len > 32) { - return UINT_MAX; - } - u8_t num[4] = {0}; - for (int i = 0; i < 4; ++i) { - u32_t len = (mask_len > 8 ? 8 : mask_len); - if (len > 0) { - u8_t byte = 0x80;// binary 1000|0000 - u8_t bit = 0x80; // binary 1000|0000 - for (u32_t j = 0; j < len - 1; ++j) { - byte = (bit >> 1U) | byte; - bit >>= 1U; - } - num[i] = byte; - } - if (mask_len < 8) { - break; - } - mask_len -= 8; - } - int mask = 0; - (void)memcpy_s(&mask, sizeof(int), num, sizeof(int)); - return mask; -} - -u8_t is_no_proxy_network_segment(const struct sockaddr_in *addr_in) -{ - for (int i = 0; i < sizeof(g_special_network_segment) / sizeof(g_special_network_segment[0]); ++i) { - ip4_addr_t ip4_ip = {addr_in->sin_addr.s_addr}; - ip4_addr_t ip4_net_ip = {ipaddr_addr(g_special_network_segment[i].ip)}; - ip4_addr_t ip4_mask = {mask_len_to_mask(g_special_network_segment[i].mask_len)}; - - if (ip4_addr_netcmp(&ip4_ip, &ip4_net_ip, &ip4_mask)) { - return 1; - } - } - return 0; -} - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ \ No newline at end of file diff --git a/src/core/distributed_net/udp_transmit.c b/src/core/distributed_net/udp_transmit.c deleted file mode 100644 index f41d1cb..0000000 --- a/src/core/distributed_net/udp_transmit.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - -#include "lwip/distributed_net/udp_transmit.h" - -static s32_t get_msg_data_len(const struct msghdr *hdr) -{ - if (hdr->msg_iovlen > MAX_IOV_NUM) { - return -1; - } - - s32_t data_len = 0; - for (int i = 0; i < hdr->msg_iovlen; ++i) { - if (hdr->msg_iov[i].iov_len > MAX_UDP_PAYLOAD_LEN) { - set_errno(EMSGSIZE); - return -1; - } - data_len += (s32_t)hdr->msg_iov[i].iov_len; - if (data_len > MAX_UDP_PAYLOAD_LEN) { - set_errno(EMSGSIZE); - return -1; - } - } - - return data_len; -} - -ssize_t udp_transmit_sendto(int sock, const void *buf, size_t buf_len, const struct sockaddr_in *dest_addr) -{ - if (buf_len > MAX_UDP_PAYLOAD_LEN) { - set_errno(EMSGSIZE); - return -1; - } - - udp_data data = {0}; - (void)memset_s(&data, sizeof(data), 0, sizeof(data)); - (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(dest_addr->sin_addr)); - data.dest_port = ntohs(dest_addr->sin_port); - - struct iovec iov[2] = {0}; - (void)memset_s(iov, sizeof(iov), 0, sizeof(iov)); - iov[0].iov_base = (void *)&data; - iov[0].iov_len = sizeof(data); - iov[1].iov_base = (void *)buf; - iov[1].iov_len = buf_len; - - struct sockaddr_in transmit_addr = {0}; - (void)memset_s(&transmit_addr, sizeof(transmit_addr), 0, sizeof(transmit_addr)); - INIT_SOCK_ADDR(&transmit_addr, LOCAL_SERVER_IP, get_local_udp_server_port()); - - struct msghdr send_hdr = {0}; - (void)memset_s(&send_hdr, sizeof(send_hdr), 0, sizeof(send_hdr)); - SET_MSG_ADDR(&send_hdr, &transmit_addr, sizeof(transmit_addr)); - send_hdr.msg_iov = iov; - send_hdr.msg_iovlen = 2; - -#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG - return lwip_sendmsg_internal(sock, &send_hdr, 0); -#else - return lwip_sendmsg(sock, &send_hdr, 0); -#endif -} - -ssize_t udp_transmit_sendmsg(int sock, const struct msghdr *hdr) -{ - if (get_msg_data_len(hdr) < 0) { - return -1; - } - - struct sockaddr_in temp_addr_in = {0}; - (void)memset_s(&temp_addr_in, sizeof(temp_addr_in), 0, sizeof(temp_addr_in)); - (void)memcpy_s(&temp_addr_in, sizeof(temp_addr_in), hdr->msg_name, MIN(sizeof(temp_addr_in), hdr->msg_namelen)); - - udp_data data = {0}; - (void)memset_s(&data, sizeof(data), 0, sizeof(data)); - (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(temp_addr_in.sin_addr)); - data.dest_port = ntohs(temp_addr_in.sin_port); - - u32_t size = sizeof(struct iovec) * (hdr->msg_iovlen + 1); - struct iovec *iov = mem_malloc(size); - if (iov == NULL) { - set_errno(ENOMEM); - return -1; - } - (void)memset_s(iov, size, 0, size); - iov[0].iov_base = (void *)&data; - iov[0].iov_len = sizeof(data); - for (int i = 0; i < hdr->msg_iovlen; ++i) { - iov[i + 1].iov_base = hdr->msg_iov[i].iov_base; - iov[i + 1].iov_len = hdr->msg_iov[i].iov_len; - } - - struct sockaddr_in transmit_addr = {0}; - (void)memset_s(&transmit_addr, sizeof(transmit_addr), 0, sizeof(transmit_addr)); - INIT_SOCK_ADDR(&transmit_addr, LOCAL_SERVER_IP, get_local_udp_server_port()); - - struct msghdr send_hdr = {0}; - (void)memset_s(&send_hdr, sizeof(send_hdr), 0, sizeof(send_hdr)); - SET_MSG_ADDR(&send_hdr, &transmit_addr, sizeof(transmit_addr)); - send_hdr.msg_iov = iov; - send_hdr.msg_iovlen = hdr->msg_iovlen + 1; - -#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG - ssize_t ret = lwip_sendmsg_internal(sock, &send_hdr, 0); -#else - ssize_t ret = lwip_sendmsg(sock, &send_hdr, 0); -#endif - mem_free(iov); - return ret; -} - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ diff --git a/src/core/dns.c b/src/core/dns.c index 1a3326f..6540f14 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -86,11 +86,6 @@ #include "lwip/opt.h" -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL -#include "lwip/distributed_net/distributed_net.h" -#include "lwip/distributed_net/udp_transmit.h" -#endif - #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" @@ -282,7 +277,7 @@ DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ static void dns_init_local(void); -static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); +static err_t dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); #endif /* DNS_LOCAL_HOSTLIST */ @@ -324,10 +319,6 @@ dns_init(void) ip_addr_t dnsserver; DNS_SERVER_ADDRESS(&dnsserver); dns_setserver(0, &dnsserver); -#ifdef DNS_SERVER_ADDRESS_SECONDARY - DNS_SERVER_ADDRESS_SECONDARY(&dnsserver); - dns_setserver(1, &dnsserver); -#endif #endif /* DNS_SERVER_ADDRESS */ LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", @@ -407,31 +398,6 @@ dns_tmr(void) dns_check_entries(); } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -dns_tmr_tick(void) -{ - u32_t tick = 0; - u32_t val; - s32_t i; - - for (i = 0; i < DNS_TABLE_SIZE; i++) { - if ((dns_table[i].state == DNS_STATE_NEW) || - (dns_table[i].state == DNS_STATE_ASKING)) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "dns_tmr_tick")); - return 1; - } - if (dns_table[i].state == DNS_STATE_DONE) { - val = dns_table[i].ttl; - SET_TMR_TICK(tick, val); - } - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dns_tmr_tick", tick)); - return tick; -} -#endif - #if DNS_LOCAL_HOSTLIST static void dns_init_local(void) @@ -510,18 +476,32 @@ dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) err_t dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) { + size_t hostnamelen; LWIP_UNUSED_ARG(dns_addrtype); - return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); + if ((addr == NULL) || + (!hostname) || (!hostname[0])) { + return ERR_ARG; + } + hostnamelen = strlen(hostname); + if (hostname[hostnamelen - 1] == '.') { + hostnamelen--; + } + if (hostnamelen >= DNS_MAX_NAME_LENGTH) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_local_lookup: name too long to resolve\n")); + return ERR_ARG; + } + return dns_lookup_local(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); } /* Internal implementation for dns_local_lookup and dns_lookup */ static err_t -dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) { #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC struct local_hostlist_entry *entry = local_hostlist_dynamic; while (entry != NULL) { - if ((lwip_stricmp(entry->name, hostname) == 0) && + if ((lwip_strnicmp(entry->name, hostname, hostnamelen) == 0) && + !entry->name[hostnamelen] && LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { if (addr) { ip_addr_copy(*addr, entry->addr); @@ -533,7 +513,8 @@ dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_ #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ size_t i; for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { - if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && + if ((lwip_strnicmp(local_hostlist_static[i].name, hostname, hostnamelen) == 0) && + !local_hostlist_static[i].name[hostnamelen] && LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { if (addr) { ip_addr_copy(*addr, local_hostlist_static[i].addr); @@ -564,7 +545,7 @@ dns_local_removehost(const char *hostname, const ip_addr_t *addr) struct local_hostlist_entry *last_entry = NULL; while (entry != NULL) { if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && - ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { + ((addr == NULL) || ip_addr_eq(&entry->addr, addr))) { struct local_hostlist_entry *free_entry; if (last_entry != NULL) { last_entry->next = entry->next; @@ -627,30 +608,34 @@ dns_local_addhost(const char *hostname, const ip_addr_t *addr) * for a hostname. * * @param name the hostname to look up + * @param hostnamelen length of the hostname * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname * was not found in the cached dns_table. * @return ERR_OK if found, ERR_ARG if not found */ static err_t -dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) { + size_t namelen; u8_t i; #if DNS_LOCAL_HOSTLIST - if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + if (dns_lookup_local(name, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { return ERR_OK; } #endif /* DNS_LOCAL_HOSTLIST */ #ifdef DNS_LOOKUP_LOCAL_EXTERN - if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { + if (DNS_LOOKUP_LOCAL_EXTERN(name, hostnamelen, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { return ERR_OK; } #endif /* DNS_LOOKUP_LOCAL_EXTERN */ + namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); /* Walk through name list, return entry if found. If not, return NULL. */ for (i = 0; i < DNS_TABLE_SIZE; ++i) { if ((dns_table[i].state == DNS_STATE_DONE) && - (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && + (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) && + !dns_table[i].name[namelen] && LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); @@ -808,18 +793,8 @@ dns_send(u8_t idx) } /* if here, we have either a new query or a retry on a previous query to process */ -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (is_distributed_net_enabled()) { - p = pbuf_alloc(PBUF_TRANSPORT, - (u16_t)(sizeof(udp_data) + SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); - } else { - p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); - } -#else p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); -#endif - if (p != NULL) { const ip_addr_t *dst; u16_t dst_port; @@ -828,41 +803,12 @@ dns_send(u8_t idx) hdr.id = lwip_htons(entry->txid); hdr.flags1 = DNS_FLAG1_RD; hdr.numquestions = PP_HTONS(1); -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (is_distributed_net_enabled()) { - udp_data udp_data_hdr = {0}; - (void)memset_s(&udp_data_hdr, sizeof(udp_data_hdr), 0, sizeof(udp_data_hdr)); - dst = &dns_servers[entry->server_idx]; - -#if LWIP_IPV6 - (void)strcpy_s(udp_data_hdr.dest_addr, sizeof(udp_data_hdr.dest_addr), ip4addr_ntoa(&dst->u_addr.ip4)); -#else - (void)strcpy_s(udp_data_hdr.dest_addr, sizeof(udp_data_hdr.dest_addr), ip4addr_ntoa(dst)); -#endif - - udp_data_hdr.dest_port = DNS_SERVER_PORT; - - pbuf_take(p, &udp_data_hdr, sizeof(udp_data_hdr)); - pbuf_take_at(p, &hdr, SIZEOF_DNS_HDR, sizeof(udp_data_hdr)); - } else { - pbuf_take(p, &hdr, SIZEOF_DNS_HDR); - } -#else pbuf_take(p, &hdr, SIZEOF_DNS_HDR); -#endif hostname = entry->name; --hostname; /* convert hostname into suitable query format. */ -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (is_distributed_net_enabled()) { - query_idx = sizeof(udp_data) + SIZEOF_DNS_HDR; - } else { - query_idx = SIZEOF_DNS_HDR; - } -#else query_idx = SIZEOF_DNS_HDR; -#endif do { ++hostname; hostname_part = hostname; @@ -920,27 +866,7 @@ dns_send(u8_t idx) dst_port = DNS_SERVER_PORT; dst = &dns_servers[entry->server_idx]; } -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (is_distributed_net_enabled()) { - ip_addr_t local_addr = {0}; - dst_port = get_local_udp_server_port(); - -#if LWIP_IPV6 - local_addr.u_addr.ip4.addr = ipaddr_addr(LOCAL_SERVER_IP); - local_addr.type = IPADDR_TYPE_V4; -#else - local_addr.addr = ipaddr_addr(LOCAL_SERVER_IP); -#endif -#if (defined(EMUI_WEB_CLIENT)) - DISTRIBUTED_NET_START_UDP_SERVER(); -#endif - err = udp_sendto(dns_pcbs[pcb_idx], p, &local_addr, dst_port); - } else { - err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); - } -#else err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); -#endif /* free pbuf */ pbuf_free(p); @@ -1311,28 +1237,9 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, { /* Check whether response comes from the same network address to which the question was sent. (RFC 5452) */ -#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - if (is_distributed_net_enabled()) { -#if LWIP_IPV6 - if (addr->type != IPADDR_TYPE_V4 || addr->u_addr.ip4.addr != ipaddr_addr(LOCAL_SERVER_IP) || - port != get_local_udp_server_port()) { - goto ignore_packet; /* ignore this packet */ - } -#else - if (addr->addr != ipaddr_addr(LOCAL_SERVER_IP) || port != get_local_udp_server_port()) { - goto ignore_packet; /* ignore this packet */ - } -#endif - } else { - if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { - goto ignore_packet; /* ignore this packet */ - } - } -#else - if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { + if (!ip_addr_eq(addr, &dns_servers[entry->server_idx])) { goto ignore_packet; /* ignore this packet */ } -#endif } /* Check if the name in the "question" part match with the name in the entry and @@ -1492,13 +1399,18 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, struct dns_table_entry *entry = NULL; size_t namelen; struct dns_req_entry *req; - #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) u8_t r; +#endif + + namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) /* check for duplicate entries */ for (i = 0; i < DNS_TABLE_SIZE; i++) { if ((dns_table[i].state == DNS_STATE_ASKING) && - (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { + (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) && + !dns_table[i].name[namelen]) { #if LWIP_IPV4 && LWIP_IPV6 if (dns_table[i].reqaddrtype != dns_addrtype) { /* requested address types don't match @@ -1509,7 +1421,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, #endif /* LWIP_IPV4 && LWIP_IPV6 */ /* this is a duplicate entry, find a free request entry */ for (r = 0; r < DNS_MAX_REQUESTS; r++) { - if (dns_requests[r].found == 0) { + if (dns_requests[r].found == NULL) { dns_requests[r].found = found; dns_requests[r].arg = callback_arg; dns_requests[r].dns_table_idx = i; @@ -1585,7 +1497,6 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); req->found = found; req->arg = callback_arg; - namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); MEMCPY(entry->name, name, namelen); entry->name[namelen] = 0; @@ -1675,8 +1586,11 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call } #endif hostnamelen = strlen(hostname); + if (hostname[hostnamelen - 1] == '.') { + hostnamelen--; + } if (hostnamelen >= DNS_MAX_NAME_LENGTH) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); + LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve\n")); return ERR_ARG; } @@ -1699,7 +1613,7 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call } } /* already have this address cached? */ - if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { return ERR_OK; } #if LWIP_IPV4 && LWIP_IPV6 @@ -1711,7 +1625,7 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call } else { fallback = LWIP_DNS_ADDRTYPE_IPV4; } - if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { + if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { return ERR_OK; } } diff --git a/src/core/inet_chksum.c b/src/core/inet_chksum.c index 818c68f..6a343ed 100644 --- a/src/core/inet_chksum.c +++ b/src/core/inet_chksum.c @@ -1,6 +1,6 @@ /** * @file - * Internet checksum functions.\n + * Internet checksum functions. * * These are some reference implementations of the checksum algorithm, with the * aim of being simple, correct and fully portable. Checksumming is the @@ -74,7 +74,7 @@ u16_t lwip_standard_chksum(const void *dataptr, int len); * @return host order (!) lwip checksum (non-inverted Internet sum) * * @note accumulator size limits summable length to 64k - * @note host endianess is irrelevant (p3 RFC1071) + * @note host endianness is irrelevant (p3 RFC1071) */ u16_t lwip_standard_chksum(const void *dataptr, int len) diff --git a/src/core/init.c b/src/core/init.c index e862d51..b906eff 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -57,9 +57,6 @@ #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/api.h" -#ifdef LOSCFG_NET_CONTAINER -#include "lwip/net_group.h" -#endif #include "netif/ppp/ppp_opts.h" #include "netif/ppp/ppp_impl.h" @@ -130,7 +127,7 @@ PACK_STRUCT_END #endif /* There must be sufficient timeouts, taking into account requirements of the subsystems. */ #if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < LWIP_NUM_SYS_TIMEOUT_INTERNAL) -#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#error "MEMP_NUM_SYS_TIMEOUT is too low to accommodate all required timeouts" #endif #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" @@ -187,8 +184,8 @@ PACK_STRUCT_END #if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" #endif -#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) -#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" +#if (((!LWIP_DHCP) || (!LWIP_ARP) || (!LWIP_ACD)) && LWIP_DHCP_DOES_ACD_CHECK) +#error "If you want to use DHCP ACD checking, you have to define LWIP_DHCP=1, LWIP_ARP=1 and LWIP_ACD=1 in your lwipopts.h" #endif #if (!LWIP_ARP && LWIP_AUTOIP) #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" @@ -199,8 +196,11 @@ PACK_STRUCT_END #if (LWIP_ALTCP && LWIP_EVENT_API) #error "The application layered tcp API does not work with LWIP_EVENT_API" #endif -#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) -#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" +#if (MEM_CUSTOM_ALLOCATOR && !(defined(MEM_CUSTOM_FREE) && defined(MEM_CUSTOM_MALLOC) && defined(MEM_CUSTOM_CALLOC))) +#error "All of MEM_CUSTOM_FREE/MEM_CUSTOM_MALLOC/MEM_CUSTOM_CALLOC must be provided if MEM_CUSTOM_ALLOCATOR is enabled in your lwipopts.h" +#endif +#if (MEM_USE_POOLS && MEM_CUSTOM_ALLOCATOR) +#error "MEM_USE_POOLS may not be used with a custom allocator (MEM_CUSTOM_ALLOCATOR or MEM_LIBC_MALLOC) enabled in your lwipopts.h" #endif #if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" @@ -223,6 +223,9 @@ PACK_STRUCT_END #if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6 #error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" #endif +#if PPP_SUPPORT && CCP_SUPPORT && !MPPE_SUPPORT +#error "CCP_SUPPORT needs MPPE_SUPPORT turned on" +#endif #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" #endif @@ -240,9 +243,9 @@ PACK_STRUCT_END #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" #endif #endif /* LWIP_NETCONN && LWIP_TCP */ -// #if LWIP_NETCONN_FULLDUPLEX && !LWIP_NETCONN_SEM_PER_THREAD -// #error "For LWIP_NETCONN_FULLDUPLEX to work, LWIP_NETCONN_SEM_PER_THREAD is required" -// #endif +#if LWIP_NETCONN_FULLDUPLEX && !LWIP_NETCONN_SEM_PER_THREAD +#error "For LWIP_NETCONN_FULLDUPLEX to work, LWIP_NETCONN_SEM_PER_THREAD is required" +#endif /* Compile-time checks for deprecated options. @@ -309,6 +312,9 @@ PACK_STRUCT_END #if TCP_SNDLOWAT >= TCP_SND_BUF #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif +#if TCP_MSS >= ((16 * 1024) - 1) +#error "lwip_sanity_check: WARNING: TCP_MSS must be <= 16382 to prevent u16_t underflow in TCP_SNDLOWAT calculation!" +#endif #if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" #endif @@ -352,11 +358,7 @@ lwip_init(void) mem_init(); memp_init(); pbuf_init(); -#ifdef LOSCFG_NET_CONTAINER - netif_init(get_root_net_group()); -#else netif_init(); -#endif #if LWIP_IPV4 ip_init(); #if LWIP_ARP diff --git a/src/core/ip.c b/src/core/ip.c index 4d66f99..18514cf 100644 --- a/src/core/ip.c +++ b/src/core/ip.c @@ -164,18 +164,4 @@ ip_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_IPV4 && LWIP_IPV6 */ -#ifdef LOSCFG_NET_CONTAINER -void set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group) -{ - get_default_net_group_ops()->set_ippcb_net_group(pcb, group); -} - -struct net_group *get_net_group_from_ippcb(struct ip_pcb *pcb) -{ - if (pcb != NULL) { - return get_default_net_group_ops()->get_net_group_from_ippcb(pcb); - } - return NULL; -} -#endif #endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/src/core/ipv4/acd.c b/src/core/ipv4/acd.c new file mode 100644 index 0000000..92f3b5a --- /dev/null +++ b/src/core/ipv4/acd.c @@ -0,0 +1,557 @@ +/** + * @file + * + * ACD IPv4 Address Conflict Detection + * + * This is an IPv4 address conflict detection implementation for the lwIP TCP/IP + * stack. It aims to be conform to RFC5227. + * + * @defgroup acd ACD + * @ingroup ip4 + * ACD related functions + * USAGE: + * + * define @ref LWIP_ACD 1 in your lwipopts.h + * Options: + * ACD_TMR_INTERVAL msecs, + * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. + * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + * + * For fixed IP: + * - call acd_start after selecting an IP address. The caller will be informed + * on conflict status via the callback function. + * + * With AUTOIP: + * - will be called from the autoip module. No extra's needed. + * + * With DHCP: + * - enable LWIP_DHCP_DOES_ACD_CHECK. Then it will be called from the dhcp module. + * No extra's needed. + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * Copyright (c) 2018 Jasper Verschueren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Jasper Verschueren + * Author: Dominik Spies + */ + +#include "lwip/opt.h" + +/* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV4 && LWIP_ACD + +#include + +#include "lwip/acd.h" +#include "lwip/prot/acd.h" + +#define ACD_FOREACH(acd, acd_list) for ((acd) = acd_list; (acd) != NULL; (acd) = (acd)->next) + +#define ACD_TICKS_PER_SECOND (1000 / ACD_TMR_INTERVAL) + +/* Define good random function (LWIP_RAND) in lwipopts.h */ +#ifdef LWIP_RAND +#define LWIP_ACD_RAND(netif, acd) LWIP_RAND() +#else /* LWIP_RAND */ +#ifdef LWIP_AUTOIP_RAND +#include "lwip/autoip.h" +#define LWIP_ACD_RAND(netif, acd) LWIP_AUTOIP_RAND(netif) /* for backwards compatibility */ +#else +#define LWIP_ACD_RAND(netif, acd) ((((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ + ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ + ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ + ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ + (acd->sent_num)) +#endif /* LWIP_AUTOIP_RAND */ +#endif /* LWIP_RAND */ + + +#define ACD_RANDOM_PROBE_WAIT(netif, acd) (LWIP_ACD_RAND(netif, acd) % \ + (PROBE_WAIT * ACD_TICKS_PER_SECOND)) + +#define ACD_RANDOM_PROBE_INTERVAL(netif, acd) ((LWIP_ACD_RAND(netif, acd) % \ + ((PROBE_MAX - PROBE_MIN) * ACD_TICKS_PER_SECOND)) + \ + (PROBE_MIN * ACD_TICKS_PER_SECOND )) + +/* Function definitions */ +static void acd_restart(struct netif *netif, struct acd *acd); +static void acd_handle_arp_conflict(struct netif *netif, struct acd *acd); +static void acd_put_in_passive_mode(struct netif *netif, struct acd *acd); + +/** + * @ingroup acd + * Add ACD client to the client list and initialize callback function + * + * @param netif network interface on which to start the acd + * client + * @param acd acd module to be added to the list + * @param acd_conflict_callback callback to be called when conflict information + * is available + */ +err_t +acd_add(struct netif *netif, struct acd *acd, + acd_conflict_callback_t acd_conflict_callback) +{ + struct acd *acd2; + + /* Set callback */ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("acd_conflict_callback != NULL", acd_conflict_callback != NULL); + acd->acd_conflict_callback = acd_conflict_callback; + + /* Check if the acd struct is already added */ + for (acd2 = netif->acd_list; acd2 != NULL; acd2 = acd2->next) { + if (acd2 == acd) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_add(): acd already added to list\n")); + return ERR_OK; + } + } + + /* add acd struct to the list */ + acd->next = netif->acd_list; + netif->acd_list = acd; + + return ERR_OK; +} + +/** + * @ingroup acd + * Remove ACD client from the client list + * + * @param netif network interface from which to remove the acd client + * @param acd acd module to be removed from the list + */ +void +acd_remove(struct netif *netif, struct acd *acd) +{ + struct acd *acd2, *prev = NULL; + + LWIP_ASSERT_CORE_LOCKED(); + + for (acd2 = netif->acd_list; acd2 != NULL; acd2 = acd2->next) { + if (acd2 == acd) { + if (prev) { + prev->next = acd->next; + } else { + netif->acd_list = acd->next; + } + return; + } + prev = acd2; + } + LWIP_ASSERT(("acd_remove(): acd not on list\n"), 0); +} + + +/** + * @ingroup acd + * Start ACD client + * + * @param netif network interface on which to start the acd client + * @param acd acd module to start + * @param ipaddr ip address to perform acd on + */ +err_t +acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr) +{ + err_t result = ERR_OK; + + LWIP_UNUSED_ARG(netif); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_start(netif=%p) %c%c%"U16_F"\n", + (void *)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + + /* init probing state */ + acd->sent_num = 0; + acd->lastconflict = 0; + ip4_addr_copy(acd->ipaddr, ipaddr); + acd->state = ACD_STATE_PROBE_WAIT; + + acd->ttw = (u16_t)(ACD_RANDOM_PROBE_WAIT(netif, acd)); + + return result; +} + +/** + * @ingroup acd + * Stop ACD client + * + * @param acd acd module to stop + */ +err_t +acd_stop(struct acd *acd) +{ + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_stop\n")); + + if (acd != NULL) { + acd->state = ACD_STATE_OFF; + } + return ERR_OK; +} + +/** + * @ingroup acd + * Inform the ACD modules when the link goes down + * + * @param netif network interface on which to inform the ACD clients + */ +void +acd_network_changed_link_down(struct netif *netif) +{ + struct acd *acd; + /* loop over the acd's*/ + ACD_FOREACH(acd, netif->acd_list) { + acd_stop(acd); + } +} + +/** + * Has to be called in loop every ACD_TMR_INTERVAL milliseconds + */ +void +acd_tmr(void) +{ + struct netif *netif; + struct acd *acd; + /* loop through netif's */ + NETIF_FOREACH(netif) { + ACD_FOREACH(acd, netif->acd_list) { + if (acd->lastconflict > 0) { + acd->lastconflict--; + } + + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, + ("acd_tmr() ACD-State: %"U16_F", ttw=%"U16_F"\n", + (u16_t)(acd->state), acd->ttw)); + + if (acd->ttw > 0) { + acd->ttw--; + } + + switch (acd->state) { + case ACD_STATE_PROBE_WAIT: + case ACD_STATE_PROBING: + if (acd->ttw == 0) { + acd->state = ACD_STATE_PROBING; + etharp_acd_probe(netif, &acd->ipaddr); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, + ("acd_tmr() PROBING Sent Probe\n")); + acd->sent_num++; + if (acd->sent_num >= PROBE_NUM) { + /* Switch to ANNOUNCE_WAIT: last probe is sent*/ + acd->state = ACD_STATE_ANNOUNCE_WAIT; + + acd->sent_num = 0; + + /* calculate time to wait before announcing */ + acd->ttw = (u16_t)(ANNOUNCE_WAIT * ACD_TICKS_PER_SECOND); + } else { + /* calculate time to wait to next probe */ + acd->ttw = (u16_t)(ACD_RANDOM_PROBE_INTERVAL(netif, acd)); + } + } + break; + + case ACD_STATE_ANNOUNCE_WAIT: + case ACD_STATE_ANNOUNCING: + if (acd->ttw == 0) { + if (acd->sent_num == 0) { + acd->state = ACD_STATE_ANNOUNCING; + + /* reset conflict count to ensure fast re-probing after announcing */ + acd->num_conflicts = 0; + + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr), + ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr))); + } + + etharp_acd_announce(netif, &acd->ipaddr); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, + ("acd_tmr() ANNOUNCING Sent Announce\n")); + acd->ttw = ANNOUNCE_INTERVAL * ACD_TICKS_PER_SECOND; + acd->sent_num++; + + if (acd->sent_num >= ANNOUNCE_NUM) { + acd->state = ACD_STATE_ONGOING; + acd->sent_num = 0; + acd->ttw = 0; + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_tmr(): changing state to ONGOING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr), + ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr))); + + /* finally, let acd user know that the address is good and can be used */ + acd->acd_conflict_callback(netif, ACD_IP_OK); + } + } + break; + + case ACD_STATE_RATE_LIMIT: + if (acd->ttw == 0) { + /* acd should be stopped because ipaddr isn't valid any more */ + acd_stop(acd); + /* let the acd user (after rate limit interval) know that their is + * a conflict detected. So it can restart the address acquiring + * process.*/ + acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT); + } + break; + + default: + /* nothing to do in other states */ + break; + } + } + } +} + +/** + * Restarts the acd module + * + * The number of conflicts is increased and the upper layer is informed. + */ +static void +acd_restart(struct netif *netif, struct acd *acd) +{ + /* increase conflict counter. */ + acd->num_conflicts++; + + /* Decline the address */ + acd->acd_conflict_callback(netif, ACD_DECLINE); + + /* if we tried more then MAX_CONFLICTS we must limit our rate for + * acquiring and probing addresses. compliant to RFC 5227 Section 2.1.1 */ + if (acd->num_conflicts >= MAX_CONFLICTS) { + acd->state = ACD_STATE_RATE_LIMIT; + acd->ttw = (u16_t)(RATE_LIMIT_INTERVAL * ACD_TICKS_PER_SECOND); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("acd_restart(): rate limiting initiated. too many conflicts\n")); + } + else { + /* acd should be stopped because ipaddr isn't valid any more */ + acd_stop(acd); + /* let the acd user know right away that their is a conflict detected. + * So it can restart the address acquiring process. */ + acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT); + } +} + +/** + * Handles every incoming ARP Packet, called by etharp_input(). + * + * @param netif network interface to use for acd processing + * @param hdr Incoming ARP packet + */ +void +acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + struct acd *acd; + ip4_addr_t sipaddr, dipaddr; + struct eth_addr netifaddr; + SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN); + + /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support + * compilers without structure packing (not using structure copy which + * breaks strict-aliasing rules). + */ + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); + + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, ("acd_arp_reply()\n")); + + /* loop over the acd's*/ + ACD_FOREACH(acd, netif->acd_list) { + switch(acd->state) { + case ACD_STATE_OFF: + case ACD_STATE_RATE_LIMIT: + default: + /* do nothing */ + break; + + case ACD_STATE_PROBE_WAIT: + case ACD_STATE_PROBING: + case ACD_STATE_ANNOUNCE_WAIT: + /* RFC 5227 Section 2.1.1: + * from beginning to after ANNOUNCE_WAIT seconds we have a conflict if + * ip.src == ipaddr (someone is already using the address) + * OR + * ip.dst == ipaddr && hw.src != own hwaddr (someone else is probing it) + */ + if ((ip4_addr_eq(&sipaddr, &acd->ipaddr)) || + (ip4_addr_isany_val(sipaddr) && + ip4_addr_eq(&dipaddr, &acd->ipaddr) && + !eth_addr_eq(&netifaddr, &hdr->shwaddr))) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("acd_arp_reply(): Probe Conflict detected\n")); + acd_restart(netif, acd); + } + break; + + case ACD_STATE_ANNOUNCING: + case ACD_STATE_ONGOING: + case ACD_STATE_PASSIVE_ONGOING: + /* RFC 5227 Section 2.4: + * in any state we have a conflict if + * ip.src == ipaddr && hw.src != own hwaddr (someone is using our address) + */ + if (ip4_addr_eq(&sipaddr, &acd->ipaddr) && + !eth_addr_eq(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("acd_arp_reply(): Conflicting ARP-Packet detected\n")); + acd_handle_arp_conflict(netif, acd); + } + break; + } + } +} + +/** + * Handle a IP address conflict after an ARP conflict detection + */ +static void +acd_handle_arp_conflict(struct netif *netif, struct acd *acd) +{ + /* RFC5227, 2.4 "Ongoing Address Conflict Detection and Address Defense" + allows three options where: + a) means retreat on the first conflict, + b) allows to keep an already configured address when having only one + conflict in DEFEND_INTERVAL seconds and + c) the host will not give up it's address and defend it indefinitely + + We use option b) when the acd module represents the netif address, since it + helps to improve the chance that one of the two conflicting hosts may be + able to retain its address. while we are flexible enough to help network + performance + + We use option a) when the acd module does not represent the netif address, + since we cannot have the acd module announcing or restarting. This + situation occurs for the LL acd module when a routable address is used on + the netif but the LL address is still open in the background. */ + + if (acd->state == ACD_STATE_PASSIVE_ONGOING) { + /* Immediately back off on a conflict. */ + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_handle_arp_conflict(): conflict when we are in passive mode -> back off\n")); + acd_stop(acd); + acd->acd_conflict_callback(netif, ACD_DECLINE); + } + else { + if (acd->lastconflict > 0) { + /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_handle_arp_conflict(): conflict within DEFEND_INTERVAL -> retreating\n")); + + /* Active TCP sessions are aborted when removing the ip address but a bad + * connection was inevitable anyway with conflicting hosts */ + acd_restart(netif, acd); + } else { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_handle_arp_conflict(): we are defending, send ARP Announce\n")); + etharp_acd_announce(netif, &acd->ipaddr); + acd->lastconflict = DEFEND_INTERVAL * ACD_TICKS_PER_SECOND; + } + } +} + +/** + * Put the acd module in passive ongoing conflict detection. + */ +static void +acd_put_in_passive_mode(struct netif *netif, struct acd *acd) +{ + switch(acd->state) { + case ACD_STATE_OFF: + case ACD_STATE_PASSIVE_ONGOING: + default: + /* do nothing */ + break; + + case ACD_STATE_PROBE_WAIT: + case ACD_STATE_PROBING: + case ACD_STATE_ANNOUNCE_WAIT: + case ACD_STATE_RATE_LIMIT: + acd_stop(acd); + acd->acd_conflict_callback(netif, ACD_DECLINE); + break; + + case ACD_STATE_ANNOUNCING: + case ACD_STATE_ONGOING: + acd->state = ACD_STATE_PASSIVE_ONGOING; + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_put_in_passive_mode()\n")); + break; + } +} + +/** + * @ingroup acd + * Inform the ACD modules of address changes + * + * @param netif network interface on which the address is changing + * @param old_addr old ip address + * @param new_addr new ip address + */ +void +acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr, + const ip_addr_t *new_addr) +{ + struct acd *acd; + + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_netif_ip_addr_changed(): Address changed\n")); + + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_netif_ip_addr_changed(): old address = %s\n", ipaddr_ntoa(old_addr))); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_netif_ip_addr_changed(): new address = %s\n", ipaddr_ntoa(new_addr))); + + /* If we change from ANY to an IP or from an IP to ANY we do nothing */ + if (ip_addr_isany(old_addr) || ip_addr_isany(new_addr)) { + return; + } + + ACD_FOREACH(acd, netif->acd_list) { + /* Find ACD module of old address */ + if(ip4_addr_eq(&acd->ipaddr, ip_2_ip4(old_addr))) { + /* Did we change from a LL address to a routable address? */ + if (ip_addr_islinklocal(old_addr) && !ip_addr_islinklocal(new_addr)) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("acd_netif_ip_addr_changed(): changed from LL to routable address\n")); + /* Put the module in passive conflict detection mode */ + acd_put_in_passive_mode(netif, acd); + } + } + } +} + +#endif /* LWIP_IPV4 && LWIP_ACD */ diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index 7ff59b1..461a005 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -3,7 +3,9 @@ * AutoIP Automatic LinkLocal IP Configuration * * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform - * with RFC 3927. + * with RFC 3927. It uses IPv4 address conflict detection to evaluate the chosen + * address. The ACD module aims to be conform to RFC 5227. + * RFC 5227 is extracted out of RFC 3927 so the acd module fits nicely in autoip. * * @defgroup autoip AUTOIP * @ingroup ip4 @@ -11,10 +13,6 @@ * USAGE: * * define @ref LWIP_AUTOIP 1 in your lwipopts.h - * Options: - * AUTOIP_TMR_INTERVAL msecs, - * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. - * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... * * Without DHCP: * - Call autoip_start() after netif_add(). @@ -65,21 +63,12 @@ #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/autoip.h" +#include "lwip/acd.h" #include "lwip/etharp.h" #include "lwip/prot/autoip.h" #include -/** Pseudo random macro based on netif informations. - * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ -#ifndef LWIP_AUTOIP_RAND -#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ - ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ - ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ - ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ - (netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0)) -#endif /* LWIP_AUTOIP_RAND */ - /** * Macro that generates the initial IP address to be tried by AUTOIP. * If you want to override this, define it to something else in lwipopts.h. @@ -90,9 +79,12 @@ ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ -/* static functions */ -static err_t autoip_arp_announce(struct netif *netif); -static void autoip_start_probing(struct netif *netif); +/* Function definitions */ +static void autoip_restart(struct netif *netif); +static void autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr); +static err_t autoip_bind(struct netif *netif); +static void autoip_conflict_callback(struct netif *netif, + acd_callback_enum_t state); /** * @ingroup autoip @@ -117,6 +109,23 @@ autoip_set_struct(struct netif *netif, struct autoip *autoip) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); } +/** + * @ingroup autoip + * Remove a struct autoip previously set to the netif using autoip_set_struct() + * + * @param netif the netif for which to set the struct autoip + */ +void +autoip_remove_struct(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("netif has no struct autoip set", + netif_autoip_data(netif) != NULL); + + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, NULL); +} + /** Restart AutoIP client and check the next address (conflict detected) * * @param netif The netif under AutoIP control @@ -129,35 +138,6 @@ autoip_restart(struct netif *netif) autoip_start(netif); } -/** - * Handle a IP address conflict after an ARP conflict detection - */ -static void -autoip_handle_arp_conflict(struct netif *netif) -{ - struct autoip *autoip = netif_autoip_data(netif); - - /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where - a) means retreat on the first conflict and - b) allows to keep an already configured address when having only one - conflict in 10 seconds - We use option b) since it helps to improve the chance that one of the two - conflicting hosts may be able to retain its address. */ - - if (autoip->lastconflict > 0) { - /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); - - /* Active TCP sessions are aborted when removing the ip addresss */ - autoip_restart(netif); - } else { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); - autoip_arp_announce(netif); - autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; - } -} /** * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 @@ -195,29 +175,6 @@ autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr) ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); } -/** - * Sends an ARP probe from a network interface - * - * @param netif network interface used to send the probe - */ -static err_t -autoip_arp_probe(struct netif *netif) -{ - struct autoip *autoip = netif_autoip_data(netif); - /* this works because netif->ip_addr is ANY */ - return etharp_request(netif, &autoip->llipaddr); -} - -/** - * Sends an ARP announce from a network interface - * - * @param netif network interface used to send the announce - */ -static err_t -autoip_arp_announce(struct netif *netif) -{ - return etharp_gratuitous(netif); -} /** * Configure interface for use with current LL IP-Address @@ -230,6 +187,8 @@ autoip_bind(struct netif *netif) struct autoip *autoip = netif_autoip_data(netif); ip4_addr_t sn_mask, gw_addr; + autoip->state = AUTOIP_STATE_BOUND; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num, @@ -245,6 +204,35 @@ autoip_bind(struct netif *netif) return ERR_OK; } +/** +* Handle conflict information from ACD module +* +* @param netif network interface to handle conflict information on +* @param state acd_callback_enum_t + */ +static void +autoip_conflict_callback(struct netif *netif, acd_callback_enum_t state) +{ + struct autoip *autoip = netif_autoip_data(netif); + + switch (state) { + case ACD_IP_OK: + autoip_bind(netif); + break; + case ACD_RESTART_CLIENT: + autoip_restart(netif); + break; + case ACD_DECLINE: + /* "delete" conflicting address so a new one will be selected in + * autoip_start() */ + ip4_addr_set_any(&autoip->llipaddr); + autoip_stop(netif); + break; + default: + break; + } +} + /** * @ingroup autoip * Start AutoIP client @@ -260,14 +248,6 @@ autoip_start(struct netif *netif) LWIP_ASSERT_CORE_LOCKED(); LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); - /* Set IP-Address, Netmask and Gateway to 0 to make sure that - * ARP Packets are formed correctly - */ - netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], - netif->name[1], (u16_t)netif->num)); if (autoip == NULL) { /* no AutoIP client attached yet? */ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, @@ -280,62 +260,73 @@ autoip_start(struct netif *netif) } /* store this AutoIP client in the netif */ netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); - } else { - autoip->state = AUTOIP_STATE_OFF; - autoip->ttw = 0; - autoip->sent_num = 0; - ip4_addr_set_zero(&autoip->llipaddr); - autoip->lastconflict = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip\n")); } - autoip_create_addr(netif, &(autoip->llipaddr)); - autoip_start_probing(netif); + if (autoip->state == AUTOIP_STATE_OFF) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + + /* add acd struct to list*/ + acd_add(netif, &autoip->acd, autoip_conflict_callback); + + /* In accordance to RFC3927 section 2.1: + * Keep using the same link local address as much as possible. + * Only when there is none or when there was a conflict, select a new one. + */ + if (!ip4_addr_islinklocal(&autoip->llipaddr)) { + autoip_create_addr(netif, &(autoip->llipaddr)); + } + autoip->state = AUTOIP_STATE_CHECKING; + acd_start(netif, &autoip->acd, autoip->llipaddr); + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start(): already started on netif=%p %c%c%"U16_F"\n", + (void *)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + } return result; } -static void -autoip_start_probing(struct netif *netif) + +/** + * Handle a possible change in the network configuration: link up + * + * If there is an AutoIP address configured and AutoIP is not in cooperation + * with DHCP, start probing for previous address. + */ +void +autoip_network_changed_link_up(struct netif *netif) { struct autoip *autoip = netif_autoip_data(netif); - autoip->state = AUTOIP_STATE_PROBING; - autoip->sent_num = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - - /* time to wait to first probe, this is randomly - * chosen out of 0 to PROBE_WAIT seconds. - * compliant to RFC 3927 Section 2.2.1 - */ - autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); - - /* - * if we tried more then MAX_CONFLICTS we must limit our rate for - * acquiring and probing address - * compliant to RFC 3927 Section 2.2.1 - */ - if (autoip->tried_llipaddr > MAX_CONFLICTS) { - autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; + if (autoip && (autoip->state != AUTOIP_STATE_OFF) && !LWIP_DHCP_AUTOIP_COOP) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_network_changed_link_up(): start acd\n")); + autoip->state = AUTOIP_STATE_CHECKING; + /* Start acd check again for the last used address */ + acd_start(netif, &autoip->acd, autoip->llipaddr); } } /** - * Handle a possible change in the network configuration. + * Handle a possible change in the network configuration: link down * - * If there is an AutoIP address configured, take the interface down - * and begin probing with the same address. + * If there is an AutoIP address configured and AutoIP is in cooperation + * with DHCP, then stop the autoip module. When the link goes up, we do not want + * the autoip module to start again. DHCP will initiate autoip when needed. */ void -autoip_network_changed(struct netif *netif) +autoip_network_changed_link_down(struct netif *netif) { struct autoip *autoip = netif_autoip_data(netif); - if (autoip && (autoip->state != AUTOIP_STATE_OFF)) { - autoip_start_probing(netif); + if (autoip && (autoip->state != AUTOIP_STATE_OFF) && LWIP_DHCP_AUTOIP_COOP) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_network_changed_link_down(): stop autoip\n")); + autoip_stop(netif); } } @@ -356,195 +347,33 @@ autoip_stop(struct netif *netif) if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); } + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,("autoip_stop()\n")); } return ERR_OK; } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -autoip_tmr_tick(void) -{ - struct netif *netif = NULL; - u32_t tick = 0; - NETIF_FOREACH(netif) { - struct autoip *autoip = netif_autoip_data(netif); - if ((autoip != NULL) && (autoip->ttw > 0)) { - if ((autoip->state == AUTOIP_STATE_PROBING) || - (autoip->state == AUTOIP_STATE_ANNOUNCING)) { - SET_TMR_TICK(tick, autoip->ttw); - } - } - } - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "autoip_tmr_tick", tick)); - return tick; -} - -#endif - -/** - * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds - */ -void -autoip_tmr(void) -{ - struct netif *netif; - /* loop through netif's */ - NETIF_FOREACH(netif) { - struct autoip *autoip = netif_autoip_data(netif); - /* only act on AutoIP configured interfaces */ - if (autoip != NULL) { - if (autoip->lastconflict > 0) { - autoip->lastconflict--; - } - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", - (u16_t)(autoip->state), autoip->ttw)); - - if (autoip->ttw > 0) { - autoip->ttw--; - } - - switch (autoip->state) { - case AUTOIP_STATE_PROBING: - if (autoip->ttw == 0) { - if (autoip->sent_num >= PROBE_NUM) { - /* Switch to ANNOUNCING: now we can bind to an IP address and use it */ - autoip->state = AUTOIP_STATE_ANNOUNCING; - autoip_bind(netif); - /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP - which counts as an announcement */ - autoip->sent_num = 1; - autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - } else { - autoip_arp_probe(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); - autoip->sent_num++; - if (autoip->sent_num == PROBE_NUM) { - /* calculate time to wait to for announce */ - autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - } else { - /* calculate time to wait to next probe */ - autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % - ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + - PROBE_MIN * AUTOIP_TICKS_PER_SECOND); - } - } - } - break; - - case AUTOIP_STATE_ANNOUNCING: - if (autoip->ttw == 0) { - autoip_arp_announce(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); - autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; - autoip->sent_num++; - - if (autoip->sent_num >= ANNOUNCE_NUM) { - autoip->state = AUTOIP_STATE_BOUND; - autoip->sent_num = 0; - autoip->ttw = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - } - } - break; - - default: - /* nothing to do in other states */ - break; - } - } - } -} - -/** - * Handles every incoming ARP Packet, called by etharp_input(). - * - * @param netif network interface to use for autoip processing - * @param hdr Incoming ARP packet - */ -void -autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) -{ - struct autoip *autoip = netif_autoip_data(netif); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); - if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) { - /* when ip.src == llipaddr && hw.src != netif->hwaddr - * - * when probing ip.dst == llipaddr && hw.src != netif->hwaddr - * we have a conflict and must solve it - */ - ip4_addr_t sipaddr, dipaddr; - struct eth_addr netifaddr; - SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN); - - /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). - */ - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); - - if (autoip->state == AUTOIP_STATE_PROBING) { - /* RFC 3927 Section 2.2.1: - * from beginning to after ANNOUNCE_WAIT - * seconds we have a conflict if - * ip.src == llipaddr OR - * ip.dst == llipaddr && hw.src != own hwaddr - */ - if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) || - (ip4_addr_isany_val(sipaddr) && - ip4_addr_cmp(&dipaddr, &autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Probe Conflict detected\n")); - autoip_restart(netif); - } - } else { - /* RFC 3927 Section 2.5: - * in any state we have a conflict if - * ip.src == llipaddr && hw.src != own hwaddr - */ - if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); - autoip_handle_arp_conflict(netif); - } - } - } -} - /** check if AutoIP supplied netif->ip_addr * * @param netif the netif to check - * @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING), + * @return 1 if AutoIP supplied netif->ip_addr (state BOUND), * 0 otherwise */ u8_t -autoip_supplied_address(const struct netif *netif) +autoip_supplied_address(struct netif *netif) { - if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) { - struct autoip *autoip = netif_autoip_data(netif); - return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING); - } - return 0; + struct autoip *autoip = netif_autoip_data(netif); + return (autoip != NULL) + && (ip4_addr_eq(netif_ip4_addr(netif), &(autoip->llipaddr))) + && (autoip->state == AUTOIP_STATE_BOUND); } u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr) { struct autoip *autoip = netif_autoip_data(netif); - return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr)); + return (autoip != NULL) + && (ip4_addr_eq(addr, &(autoip->llipaddr))) + && (autoip->state == AUTOIP_STATE_BOUND); } #endif /* LWIP_IPV4 && LWIP_AUTOIP */ diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index f4f80e7..12e0068 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -75,6 +75,7 @@ #include "lwip/def.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" +#include "lwip/acd.h" #include "lwip/dns.h" #include "lwip/etharp.h" #include "lwip/prot/dhcp.h" @@ -92,6 +93,46 @@ #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) #endif +/** DHCP_ADD_EXTRA_REQUEST_OPTIONS: Additional options added to the list of options + * that the client requests from the servers (opt 55: DHCP_OPTION_PARAMETER_REQUEST_LIST) + * If additional options are requested, define this macro as a comma separated list, with leading comma. + * This macro is useful for example when requested vendor specific ids (VCI/VSI options), here is an example + * of requesting the VSI option (option 43) (yes, the notation is a bit strange, but it works :) + * (NOTE: the space between # and define is required because of doxygen...) + * # define DHCP_ADD_EXTRA_REQUEST_OPTIONS ,43 + */ +#ifndef DHCP_ADD_EXTRA_REQUEST_OPTIONS +#define DHCP_ADD_EXTRA_REQUEST_OPTIONS +#endif + +/** DHCP_DEFINE_CUSTOM_TIMEOUTS: if this is defined then you can customize various DHCP timeouts using these macros: + - DHCP_SET_TIMEOUT_FROM_OFFERED_T0_LEASE() to adjust the t0 lease timeout from the offered value + - DHCP_SET_TIMEOUT_FROM_OFFERED_T1_RENEW() same for t1 renew + - DHCP_SET_TIMEOUT_FROM_OFFERED_T2_REBIND() same for t2 rebind + - DHCP_NEXT_TIMEOUT_THRESHOLD to adjust the period of the next timeout + - DHCP_REQUEST_BACKOFF_SEQUENCE to adjust back-off times based on DHCP request attempts + */ +#ifndef DHCP_DEFINE_CUSTOM_TIMEOUTS +#define SET_TIMEOUT_FROM_OFFERED(result, offered, min, max) do { \ + u32_t timeout = (offered + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; \ + if (timeout > max) { \ + timeout = max; \ + } \ + if (timeout == min) { \ + timeout = 1; \ + } \ + result = (dhcp_timeout_t)timeout; \ +} while(0) + +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T0_LEASE(res, dhcp) SET_TIMEOUT_FROM_OFFERED(res, (dhcp)->offered_t0_lease, 0, 0xffff) +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T1_RENEW(res, dhcp) SET_TIMEOUT_FROM_OFFERED(res, (dhcp)->offered_t1_renew, 0, 0xffff) +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T2_REBIND(res, dhcp) SET_TIMEOUT_FROM_OFFERED(res, (dhcp)->offered_t2_rebind, 0, 0xffff) + +#define DHCP_NEXT_TIMEOUT_THRESHOLD ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS) +#define DHCP_REQUEST_BACKOFF_SEQUENCE(tries) (u16_t)(( (tries) < 6 ? 1 << (tries) : 60) * 1000) + +#endif /* DHCP_DEFINE_CUSTOM_TIMEOUTS */ + /** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) */ @@ -116,7 +157,7 @@ #define DHCP_MIN_REPLY_LEN 44 #define REBOOT_TRIES 2 -#if 0 /* The following codes are moved to dhcp.h for fixing it's todo, kept here just for notice */ + #if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS #if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS #define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS @@ -127,6 +168,11 @@ #define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 #endif +#ifndef LWIP_DHCP_INPUT_ERROR +#define LWIP_DHCP_INPUT_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;} } while(0) +#endif + /** Option handling: options are parsed in dhcp_parse_reply * and saved in an array where other functions can load them from. * This might be moved into the struct dhcp (not necessarily since @@ -154,17 +200,11 @@ enum dhcp_option_idx { /** Holds the decoded option values, only valid while in dhcp_recv. @todo: move this into struct dhcp? */ -u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; +static u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; /** Holds a flag which option was received and is contained in dhcp_rx_options_val, only valid while in dhcp_recv. @todo: move this into struct dhcp? */ -u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; -#endif - -#ifndef LWIP_DHCP_INPUT_ERROR -#define LWIP_DHCP_INPUT_ERROR(message, expression, handler) do { if (!(expression)) { \ - handler;} } while(0) -#endif +static u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; static u8_t dhcp_discover_request_options[] = { DHCP_OPTION_SUBNET_MASK, @@ -176,6 +216,7 @@ static u8_t dhcp_discover_request_options[] = { #if LWIP_DHCP_GET_NTP_SRV , DHCP_OPTION_NTP #endif /* LWIP_DHCP_GET_NTP_SRV */ + DHCP_ADD_EXTRA_REQUEST_OPTIONS }; #ifdef DHCP_GLOBAL_XID @@ -183,12 +224,12 @@ static u32_t xid; static u8_t xid_initialised; #endif /* DHCP_GLOBAL_XID */ -#define dhcp_option_given(dhcp, idx) ((dhcp)->rx_options_given[idx] != 0) -#define dhcp_got_option(dhcp, idx) ((dhcp)->rx_options_given[idx] = 1) -#define dhcp_clear_option(dhcp, idx) ((dhcp)->rx_options_given[idx] = 0) -#define dhcp_clear_all_options(dhcp) (memset((dhcp)->rx_options_given, 0, sizeof((dhcp)->rx_options_given))) -#define dhcp_get_option_value(dhcp, idx) ((dhcp)->rx_options_val[idx]) -#define dhcp_set_option_value(dhcp, idx, val) ((dhcp)->rx_options_val[idx] = (val)) +#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) static struct udp_pcb *dhcp_pcb; static u8_t dhcp_pcb_refcount; @@ -197,9 +238,9 @@ static u8_t dhcp_pcb_refcount; static err_t dhcp_discover(struct netif *netif); static err_t dhcp_select(struct netif *netif); static void dhcp_bind(struct netif *netif); -#if DHCP_DOES_ARP_CHECK +#if LWIP_DHCP_DOES_ACD_CHECK static err_t dhcp_decline(struct netif *netif); -#endif /* DHCP_DOES_ARP_CHECK */ +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ static err_t dhcp_rebind(struct netif *netif); static err_t dhcp_reboot(struct netif *netif); static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); @@ -295,13 +336,56 @@ dhcp_handle_nak(struct netif *netif) dhcp_discover(netif); } -#if DHCP_DOES_ARP_CHECK +#if LWIP_DHCP_DOES_ACD_CHECK +/** +* Handle conflict information from ACD module +* +* @param netif network interface to handle conflict information on +* @param state acd_callback_enum_t + */ +static void +dhcp_conflict_callback(struct netif *netif, acd_callback_enum_t state) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + u16_t msecs; + + LWIP_ASSERT("DHCP should be enabled at this point, but it is not!", + (dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)); + + switch (state) { + case ACD_IP_OK: + dhcp_bind(netif); + break; + case ACD_RESTART_CLIENT: + /* wait 10s before restarting + * According to RFC2131 section 3.1 point 5: + * If the client detects that the address is already in use (e.g., through + * the use of ARP), the client MUST send a DHCPDECLINE message to the + * server and restarts the configuration process. The client SHOULD wait + * a minimum of ten seconds before restarting the configuration process to + * avoid excessive network traffic in case of looping. */ + dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + msecs = 10 * 1000; + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); + break; + case ACD_DECLINE: + /* remove IP address from interface + * (prevents routing from selecting this interface) */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + /* Let the DHCP server know we will not use the address */ + dhcp_decline(netif); + break; + default: + break; + } +} + /** * Checks if the offered IP address is already in use. * - * It does so by sending an ARP request for the offered address and - * entering CHECKING state. If no ARP reply is received within a small - * interval, the address is assumed to be free for use by us. + * It does this according to the address conflict detection method described in + * RFC5227. * * @param netif the netif under DHCP control */ @@ -309,25 +393,15 @@ static void dhcp_check(struct netif *netif) { struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result; - u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], (s16_t)netif->name[1])); dhcp_set_state(dhcp, DHCP_STATE_CHECKING); - /* create an ARP query for the offered IP address, expecting that no host - responds, as the IP address should not be in use. */ - result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); - if (result != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = 500; - dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); + + /* start ACD module */ + acd_start(netif, &dhcp->acd, dhcp->offered_ip_addr); } -#endif /* DHCP_DOES_ARP_CHECK */ +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ /** * Remember the configuration offered by a DHCP server. @@ -438,11 +512,7 @@ dhcp_coarse_tmr(void) struct netif *netif; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); /* iterate through all network interfaces */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif /* only act on DHCP configured interfaces */ struct dhcp *dhcp = netif_dhcp_data(netif); if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { @@ -467,65 +537,6 @@ dhcp_coarse_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" - -u32_t -dhcp_coarse_tmr_tick(void) -{ - struct netif *netif; - u32_t tick = 0; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); - /* iterate through all network interfaces */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - struct dhcp *dhcp = netif_dhcp_data(netif); - if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { - if (dhcp->t0_timeout > 0) { - if (dhcp->t0_timeout > dhcp->lease_used) { - SET_TMR_TICK(tick, dhcp->t0_timeout - dhcp->lease_used); - } else { - SET_TMR_TICK(tick, 1); - } - } - if (dhcp->t2_rebind_time > 0) { - SET_TMR_TICK(tick, dhcp->t2_rebind_time); - } - if (dhcp->t1_renew_time > 0) { - SET_TMR_TICK(tick, dhcp->t1_renew_time); - } - } - } - return tick; -} - -u32_t -dhcp_fine_tmr_tick(void) -{ - struct netif *netif; - u32_t tick = 0; - /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - struct dhcp *dhcp = netif_dhcp_data(netif); - if (dhcp != NULL) { - if (dhcp->request_timeout > 0) { - SET_TMR_TICK(tick, dhcp->request_timeout); - } - } - } - return tick; -} -#endif /* LWIP_LOWPOWER */ - /** * DHCP transaction timeout handling (this function must be called every 500ms, * see @ref DHCP_FINE_TIMER_MSECS). @@ -538,11 +549,7 @@ dhcp_fine_tmr(void) { struct netif *netif; /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif struct dhcp *dhcp = netif_dhcp_data(netif); /* only act on DHCP configured interfaces */ if (dhcp != NULL) { @@ -588,19 +595,6 @@ dhcp_timeout(struct netif *netif) dhcp_release_and_stop(netif); dhcp_start(netif); } -#if DHCP_DOES_ARP_CHECK - /* received no ARP reply for the offered address (which is good) */ - } else if (dhcp->state == DHCP_STATE_CHECKING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); - if (dhcp->tries <= 1) { - dhcp_check(netif); - /* no ARP replies on the offered address, - looks like the IP address is indeed free */ - } else { - /* bind the interface to the offered address */ - dhcp_bind(netif); - } -#endif /* DHCP_DOES_ARP_CHECK */ } else if (dhcp->state == DHCP_STATE_REBOOTING) { if (dhcp->tries < REBOOT_TRIES) { dhcp_reboot(netif); @@ -631,8 +625,8 @@ dhcp_t1_timeout(struct netif *netif) DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ dhcp_renew(netif); /* Calculate next timeout */ - if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { - dhcp->t1_renew_time = (u16_t)((dhcp->t2_timeout - dhcp->lease_used) / 2); + if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= DHCP_NEXT_TIMEOUT_THRESHOLD) { + dhcp->t1_renew_time = (dhcp_timeout_t)((dhcp->t2_timeout - dhcp->lease_used) / 2); } } } @@ -657,8 +651,8 @@ dhcp_t2_timeout(struct netif *netif) DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */ dhcp_rebind(netif); /* Calculate next timeout */ - if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { - dhcp->t2_rebind_time = (u16_t)((dhcp->t0_timeout - dhcp->lease_used) / 2); + if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= DHCP_NEXT_TIMEOUT_THRESHOLD) { + dhcp->t2_rebind_time = (dhcp_timeout_t)((dhcp->t0_timeout - dhcp->lease_used) / 2); } } } @@ -723,9 +717,9 @@ dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { /* remember given subnet mask */ ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); - dhcp->subnet_mask_given = 1; + dhcp->flags |= DHCP_FLAG_SUBNET_MASK_GIVEN; } else { - dhcp->subnet_mask_given = 0; + dhcp->flags &= ~DHCP_FLAG_SUBNET_MASK_GIVEN; } /* gateway router */ @@ -769,6 +763,8 @@ dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) /* clear data structure */ memset(dhcp, 0, sizeof(struct dhcp)); + /* mark this as externally allocated */ + dhcp->flags |= DHCP_FLAG_EXTERNAL_MEM; /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); } @@ -784,11 +780,15 @@ dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) */ void dhcp_cleanup(struct netif *netif) { + struct dhcp *dhcp; LWIP_ASSERT_CORE_LOCKED(); LWIP_ASSERT("netif != NULL", netif != NULL); - if (netif_dhcp_data(netif) != NULL) { - mem_free(netif_dhcp_data(netif)); + dhcp = netif_dhcp_data(netif); + if (dhcp != NULL) { + if (!(dhcp->flags & DHCP_FLAG_EXTERNAL_MEM)) { + mem_free(dhcp); + } netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL); } } @@ -835,7 +835,7 @@ dhcp_start(struct netif *netif) /* store this dhcp client in the netif */ netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp\n")); /* already has DHCP client attached */ } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); @@ -850,6 +850,13 @@ dhcp_start(struct netif *netif) memset(dhcp, 0, sizeof(struct dhcp)); /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ + +#if LWIP_DHCP_DOES_ACD_CHECK + /* add acd struct to list*/ + acd_add(netif, &dhcp->acd, dhcp_conflict_callback); +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ @@ -928,7 +935,7 @@ dhcp_inform(struct netif *netif) * address is still valid. */ void -dhcp_network_changed(struct netif *netif) +dhcp_network_changed_link_up(struct netif *netif) { struct dhcp *dhcp = netif_dhcp_data(netif); @@ -951,12 +958,6 @@ dhcp_network_changed(struct netif *netif) /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the state changes, SELECTING: continue with current 'rid' as we stay in the same state */ -#if LWIP_DHCP_AUTOIP_COOP - if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ /* ensure we start with short timeouts, even if already discovering */ dhcp->tries = 0; dhcp_discover(netif); @@ -964,37 +965,7 @@ dhcp_network_changed(struct netif *netif) } } -#if DHCP_DOES_ARP_CHECK -/** - * Match an ARP reply with the offered IP address: - * check whether the offered IP address is not in use using ARP - * - * @param netif the network interface on which the reply was received - * @param addr The IP address we received a reply from - */ -void -dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) -{ - struct dhcp *dhcp; - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - dhcp = netif_dhcp_data(netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); - /* is a DHCP client doing an ARP check? */ - if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", - ip4_addr_get_u32(addr))); - /* did a host respond with the address we - were offered by the DHCP server? */ - if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) { - /* we will not accept the offered address */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); - dhcp_decline(netif); - } - } -} - +#if LWIP_DHCP_DOES_ACD_CHECK /** * Decline an offered lease. * @@ -1009,12 +980,12 @@ dhcp_decline(struct netif *netif) { struct dhcp *dhcp = netif_dhcp_data(netif); err_t result; - u16_t msecs; struct pbuf *p_out; u16_t options_out_len; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + /* create and initialize the DHCP message header */ p_out = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len); if (p_out != NULL) { @@ -1034,15 +1005,9 @@ dhcp_decline(struct netif *netif) ("dhcp_decline: could not allocate DHCP request\n")); result = ERR_MEM; } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = 10 * 1000; - dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); return result; } -#endif /* DHCP_DOES_ARP_CHECK */ +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ /** @@ -1062,6 +1027,12 @@ dhcp_discover(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES) { + autoip_start(netif); + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + ip4_addr_set_any(&dhcp->offered_ip_addr); dhcp_set_state(dhcp, DHCP_STATE_SELECTING); /* create and initialize the DHCP message header */ @@ -1073,6 +1044,10 @@ dhcp_discover(struct netif *netif) options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); +#if LWIP_NETIF_HOSTNAME && LWIP_DHCP_DISCOVER_ADD_HOSTNAME + options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); +#endif /* LWIP NETIF HOSTNAME && LWIP_DHCP_DISCOVER_ADD_HOSTNAME */ + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); @@ -1082,22 +1057,17 @@ dhcp_discover(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n")); udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()\n")); pbuf_free(p_out); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); } + if (dhcp->tries < 255) { dhcp->tries++; } -#if LWIP_DHCP_AUTOIP_COOP - if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; - autoip_start(netif); - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); + msecs = DHCP_REQUEST_BACKOFF_SEQUENCE(dhcp->tries); dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); return result; @@ -1112,7 +1082,6 @@ dhcp_discover(struct netif *netif) static void dhcp_bind(struct netif *netif) { - u32_t timeout; struct dhcp *dhcp; ip4_addr_t sn_mask, gw_addr; LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); @@ -1126,14 +1095,7 @@ dhcp_bind(struct netif *netif) if (dhcp->offered_t0_lease != 0xffffffffUL) { /* set renewal period timer */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); - timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if (timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t0_timeout = (u16_t)timeout; - if (dhcp->t0_timeout == 0) { - dhcp->t0_timeout = 1; - } + DHCP_SET_TIMEOUT_FROM_OFFERED_T0_LEASE(dhcp->t0_timeout, dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000)); } @@ -1141,28 +1103,14 @@ dhcp_bind(struct netif *netif) if (dhcp->offered_t1_renew != 0xffffffffUL) { /* set renewal period timer */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); - timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if (timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t1_timeout = (u16_t)timeout; - if (dhcp->t1_timeout == 0) { - dhcp->t1_timeout = 1; - } + DHCP_SET_TIMEOUT_FROM_OFFERED_T1_RENEW(dhcp->t1_timeout, dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew * 1000)); dhcp->t1_renew_time = dhcp->t1_timeout; } /* set renewal period timer */ if (dhcp->offered_t2_rebind != 0xffffffffUL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); - timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if (timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t2_timeout = (u16_t)timeout; - if (dhcp->t2_timeout == 0) { - dhcp->t2_timeout = 1; - } + DHCP_SET_TIMEOUT_FROM_OFFERED_T2_REBIND(dhcp->t2_timeout, dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind * 1000)); dhcp->t2_rebind_time = dhcp->t2_timeout; } @@ -1172,7 +1120,7 @@ dhcp_bind(struct netif *netif) dhcp->t1_timeout = 0; } - if (dhcp->subnet_mask_given) { + if (dhcp->flags & DHCP_FLAG_SUBNET_MASK_GIVEN) { /* copy offered network mask */ ip4_addr_copy(sn_mask, dhcp->offered_sn_mask); } else { @@ -1189,13 +1137,6 @@ dhcp_bind(struct netif *netif) ip4_addr_copy(gw_addr, dhcp->offered_gw_addr); -#if LWIP_DHCP_AUTOIP_COOP - if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n", ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr))); /* netif is now bound to DHCP leased address - set this before assigning the address @@ -1439,12 +1380,10 @@ dhcp_release_and_stop(struct netif *netif) dhcp_set_state(dhcp, DHCP_STATE_OFF); } -#if LWIP_DHCP_AUTOIP_COOP - if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ +#if LWIP_DHCP_DOES_ACD_CHECK + /* stop acd because we may be in checking state and the callback would trigger a bind */ + acd_remove(netif, &dhcp->acd); +#endif if (dhcp->pcb_allocated != 0) { dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ @@ -1638,7 +1577,7 @@ again: } else { len = (q->next != NULL ? ((u8_t *)q->next->payload)[0] : 0); } - /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F"\n", msg_offset, q->len)); */ decode_len = len; switch (op) { /* case(DHCP_OPTION_END): handled above */ @@ -1661,7 +1600,7 @@ again: /* special case: there might be more than one server */ LWIP_DHCP_INPUT_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); /* limit number of DNS servers */ - decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_PROVIDE_DNS_SERVERS); LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_DNS_SERVER; break; @@ -1812,7 +1751,7 @@ decode_next: /* make sure the string is really NULL-terminated */ dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; } -#endif /* LWIP_DHCP_BOOTP_FILE */ +#endif /* LWIP_DHCP_BOOTP_FILE */ return ERR_OK; } @@ -1891,10 +1830,11 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, /* message type is DHCP ACK? */ if (msg_type == DHCP_ACK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); - /* in requesting state? */ - if (dhcp->state == DHCP_STATE_REQUESTING) { + /* in requesting state or just reconnected to the network? */ + if ((dhcp->state == DHCP_STATE_REQUESTING) || + (dhcp->state == DHCP_STATE_REBOOTING)) { dhcp_handle_ack(netif, msg_in); -#if DHCP_DOES_ARP_CHECK +#if LWIP_DHCP_DOES_ACD_CHECK if ((netif->flags & NETIF_FLAG_ETHARP) != 0) { /* check if the acknowledged lease address is already in use */ dhcp_check(netif); @@ -1907,8 +1847,8 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, dhcp_bind(netif); #endif } - /* already bound to the given lease address? */ - else if ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) || + /* already bound to the given lease address and using it? */ + else if ((dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING)) { dhcp_handle_ack(netif, msg_in); dhcp_bind(netif); diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c index 3fc85ef..3092dc9 100644 --- a/src/core/ipv4/etharp.c +++ b/src/core/ipv4/etharp.c @@ -7,7 +7,7 @@ * requests from other machines for our physical address. * * This implementation complies with RFC 826 (Ethernet ARP). It supports - * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * Gratuitous ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 * if an interface calls etharp_gratuitous(our_netif) upon address change. */ @@ -52,6 +52,7 @@ #include "lwip/snmp.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" +#include "lwip/acd.h" #include "lwip/prot/iana.h" #include "netif/ethernet.h" @@ -141,7 +142,7 @@ static err_t etharp_raw(struct netif *netif, /** * Free a complete queue of etharp entries * - * @param q a qeueue of etharp_q_entry's to free + * @param q a queue of etharp_q_entry's to free */ static void free_etharp_q(struct etharp_q_entry *q) @@ -187,35 +188,6 @@ etharp_free_entry(int i) #endif /* LWIP_DEBUG */ } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -etharp_tmr_tick(void) -{ - s32_t i; - u32_t tick = 0; - u32_t time; - - for (i = 0; i < ARP_TABLE_SIZE; i++) { - u8_t state = arp_table[i].state; - if ((state != ETHARP_STATE_EMPTY) -#if ETHARP_SUPPORT_STATIC_ENTRIES - && (state != ETHARP_STATE_STATIC) -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - ) { - if (arp_table[i].state != ETHARP_STATE_STABLE) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "etharp_tmr_tick")); - return 1; - } - time = (u32_t)ARP_MAXAGE - arp_table[i].ctime; - SET_TMR_TICK(tick, time); - } - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "etharp_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - /** * Clears expired entries in the ARP table. * @@ -320,7 +292,7 @@ etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif *netif) LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ - if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) + if (ipaddr && ip4_addr_eq(ipaddr, &arp_table[i].ipaddr) #if ETHARP_TABLE_MATCH_NETIF && ((netif == NULL) || (netif == arp_table[i].netif)) #endif /* ETHARP_TABLE_MATCH_NETIF */ @@ -537,11 +509,8 @@ etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); -#ifdef LOSCFG_NET_CONTAINER - netif = ip4_route(ipaddr, get_root_net_group()); -#else + netif = ip4_route(ipaddr); -#endif if (netif == NULL) { return ERR_RTE; } @@ -675,7 +644,7 @@ etharp_input(struct pbuf *p, struct netif *netif) struct etharp_hdr *hdr; /* these are aligned properly, whereas the ARP header fields might not be */ ip4_addr_t sipaddr, dipaddr; - u8_t for_us; + u8_t for_us, from_us; LWIP_ASSERT_CORE_LOCKED(); @@ -698,12 +667,16 @@ etharp_input(struct pbuf *p, struct netif *netif) } ETHARP_STATS_INC(etharp.recv); -#if LWIP_AUTOIP - /* We have to check if a host already has configured our random - * created link local address and continuously check if there is - * a host with this IP-address so we can detect collisions */ - autoip_arp_reply(netif, hdr); -#endif /* LWIP_AUTOIP */ +#if LWIP_ACD + /* We have to check if a host already has configured our ip address and + * continuously check if there is a host with this IP-address so we can + * detect collisions. + * acd_arp_reply ensures the detection of conflicts. It will handle possible + * defending or retreating and will make sure a new IP address is selected. + * etharp_input does not need to handle packets that originate "from_us". + */ + acd_arp_reply(netif, hdr); +#endif /* LWIP_ACD */ /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ @@ -713,9 +686,12 @@ etharp_input(struct pbuf *p, struct netif *netif) /* this interface is not configured? */ if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { for_us = 0; + from_us = 0; } else { /* ARP packet directed to us? */ - for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); + for_us = (u8_t)ip4_addr_eq(&dipaddr, netif_ip4_addr(netif)); + /* ARP packet from us? */ + from_us = (u8_t)ip4_addr_eq(&sipaddr, netif_ip4_addr(netif)); } /* ARP message directed to us? @@ -736,7 +712,7 @@ etharp_input(struct pbuf *p, struct netif *netif) LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n")); /* ARP request for our address? */ - if (for_us) { + if (for_us && !from_us) { /* send ARP response */ etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, @@ -756,13 +732,6 @@ etharp_input(struct pbuf *p, struct netif *netif) case PP_HTONS(ARP_REPLY): /* ARP reply. We already updated the ARP cache earlier. */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n")); -#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) - /* DHCP wants to know about ARP replies from any host with an - * IP address also offered to us by the DHCP server. We do not - * want to take a duplicate IP address on a single network. - * @todo How should we handle redundant (fail-over) interfaces? */ - dhcp_arp_reply(netif, &sipaddr); -#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ break; default: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode))); @@ -854,7 +823,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) netif_addr_idx_t i; /* outside local network? if so, this can neither be a global broadcast nor a subnet broadcast. */ - if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && + if (!ip4_addr_net_eq(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && !ip4_addr_islinklocal(ipaddr)) { #if LWIP_AUTOIP struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr *, q->payload); @@ -894,7 +863,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) #if ETHARP_TABLE_MATCH_NETIF (arp_table[etharp_cached_entry].netif == netif) && #endif - (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { + (ip4_addr_eq(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { /* the per-pcb-cached entry is stable and the right one! */ ETHARP_STATS_INC(etharp.cachehit); return etharp_output_to_arp_index(netif, q, etharp_cached_entry); @@ -911,7 +880,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) #if ETHARP_TABLE_MATCH_NETIF (arp_table[i].netif == netif) && #endif - (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { + (ip4_addr_eq(dst_addr, &arp_table[i].ipaddr))) { /* found an existing, stable entry */ ETHARP_SET_ADDRHINT(netif, i); return etharp_output_to_arp_index(netif, q, i); @@ -1046,7 +1015,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) * new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ p = q; while (p) { - LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); + LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == NULL)); if (PBUF_NEEDS_COPY(p)) { copy_needed = 1; break; @@ -1070,7 +1039,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); if (new_entry != NULL) { unsigned int qlen = 0; - new_entry->next = 0; + new_entry->next = NULL; new_entry->p = p; if (arp_table[i].q != NULL) { /* queue was already existent, append the new entry to the end */ @@ -1241,4 +1210,42 @@ etharp_request(struct netif *netif, const ip4_addr_t *ipaddr) return etharp_request_dst(netif, ipaddr, ðbroadcast); } +#if LWIP_ACD +/** + * Send an ARP request packet probing for an ipaddr. + * Used to send probe messages for address conflict detection. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address to probe + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +err_t +etharp_acd_probe(struct netif *netif, const ip4_addr_t *ipaddr) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, + (struct eth_addr *)netif->hwaddr, IP4_ADDR_ANY4, ðzero, + ipaddr, ARP_REQUEST); +} + +/** + * Send an ARP request packet announcing an ipaddr. + * Used to send announce messages for address conflict detection. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address to announce + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +err_t +etharp_acd_announce(struct netif *netif, const ip4_addr_t *ipaddr) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, + (struct eth_addr *)netif->hwaddr, ipaddr, ðzero, + ipaddr, ARP_REQUEST); +} +#endif /* LWIP_ACD */ + #endif /* LWIP_IPV4 && LWIP_ARP */ diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index 40e16b0..f35ff4b 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -171,7 +171,7 @@ icmp_input(struct pbuf *p, struct netif *inp) goto icmperr; } if (r->len < hlen + sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header")); + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header\n")); pbuf_free(r); goto icmperr; } @@ -179,13 +179,13 @@ icmp_input(struct pbuf *p, struct netif *inp) MEMCPY(r->payload, iphdr_in, hlen); /* switch r->payload back to icmp header (cannot fail) */ if (pbuf_remove_header(r, hlen)) { - LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0); + LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed", 0); pbuf_free(r); goto icmperr; } /* copy the rest of the packet without ip header */ if (pbuf_copy(r, p) != ERR_OK) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed")); + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed\n")); pbuf_free(r); goto icmperr; } @@ -196,7 +196,7 @@ icmp_input(struct pbuf *p, struct netif *inp) } else { /* restore p->payload to point to icmp header (cannot fail) */ if (pbuf_remove_header(p, hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN)) { - LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); + LWIP_ASSERT("icmp_input: restoring original p->payload failed", 0); goto icmperr; } } @@ -206,13 +206,14 @@ icmp_input(struct pbuf *p, struct netif *inp) * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ iecho = (struct icmp_echo_hdr *)p->payload; if (pbuf_add_header(p, hlen)) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet")); + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet\n")); } else { err_t ret; struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; ip4_addr_copy(iphdr->src, *src); ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); + p->if_idx = NETIF_NO_INDEX; /* we're reusing this pbuf, so reset its if_idx */ #if CHECKSUM_GEN_ICMP IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { /* adjust the checksum */ @@ -341,8 +342,7 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; - /* we can use the echo header here */ - struct icmp_echo_hdr *icmphdr; + struct icmp_hdr *icmphdr; ip4_addr_t iphdr_src; struct netif *netif; u16_t response_pkt_len; @@ -357,49 +357,39 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) } /* ICMP header + part of original packet */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + response_pkt_len, PBUF_RAM); + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_hdr) + response_pkt_len, PBUF_RAM); if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_send_response: failed to allocate pbuf for ICMP packet.\n")); MIB2_STATS_INC(mib2.icmpouterrors); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_echo_hdr) + response_pkt_len))); + (q->len >= (sizeof(struct icmp_hdr) + response_pkt_len))); iphdr = (struct ip_hdr *)p->payload; - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_send_response: Sending ICMP type %02X for packet from ", type)); ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); - icmphdr = (struct icmp_echo_hdr *)q->payload; + icmphdr = (struct icmp_hdr *)q->payload; icmphdr->type = type; icmphdr->code = code; - icmphdr->id = 0; - icmphdr->seqno = 0; + icmphdr->data = 0; /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, - response_pkt_len); + pbuf_copy_partial_pbuf(q, p, response_pkt_len, sizeof(struct icmp_hdr)); ip4_addr_copy(iphdr_src, iphdr->src); #ifdef LWIP_HOOK_IP4_ROUTE_SRC { ip4_addr_t iphdr_dst; ip4_addr_copy(iphdr_dst, iphdr->dest); -#ifdef LOSCFG_NET_CONTAINER - netif = ip4_route_src(&iphdr_dst, &iphdr_src, get_root_net_group()); -#else netif = ip4_route_src(&iphdr_dst, &iphdr_src); -#endif } -#else -#ifdef LOSCFG_NET_CONTAINER - netif = ip4_route(&iphdr_src, get_root_net_group()); #else netif = ip4_route(&iphdr_src); -#endif #endif if (netif != NULL) { /* calculate checksum */ diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 4ab8832..a74df16 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -220,7 +220,7 @@ igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr) struct igmp_group *group = netif_igmp_data(ifp); while (group != NULL) { - if (ip4_addr_cmp(&(group->group_address), addr)) { + if (ip4_addr_eq(&(group->group_address), addr)) { return group; } group = group->next; @@ -266,13 +266,13 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) if (list_head == NULL) { /* this is the first entry in linked list */ LWIP_ASSERT("igmp_lookup_group: first group must be allsystems", - (ip4_addr_cmp(addr, &allsystems) != 0)); + (ip4_addr_eq(addr, &allsystems) != 0)); group->next = NULL; netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); } else { /* append _after_ first entry */ LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems", - (ip4_addr_cmp(addr, &allsystems) == 0)); + (ip4_addr_eq(addr, &allsystems) == 0)); group->next = list_head->next; list_head->next = group; } @@ -366,7 +366,7 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest) switch (igmp->igmp_msgtype) { case IGMP_MEMB_QUERY: /* IGMP_MEMB_QUERY to the "all systems" address ? */ - if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) { + if ((ip4_addr_eq(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) { /* THIS IS THE GENERAL QUERY */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); @@ -395,7 +395,7 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest) if (!ip4_addr_isany(&igmp->igmp_group_address)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); ip4_addr_debug_print_val(IGMP_DEBUG, igmp->igmp_group_address); - if (ip4_addr_cmp(dest, &allsystems)) { + if (ip4_addr_eq(dest, &allsystems)) { ip4_addr_t groupaddr; LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); /* we first need to re-look for the group since we used dest last time */ @@ -455,16 +455,12 @@ igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif /* Should we join this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) { err = igmp_joingroup_netif(netif, groupaddr); if (err != ERR_OK) { /* Return an error even if some network interfaces are joined */ @@ -494,7 +490,7 @@ igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* make sure it is an igmp-enabled netif */ LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); @@ -556,16 +552,12 @@ igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif /* Should we leave this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) { err_t res = igmp_leavegroup_netif(netif, groupaddr); if (err != ERR_OK) { /* Store this result if we have not yet gotten a success */ @@ -594,7 +586,7 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* make sure it is an igmp-enabled netif */ LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); @@ -649,11 +641,8 @@ void igmp_tmr(void) { struct netif *netif; -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else + NETIF_FOREACH(netif) { -#endif struct igmp_group *group = netif_igmp_data(netif); while (group != NULL) { @@ -668,32 +657,6 @@ igmp_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -igmp_tmr_tick(void) -{ - struct netif *netif = NULL; - u32_t tick = 0; -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - struct igmp_group *group = netif_igmp_data(netif); - while (group != NULL) { - if (group->timer > 0) { - SET_TMR_TICK(tick, group->timer); - } - group = group->next; - } - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "igmp_tmr_tick", tick)); - return tick; -} -#endif - /** * Called if a timeout for one group is reached. * Sends a report for this group. @@ -706,7 +669,7 @@ igmp_timeout(struct netif *netif, struct igmp_group *group) /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group (unless it is the allsystems group) */ if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && - (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { + (!(ip4_addr_eq(&(group->group_address), &allsystems)))) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)netif)); diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 11f93d8..e044bff 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -126,11 +126,7 @@ ip4_set_default_multicast_netif(struct netif *default_multicast_netif) * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides the parameters. */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest, struct net_group *group) -#else ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) -#endif { if (src != NULL) { /* when src==NULL, the hook is called from ip4_route(dest) */ @@ -139,11 +135,7 @@ ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) return netif; } } -#ifdef LOSCFG_NET_CONTAINER - return ip4_route(dest, group); -#else return ip4_route(dest); -#endif } #endif /* LWIP_HOOK_IP4_ROUTE_SRC */ @@ -157,11 +149,7 @@ ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) * @return the netif on which to send to reach dest */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -ip4_route(const ip4_addr_t *dest, struct net_group *group) -#else ip4_route(const ip4_addr_t *dest) -#endif { #if !LWIP_SINGLE_NETIF struct netif *netif; @@ -179,20 +167,16 @@ ip4_route(const ip4_addr_t *dest) LWIP_UNUSED_ARG(dest); /* iterate through netifs */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif /* is the netif up, does it have a link and a valid address? */ if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { /* network mask matches? */ - if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { + if (ip4_addr_net_eq(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { /* return netif on which to forward IP packet */ return netif; } /* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */ - if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) { + if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_eq(dest, netif_ip4_gw(netif))) { /* return netif on which to forward IP packet */ return netif; } @@ -200,23 +184,14 @@ ip4_route(const ip4_addr_t *dest) } #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF - /* loopif is disabled, looopback traffic is passed through any netif */ + /* loopif is disabled, loopback traffic is passed through any netif */ if (ip4_addr_isloopback(dest)) { /* don't check for link on loopback traffic */ -#ifdef LOSCFG_NET_CONTAINER - if (group->netif_default != NULL && netif_is_up(group->netif_default)) { - return group->netif_default; -#else - if (netif_default != NULL && netif_is_up(netif_default)) { + if ((netif_default != NULL) && netif_is_up(netif_default)) { return netif_default; -#endif } /* default netif is not up, just use any netif for loopback traffic */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (netif_is_up(netif)) { return netif; } @@ -237,14 +212,9 @@ ip4_route(const ip4_addr_t *dest) } #endif #endif /* !LWIP_SINGLE_NETIF */ -#ifdef LOSCFG_NET_CONTAINER - if ((group->netif_default == NULL) || !netif_is_up(group->netif_default) || - !netif_is_link_up(group->netif_default) || - ip4_addr_isany_val(*netif_ip4_addr(group->netif_default)) || ip4_addr_isloopback(dest)) { -#else + if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) { -#endif /* No matching netif found and default netif is not usable. If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", @@ -253,11 +223,8 @@ ip4_route(const ip4_addr_t *dest) MIB2_STATS_INC(mib2.ipoutnoroutes); return NULL; } -#ifdef LOSCFG_NET_CONTAINER - return group->netif_default; -#else + return netif_default; -#endif } #if IP_FORWARD @@ -369,6 +336,40 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100))); } + /* Take care of setting checksums to 0 for checksum offload netifs */ + if (CHECKSUM_GEN_IP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP)) { + IPH_CHKSUM_SET(iphdr, 0); + } + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP +#if LWIP_UDPLITE + case IP_PROTO_UDPLITE: +#endif + case IP_PROTO_UDP: + if (CHECKSUM_GEN_UDP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_UDP)) { + ((struct udp_hdr *)((u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif +#if LWIP_TCP + case IP_PROTO_TCP: + if (CHECKSUM_GEN_TCP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_TCP)) { + ((struct tcp_hdr *)((u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif +#if LWIP_ICMP + case IP_PROTO_ICMP: + if (CHECKSUM_GEN_ICMP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP)) { + ((struct icmp_hdr *)((u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif + default: + /* there's really nothing to do here other than satisfying 'switch-default' */ + break; + } + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); @@ -415,7 +416,7 @@ ip4_input_accept(struct netif *netif) /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) { /* unicast to this interface address? */ - if (ip4_addr_cmp(ip4_current_dest_addr(), netif_ip4_addr(netif)) || + if (ip4_addr_eq(ip4_current_dest_addr(), netif_ip4_addr(netif)) || /* or broadcast on this interface network address? */ ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF @@ -474,10 +475,6 @@ ip4_input(struct pbuf *p, struct netif *inp) IP_STATS_INC(ip.recv); MIB2_STATS_INC(mib2.ipinreceives); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_netif(inp); -#endif - /* identify the IP header */ iphdr = (struct ip_hdr *)p->payload; if (IPH_V(iphdr) != 4) { @@ -559,7 +556,7 @@ ip4_input(struct pbuf *p, struct netif *inp) /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */ ip4_addr_t allsystems; IP4_ADDR(&allsystems, 224, 0, 0, 1); - if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) && + if (ip4_addr_eq(ip4_current_dest_addr(), &allsystems) && ip4_addr_isany(ip4_current_src_addr())) { check_ip_src = 0; } @@ -589,11 +586,7 @@ ip4_input(struct pbuf *p, struct netif *inp) #endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ { #if !LWIP_SINGLE_NETIF -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (netif == inp) { /* we checked that before already */ continue; @@ -1022,13 +1015,13 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d ip4_debug_print(p); #if ENABLE_LOOPBACK - if (ip4_addr_cmp(dest, netif_ip4_addr(netif)) + if (ip4_addr_eq(dest, netif_ip4_addr(netif)) #if !LWIP_HAVE_LOOPIF || ip4_addr_isloopback(dest) #endif /* !LWIP_HAVE_LOOPIF */ ) { /* Packet to self, enqueue it for loopback */ - LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); } #if LWIP_MULTICAST_TX_OPTIONS @@ -1072,13 +1065,8 @@ ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif; LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_curr_process_net_group(); - if ((netif = ip4_route_src(src, dest, group)) == NULL) { -#else if ((netif = ip4_route_src(src, dest)) == NULL) { -#endif LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); diff --git a/src/core/ipv4/ip4_addr.c b/src/core/ipv4/ip4_addr.c index f99d8dd..79127ac 100644 --- a/src/core/ipv4/ip4_addr.c +++ b/src/core/ipv4/ip4_addr.c @@ -73,7 +73,7 @@ ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif) } else if (addr == ip4_addr_get_u32(netif_ip4_addr(netif))) { return 0; /* on the same (sub) network... */ - } else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) + } else if (ip4_addr_net_eq(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) /* ...and host identifier bits are all ones? =>... */ && ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) == (IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) { diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index 50068ff..5303144 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -106,8 +106,8 @@ PACK_STRUCT_END #endif #define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ - (ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ - ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ + (ip4_addr_eq(&(iphdrA)->src, &(iphdrB)->src) && \ + ip4_addr_eq(&(iphdrA)->dest, &(iphdrB)->dest) && \ IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 /* global variables */ @@ -213,26 +213,6 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p return pbufs_freed; } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -ip_reass_tmr_tick(void) -{ - struct ip_reassdata *r = NULL; - u32_t tick = 0; - u32_t val; - - r = reassdatagrams; - while (r != NULL) { - val = r->timer + 1; - SET_TMR_TICK(tick, val); - r = r->next; - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip_reass_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - #if IP_REASS_FREE_OLDEST /** * Free the oldest datagram to make room for enqueueing new fragments. diff --git a/src/core/ipv6/dhcp6.c b/src/core/ipv6/dhcp6.c index 36fbc16..e6a7e64 100644 --- a/src/core/ipv6/dhcp6.c +++ b/src/core/ipv6/dhcp6.c @@ -16,8 +16,8 @@ * - only start requests if a valid local address is available on the netif * - only start information requests if required (not for every RA) * - * dhcp6_enable_stateful() enables stateful DHCPv6 for a netif (stateless disabled)\n - * dhcp6_enable_stateless() enables stateless DHCPv6 for a netif (stateful disabled)\n + * dhcp6_enable_stateful() enables stateful DHCPv6 for a netif (stateless disabled)
    + * dhcp6_enable_stateless() enables stateless DHCPv6 for a netif (stateful disabled)
    * dhcp6_disable() disable DHCPv6 for a netif * * When enabled, requests are only issued after receipt of RA with the @@ -240,7 +240,7 @@ dhcp6_get_struct(struct netif *netif, const char *dbg_requester) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL); return NULL; } - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: allocated dhcp6", dbg_requester)); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: allocated dhcp6\n", dbg_requester)); dhcp6->pcb_allocated = 1; } return dhcp6; @@ -299,7 +299,7 @@ err_t dhcp6_enable_stateful(struct netif *netif) { LWIP_UNUSED_ARG(netif); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("stateful dhcp6 not implemented yet")); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("stateful dhcp6 not implemented yet\n")); return ERR_VAL; } @@ -324,12 +324,12 @@ dhcp6_enable_stateless(struct netif *netif) return ERR_MEM; } if (dhcp6_stateless_enabled(dhcp6)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 already enabled")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 already enabled\n")); return ERR_OK; } else if (dhcp6->state != DHCP6_STATE_OFF) { /* stateful running */ /* @todo: stop stateful once it is implemented */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): switching from stateful to stateless DHCPv6")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): switching from stateful to stateless DHCPv6\n")); } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 enabled\n")); dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_enable_stateless"); @@ -453,14 +453,14 @@ dhcp6_information_request(struct netif *netif, struct dhcp6 *dhcp6) { const u16_t requested_options[] = { #if LWIP_DHCP6_PROVIDE_DNS_SERVERS - DHCP6_OPTION_DNS_SERVERS, + DHCP6_OPTION_DNS_SERVERS, DHCP6_OPTION_DOMAIN_LIST #endif #if LWIP_DHCP6_GET_NTP_SRV , DHCP6_OPTION_SNTP_SERVERS #endif }; - + u16_t msecs; struct pbuf *p_out; u16_t options_out_len; @@ -579,7 +579,7 @@ dhcp6_handle_config_reply(struct netif *netif, struct pbuf *p_msg_in) } #endif /* LWIP_IPV6_DHCP6_STATELESS */ -/** This function is called from nd6 module when an RA messsage is received +/** This function is called from nd6 module when an RA message is received * It triggers DHCPv6 requests (if enabled). */ void @@ -645,7 +645,7 @@ dhcp6_parse_reply(struct pbuf *p, struct dhcp6 *dhcp6) /* overflow */ return ERR_BUF; } - /* copy option + length, might be split accross pbufs */ + /* copy option + length, might be split across pbufs */ op_len = (u8_t *)pbuf_get_contiguous(p, op_len_buf, 4, 4, offset); if (op_len == NULL) { /* failed to get option and length */ @@ -800,11 +800,7 @@ dhcp6_tmr(void) { struct netif *netif; /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); /* only act on DHCPv6 configured interfaces */ if (dhcp6 != NULL) { @@ -822,29 +818,4 @@ dhcp6_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -dhcp6_tmr_tick() -{ - struct netif *netif = NULL; - u32_t tick = 0; - /* loop through netif's */ - #ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); - /* only act on DHCPv6 configured interfaces */ - if ((dhcp6 != NULL) && (dhcp6->request_timeout > 0)) { - SET_TMR_TICK(tick, dhcp6->request_timeout); - } - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dhcp6_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - #endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index 2313cfc..ed0bd7b 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -360,11 +360,7 @@ icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, /* Swap source and destination for the reply. */ reply_dest = src_addr; reply_src = dest_addr; -#ifdef LOSCFG_NET_CONTAINER - netif = ip6_route(reply_src, reply_dest, get_root_net_group()); -#else netif = ip6_route(reply_src, reply_dest); -#endif if (netif == NULL) { ICMP6_STATS_INC(icmp6.rterr); return; @@ -392,7 +388,6 @@ icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, struct pbuf *q; struct icmp6_hdr *icmp6hdr; u16_t datalen = LWIP_MIN(p->tot_len, LWIP_ICMP6_DATASIZE); - u16_t offset; /* ICMPv6 header + datalen (as much of the offending packet as possible) */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + datalen, @@ -410,16 +405,8 @@ icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, icmp6hdr->code = code; icmp6hdr->data = lwip_htonl(data); - /* copy fields from original packet (which may be a chain of pbufs) */ - offset = sizeof(struct icmp6_hdr); - while (p && datalen) { - u16_t len = LWIP_MIN(datalen, p->len); - err_t res = pbuf_take_at(q, p->payload, len, offset); - if (res != ERR_OK) break; - datalen -= len; - offset += len; - p = p->next; - } + /* copy fields from original packet */ + pbuf_copy_partial_pbuf(q, p, datalen, sizeof(struct icmp6_hdr)); /* calculate checksum */ icmp6hdr->chksum = 0; diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index c19fa08..2c25f8a 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -83,11 +83,7 @@ * @return the netif on which to send to reach dest */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, struct net_group *group) -#else ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) -#endif { #if LWIP_SINGLE_NETIF LWIP_UNUSED_ARG(src); @@ -99,22 +95,12 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) LWIP_ASSERT_CORE_LOCKED(); /* If single netif configuration, fast return. */ -#ifdef LOSCFG_NET_CONTAINER - if ((group->netif_list != NULL) && (group->netif_list->next == NULL)) { - if (!netif_is_up(group->netif_list) || !netif_is_link_up(group->netif_list) || - (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, group->netif_list))) { -#else if ((netif_list != NULL) && (netif_list->next == NULL)) { if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list) || (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, netif_list))) { -#endif return NULL; } -#ifdef LOSCFG_NET_CONTAINER - return group->netif_list; -#else return netif_list; -#endif } #if LWIP_IPV6_SCOPES @@ -127,11 +113,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) IP6_ADDR_ZONECHECK(dest); /* Find a netif based on the zone. For custom mappings, one zone may map * to multiple netifs, so find one that can actually send a packet. */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (ip6_addr_test_zone(dest, netif) && netif_is_up(netif) && netif_is_link_up(netif)) { return netif; @@ -168,11 +150,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #if LWIP_IPV6_SCOPES if (ip6_addr_has_zone(src)) { /* Find a netif matching the source zone (relatively cheap). */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (netif_is_up(netif) && netif_is_link_up(netif) && ip6_addr_test_zone(src, netif)) { return netif; @@ -182,17 +160,13 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #endif /* LWIP_IPV6_SCOPES */ { /* Find a netif matching the source address (relatively expensive). */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp_zoneless(src, netif_ip6_addr(netif, i))) { + ip6_addr_zoneless_eq(src, netif_ip6_addr(netif, i))) { return netif; } } @@ -219,19 +193,15 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) * such, the destination address may still match a local address, and so we * still need to check for exact matches here. By (lwIP) policy, statically * configured addresses do always have an implied local /64 subnet. */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) && + ip6_addr_net_eq(dest, netif_ip6_addr(netif, i)) && (netif_ip6_addr_isstatic(netif, i) || - ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) { + ip6_addr_nethost_eq(dest, netif_ip6_addr(netif, i)))) { return netif; } } @@ -246,17 +216,13 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) /* Try with the netif that matches the source address. Given the earlier rule * for scoped source addresses, this applies to unscoped addresses only. */ if (!ip6_addr_isany(src)) { -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { + ip6_addr_eq(src, netif_ip6_addr(netif, i))) { return netif; } } @@ -267,20 +233,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) /* loopif is disabled, loopback traffic is passed through any netif */ if (ip6_addr_isloopback(dest)) { /* don't check for link on loopback traffic */ -#ifdef LOSCFG_NET_CONTAINER - if (group->netif_default != NULL && netif_is_up(group->netif_default)) { - return group->netif_default; -#else if (netif_default != NULL && netif_is_up(netif_default)) { return netif_default; -#endif } /* default netif is not up, just use any netif for loopback traffic */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (netif_is_up(netif)) { return netif; } @@ -291,19 +248,10 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #endif /* !LWIP_SINGLE_NETIF */ /* no matching netif found, use default netif, if up */ -#ifdef LOSCFG_NET_CONTAINER - if ((group->netif_default == NULL) || !netif_is_up(group->netif_default) || - !netif_is_link_up(group->netif_default)) { -#else if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { -#endif return NULL; } -#ifdef LOSCFG_NET_CONTAINER - return group->netif_default; -#else return netif_default; -#endif } /** @@ -384,8 +332,8 @@ ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) /* @todo compute the actual common bits, for longest matching prefix. */ /* We cannot count on the destination address having a proper zone * assignment, so do not compare zones in this case. */ - cand_bits = ip6_addr_netcmp_zoneless(cand_addr, dest); /* just 1 or 0 for now */ - if (cand_bits && ip6_addr_nethostcmp(cand_addr, dest)) { + cand_bits = ip6_addr_net_zoneless_eq(cand_addr, dest); /* just 1 or 0 for now */ + if (cand_bits && ip6_addr_nethost_eq(cand_addr, dest)) { return netif_ip_addr6(netif, i); /* Rule 1 */ } if ((best_addr == NULL) || /* no alternative yet */ @@ -529,7 +477,7 @@ ip6_input_accept(struct netif *netif) * scope as well (e.g., is this interface on the same link?). */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i)) + ip6_addr_eq(ip6_current_dest_addr(), netif_ip6_addr(netif, i)) #if IPV6_CUSTOM_SCOPES && (!ip6_addr_has_zone(ip6_current_src_addr()) || ip6_addr_test_zone(ip6_current_src_addr(), netif)) @@ -576,10 +524,6 @@ ip6_input(struct pbuf *p, struct netif *inp) IP6_STATS_INC(ip6.recv); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_netif(inp); -#endif - /* identify the IP header */ ip6hdr = (struct ip6_hdr *)p->payload; if (IP6H_V(ip6hdr) != 6) { @@ -667,7 +611,7 @@ ip6_input(struct pbuf *p, struct netif *inp) netif = NULL; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + ip6_addr_solicitednode_eq(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { netif = inp; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); @@ -708,11 +652,7 @@ ip6_input(struct pbuf *p, struct netif *inp) } #endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ #if !LWIP_SINGLE_NETIF -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, group) { -#else NETIF_FOREACH(netif) { -#endif if (netif == inp) { /* we checked that before already */ continue; @@ -763,6 +703,10 @@ netif_found: /* Init header length. */ hlen = hlen_tot = IP6_HLEN; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); + ip6_debug_print(p); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + /* Move to payload. */ pbuf_remove_header(p, IP6_HLEN); @@ -1067,9 +1011,10 @@ netif_found: goto ip6_input_cleanup; } - /* Returned p point to IPv6 header. + /* Returned p points to IPv6 header. * Update all our variables and pointers and continue. */ ip6hdr = (struct ip6_hdr *)p->payload; + ip_data.current_ip6_header = ip6hdr; nexth = &IP6H_NEXTH(ip6hdr); hlen = hlen_tot = IP6_HLEN; pbuf_remove_header(p, IP6_HLEN); @@ -1102,12 +1047,8 @@ netif_found: options_done: /* send to upper layers */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); - ip6_debug_print(p); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - ip_data.current_ip_header_tot_len = hlen_tot; - + #if LWIP_RAW /* p points to IPv6 header again for raw_input. */ pbuf_add_header_force(p, hlen_tot); @@ -1305,7 +1246,7 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, #endif /* !LWIP_HAVE_LOOPIF */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { + ip6_addr_eq(dest, netif_ip6_addr(netif, i))) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); @@ -1357,26 +1298,14 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_curr_process_net_group(); -#endif - if (dest != LWIP_IP_HDRINCL) { -#ifdef LOSCFG_NET_CONTAINER - netif = ip6_route(src, dest, group); -#else netif = ip6_route(src, dest); -#endif } else { /* IP header included in p, read addresses. */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy_from_packed(src_addr, ip6hdr->src); ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); -#ifdef LOSCFG_NET_CONTAINER - netif = ip6_route(&src_addr, &dest_addr, group); -#else netif = ip6_route(&src_addr, &dest_addr); -#endif dest = &dest_addr; } diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index de80f8e..6e0ac86 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -46,6 +46,7 @@ #include "lwip/ip_addr.h" #include "lwip/def.h" +#include "lwip/netif.h" #include @@ -57,7 +58,7 @@ const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); #define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10)) -#if 0 // this ip6addr_aton is buggy, fixed in `fixme.c' + /** * Check whether "cp" is a valid ascii representation * of an IPv6 address and convert to a binary address. @@ -185,6 +186,17 @@ fix_byte_order_and_return: } ip6_addr_clear_zone(addr); +#if LWIP_IPV6_SCOPES + if (*s == '%') { + const char *scopestr = s + 1; + if (*scopestr) { + struct netif *netif = netif_find(scopestr); + if (netif) { + ip6_addr_assign_zone(addr, IP6_UNKNOWN, netif); + } + } + } +#endif } if (current_block_index != 7) { @@ -193,7 +205,7 @@ fix_byte_order_and_return: return 1; } -#endif + /** * Convert numeric IPv6 address into ASCII representation. * returns ptr to static buffer; not reentrant! diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index 2bfaa37..ba91cfd 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -137,26 +137,6 @@ ip6_reass_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -ip6_reass_tmr_tick(void) -{ - u32_t tick = 0; - u32_t val = 0; - struct ip6_reassdata *r = NULL; - - r = reassdatagrams; - while (r != NULL) { - val = r->timer + 1; - SET_TMR_TICK(tick, val); - r = r->next; - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip6_reass_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - /** * Free a datagram (struct ip6_reassdata) and all its pbufs. * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), @@ -182,11 +162,11 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) ipr->p = iprh->next_pbuf; /* Restore the part that we've overwritten with our helper structure, or we * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ - MEMCPY(p->payload, ipr->orig_hdr, sizeof(iprh)); + MEMCPY(p->payload, ipr->orig_hdr, sizeof(*iprh)); /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). This cannot fail since we already checked when receiving this fragment. */ if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) { - LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); + LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed", 0); } else { /* Reconstruct the zoned source and destination addresses, so that we do @@ -340,8 +320,8 @@ ip6_reass(struct pbuf *p) in the reassembly buffer. If so, we proceed with copying the fragment into the buffer. */ if ((frag_hdr->_identification == ipr->identification) && - ip6_addr_cmp_packed(ip6_current_src_addr(), &(IPV6_FRAG_SRC(ipr)), ipr->src_zone) && - ip6_addr_cmp_packed(ip6_current_dest_addr(), &(IPV6_FRAG_DEST(ipr)), ipr->dest_zone)) { + ip6_addr_packed_eq(ip6_current_src_addr(), &(IPV6_FRAG_SRC(ipr)), ipr->src_zone) && + ip6_addr_packed_eq(ip6_current_dest_addr(), &(IPV6_FRAG_DEST(ipr)), ipr->dest_zone)) { IP6_FRAG_STATS_INC(ip6_frag.cachehit); break; } @@ -467,6 +447,19 @@ ip6_reass(struct pbuf *p) } } #endif /* IP_REASS_CHECK_OVERLAP */ + /* Check if the fragments received so far have no gaps. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + if (end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the following fragment */ + valid = 0; + } /* the new pbuf should be inserted before this */ next_pbuf = q; if (iprh_prev != NULL) { @@ -672,12 +665,13 @@ ip6_reass(struct pbuf *p) /* Move pbuf back to IPv6 header. This should never fail. */ if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) { - LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); + LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed", 0); pbuf_free(p); return NULL; } /* Return the pbuf chain */ + MIB2_STATS_INC(mib2.ip6reasmoks); return p; } /* the datagram is not (yet?) reassembled completely */ diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index c8ec789..ac4fb01 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -5,12 +5,12 @@ * @defgroup mld6 MLD6 * @ingroup ip6 * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. - * No support for MLDv2.\n - * Note: The allnodes (ff01::1, ff02::1) group is assumed be received by your + * No support for MLDv2.
    + * Note: The allnodes (ff01::1, ff02::1) group is assumed be received by your * netif since it must always be received for correct IPv6 operation (e.g. SLAAC). - * Ensure the netif filters are configured accordingly!\n + * Ensure the netif filters are configured accordingly!
    * The netif flags also need NETIF_FLAG_MLD6 flag set to enable MLD6 on a - * netif ("netif->flags |= NETIF_FLAG_MLD6;").\n + * netif ("netif->flags |= NETIF_FLAG_MLD6;").
    * To be called from TCPIP thread. */ @@ -146,7 +146,7 @@ mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) struct mld_group *group = netif_mld6_data(ifp); while (group != NULL) { - if (ip6_addr_cmp(&(group->group_address), addr)) { + if (ip6_addr_eq(&(group->group_address), addr)) { return group; } group = group->next; @@ -320,11 +320,7 @@ mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) LWIP_ASSERT_CORE_LOCKED(); /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif /* Should we join this interface ? */ if (ip6_addr_isany(srcaddr) || netif_get_ip6_addr_match(netif, srcaddr) >= 0) { @@ -413,11 +409,7 @@ mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) LWIP_ASSERT_CORE_LOCKED(); /* loop through netif's */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif /* Should we leave this interface ? */ if (ip6_addr_isany(srcaddr) || netif_get_ip6_addr_match(netif, srcaddr) >= 0) { @@ -505,11 +497,7 @@ mld6_tmr(void) { struct netif *netif; -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif struct mld_group *group = netif_mld6_data(netif); while (group != NULL) { @@ -529,35 +517,6 @@ mld6_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" - -u32_t -mld6_tmr_tick(void) -{ - struct netif *netif = NULL; - u32_t tick = 0; - -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - struct mld_group *group = netif_mld6_data(netif); - while (group != NULL) { - if (group->timer > 0) { - SET_TMR_TICK(tick, group->timer); - } - group = group->next; - } - } - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "mld6_tmr_tick", tick)); - return tick; -} -#endif - /** * Schedule a delayed membership report for a group * diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 47ab8ad..f7b5f56 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -72,6 +72,18 @@ #if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK #error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK #endif +#if LWIP_ND6_NUM_NEIGHBORS > 127 +#error LWIP_ND6_NUM_NEIGHBORS must fit into an s8_t (max value: 127) +#endif +#if LWIP_ND6_NUM_DESTINATIONS > 32767 +#error LWIP_ND6_NUM_DESTINATIONS must fit into an s16_t (max value: 32767) +#endif +#if LWIP_ND6_NUM_PREFIXES > 127 +#error LWIP_ND6_NUM_PREFIXES must fit into an s8_t (max value: 127) +#endif +#if LWIP_ND6_NUM_ROUTERS > 127 +#error LWIP_ND6_NUM_ROUTERS must fit into an s8_t (max value: 127) +#endif /* Router tables. */ struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; @@ -83,8 +95,11 @@ struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ +#if LWIP_ND6_QUEUEING +static u8_t nd6_queue_size = 0; +#endif + /* Index for cache entries. */ -static u8_t nd6_cached_neighbor_index; static netif_addr_idx_t nd6_cached_destination_index; /* Multicast address holder. */ @@ -210,7 +225,7 @@ nd6_process_autoconfig_prefix(struct netif *netif, for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { addr_state = netif_ip6_addr_state(netif, i); if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) && - ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) { + ip6_addr_net_eq(prefix_addr, netif_ip6_addr(netif, i))) { /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e). * The valid lifetime will never drop to zero as a result of this. */ u32_t remaining_life = netif_ip6_addr_valid_life(netif, i); @@ -258,7 +273,7 @@ nd6_process_autoconfig_prefix(struct netif *netif, free_idx = 0; for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { - if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) { + if (ip6_addr_eq(&ip6addr, netif_ip6_addr(netif, i))) { return; /* formed address already exists */ } } else if (free_idx == 0) { @@ -338,7 +353,7 @@ nd6_input(struct pbuf *p, struct netif *inp) for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) { /* We are using a duplicate address. */ nd6_duplicate_addr_detected(inp, i); @@ -475,7 +490,7 @@ nd6_input(struct pbuf *p, struct netif *inp) if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && ip6_addr_isany(ip6_current_src_addr()))) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) { accepted = 1; break; } @@ -492,7 +507,7 @@ nd6_input(struct pbuf *p, struct netif *inp) /* Sender is validating this address. */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + ip6_addr_eq(&target_address, netif_ip6_addr(inp, i))) { /* Send a NA back so that the sender does not use this address. */ nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { @@ -672,7 +687,7 @@ nd6_input(struct pbuf *p, struct netif *inp) case ND6_OPTION_TYPE_SOURCE_LLADDR: { struct lladdr_option *lladdr_opt; - if (option_len < sizeof(struct lladdr_option)) { + if (option_len < (ND6_LLADDR_OPTION_MIN_LENGTH + inp->hwaddr_len)) { goto lenerr_drop_free_return; } lladdr_opt = (struct lladdr_option *)buffer; @@ -782,7 +797,7 @@ nd6_input(struct pbuf *p, struct netif *inp) u8_t s; for (s = 0; s < DNS_MAX_SERVERS; s++) { const ip_addr_t *addr = dns_getserver(s); - if(ip_addr_cmp(addr, &rdnss_address)) { + if(ip_addr_eq(addr, &rdnss_address)) { dns_setserver(s, NULL); } } @@ -1032,7 +1047,7 @@ nd6_tmr(void) * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */ s8_t j; for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) { - if (ip6_addr_cmp(&destination_cache[j].next_hop_addr, + if (ip6_addr_eq(&destination_cache[j].next_hop_addr, &default_router_list[i].neighbor_entry->next_hop_address)) { ip6_addr_set_any(&destination_cache[j].destination_addr); } @@ -1061,11 +1076,7 @@ nd6_tmr(void) } /* Process our own addresses, updating address lifetimes and/or DAD state. */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { u8_t addr_state; #if LWIP_IPV6_ADDRESS_LIFETIMES @@ -1146,11 +1157,7 @@ nd6_tmr(void) /* Send router solicitation messages, if necessary. */ if (!nd6_tmr_rs_reduction) { nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) { -#else NETIF_FOREACH(netif) { -#endif if ((netif->rs_count > 0) && netif_is_up(netif) && netif_is_link_up(netif) && !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && @@ -1167,109 +1174,9 @@ nd6_tmr(void) } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -u32_t -nd6_tmr_tick(void) -{ - s8_t i; - struct netif *netif = NULL; - u32_t tick = 0; - u32_t val = 0; - - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - switch (neighbor_cache[i].state) { - case ND6_PROBE: - case ND6_INCOMPLETE: /* state PROBE and INCOMPLETE return 1 */ - return 1; - case ND6_REACHABLE: - /* Send queued packets, if any are left. Should have been sent already. */ - if (neighbor_cache[i].q != NULL) { - return 1; - } - if (neighbor_cache[i].counter.reachable_time >= ND6_TMR_INTERVAL) { - val = neighbor_cache[i].counter.reachable_time / ND6_TMR_INTERVAL; - SET_TMR_TICK(tick, val); - } - break; - case ND6_DELAY: - val = neighbor_cache[i].counter.delay_time; - SET_TMR_TICK(tick, val); - break; - default: - /* Do nothing. */ - break; - } - } - - /* Process router entries. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if (default_router_list[i].neighbor_entry != NULL) { - val = default_router_list[i].invalidation_timer; - SET_TMR_TICK(tick, val); - } - } - - /* Process prefix entries. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { - if (prefix_list[i].netif != NULL) { - val = prefix_list[i].invalidation_timer; - SET_TMR_TICK(tick, val); - } - } - - /* Process our own addresses, updating address lifetimes and/or DAD state. */ -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(netif, get_root_net_group()) -#else - NETIF_FOREACH(netif) -#endif - { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { - u8_t addr_state; -#if LWIP_IPV6_ADDRESS_LIFETIMES - /* Step 1: update address lifetimes (valid and preferred). */ - addr_state = netif_ip6_addr_state(netif, i); - if (!ip6_addr_isinvalid(addr_state) && - !netif_ip6_addr_isstatic(netif, i)) { - u32_t life = netif_ip6_addr_valid_life(netif, i); - if (!ip6_addr_life_isinfinite(life)) { - SET_TMR_TICK(tick, life); - } - - life = netif_ip6_addr_pref_life(netif, i); - if (!ip6_addr_life_isinfinite(life)) { - SET_TMR_TICK(tick, life); - } - } - /* The address state may now have changed, so reobtain it next. */ -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ - /* Step 2: update DAD state. */ - addr_state = netif_ip6_addr_state(netif, i); - if (ip6_addr_istentative(addr_state)) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "nd6_tmr_tick")); - return 1; - } - } - } - - /* Router solicitations are sent in 4 second intervals (see RFC 4861, ch. 6.3.7) */ - /* ND6_RTR_SOLICITATION_INTERVAL */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - if (nd6_tmr_rs_reduction > 0) { - val = nd6_tmr_rs_reduction; - SET_TMR_TICK(tick, val); - } -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "nd6_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - /** Send a neighbor solicitation message for a specific neighbor cache entry * - * @param entry the neightbor cache entry for wich to send the message + * @param entry the neighbor cache entry for which to send the message * @param flags one of ND6_SEND_FLAG_* */ static void @@ -1299,7 +1206,7 @@ nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) int i; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_netcmp(target_addr, netif_ip6_addr(netif, i))) { + ip6_addr_net_eq(target_addr, netif_ip6_addr(netif, i))) { src_addr = netif_ip6_addr(netif, i); break; } @@ -1522,7 +1429,7 @@ nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) { s8_t i; for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { + if (ip6_addr_eq(ip6addr, &(neighbor_cache[i].next_hop_address))) { return i; } } @@ -1684,7 +1591,7 @@ nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) IP6_ADDR_ZONECHECK(ip6addr); for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { + if (ip6_addr_eq(ip6addr, &(destination_cache[i].destination_addr))) { return i; } } @@ -1755,7 +1662,7 @@ nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { if ((prefix_list[i].netif == netif) && (prefix_list[i].invalidation_timer > 0) && - ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { + ip6_addr_net_eq(ip6addr, &(prefix_list[i].prefix))) { return 1; } } @@ -1766,7 +1673,7 @@ nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && netif_ip6_addr_isstatic(netif, i) && - ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { + ip6_addr_net_eq(ip6addr, netif_ip6_addr(netif, i))) { return 1; } } @@ -1800,7 +1707,7 @@ nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) /* Look for valid routers. A reachable router is preferred. */ valid_router = -1; for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - /* Is the router netif both set and apppropriate? */ + /* Is the router netif both set and appropriate? */ if (default_router_list[i].neighbor_entry != NULL) { router_netif = default_router_list[i].neighbor_entry->netif; if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : @@ -1870,7 +1777,7 @@ nd6_find_route(const ip6_addr_t *ip6addr) * matches. Pick the first one that is associated with a suitable netif. */ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { netif = prefix_list[i].netif; - if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) && + if ((netif != NULL) && ip6_addr_net_eq(&prefix_list[i].prefix, ip6addr) && netif_is_up(netif) && netif_is_link_up(netif)) { return netif; } @@ -1905,7 +1812,7 @@ nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if ((default_router_list[i].neighbor_entry != NULL) && ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && - ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { + ip6_addr_eq(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { return i; } } @@ -1955,9 +1862,9 @@ nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { /* check if router already exists (this is a special case for 2 netifs on the same subnet - e.g. wifi and cable) */ - if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ - return router_index; - } + if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ + return router_index; + } if (default_router_list[router_index].neighbor_entry == NULL) { /* remember lowest free index to create a new entry */ free_router_index = router_index; @@ -1991,7 +1898,7 @@ nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) /* Look for prefix in list. */ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { - if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && + if ((ip6_addr_net_eq(&(prefix_list[i].prefix), prefix)) && (prefix_list[i].netif == netif)) { return i; } @@ -2048,6 +1955,7 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) #endif /* LWIP_HOOK_ND6_GET_GW */ s8_t i; s16_t dst_idx; + struct nd6_destination_cache_entry *dest; IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); @@ -2061,8 +1969,11 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) } #endif /* LWIP_NETIF_HWADDRHINT */ + LWIP_ASSERT("sane cache index", nd6_cached_destination_index < LWIP_ND6_NUM_DESTINATIONS); + /* Look for ip6addr in destination cache. */ - if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + dest = &destination_cache[nd6_cached_destination_index]; + if (ip6_addr_eq(ip6addr, &dest->destination_addr)) { /* the cached entry index is the right one! */ /* do nothing. */ ND6_STATS_INC(nd6.cachehit); @@ -2073,6 +1984,7 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) /* found destination entry. make it our new cached index. */ LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; + dest = &destination_cache[dst_idx]; } else { /* Not found. Create a new destination entry. */ dst_idx = nd6_new_destination_cache_entry(); @@ -2080,72 +1992,71 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) /* got new destination entry. make it our new cached index. */ LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; + dest = &destination_cache[dst_idx]; } else { /* Could not create a destination cache entry. */ return ERR_MEM; } /* Copy dest address to destination cache. */ - ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); + ip6_addr_set(&dest->destination_addr, ip6addr); /* Now find the next hop. is it a neighbor? */ if (ip6_addr_islinklocal(ip6addr) || nd6_is_prefix_in_netif(ip6addr, netif)) { /* Destination in local link. */ - destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); - ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); + dest->pmtu = netif_mtu6(netif); + ip6_addr_copy(dest->next_hop_addr, dest->destination_addr); #ifdef LWIP_HOOK_ND6_GET_GW } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { /* Next hop for destination provided by hook function. */ - destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; - ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); + dest->pmtu = netif->mtu; + ip6_addr_set(&dest->next_hop_addr, next_hop_addr); #endif /* LWIP_HOOK_ND6_GET_GW */ } else { /* We need to select a router. */ i = nd6_select_router(ip6addr, netif); if (i < 0) { /* No router found. */ - ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); + ip6_addr_set_any(&dest->destination_addr); return ERR_RTE; } - destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ - ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); + dest->pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ + ip6_addr_copy(dest->next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); } } - } - #if LWIP_NETIF_HWADDRHINT - if (netif->hints != NULL) { - /* per-pcb cached entry was given */ - netif->hints->addr_hint = nd6_cached_destination_index; - } + if (netif->hints != NULL) { + /* per-pcb cached entry was given */ + netif->hints->addr_hint = nd6_cached_destination_index; + } #endif /* LWIP_NETIF_HWADDRHINT */ + } /* Look in neighbor cache for the next-hop address. */ - if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), - &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + if (ip6_addr_eq(&dest->next_hop_addr, + &(neighbor_cache[dest->cached_neighbor_idx].next_hop_address))) { /* Cache hit. */ /* Do nothing. */ ND6_STATS_INC(nd6.cachehit); } else { - i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); + i = nd6_find_neighbor_cache_entry(&dest->next_hop_addr); if (i >= 0) { /* Found a matching record, make it new cached entry. */ - nd6_cached_neighbor_index = i; + dest->cached_neighbor_idx = i; } else { /* Neighbor not in cache. Make a new entry. */ i = nd6_new_neighbor_cache_entry(); if (i >= 0) { /* got new neighbor entry. make it our new cached index. */ - nd6_cached_neighbor_index = i; + dest->cached_neighbor_idx = i; } else { /* Could not create a neighbor cache entry. */ return ERR_MEM; } /* Initialize fields. */ - ip6_addr_copy(neighbor_cache[i].next_hop_address, - destination_cache[nd6_cached_destination_index].next_hop_addr); + ip6_addr_copy(neighbor_cache[i].next_hop_address, dest->next_hop_addr); neighbor_cache[i].isrouter = 0; neighbor_cache[i].netif = netif; neighbor_cache[i].state = ND6_INCOMPLETE; @@ -2155,9 +2066,9 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) } /* Reset this destination's age. */ - destination_cache[nd6_cached_destination_index].age = 0; + dest->age = 0; - return nd6_cached_neighbor_index; + return dest->cached_neighbor_idx; } /** @@ -2217,7 +2128,11 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) /* queue packet ... */ #if LWIP_ND6_QUEUEING /* allocate a new nd6 queue entry */ - new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + new_entry = NULL; + if (nd6_queue_size < MEMP_NUM_ND6_QUEUE) { + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + nd6_queue_size++; + } if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { /* Free oldest packet (as per RFC recommendation) */ r = neighbor_cache[neighbor_index].q; @@ -2225,6 +2140,7 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) r->next = NULL; nd6_free_q(r); new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + nd6_queue_size++; } if (new_entry != NULL) { new_entry->next = NULL; @@ -2283,6 +2199,7 @@ nd6_free_q(struct nd6_q_entry *q) LWIP_ASSERT("r->p != NULL", (r->p != NULL)); pbuf_free(r->p); memp_free(MEMP_ND6_QUEUE, r); + nd6_queue_size--; } } #endif /* LWIP_ND6_QUEUEING */ @@ -2323,6 +2240,7 @@ nd6_send_q(s8_t i) pbuf_free(q->p); /* now queue entry can be freed */ memp_free(MEMP_ND6_QUEUE, q); + nd6_queue_size--; } #else /* LWIP_ND6_QUEUEING */ if (neighbor_cache[i].q != NULL) { @@ -2439,9 +2357,10 @@ nd6_reachability_hint(const ip6_addr_t *ip6addr) { s8_t i; s16_t dst_idx; + struct nd6_destination_cache_entry *dest; /* Find destination in cache. */ - if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + if (ip6_addr_eq(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { dst_idx = nd6_cached_destination_index; ND6_STATS_INC(nd6.cachehit); } else { @@ -2452,11 +2371,12 @@ nd6_reachability_hint(const ip6_addr_t *ip6addr) } /* Find next hop neighbor in cache. */ - if (ip6_addr_cmp(&(destination_cache[dst_idx].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { - i = nd6_cached_neighbor_index; + dest = &destination_cache[dst_idx]; + if (ip6_addr_eq(&dest->next_hop_addr, &(neighbor_cache[dest->cached_neighbor_idx].next_hop_address))) { + i = dest->cached_neighbor_idx; ND6_STATS_INC(nd6.cachehit); } else { - i = nd6_find_neighbor_cache_entry(&(destination_cache[dst_idx].next_hop_addr)); + i = nd6_find_neighbor_cache_entry(&dest->next_hop_addr); } if (i < 0) { return; diff --git a/src/core/lowpower.c b/src/core/lowpower.c deleted file mode 100644 index 63abefe..0000000 --- a/src/core/lowpower.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "lwip/opt.h" - -#if LWIP_LOWPOWER -#include "lwip/priv/tcp_priv.h" - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/priv/tcpip_priv.h" - -#include "lwip/ip4_frag.h" -#include "lwip/etharp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/nd6.h" -#include "lwip/ip6_frag.h" -#include "lwip/mld6.h" -#include "lwip/dhcp6.h" -#include "lwip/sys.h" -#include "lwip/pbuf.h" -#include "netif/lowpan6.h" -#include "lwip/api.h" - -#include "lwip/lowpower.h" - -#define TIMEOUT_MAX 120000 /* two mins */ -#define SYS_TIMEOUT_WAIT_TICKS 30 -#define SYS_TIMEOUT_WAIT_TIME_MS 3 - -static u32_t g_wake_up_time = TIMEOUT_MAX; -static enum lowpower_mod g_lowpower_switch = LOW_TMR_LOWPOWER_MOD; -static struct timer_entry *g_timer_header = NULL; -static struct timer_mng g_timer_mng = { LOW_TMR_TIMER_HANDLING, 0 }; -static u32_t g_last_check_timeout = 0; - -static const struct timer_handler lowpower_timer_handler[] = { -#if LWIP_TCP - /* - * The TCP timer is a special case: it does not have to run always and - * is triggered to start from TCP using tcp_timer_needed() - */ - {TCP_FAST_INTERVAL, tcp_fasttmr, tcp_fast_tmr_tick TCP_FASTTMR_NAME}, - {TCP_SLOW_INTERVAL, tcp_slowtmr, tcp_slow_tmr_tick TCP_SLOWTMR_NAME}, -#endif /* LWIP_TCP */ - -#if LWIP_IPV4 -#if IP_REASSEMBLY - {IP_TMR_INTERVAL, ip_reass_tmr, ip_reass_tmr_tick IP_REASSTRM_NAME}, -#endif /* IP_REASSEMBLY */ - -#if LWIP_ARP - {ARP_TMR_INTERVAL, etharp_tmr, etharp_tmr_tick ETHARPTMR_NAME}, -#endif /* LWIP_ARP */ - -#if LWIP_DHCP - {DHCP_FINE_TIMER_MSECS, dhcp_fine_tmr, dhcp_fine_tmr_tick DHCP_FINETMR_NAME}, - {DHCP_COARSE_TIMER_MSECS, dhcp_coarse_tmr, dhcp_coarse_tmr_tick DHCP_COARSETMR_NAME}, -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP - {AUTOIP_TMR_INTERVAL, autoip_tmr, autoip_tmr_tick AUTOIPTMR_NAME}, -#endif /* LWIP_AUTOIP */ - -#if LWIP_IGMP - {IGMP_TMR_INTERVAL, igmp_tmr, igmp_tmr_tick IGMPTMR_NAME}, -#endif /* LWIP_IGMP */ -#endif /* LWIP_IPV4 */ - -#if LWIP_DNS - {DNS_TMR_INTERVAL, dns_tmr, dns_tmr_tick DNSTMR_NAME}, -#endif /* LWIP_DNS */ - -#if LWIP_IPV6 - {ND6_TMR_INTERVAL, nd6_tmr, nd6_tmr_tick ND6TMR_NAME}, -#if LWIP_IPV6_REASS - {IP6_REASS_TMR_INTERVAL, ip6_reass_tmr, ip6_reass_tmr_tick IP6_TREASSTMR_NAME}, -#endif /* LWIP_IPV6_REASS */ - -#if LWIP_IPV6_MLD - {MLD6_TMR_INTERVAL, mld6_tmr, mld6_tmr_tick MLD6TMR_NAME}, -#endif /* LWIP_IPV6_MLD */ - -#if LWIP_IPV6_DHCP6 - {DHCP6_TIMER_MSECS, dhcp6_tmr, dhcp6_tmr_tick DHCP6TMR_NAME}, -#endif /* LWIP_IPV6_DHCP6 */ - -#if LWIP_6LOWPAN - {LOWPAN6_TMR_INTERVAL, lowpan6_tmr, lowpan6_tmr_tick LOWPAN6TMR_NAME}, -#endif /* LWIP_6LOWPAN */ -#endif /* LWIP_IPV6 */ -}; - -void -set_timer_state(enum timer_state state, u32_t waiting_time) -{ - g_timer_mng.waiting_time = waiting_time; - g_timer_mng.state = state; -} - -/* should not call by tcpip_thread */ -u8_t -sys_timeout_waiting_long(void) -{ - u8_t i = 0; - u8_t j = 0; - - while (g_timer_mng.state == LOW_TMR_GETING_TICKS) { - i++; - if (i == SYS_TIMEOUT_WAIT_TICKS) { - i = 0; - j++; - if (j == SYS_TIMEOUT_WAIT_TIME_MS) { - break; - } - sys_msleep(1); - } - } - - if (g_timer_mng.state == LOW_TMR_TIMER_WAITING) { - return ((g_timer_mng.waiting_time > TIMEOUT_TICK) ? 1 : 0); - } - - return 0; -} - -err_t -sys_timeout_reg( - u32_t msec, - sys_timeout_handler handler, - void *arg, -#if LOWPOWER_TIMER_DEBUG - char *name, -#endif - get_next_timeout next_tick) -{ - struct timer_entry *timeout = NULL; - struct timer_entry *temp = NULL; - - if (handler == NULL) { - return -1; - } - - timeout = (struct timer_entry *)memp_malloc(MEMP_SYS_TIMEOUT); - if (timeout == NULL) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("sys_timeout_reg: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty")); - return -1; - } - - timeout->handler = handler; - timeout->clock_max = msec / TIMEOUT_TICK; /* time interval */ - timeout->next_tick = next_tick; - timeout->timeout = sys_now(); - timeout->args = arg; - timeout->enable = 0; - -#if LOWPOWER_TIMER_DEBUG - timeout->name = name; -#endif - - /* add list tail */ - timeout->next = NULL; - if (g_timer_header == NULL) { - g_timer_header = timeout; - } else { - temp = g_timer_header; - while (temp->next != NULL) { - temp = temp->next; - } - temp->next = timeout; - } - - return 0; -} - -/* deal timeout and return next timer prev */ -static void -timeout_handler(struct timer_entry *t, u32_t now) -{ -#if LOWPOWER_TIMER_DEBUG - if (t->name != NULL) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s timeout: now:%u\n", t->name, now)); - } -#endif - - t->handler(t->args); - LWIP_UNUSED_ARG(now); - t->timeout += t->clock_max * TIMEOUT_TICK; -} - -static u32_t -get_timer_tick(struct timer_entry *t) -{ - u32_t tick; - - /* disable lowpower, need to timeout once a tick */ - if (g_lowpower_switch == LOW_TMR_NORMAL_MOD) { - return t->clock_max; - } - - if (t->next_tick != NULL) { - tick = t->next_tick(); - } else { - tick = 1; - LWIP_DEBUGF(LOWPOWER_DEBUG, ("next->tick is NULL\n")); - } - tick *= t->clock_max; - return tick; -} - -static void -handle_timer_and_free(struct timer_entry **pt, struct timer_entry **pn, struct timer_entry *p) -{ - struct timer_entry *t = *pt; - struct timer_entry *n = *pn; - /* insert after previous node or as the header */ - if (p == NULL) { - g_timer_header = n; - } else { - p->next = n; - } - - t->next = NULL; - sys_timeout_handler handler = t->handler; - void *args = t->args; - memp_free(MEMP_SYS_TIMEOUT, t); - *pt = NULL; - handler(args); - - /* the last entry */ - if ((n == NULL) && (p != NULL)) { - *pn = p->next; - } -} - -static u32_t -get_sleep_time(u32_t now) -{ - struct timer_entry *t = NULL; - struct timer_entry *n = NULL; - struct timer_entry *p = NULL; - u32_t msec = TIMEOUT_MAX; - u32_t tick; - u32_t temp; - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n*******get_sleep_time*****************\n")); - - for (t = g_timer_header, p = NULL; t != NULL; t = n) { - n = t->next; -again: - tick = get_timer_tick(t); - if (tick == 0) { - t->enable = 0; - p = t; - continue; - } - - if (t->enable == 0) { - t->timeout = now; - } - t->enable = 1; - temp = tick * TIMEOUT_TICK; - - if (temp <= now - t->timeout) { - if (t->next_tick == NULL) { - handle_timer_and_free(&t, &n, p); - /* t is free p=p */ - continue; - } - timeout_handler(t, now); - goto again; - } - - temp = temp - (now - t->timeout); - msec = msec > temp ? temp : msec; - p = t; - } - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("msec = %u now = %u\n", msec, now)); - return msec; -} - -static void -check_timeout(u32_t now) -{ - struct timer_entry *t = NULL; - struct timer_entry *n = NULL; - struct timer_entry *p = NULL; - u32_t msec; - u32_t ticks; - u32_t i; - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n**********timeout**************\n")); - LWIP_DEBUGF(LOWPOWER_DEBUG, ("now = %u\n", now)); - - for (t = g_timer_header, p = NULL; t != NULL; t = n) { - n = t->next; - if (t->enable == 0) { - p = t; - continue; - } - - msec = now - t->timeout; - ticks = msec / TIMEOUT_TICK; - ticks = ticks / t->clock_max; - - for (i = 0; i < ticks; i++) { - /* remove timer_entry form list */ - if (t->next_tick == NULL) { - handle_timer_and_free(&t, &n, p); - break; - } - timeout_handler(t, now); - PBUF_CHECK_FREE_OOSEQ(); - } - if (t != NULL) { - p = t; - } - } -} - -void -tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) -{ - u32_t sleeptime; - u32_t ret; - u32_t now; - -again: - if (g_timer_header == NULL) { - UNLOCK_TCPIP_CORE(); - (void)sys_arch_mbox_fetch(mbox, msg, 0); - LOCK_TCPIP_CORE(); - return; - } - - set_timer_state(LOW_TMR_GETING_TICKS, 0); - sleeptime = get_sleep_time(sys_now()); - sleeptime = sleeptime > sys_timeout_get_wake_time() ? sys_timeout_get_wake_time() : sleeptime; - set_timer_state(LOW_TMR_TIMER_WAITING, sleeptime); - - sys_timeout_set_wake_time(TIMEOUT_MAX); - UNLOCK_TCPIP_CORE(); - ret = sys_arch_mbox_fetch(mbox, msg, sleeptime); - LOCK_TCPIP_CORE(); - set_timer_state(LOW_TMR_TIMER_HANDLING, 0); - now = sys_now(); - if ((now - g_last_check_timeout) >= TIMEOUT_CHECK) { - check_timeout(sys_now()); - g_last_check_timeout = sys_now(); - } - - if (ret == SYS_ARCH_TIMEOUT) { - goto again; - } -} - -void -lowpower_cycle_tmr(void *args) -{ - struct timer_handler *handler = (struct timer_handler *)args; - - handler->handler(); -} - -err_t -set_timer_interval(u8_t i, u32_t interval) -{ - if (i >= LWIP_ARRAYSIZE(lowpower_timer_handler)) { - return -1; - } - return sys_timeout_reg(interval, lowpower_cycle_tmr, - (void *)(&lowpower_timer_handler[i]), -#if LOWPOWER_TIMER_DEBUG - lowpower_timer_handler[i].name, -#endif - lowpower_timer_handler[i].next_tick); -} - -/* registed when init */ -void -tcp_timer_needed(void) -{} - -void -sys_timeouts_init(void) -{ - u8_t i; - - for (i = 0; i < LWIP_ARRAYSIZE(lowpower_timer_handler); i++) { - if (set_timer_interval(i, lowpower_timer_handler[i].interval) != 0) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("ERROR:regist timer faild! i = %u\n", i)); - } - } -} - -void -sys_untimeout(sys_timeout_handler handler, void *arg) -{ - struct timer_entry *t = NULL; - struct timer_entry *p = NULL; - struct timer_entry *n = NULL; - - for (t = g_timer_header, p = NULL; t != NULL; t = n) { - n = t->next; - if ((t->handler == handler) && (t->args == arg)) { - if (p == NULL) { - g_timer_header = t->next; - } else { - p->next = t->next; - } - t->next = NULL; - memp_free(MEMP_SYS_TIMEOUT, t); - t = NULL; - } - if (t != NULL) { - p = t; - } - } -} -void -sys_restart_timeouts(void) -{} - -err_t -sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) -{ - return sys_timeout_reg(msecs, handler, arg, -#if LOWPOWER_TIMER_DEBUG - NULL, -#endif - NULL); -} - -void -sys_timeout_set_wake_time(u32_t val) -{ - g_wake_up_time = val; -} - -u32_t -sys_timeout_get_wake_time(void) -{ - return g_wake_up_time; -} - -void -set_lowpower_mod(enum lowpower_mod sw) -{ - g_lowpower_switch = sw; -} - -enum lowpower_mod -get_lowpowper_mod(void) -{ - return g_lowpower_switch; -} -#endif /* LWIP_LOWPOWER */ diff --git a/src/core/mem.c b/src/core/mem.c index 315fb3c..0aa34a2 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -60,6 +60,7 @@ #include "lwip/stats.h" #include "lwip/err.h" +#include /* snprintf */ #include #if MEM_LIBC_MALLOC @@ -151,7 +152,7 @@ mem_overflow_init_raw(void *p, size_t size) } #endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ -#if MEM_LIBC_MALLOC || MEM_USE_POOLS +#if MEM_CUSTOM_ALLOCATOR || MEM_USE_POOLS /** mem_init is not used when using pools instead of a heap or using * C library malloc(). @@ -171,23 +172,9 @@ mem_trim(void *mem, mem_size_t size) LWIP_UNUSED_ARG(size); return mem; } -#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ +#endif /* MEM_CUSTOM_ALLOCATOR || MEM_USE_POOLS */ -#if MEM_LIBC_MALLOC -/* lwIP heap implemented using C library malloc() */ - -/* in case C library malloc() needs extra protection, - * allow these defines to be overridden. - */ -#ifndef mem_clib_free -#define mem_clib_free free -#endif -#ifndef mem_clib_malloc -#define mem_clib_malloc malloc -#endif -#ifndef mem_clib_calloc -#define mem_clib_calloc calloc -#endif +#if MEM_CUSTOM_ALLOCATOR #if LWIP_STATS && MEM_STATS #define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) @@ -206,7 +193,7 @@ mem_trim(void *mem, mem_size_t size) void * mem_malloc(mem_size_t size) { - void *ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); + void *ret = MEM_CUSTOM_MALLOC(size + MEM_LIBC_STATSHELPER_SIZE); if (ret == NULL) { MEM_STATS_INC_LOCKED(err); } else { @@ -233,7 +220,7 @@ mem_free(void *rmem) rmem = (u8_t *)rmem - MEM_LIBC_STATSHELPER_SIZE; MEM_STATS_DEC_USED_LOCKED(used, *(mem_size_t *)rmem); #endif - mem_clib_free(rmem); + MEM_CUSTOM_FREE(rmem); } #elif MEM_USE_POOLS @@ -688,7 +675,7 @@ mem_free(void *rmem) /** * Shrink memory returned by mem_malloc(). * - * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked + * @param rmem pointer to memory allocated by mem_malloc the is to be shrunk * @param new_size required size after shrinking (needs to be smaller than or * equal to the previous size) * @return for compatibility reasons: is always == rmem, at the moment @@ -757,7 +744,7 @@ mem_trim(void *rmem, mem_size_t new_size) LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); /* remember the old next pointer */ next = mem2->next; - /* create new struct mem which is moved directly after the shrinked mem */ + /* create new struct mem which is moved directly after the shrunk mem */ ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); if (lfree == mem2) { lfree = ptr_to_mem(ptr2); @@ -805,7 +792,7 @@ mem_trim(void *rmem, mem_size_t new_size) /* else { next struct mem is used but size between mem and mem2 is not big enough to create another struct mem - -> don't do anyhting. + -> don't do anything. -> the remaining space stays unused since it is too small } */ #if MEM_OVERFLOW_CHECK @@ -977,14 +964,14 @@ mem_malloc_adjust_lfree: #endif /* MEM_USE_POOLS */ -#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) +#if MEM_CUSTOM_ALLOCATOR && (!LWIP_STATS || !MEM_STATS) void * mem_calloc(mem_size_t count, mem_size_t size) { - return mem_clib_calloc(count, size); + return MEM_CUSTOM_CALLOC(count, size); } -#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ +#else /* MEM_CUSTOM_ALLOCATOR && (!LWIP_STATS || !MEM_STATS) */ /** * Contiguously allocates enough space for count objects that are size bytes * of memory each and returns a pointer to the allocated memory. @@ -1014,4 +1001,4 @@ mem_calloc(mem_size_t count, mem_size_t size) } return p; } -#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ +#endif /* MEM_CUSTOM_ALLOCATOR && (!LWIP_STATS || !MEM_STATS) */ diff --git a/src/core/net_group.c b/src/core/net_group.c deleted file mode 100644 index c366c45..0000000 --- a/src/core/net_group.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifdef LOSCFG_NET_CONTAINER -#include "lwip/net_group.h" -#include "lwip/netif.h" - -static struct netif root_loop_netif = {0}; -static struct net_group root_net_group = { - .loop_netif = &root_loop_netif, -}; - -struct net_group *get_root_net_group(void) -{ - return &root_net_group; -} - -struct net_group *get_curr_process_net_group(void) -{ - return get_default_net_group_ops()->get_curr_process_net_group(); -} - -static void do_set_netif_net_group(struct netif *netif, struct net_group *group) -{ - (void)netif; - (void)group; -} - -static struct net_group *do_get_net_group_from_netif(struct netif *netif) -{ - (void)netif; - return get_root_net_group(); -} - -static void do_set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group) -{ - (void)pcb; - (void)group; -} - -static struct net_group *do_get_net_group_from_ippcb(struct ip_pcb *pcb) -{ - (void)pcb; - return get_root_net_group(); -} - -static struct net_group_ops root_net_group_ops = { - .get_curr_process_net_group = get_root_net_group, - .set_netif_net_group = do_set_netif_net_group, - .get_net_group_from_netif = do_get_net_group_from_netif, - .set_ippcb_net_group = do_set_ippcb_net_group, - .get_net_group_from_ippcb = do_get_net_group_from_ippcb, -}; - -struct net_group_ops *default_net_group_ops = &root_net_group_ops; - -void set_default_net_group_ops(struct net_group_ops *ops) { - default_net_group_ops = ops; -} - -struct net_group_ops *get_default_net_group_ops(void) { - return default_net_group_ops; -} -#endif diff --git a/src/core/netif.c b/src/core/netif.c index c8315ea..98e0553 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -80,6 +80,9 @@ #if LWIP_DHCP #include "lwip/dhcp.h" #endif /* LWIP_DHCP */ +#if LWIP_ACD +#include "lwip/acd.h" +#endif /* LWIP_ACD */ #if LWIP_IPV6_DHCP6 #include "lwip/dhcp6.h" #endif /* LWIP_IPV6_DHCP6 */ @@ -106,17 +109,13 @@ static netif_ext_callback_t *ext_callback; #endif -#ifndef LOSCFG_NET_CONTAINER #if !LWIP_SINGLE_NETIF struct netif *netif_list; #endif /* !LWIP_SINGLE_NETIF */ struct netif *netif_default; -#endif #define netif_index_to_num(index) ((index) - 1) -#ifndef LOSCFG_NET_CONTAINER static u8_t netif_num; -#endif #if LWIP_NUM_NETIF_CLIENT_DATA > 0 static u8_t netif_client_id; @@ -142,17 +141,16 @@ static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const i #endif -#ifdef LOSCFG_NET_CONTAINER -struct net_group *get_net_group_from_netif(struct netif *netif) { - if (netif != NULL) { - return get_default_net_group_ops()->get_net_group_from_netif(netif); - } - return NULL; -} -#else static struct netif loop_netif; + +#if LWIP_TESTMODE +struct netif* netif_get_loopif(void) +{ + return &loop_netif; +} #endif + /** * Initialize a lwip network interface structure for a loopback interface * @@ -187,11 +185,7 @@ netif_loopif_init(struct netif *netif) #endif /* LWIP_HAVE_LOOPIF */ void -#ifdef LOSCFG_NET_CONTAINER -netif_init(struct net_group *group) -#else netif_init(void) -#endif { #if LWIP_HAVE_LOOPIF #if LWIP_IPV4 @@ -204,41 +198,19 @@ netif_init(void) #define LOOPIF_ADDRINIT #endif /* LWIP_IPV4 */ -#ifdef LOSCFG_NET_CONTAINER -struct netif *loop_netif = group->loop_netif; -#endif - #if NO_SYS -#ifdef LOSCFG_NET_CONTAINER - netif_add(loop_netif, group, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); -#else netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); -#endif #else /* NO_SYS */ -#ifdef LOSCFG_NET_CONTAINER - netif_add(loop_netif, group, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); -#else netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); -#endif #endif /* NO_SYS */ #if LWIP_IPV6 -#ifdef LOSCFG_NET_CONTAINER - IP_ADDR6_HOST(loop_netif->ip6_addr, 0, 0, 0, 0x00000001UL); - loop_netif->ip6_addr_state[0] = IP6_ADDR_VALID; -#else IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; -#endif #endif /* LWIP_IPV6 */ -#ifdef LOSCFG_NET_CONTAINER - netif_set_link_up(loop_netif); - netif_set_up(loop_netif); -#else netif_set_link_up(&loop_netif); netif_set_up(&loop_netif); -#endif #endif /* LWIP_HAVE_LOOPIF */ } @@ -275,17 +247,9 @@ netif_input(struct pbuf *p, struct netif *inp) * Same as @ref netif_add but without IPv4 addresses */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -netif_add_noaddr(struct netif *netif, struct net_group *group, void *state, netif_init_fn init, netif_input_fn input) -#else netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input) -#endif { -#ifdef LOSCFG_NET_CONTAINER - return netif_add(netif, group, -#else return netif_add(netif, -#endif #if LWIP_IPV4 NULL, NULL, NULL, #endif /* LWIP_IPV4*/ @@ -303,16 +267,16 @@ netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_inp * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass - * ingress packets up in the protocol layer stack.\n + * ingress packets up in the protocol layer stack.
    * It is recommended to use a function that passes the input directly * to the stack (netif_input(), NO_SYS=1 mode) or via sending a - * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).\n + * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).
    * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET * to decide whether to forward to ethernet_input() or ip_input(). * In other words, the functions only work when the netif - * driver is implemented correctly!\n + * driver is implemented correctly!
    * Most members of struct netif should be be initialized by the - * netif init function = netif driver (init parameter of this function).\n + * netif init function = netif driver (init parameter of this function).
    * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after * setting the MAC address in struct netif.hwaddr * (IPv6 requires a link-local address). @@ -320,11 +284,7 @@ netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_inp * @return netif, or NULL if failed. */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -netif_add(struct netif *netif, struct net_group *group, -#else netif_add(struct netif *netif, -#endif #if LWIP_IPV4 const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, #endif /* LWIP_IPV4 */ @@ -336,16 +296,8 @@ netif_add(struct netif *netif, LWIP_ASSERT_CORE_LOCKED(); -#ifdef LOSCFG_NET_CONTAINER - get_default_net_group_ops()->set_netif_net_group(netif, group); -#endif - #if LWIP_SINGLE_NETIF -#ifdef LOSCFG_NET_CONTAINER - if (group->loop_netif != NULL) { -#else if (netif_default != NULL) { -#endif LWIP_ASSERT("single netif already set", 0); return NULL; } @@ -390,8 +342,8 @@ netif_add(struct netif *netif, #endif /* LWIP_NUM_NETIF_CLIENT_DATA */ #if LWIP_IPV6 #if LWIP_IPV6_AUTOCONFIG - /* IPv6 address autoconfiguration not enabled by default */ - netif->ip6_autoconfig_enabled = 0; + /* IPv6 address autoconfiguration should be enabled by default */ + netif->ip6_autoconfig_enabled = 1; #endif /* LWIP_IPV6_AUTOCONFIG */ nd6_restart_netif(netif); #endif /* LWIP_IPV6 */ @@ -410,13 +362,12 @@ netif_add(struct netif *netif, /* remember netif specific state information data */ netif->state = state; -#ifdef LOSCFG_NET_CONTAINER - netif->num = group->netif_num; -#else netif->num = netif_num; -#endif netif->input = input; +#if LWIP_ACD + netif->acd_list = NULL; +#endif /* LWIP_ACD */ NETIF_RESET_HINTS(netif); #if ENABLE_LOOPBACK netif->loop_first = NULL; @@ -457,11 +408,7 @@ netif_add(struct netif *netif, netif->num = 0; } num_netifs = 0; -#ifdef LOSCFG_NET_CONTAINER - for (netif2 = group->netif_list; netif2 != NULL; netif2 = netif2->next) { -#else for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) { -#endif LWIP_ASSERT("netif already added", netif2 != netif); num_netifs++; LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255); @@ -473,27 +420,14 @@ netif_add(struct netif *netif, } while (netif2 != NULL); } if (netif->num == 254) { -#ifdef LOSCFG_NET_CONTAINER - group->netif_num = 0; -#else netif_num = 0; -#endif } else { -#ifdef LOSCFG_NET_CONTAINER - group->netif_num = (u8_t)(netif->num + 1); -#else netif_num = (u8_t)(netif->num + 1); -#endif } /* add this netif to the list */ -#ifdef LOSCFG_NET_CONTAINER - netif->next = group->netif_list; - group->netif_list = netif; -#else netif->next = netif_list; netif_list = netif; -#endif #endif /* "LWIP_SINGLE_NETIF */ mib2_netif_added(netif); @@ -543,7 +477,7 @@ netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *ol LWIP_ASSERT("invalid pointer", old_addr != NULL); /* address is actually being changed? */ - if (ip4_addr_cmp(ipaddr, netif_ip4_addr(netif)) == 0) { + if (ip4_addr_eq(ipaddr, netif_ip4_addr(netif)) == 0) { ip_addr_t new_addr; *ip_2_ip4(&new_addr) = *ipaddr; IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4); @@ -553,6 +487,10 @@ netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *ol LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); netif_do_ip_addr_changed(old_addr, &new_addr); +#if LWIP_ACD + acd_netif_ip_addr_changed(netif, old_addr, &new_addr); +#endif /* LWIP_ACD */ + mib2_remove_ip4(netif); mib2_remove_route_ip4(0, netif); /* set new IP address to netif */ @@ -606,7 +544,7 @@ static int netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm) { /* address is actually being changed? */ - if (ip4_addr_cmp(netmask, netif_ip4_netmask(netif)) == 0) { + if (ip4_addr_eq(netmask, netif_ip4_netmask(netif)) == 0) { #if LWIP_NETIF_EXT_STATUS_CALLBACK LWIP_ASSERT("invalid pointer", old_nm != NULL); ip_addr_copy(*old_nm, *netif_ip_netmask4(netif)); @@ -670,7 +608,7 @@ static int netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw) { /* address is actually being changed? */ - if (ip4_addr_cmp(gw, netif_ip4_gw(netif)) == 0) { + if (ip4_addr_eq(gw, netif_ip4_gw(netif)) == 0) { #if LWIP_NETIF_EXT_STATUS_CALLBACK LWIP_ASSERT("invalid pointer", old_gw != NULL); ip_addr_copy(*old_gw, *netif_ip_gw4(netif)); @@ -804,6 +742,12 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t * #if LWIP_NETIF_EXT_STATUS_CALLBACK if (change_reason != LWIP_NSC_NONE) { change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED; + } + if (!remove) { + /* Issue a callback even if the address hasn't changed, eg. DHCP reboot */ + change_reason |= LWIP_NSC_IPV4_ADDR_VALID; + } + if (change_reason != LWIP_NSC_NONE) { netif_invoke_ext_callback(netif, change_reason, &cb_args); } #endif @@ -828,13 +772,7 @@ netif_remove(struct netif *netif) if (netif == NULL) { return; } -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_netif(netif); - if (group == NULL) { - return; - } -#endif netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL); #if LWIP_IPV4 @@ -869,35 +807,18 @@ netif_remove(struct netif *netif) mib2_remove_ip4(netif); /* this netif is default? */ -#ifdef LOSCFG_NET_CONTAINER - if (group->netif_default == netif) { -#else if (netif_default == netif) { -#endif /* reset default netif */ -#ifdef LOSCFG_NET_CONTAINER - netif_set_default(NULL, group); -#else netif_set_default(NULL); -#endif } #if !LWIP_SINGLE_NETIF /* is it the first netif? */ -#ifdef LOSCFG_NET_CONTAINER - if (group->netif_list == netif) { - group->netif_list = netif->next; -#else if (netif_list == netif) { netif_list = netif->next; -#endif } else { /* look for netif further down the list */ struct netif *tmp_netif; -#ifdef LOSCFG_NET_CONTAINER - NETIF_FOREACH(tmp_netif, group) { -#else NETIF_FOREACH(tmp_netif) { -#endif if (tmp_netif->next == netif) { tmp_netif->next = netif->next; break; @@ -925,11 +846,7 @@ netif_remove(struct netif *netif) * @param netif the default network interface */ void -#ifdef LOSCFG_NET_CONTAINER -netif_set_default(struct netif *netif, struct net_group *group) -#else netif_set_default(struct netif *netif) -#endif { LWIP_ASSERT_CORE_LOCKED(); @@ -940,22 +857,11 @@ netif_set_default(struct netif *netif) /* install default route */ mib2_add_route_ip4(1, netif); } -#ifdef LOSCFG_NET_CONTAINER - group->netif_default = netif; -#else netif_default = netif; -#endif LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); } -#ifdef LOSCFG_NET_CONTAINER -void -netif_set_default2(struct netif *netif) -{ - netif_set_default(netif, get_curr_process_net_group()); -} -#endif /** * @ingroup netif * Bring an interface up, available for processing @@ -1006,8 +912,11 @@ netif_issue_reports(struct netif *netif, u8_t report_type) #if LWIP_IPV4 if ((report_type & NETIF_REPORT_TYPE_IPV4) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { -#if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ +#if LWIP_ARP && !LWIP_ACD + /* For Ethernet network interfaces: + * we would like to send a "gratuitous ARP". + * Only needs to be done here if ACD isn't configured. + */ if (netif->flags & (NETIF_FLAG_ETHARP)) { etharp_gratuitous(netif); } @@ -1116,11 +1025,11 @@ netif_set_link_up(struct netif *netif) netif_set_flags(netif, NETIF_FLAG_LINK_UP); #if LWIP_DHCP - dhcp_network_changed(netif); + dhcp_network_changed_link_up(netif); #endif /* LWIP_DHCP */ #if LWIP_AUTOIP - autoip_network_changed(netif); + autoip_network_changed_link_up(netif); #endif /* LWIP_AUTOIP */ netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); @@ -1152,6 +1061,15 @@ netif_set_link_down(struct netif *netif) if (netif->flags & NETIF_FLAG_LINK_UP) { netif_clear_flags(netif, NETIF_FLAG_LINK_UP); + +#if LWIP_AUTOIP + autoip_network_changed_link_down(netif); +#endif /* LWIP_AUTOIP */ + +#if LWIP_ACD + acd_network_changed_link_down(netif); +#endif /* LWIP_ACD */ + #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES netif->mtu6 = netif->mtu; #endif @@ -1212,11 +1130,7 @@ netif_loop_output(struct netif *netif, struct pbuf *p) * if not they are adjusted for 'netif'. */ #if MIB2_STATS #if LWIP_HAVE_LOOPIF -#ifdef LOSCFG_NET_CONTAINER - struct netif *stats_if = get_net_group_from_netif(netif)->loop_netif; -#else struct netif *stats_if = &loop_netif; -#endif #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ @@ -1341,11 +1255,7 @@ netif_poll(struct netif *netif) * if not they are adjusted for 'netif'. */ #if MIB2_STATS #if LWIP_HAVE_LOOPIF -#ifdef LOSCFG_NET_CONTAINER - struct netif *stats_if = get_net_group_from_netif(netif)->loop_netif; -#else struct netif *stats_if = &loop_netif; -#endif #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ @@ -1499,7 +1409,7 @@ netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); } - /* @todo: remove/readd mib2 ip6 entries? */ + /* @todo: remove/re-add mib2 ip6 entries? */ ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr); @@ -1622,7 +1532,7 @@ netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr) for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp_zoneless(netif_ip6_addr(netif, i), ip6addr)) { + ip6_addr_zoneless_eq(netif_ip6_addr(netif, i), ip6addr)) { return i; } } @@ -1678,7 +1588,7 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) /* Set a link-local zone. Even though the zone is implied by the owning * netif, setting the zone anyway has two important conceptual advantages: * 1) it avoids the need for a ton of exceptions in internal code, allowing - * e.g. ip6_addr_cmp() to be used on local addresses; + * e.g. ip6_addr_eq() to be used on local addresses; * 2) the properly zoned address is visible externally, e.g. when any outside * code enumerates available addresses or uses one to bind a socket. * Any external code unaware of address scoping is likely to just ignore the @@ -1797,17 +1707,9 @@ netif_name_to_index(const char *name) * @param name char buffer of at least NETIF_NAMESIZE bytes */ char * -#ifdef LOSCFG_NET_CONTAINER -netif_index_to_name(u8_t idx, char *name, struct net_group *group) -#else netif_index_to_name(u8_t idx, char *name) -#endif { -#ifdef LOSCFG_NET_CONTAINER - struct netif *netif = netif_get_by_index(idx, group); -#else struct netif *netif = netif_get_by_index(idx); -#endif if (netif != NULL) { name[0] = netif->name[0]; @@ -1825,23 +1727,14 @@ netif_index_to_name(u8_t idx, char *name) * @param idx index of netif to find */ struct netif * -#ifdef LOSCFG_NET_CONTAINER -netif_get_by_index(u8_t idx, struct net_group *group) -#else netif_get_by_index(u8_t idx) -#endif { struct netif *netif; LWIP_ASSERT_CORE_LOCKED(); -#ifdef LOSCFG_NET_CONTAINER - if (idx != NETIF_NO_INDEX && group != NULL) { - NETIF_FOREACH(netif, group) { -#else if (idx != NETIF_NO_INDEX) { NETIF_FOREACH(netif) { -#endif if (idx == netif_get_index(netif)) { return netif; /* found! */ } @@ -1851,7 +1744,6 @@ netif_get_by_index(u8_t idx) return NULL; } -#ifndef netif_find /** * @ingroup netif * Find a network interface by searching for its name @@ -1888,7 +1780,6 @@ netif_find(const char *name) LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); return NULL; } -#endif #if LWIP_NETIF_EXT_STATUS_CALLBACK /** @@ -1934,11 +1825,11 @@ netif_remove_ext_callback(netif_ext_callback_t* callback) if (iter == callback) { LWIP_ASSERT("last != NULL", last != NULL); last->next = callback->next; - callback->next = NULL; - return; + break; } } } + callback->next = NULL; } /** @@ -1955,8 +1846,10 @@ netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const LWIP_ASSERT("netif must be != NULL", netif != NULL); while (callback != NULL) { + /* cache next pointer: the callback might unregister itself */ + netif_ext_callback_t *next = callback->next; callback->callback_fn(netif, reason, args); - callback = callback->next; + callback = next; } } #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */ diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 7638dfd..54a6e0e 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -186,6 +186,8 @@ pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, p->flags = flags; p->ref = 1; p->if_idx = NETIF_NO_INDEX; + + LWIP_PBUF_CUSTOM_DATA_INIT(p); } /** @@ -441,8 +443,11 @@ pbuf_realloc(struct pbuf *p, u16_t new_len) #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ ) { /* reallocate and adjust the length of the pbuf that will be split */ - q = (struct pbuf *)mem_trim(q, (mem_size_t)(((u8_t *)q->payload - (u8_t *)q) + rem_len)); - LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); + struct pbuf *r = (struct pbuf *)mem_trim(q, (mem_size_t)(((u8_t *)q->payload - (u8_t *)q) + rem_len)); + LWIP_ASSERT("mem_trim returned r == NULL", r != NULL); + /* help to detect faulty overridden implementation of mem_trim */ + LWIP_ASSERT("mem_trim returned r != q", r == q); + LWIP_UNUSED_ARG(r); } /* adjust length fields for new last pbuf */ q->len = rem_len; @@ -677,7 +682,7 @@ pbuf_free_header(struct pbuf *q, u16_t size) struct pbuf *f = p; free_left = (u16_t)(free_left - p->len); p = p->next; - f->next = 0; + f->next = NULL; pbuf_free(f); } else { pbuf_remove_header(p, free_left); @@ -705,7 +710,6 @@ pbuf_free_header(struct pbuf *q, u16_t size) * @return the number of pbufs that were de-allocated * from the head of the chain. * - * @note MUST NOT be called on a packet queue (Not verified to work yet). * @note the reference counter of a pbuf equals the number of pointers * that refer to the pbuf (or into the pbuf). * @@ -856,6 +860,7 @@ pbuf_cat(struct pbuf *h, struct pbuf *t) LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", ((h != NULL) && (t != NULL)), return;); + LWIP_ASSERT("Creating an infinite loop", h != t); /* proceed to last pbuf of chain */ for (p = h; p->next != NULL; p = p->next) { @@ -941,12 +946,7 @@ pbuf_dechain(struct pbuf *p) /** * @ingroup pbuf - * Create PBUF_RAM copies of pbufs. - * - * Used to queue packets on behalf of the lwIP stack, such as - * ARP based queueing. - * - * @note You MUST explicitly use p = pbuf_take(p); + * Copy the contents of one packet buffer into another. * * @note Only one packet is copied, no packet queue! * @@ -956,6 +956,7 @@ pbuf_dechain(struct pbuf *p) * @return ERR_OK if pbuf was copied * ERR_ARG if one of the pbufs is NULL or p_to is not big * enough to hold p_from + * ERR_VAL if any of the pbufs are part of a queue */ err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from) @@ -987,8 +988,7 @@ pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from) err_t pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_len, u16_t offset) { - size_t offset_to = offset, offset_from = 0, len_calc; - u16_t len; + size_t offset_to = offset, offset_from = 0, len; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy_partial_pbuf(%p, %p, %"U16_F", %"U16_F")\n", (const void *)p_to, (const void *)p_from, copy_len, offset)); @@ -1005,16 +1005,16 @@ pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_ /* copy one part of the original chain */ if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { /* complete current p_from fits into current p_to */ - len_calc = p_from->len - offset_from; + len = p_from->len - offset_from; } else { /* current p_from does not fit into current p_to */ - len_calc = p_to->len - offset_to; + len = p_to->len - offset_to; } - len = (u16_t)LWIP_MIN(copy_len, len_calc); + len = LWIP_MIN(copy_len, len); MEMCPY((u8_t *)p_to->payload + offset_to, (u8_t *)p_from->payload + offset_from, len); offset_to += len; offset_from += len; - copy_len -= len; + copy_len = (u16_t)(copy_len - len); LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); if (offset_from >= p_from->len) { @@ -1097,12 +1097,15 @@ pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset * a copy into the user-supplied buffer. * * @param p the pbuf from which to copy data - * @param buffer the application supplied buffer - * @param bufsize size of the application supplied buffer - * @param len length of data to copy (dataptr must be big enough). No more - * than buf->tot_len will be copied, irrespective of len + * @param buffer the application supplied buffer. May be NULL if the caller does not + * want to copy. In this case, offset + len should be checked against p->tot_len, + * since there's no way for the caller to know why NULL is returned. + * @param bufsize size of the application supplied buffer (when buffer is != NULL) + * @param len length of data to copy (p and buffer must be big enough) * @param offset offset into the packet buffer from where to begin copying len bytes - * @return the number of bytes copied, or 0 on failure + * @return - pointer into pbuf payload if that is already contiguous (no copy needed) + * - pointer to 'buffer' if data was not contiguous and had to be copied + * - NULL on error */ void * pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) @@ -1111,8 +1114,7 @@ pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t le u16_t out_offset; LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;); - LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;); - LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;); + LWIP_ERROR("pbuf_get_contiguous: invalid bufsize", (buffer == NULL) || (bufsize >= len), return NULL;); q = pbuf_skip_const(p, offset, &out_offset); if (q != NULL) { @@ -1120,6 +1122,10 @@ pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t le /* all data in this pbuf, return zero-copy */ return (u8_t *)q->payload + out_offset; } + if (buffer == NULL) { + /* the caller does not want to copy */ + return NULL; + } /* need to copy */ if (pbuf_copy_partial(q, buffer, len, out_offset) != len) { /* copying failed: pbuf is too short */ @@ -1206,7 +1212,7 @@ pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset) * @param in input pbuf * @param in_offset offset to skip * @param out_offset resulting offset in the returned pbuf - * @return the pbuf in the queue where the offset is + * @return the pbuf in the queue where the offset is or NULL when the offset is too high */ struct pbuf * pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset) diff --git a/src/core/raw.c b/src/core/raw.c index 1b375ba..d85aaec 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -2,14 +2,14 @@ * @file * Implementation of raw protocol PCBs for low-level handling of * different types of protocols besides (or overriding) those - * already available in lwIP.\n + * already available in lwIP.
    * See also @ref raw_raw * * @defgroup raw_raw RAW * @ingroup callbackstyle_api * Implementation of raw protocol PCBs for low-level handling of * different types of protocols besides (or overriding) those - * already available in lwIP.\n + * already available in lwIP.
    * @see @ref api */ @@ -106,7 +106,7 @@ raw_input_local_match(struct raw_pcb *pcb, u8_t broadcast) #endif /* LWIP_IPV4 */ /* Handle IPv4 and IPv6: catch all or exact match */ if (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { return 1; } } @@ -135,9 +135,6 @@ raw_input_state_t raw_input(struct pbuf *p, struct netif *inp) { struct raw_pcb *pcb, *prev; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *inp_net_group = get_net_group_from_netif(inp); -#endif s16_t proto; raw_input_state_t ret = RAW_INPUT_NONE; u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); @@ -167,14 +164,9 @@ raw_input(struct pbuf *p, struct netif *inp) /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while (pcb != NULL) { -#ifdef LOSCFG_NET_CONTAINER - if (inp_net_group == get_net_group_from_raw_pcb(pcb) && - (pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && -#else if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && -#endif (((pcb->flags & RAW_FLAGS_CONNECTED) == 0) || - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()))) { /* receive callback function available? */ if (pcb->recv != NULL) { u8_t eaten; @@ -370,15 +362,8 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_raw_pcb(pcb); -#endif if (pcb->netif_idx != NETIF_NO_INDEX) { -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index(pcb->netif_idx, group); -#else netif = netif_get_by_index(pcb->netif_idx); -#endif } else { #if LWIP_MULTICAST_TX_OPTIONS netif = NULL; @@ -386,27 +371,20 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) /* For multicast-destined packets, use the user-provided interface index to * determine the outgoing interface, if an interface index is set and a * matching netif can be found. Otherwise, fall back to regular routing. */ -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index(pcb->mcast_ifindex, group); -#else netif = netif_get_by_index(pcb->mcast_ifindex); -#endif } if (netif == NULL) #endif /* LWIP_MULTICAST_TX_OPTIONS */ { -#ifdef LOSCFG_NET_CONTAINER - netif = ip_route(&pcb->local_ip, ipaddr, group); -#else netif = ip_route(&pcb->local_ip, ipaddr); -#endif } } if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr); + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("\n")); return ERR_RTE; } @@ -603,16 +581,6 @@ raw_remove(struct raw_pcb *pcb) memp_free(MEMP_RAW_PCB, pcb); } -#ifdef LOSCFG_NET_CONTAINER -void set_raw_pcb_net_group(struct raw_pcb *pcb, struct net_group *group) -{ - set_ippcb_net_group((struct ip_pcb *)pcb, group); -} - -struct net_group *get_net_group_from_raw_pcb(struct raw_pcb *pcb) { - return get_net_group_from_ippcb((struct ip_pcb *)pcb); -} -#endif /** * @ingroup raw_raw * Create a RAW PCB. @@ -642,6 +610,7 @@ raw_new(u8_t proto) #if LWIP_MULTICAST_TX_OPTIONS raw_set_multicast_ttl(pcb, RAW_TTL); #endif /* LWIP_MULTICAST_TX_OPTIONS */ + pcb_tci_init(pcb); pcb->next = raw_pcbs; raw_pcbs = pcb; } @@ -692,7 +661,7 @@ void raw_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_a if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&rpcb->local_ip, old_addr)) { + if (ip_addr_eq(&rpcb->local_ip, old_addr)) { /* The PCB is bound to the old ipaddr and * is set to bound to the new one instead */ ip_addr_copy(rpcb->local_ip, *new_addr); diff --git a/src/core/stats.c b/src/core/stats.c index 34e9b27..95445ec 100644 --- a/src/core/stats.c +++ b/src/core/stats.c @@ -166,4 +166,3 @@ stats_display(void) #endif /* LWIP_STATS_DISPLAY */ #endif /* LWIP_STATS */ - diff --git a/src/core/sys.c b/src/core/sys.c index 5f08352..69d7197 100644 --- a/src/core/sys.c +++ b/src/core/sys.c @@ -45,30 +45,30 @@ * No need to implement functions in this section in NO_SYS mode. * The OS-specific code should be implemented in arch/sys_arch.h * and sys_arch.c of your port. - * + * * The operating system emulation layer provides a common interface * between the lwIP code and the underlying operating system kernel. The * general idea is that porting lwIP to new architectures requires only * small changes to a few header files and a new sys_arch * implementation. It is also possible to do a sys_arch implementation * that does not rely on any underlying operating system. - * + * * The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full * lwIP functionality, multiple threads support can be implemented in the * sys_arch, but this is not required for the basic lwIP * functionality. Timer scheduling is implemented in lwIP, but can be implemented * by the sys_arch port (LWIP_TIMERS_CUSTOM==1). - * + * * In addition to the source file providing the functionality of sys_arch, * the OS emulation layer must provide several header files defining * macros used throughout lwip. The files required and the macros they * must define are listed below the sys_arch description. - * + * * Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that * allows both using pointers or actual OS structures to be used. This way, memory * required for such types can be either allocated in place (globally or on the * stack) or on the heap (allocated internally in the "*_new()" functions). - * + * * Note: * ----- * Be careful with using mem_malloc() in sys_arch. When malloc() refers to @@ -96,7 +96,7 @@ * Mailboxes should be implemented as a queue which allows multiple messages * to be posted (implementing as a rendez-vous point where only one message can be * posted at a time can have a highly negative impact on performance). A message - * in a mailbox is just a pointer, nothing more. + * in a mailbox is just a pointer, nothing more. * * @defgroup sys_time Time * @ingroup sys_layer diff --git a/src/core/tcp.c b/src/core/tcp.c index 2055f61..ea95ffe 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -5,13 +5,13 @@ * * @defgroup tcp_raw TCP * @ingroup callbackstyle_api - * Transmission Control Protocol for IP\n + * Transmission Control Protocol for IP
    * @see @ref api * * Common functions for the TCP implementation, such as functions * for manipulating the data structures and the TCP timer functions. TCP functions - * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n - * + * related to input and output is found in tcp_in.c and tcp_out.c respectively.
    + * * TCP connection setup * -------------------- * The functions used for setting up connections is similar to that of @@ -24,7 +24,7 @@ * - tcp_listen() and tcp_listen_with_backlog() * - tcp_accept() * - tcp_connect() - * + * * Sending TCP data * ---------------- * TCP data is sent by enqueueing the data with a call to tcp_write() and @@ -34,7 +34,7 @@ * - tcp_write() * - tcp_output() * - tcp_sent() - * + * * Receiving TCP data * ------------------ * TCP data reception is callback based - an application specified @@ -44,7 +44,7 @@ * window. * - tcp_recv() * - tcp_recved() - * + * * Application polling * ------------------- * When a connection is idle (i.e., no data is either transmitted or @@ -62,7 +62,7 @@ * - tcp_close() * - tcp_abort() * - tcp_err() - * + * */ /* @@ -111,9 +111,6 @@ #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/nd6.h" -#if LWIP_LOWPOWER -#include "lwip/priv/api_msg.h" -#endif #include @@ -159,7 +156,7 @@ static const char *const tcp_state_str[] = { }; /* last local TCP port */ -static volatile u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; +static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; /* Incremented every coarse grained timer shot (typically every 500 ms). */ u32_t tcp_ticks; @@ -197,17 +194,6 @@ static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); #endif -#ifdef LOSCFG_NET_CONTAINER -void set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group) -{ - set_ippcb_net_group((struct ip_pcb *)pcb, group); -} - -struct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb) -{ - return get_net_group_from_ippcb((struct ip_pcb *)pcb); -} -#endif /** * Initialize this module. */ @@ -257,150 +243,6 @@ tcp_tmr(void) } } -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" - -static u32_t -tcp_set_timer_tick_by_persist(struct tcp_pcb *pcb, u32_t tick) -{ - u32_t val; - - if (pcb->persist_backoff > 0) { - u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; - SET_TMR_TICK(tick, backoff_cnt); - return tick; - } - - /* timer not running */ - if (pcb->rtime >= 0) { - val = pcb->rto - pcb->rtime; - if (val == 0) { - val = 1; - } - SET_TMR_TICK(tick, val); - } - return tick; -} - -static u32_t -tcp_set_timer_tick_by_keepalive(struct tcp_pcb *pcb, u32_t tick) -{ - u32_t val; - - if (ip_get_option(pcb, SOF_KEEPALIVE) && - ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT))) { - u32_t idle = (pcb->keep_idle) / TCP_SLOW_INTERVAL; - if (pcb->keep_cnt_sent == 0) { - val = idle - (tcp_ticks - pcb->tmr); - } else { - val = (tcp_ticks - pcb->tmr) - idle; - idle = (TCP_KEEP_INTVL(pcb) / TCP_SLOW_INTERVAL); - val = idle - (val % idle); - } - /* need add 1 to trig timer */ - val++; - SET_TMR_TICK(tick, val); - } - - return tick; -} - -static u32_t tcp_set_timer_tick_by_tcp_state(struct tcp_pcb *pcb, u32_t tick) -{ - u32_t val; - - /* Check if this PCB has stayed too long in FIN-WAIT-2 */ - if (pcb->state == FIN_WAIT_2) { - /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ - if (pcb->flags & TF_RXCLOSED) { - val = TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL; - SET_TMR_TICK(tick, val); - } - } - - /* Check if this PCB has stayed too long in SYN-RCVD */ - if (pcb->state == SYN_RCVD) { - val = TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL; - SET_TMR_TICK(tick, val); - } - - /* Check if this PCB has stayed too long in LAST-ACK */ - if (pcb->state == LAST_ACK) { - /* - * In a TCP connection the end that performs the active close - * is required to stay in TIME_WAIT state for 2MSL of time - */ - val = (2 * TCP_MSL) / TCP_SLOW_INTERVAL; - SET_TMR_TICK(tick, val); - } - - return tick; -} - -u32_t -tcp_slow_tmr_tick(void) -{ - struct tcp_pcb *pcb = NULL; - u32_t tick = 0; - - pcb = tcp_active_pcbs; - while (pcb != NULL) { - if (((pcb->state == SYN_SENT) && (pcb->nrtx >= TCP_SYNMAXRTX)) || - ((pcb->state == FIN_WAIT_1) || (pcb->state == CLOSING)) || - (pcb->nrtx >= TCP_MAXRTX)) { - return 1; - } - - tick = tcp_set_timer_tick_by_persist(pcb, tick); - tick = tcp_set_timer_tick_by_keepalive(pcb, tick); - - /* - * If this PCB has queued out of sequence data, but has been - * inactive for too long, will drop the data (it will eventually - * be retransmitted). - */ -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL) { - SET_TMR_TICK(tick, 1); - } -#endif /* TCP_QUEUE_OOSEQ */ - - tick = tcp_set_timer_tick_by_tcp_state(pcb, tick); - - u8_t ret = poll_tcp_needed(pcb->callback_arg, pcb); - if ((pcb->poll != NULL) && (ret != 0)) { - SET_TMR_TICK(tick, 1); - } - pcb = pcb->next; - } - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "tcp_slow_tmr_tick", tick)); - return tick; -} - -u32_t -tcp_fast_tmr_tick(void) -{ - struct tcp_pcb *pcb = NULL; - - pcb = tcp_active_pcbs; - while (pcb != NULL) { - /* send delayed ACKs or send pending FIN */ - if ((pcb->flags & TF_ACK_DELAY) || - (pcb->flags & TF_CLOSEPEND) || - (pcb->refused_data != NULL) - ) { - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "tcp_fast_tmr_tick")); - return 1; - } - pcb = pcb->next; - } - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 0\n", "tcp_fast_tmr_tick")); - return 0; -} -#endif /* LWIP_LOWPOWER */ - #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG /** Called when a listen pcb is closed. Iterates one pcb list and removes the * closed listener pcb from pcb->listener if matching. @@ -627,7 +469,7 @@ tcp_close_shutdown_fin(struct tcp_pcb *pcb) * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it (unless an error is returned). - * + * * The function may return ERR_MEM if no memory * was available for closing the connection. If so, the application * should wait and try again either by using the acknowledgment @@ -660,7 +502,7 @@ tcp_close(struct tcp_pcb *pcb) * @ingroup tcp_raw * Causes all or part of a full-duplex connection of this PCB to be shut down. * This doesn't deallocate the PCB unless shutting down both sides! - * Shutting down both sides is the same as calling tcp_close, so if it succeds + * Shutting down both sides is the same as calling tcp_close, so if it succeeds * (i.e. returns ER_OK), the PCB must not be referenced any more! * * @param pcb PCB to shutdown @@ -873,11 +715,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) /* Check if the address already is in use (on all lists) */ for (i = 0; i < max_pcb_list; i++) { for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { -#ifdef LOSCFG_NET_CONTAINER - if (cpcb->local_port == port && (get_net_group_from_tcp_pcb(pcb) == get_net_group_from_tcp_pcb(cpcb))) { -#else if (cpcb->local_port == port) { -#endif #if SO_REUSE /* Omit checking for the same port if both pcbs have REUSEADDR set. For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in @@ -890,7 +728,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && (ip_addr_isany(&cpcb->local_ip) || ip_addr_isany(ipaddr) || - ip_addr_cmp(&cpcb->local_ip, ipaddr))) { + ip_addr_eq(&cpcb->local_ip, ipaddr))) { return ERR_USE; } } @@ -960,7 +798,7 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) * When an incoming connection is accepted, the function specified with * the tcp_accept() function will be called. The pcb has to be bound * to a local port with the tcp_bind() function. - * + * * The tcp_listen() function returns a new connection identifier, and * the one passed as an argument to the function will be * deallocated. The reason for this behavior is that less memory is @@ -975,7 +813,7 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) * The backlog limits the number of outstanding connections * in the listen queue to the value specified by the backlog argument. * To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. - * + * * @param pcb the original tcp_pcb * @param backlog the incoming connections queue limit * @return tcp_pcb used for listening, consumes less memory. @@ -1033,7 +871,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) this port is only used once for every local IP. */ for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && - ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + ip_addr_eq(&lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ lpcb = NULL; res = ERR_USE; @@ -1047,9 +885,6 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) res = ERR_MEM; goto done; } -#ifdef LOSCFG_NET_CONTAINER - set_tcp_pcb_net_group((struct tcp_pcb *)lpcb, get_net_group_from_tcp_pcb(pcb)); -#endif lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; @@ -1058,6 +893,9 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) lpcb->netif_idx = pcb->netif_idx; lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; +#if LWIP_VLAN_PCP + lpcb->netif_hints.tci = pcb->netif_hints.tci; +#endif /* LWIP_VLAN_PCP */ #if LWIP_IPV4 && LWIP_IPV6 IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); #endif /* LWIP_IPV4 && LWIP_IPV6 */ @@ -1205,7 +1043,7 @@ again: * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * Sets up the pcb to connect to the remote host and sends the - * initial SYN segment which opens the connection. + * initial SYN segment which opens the connection. * * The tcp_connect() function returns immediately; it does not wait for * the connection to be properly setup. Instead, it will call the @@ -1224,7 +1062,7 @@ again: * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (on error, - the err calback will be called) + the err callback will be called) * @return ERR_VAL if invalid arguments are given * ERR_OK if connect request has been sent * other err_t values if connect request couldn't be sent @@ -1245,27 +1083,15 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_tcp_pcb(pcb); - LWIP_ERROR("tcp_connect: invalid net group", group != NULL, return ERR_RTE); -#endif LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); ip_addr_set(&pcb->remote_ip, ipaddr); pcb->remote_port = port; if (pcb->netif_idx != NETIF_NO_INDEX) { -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index(pcb->netif_idx, group); -#else netif = netif_get_by_index(pcb->netif_idx); -#endif } else { /* check if we have a route to the remote host */ -#ifdef LOSCFG_NET_CONTAINER - netif = ip_route(&pcb->local_ip, &pcb->remote_ip, group); -#else netif = ip_route(&pcb->local_ip, &pcb->remote_ip); -#endif } if (netif == NULL) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ @@ -1308,8 +1134,8 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if ((cpcb->local_port == pcb->local_port) && (cpcb->remote_port == port) && - ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && - ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { + ip_addr_eq(&cpcb->local_ip, &pcb->local_ip) && + ip_addr_eq(&cpcb->remote_ip, ipaddr)) { /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } @@ -1389,9 +1215,9 @@ tcp_slowtmr_start: } while (pcb != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN", pcb->state != LISTEN); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); if (pcb->last_timer == tcp_timer_ctr) { /* skip this pcb, we have already processed it */ prev = pcb; @@ -1889,14 +1715,14 @@ tcp_kill_prio(u8_t prio) mprio = LWIP_MIN(TCP_PRIO_MAX, prio); - /* We want to kill connections with a lower prio, so bail out if + /* We want to kill connections with a lower prio, so bail out if * supplied prio is 0 - there can never be a lower prio */ if (mprio == 0) { return; } - /* We only want kill connections with a lower prio, so decrement prio by one + /* We only want kill connections with a lower prio, so decrement prio by one * and start searching for oldest connection with same or lower priority than mprio. * We want to find the connections with the lowest possible prio, and among * these the one with the longest inactivity time. @@ -2075,14 +1901,16 @@ tcp_alloc(u8_t prio) /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = INITIAL_MSS; - pcb->rto = 3000 / TCP_SLOW_INTERVAL; - pcb->sv = 3000 / TCP_SLOW_INTERVAL; + /* Set initial TCP's retransmission timeout to 3000 ms by default. + This value could be configured in lwipopts */ + pcb->rto = LWIP_TCP_RTO_TIME / TCP_SLOW_INTERVAL; + pcb->sv = LWIP_TCP_RTO_TIME / TCP_SLOW_INTERVAL; pcb->rtime = -1; pcb->cwnd = 1; pcb->tmr = tcp_ticks; pcb->last_timer = tcp_timer_ctr; - /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example + /* RFC 5681 recommends setting ssthresh arbitrarily high and gives an example of using the largest advertised receive window. We've seen complications with receiving TCPs that use window scaling and/or window auto-tuning where the initial advertised window is very small and then grows rapidly once the @@ -2101,6 +1929,7 @@ tcp_alloc(u8_t prio) pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; #endif /* LWIP_TCP_KEEPALIVE */ + pcb_tci_init(pcb); } return pcb; } @@ -2221,7 +2050,7 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) * @ingroup tcp_raw * Used to specify the function that should be called when a fatal error * has occurred on the connection. - * + * * If a connection is aborted because of an error, the application is * alerted of this event by the err callback. Errors that might abort a * connection are when there is a shortage of memory. The callback @@ -2272,7 +2101,7 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) * number of TCP coarse grained timer shots, which typically occurs * twice a second. An interval of 10 means that the application would * be polled every 5 seconds. - * + * * When a connection is idle (i.e., no data is either transmitted or * received), lwIP will repeatedly poll the application by calling a * specified callback function. This can be used either as a watchdog @@ -2486,7 +2315,7 @@ tcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb while (pcb != NULL) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&pcb->local_ip, old_addr) + if (ip_addr_eq(&pcb->local_ip, old_addr) #if LWIP_AUTOIP /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) @@ -2521,7 +2350,7 @@ tcp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) /* PCB bound to current local interface address? */ for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { + if (ip_addr_eq(&lpcb->local_ip, old_addr)) { /* The PCB is listening to the old ipaddr and * is set to listen to the new one instead */ ip_addr_copy(lpcb->local_ip, *new_addr); @@ -2714,7 +2543,7 @@ tcp_pcbs_sane(void) /** * @defgroup tcp_raw_extargs ext arguments * @ingroup tcp_raw - * Additional data storage per tcp pcb\n + * Additional data storage per tcp pcb
    * @see @ref tcp_raw * * When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) @@ -2772,7 +2601,7 @@ tcp_ext_arg_alloc_id(void) * @param callbacks callback table (const since it is referenced, not copied!) */ void -tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks) +tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, u8_t id, const struct tcp_ext_arg_callbacks * const callbacks) { LWIP_ASSERT("pcb != NULL", pcb != NULL); LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); @@ -2791,7 +2620,7 @@ tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_ * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) * @param arg data pointer to set */ -void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg) +void tcp_ext_arg_set(struct tcp_pcb *pcb, u8_t id, void *arg) { LWIP_ASSERT("pcb != NULL", pcb != NULL); LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); @@ -2809,7 +2638,7 @@ void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg) * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) * @return data pointer at the given index */ -void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id) +void *tcp_ext_arg_get(const struct tcp_pcb *pcb, u8_t id) { LWIP_ASSERT("pcb != NULL", pcb != NULL); LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index f9b4a61..1b17e40 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -119,9 +119,6 @@ tcp_input(struct pbuf *p, struct netif *inp) { struct tcp_pcb *pcb, *prev; struct tcp_pcb_listen *lpcb; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_netif(inp); -#endif #if SO_REUSE struct tcp_pcb *lpcb_prev = NULL; struct tcp_pcb_listen *lpcb_any = NULL; @@ -262,15 +259,10 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } -#ifdef LOSCFG_NET_CONTAINER - if (group == get_net_group_from_tcp_pcb(pcb) && - pcb->remote_port == tcphdr->src && -#else if (pcb->remote_port == tcphdr->src && -#endif pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ @@ -300,15 +292,10 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } -#ifdef LOSCFG_NET_CONTAINER - if (group == get_net_group_from_tcp_pcb(pcb) && - pcb->remote_port == tcphdr->src && -#else if (pcb->remote_port == tcphdr->src && -#endif pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ @@ -336,11 +323,7 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } -#ifdef LOSCFG_NET_CONTAINER - if (group == get_net_group_from_tcp_pcb((struct tcp_pcb *)lpcb) && lpcb->local_port == tcphdr->dest) { -#else if (lpcb->local_port == tcphdr->dest) { -#endif if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { /* found an ANY TYPE (IPv4/IPv6) match */ #if SO_REUSE @@ -350,7 +333,7 @@ tcp_input(struct pbuf *p, struct netif *inp) break; #endif /* SO_REUSE */ } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { - if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { + if (ip_addr_eq(&lpcb->local_ip, ip_current_dest_addr())) { /* found an exact match */ break; } else if (ip_addr_isany(&lpcb->local_ip)) { @@ -593,7 +576,7 @@ aborted: if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); - tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), + tcp_rst_netif(ip_data.current_input_netif, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } pbuf_free(p); @@ -609,7 +592,7 @@ dropped: } /** Called from tcp_input to check for TF_CLOSED flag. This results in closing - * and deallocating a pcb at the correct place to ensure noone references it + * and deallocating a pcb at the correct place to ensure no one references it * any more. * @returns 1 if the pcb has been closed and deallocated, 0 otherwise */ @@ -657,16 +640,13 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_tcp_pcb((struct tcp_pcb *)pcb); -#endif /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), + tcp_rst_netif(ip_data.current_input_netif, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); @@ -688,9 +668,6 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_UNUSED_ARG(err); /* err not useful here */ return; } -#ifdef LOSCFG_NET_CONTAINER - set_tcp_pcb_net_group(npcb, group); -#endif #if TCP_LISTEN_BACKLOG pcb->accepts_pending++; tcp_set_flags(npcb, TF_BACKLOGPEND); @@ -713,6 +690,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG npcb->listener = pcb; #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ +#if LWIP_VLAN_PCP + npcb->netif_hints.tci = pcb->netif_hints.tci; +#endif /* LWIP_VLAN_PCP */ /* inherit socket options */ npcb->so_options = pcb->so_options & SOF_INHERITED; npcb->netif_idx = pcb->netif_idx; @@ -726,11 +706,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->snd_wnd_max = npcb->snd_wnd; #if TCP_CALCULATE_EFF_SEND_MSS -#ifdef LOSCFG_NET_CONTAINER - npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip, group); -#else npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); -#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ MIB2_STATS_INC(mib2.tcppassiveopens); @@ -819,9 +795,6 @@ tcp_process(struct tcp_pcb *pcb) err_t err; err = ERR_OK; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_tcp_pcb(pcb); -#endif LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL); @@ -879,6 +852,13 @@ tcp_process(struct tcp_pcb *pcb) tcp_parseopt(pcb); + if (flags & TCP_SYN) { + /* accept SYN only in 2 states: */ + if ((pcb->state != SYN_SENT) && (pcb->state != SYN_RCVD)) { + return ERR_OK; + } + } + /* Do different things depending on the TCP state. */ switch (pcb->state) { case SYN_SENT: @@ -897,11 +877,7 @@ tcp_process(struct tcp_pcb *pcb) pcb->state = ESTABLISHED; #if TCP_CALCULATE_EFF_SEND_MSS -#ifdef LOSCFG_NET_CONTAINER - pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, group); -#else pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); -#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); @@ -955,7 +931,12 @@ tcp_process(struct tcp_pcb *pcb) } break; case SYN_RCVD: - if (flags & TCP_ACK) { + if (flags & TCP_SYN) { + if (seqno == pcb->rcv_nxt - 1) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); + } + } else if (flags & TCP_ACK) { /* expected ACK number? */ if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { pcb->state = ESTABLISHED; @@ -1006,9 +987,6 @@ tcp_process(struct tcp_pcb *pcb) tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } - } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { - /* Looks like another copy of the SYN - retransmit our SYN-ACK */ - tcp_rexmit(pcb); } break; case CLOSE_WAIT: @@ -1177,7 +1155,6 @@ tcp_receive(struct tcp_pcb *pcb) { s16_t m; u32_t right_wnd_edge; - int found_dupack = 0; LWIP_ASSERT("tcp_receive: invalid pcb", pcb != NULL); LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); @@ -1239,7 +1216,6 @@ tcp_receive(struct tcp_pcb *pcb) if (pcb->rtime >= 0) { /* Clause 5 */ if (pcb->lastack == ackno) { - found_dupack = 1; if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { ++pcb->dupacks; } @@ -1255,11 +1231,6 @@ tcp_receive(struct tcp_pcb *pcb) } } } - /* If Clause (1) or more is true, but not a duplicate ack, reset - * count of consecutive duplicate acks */ - if (!found_dupack) { - pcb->dupacks = 0; - } } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { /* We come here when the ACK acknowledges new data. */ tcpwnd_size_t acked; @@ -1515,7 +1486,7 @@ tcp_receive(struct tcp_pcb *pcb) } pbuf_realloc(inseg.p, inseg.len); tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd", (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); } #if TCP_QUEUE_OOSEQ @@ -1564,7 +1535,7 @@ tcp_receive(struct tcp_pcb *pcb) } pbuf_realloc(inseg.p, inseg.len); tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue", (seqno + tcplen) == next->tcphdr->seqno); } pcb->ooseq = next; @@ -1575,7 +1546,7 @@ tcp_receive(struct tcp_pcb *pcb) pcb->rcv_nxt = seqno + tcplen; /* Update the receiver's (our) window. */ - LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); + LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd", pcb->rcv_wnd >= tcplen); pcb->rcv_wnd -= tcplen; tcp_update_rcv_ann_wnd(pcb); @@ -1593,7 +1564,7 @@ tcp_receive(struct tcp_pcb *pcb) recv_data = inseg.p; /* Since this pbuf now is the responsibility of the application, we delete our reference to it so that we won't - (mistakingly) deallocate it. */ + (mistakenly) deallocate it. */ inseg.p = NULL; } if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { @@ -1611,7 +1582,7 @@ tcp_receive(struct tcp_pcb *pcb) seqno = pcb->ooseq->tcphdr->seqno; pcb->rcv_nxt += TCP_TCPLEN(cseg); - LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", + LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd", pcb->rcv_wnd >= TCP_TCPLEN(cseg)); pcb->rcv_wnd -= TCP_TCPLEN(cseg); @@ -1716,10 +1687,20 @@ tcp_receive(struct tcp_pcb *pcb) ->ooseq. We check the lengths to see which one to discard. */ if (inseg.len > next->len) { + struct tcp_seg* cseg; + + /* If next segment is the last segment in ooseq + and smaller than inseg, that means it has been + trimmed before to fit our window, so we just + break here. */ + if (next->next == NULL) { + break; + } + /* The incoming segment is larger than the old segment. We replace some segments with the new one. */ - struct tcp_seg *cseg = tcp_seg_copy(&inseg); + cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { if (prev != NULL) { prev->next = cseg; @@ -1816,7 +1797,7 @@ tcp_receive(struct tcp_pcb *pcb) next->next->len = (u16_t)(pcb->rcv_nxt + pcb->rcv_wnd - seqno); pbuf_realloc(next->next->p, next->next->len); tcplen = TCP_TCPLEN(next->next); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd", (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); } } diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index f17a402..cfcc55d 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -106,7 +106,7 @@ #endif /* TCP_CHECKSUM_ON_COPY*/ /** Define this to 1 for an extra check that the output checksum is valid - * (usefule when the checksum is generated by the application, not the stack) */ + * (useful when the checksum is generated by the application, not the stack) */ #ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK #define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 #endif @@ -126,29 +126,20 @@ /* Forward declarations.*/ static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif); +static err_t tcp_output_control_segment_netif(const struct tcp_pcb *pcb, struct pbuf *p, + const ip_addr_t *src, const ip_addr_t *dst, + struct netif *netif); /* tcp_route: common code that returns a fixed bound netif or calls ip_route */ static struct netif * tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) { LWIP_UNUSED_ARG(src); /* in case IPv4-only and source-based routing is disabled */ -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_tcp_pcb(pcb); - LWIP_ERROR("tcp_route: invalid net group", group != NULL, return NULL); -#endif if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { -#ifdef LOSCFG_NET_CONTAINER - return netif_get_by_index(pcb->netif_idx, group); -#else return netif_get_by_index(pcb->netif_idx); -#endif } else { -#ifdef LOSCFG_NET_CONTAINER - return ip_route(src, dst, group); -#else return ip_route(src, dst); -#endif } } @@ -310,7 +301,7 @@ tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, /** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). * * @param pcb the tcp pcb to check for - * @param len length of data to send (checked agains snd_buf) + * @param len length of data to send (checked against snd_buf) * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise */ static err_t @@ -367,7 +358,7 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len) * it can send them more efficiently by combining them together). * To prompt the system to send data now, call tcp_output() after * calling tcp_write(). - * + * * This function enqueues the data pointed to by the argument dataptr. The length of * the data is passed as the len parameter. The apiflags can be one or more of: * - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated @@ -1049,12 +1040,12 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) u8_t optflags = 0; u8_t optlen = 0; - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", (flags & (TCP_SYN | TCP_FIN)) != 0); LWIP_ASSERT("tcp_enqueue_flags: invalid pcb", pcb != NULL); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + /* No need to check pcb->snd_queuelen if only SYN or FIN are allowed! */ /* Get options for this segment. This is a special case since this is the @@ -1934,65 +1925,61 @@ static err_t tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, const ip_addr_t *src, const ip_addr_t *dst) { - err_t err; struct netif *netif; LWIP_ASSERT("tcp_output_control_segment: invalid pbuf", p != NULL); netif = tcp_route(pcb, src, dst); if (netif == NULL) { - err = ERR_RTE; - } else { - u8_t ttl, tos; + pbuf_free(p); + return ERR_RTE; + } + return tcp_output_control_segment_netif(pcb, p, src, dst, netif); +} + +/** Output a control segment pbuf to IP. + * + * Called instead of tcp_output_control_segment when we don't have a pcb but we + * do know the interface to send to. + */ +static err_t +tcp_output_control_segment_netif(const struct tcp_pcb *pcb, struct pbuf *p, + const ip_addr_t *src, const ip_addr_t *dst, + struct netif *netif) +{ + err_t err; + u8_t ttl, tos; + + LWIP_ASSERT("tcp_output_control_segment_netif: no netif given", netif != NULL); + #if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - src, dst); - } + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + src, dst); + } #endif - if (pcb != NULL) { - NETIF_SET_HINTS(netif, LWIP_CONST_CAST(struct netif_hint*, &(pcb->netif_hints))); - ttl = pcb->ttl; - tos = pcb->tos; - } else { - /* Send output with hardcoded TTL/HL since we have no access to the pcb */ - ttl = TCP_TTL; - tos = 0; - } - TCP_STATS_INC(tcp.xmit); - err = ip_output_if(p, src, dst, ttl, tos, IP_PROTO_TCP, netif); - NETIF_RESET_HINTS(netif); + if (pcb != NULL) { + NETIF_SET_HINTS(netif, LWIP_CONST_CAST(struct netif_hint*, &(pcb->netif_hints))); + ttl = pcb->ttl; + tos = pcb->tos; + } else { + /* Send output with hardcoded TTL/HL since we have no access to the pcb */ + ttl = TCP_TTL; + tos = 0; } + TCP_STATS_INC(tcp.xmit); + err = ip_output_if(p, src, dst, ttl, tos, IP_PROTO_TCP, netif); + NETIF_RESET_HINTS(netif); + pbuf_free(p); return err; } -/** - * Send a TCP RESET packet (empty segment with RST flag set) either to - * abort a connection or to show that there is no matching local connection - * for a received segment. - * - * Called by tcp_abort() (to abort a local connection), tcp_input() (if no - * matching local pcb was found), tcp_listen_input() (if incoming segment - * has ACK flag set) and tcp_process() (received segment in the wrong state) - * - * Since a RST segment is in most cases not sent for an active connection, - * tcp_rst() has a number of arguments that are taken from a tcp_pcb for - * most other segment output functions. - * - * @param pcb TCP pcb (may be NULL if no pcb is available) - * @param seqno the sequence number to use for the outgoing segment - * @param ackno the acknowledge number to use for the outgoing segment - * @param local_ip the local IP address to send the segment from - * @param remote_ip the remote IP address to send the segment to - * @param local_port the local TCP port to send the segment from - * @param remote_port the remote TCP port to send the segment to - */ -void -tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, - const ip_addr_t *local_ip, const ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) +static struct pbuf * +tcp_rst_common(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) { struct pbuf *p; u16_t wnd; @@ -2000,6 +1987,9 @@ tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, LWIP_ASSERT("tcp_rst: invalid local_ip", local_ip != NULL); LWIP_ASSERT("tcp_rst: invalid remote_ip", remote_ip != NULL); + /* these two are passed only for checks, disable warnings without asserts */ + LWIP_UNUSED_ARG(local_ip); + LWIP_UNUSED_ARG(remote_ip); optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); @@ -2013,14 +2003,81 @@ tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, remote_port, TCP_RST | TCP_ACK, wnd); if (p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); - return; + return NULL; } tcp_output_fill_options(pcb, p, 0, 0); MIB2_STATS_INC(mib2.tcpoutrsts); - tcp_output_control_segment(pcb, p, local_ip, remote_ip); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); + return p; +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) to abort a + * connection. + * + * Called by tcp_abort() (to abort a local connection), tcp_closen() (if not + * all data has been received by the application), tcp_timewait_input() (if a + * SYN is received) and tcp_process() (received segment in the wrong state). + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param pcb TCP pcb (may be NULL if no pcb is available) + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + + p = tcp_rst_common(pcb, seqno, ackno, local_ip, remote_ip, local_port, remote_port); + if (p != NULL) { + tcp_output_control_segment(pcb, p, local_ip, remote_ip); + } +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) to show that there + * is no matching local connection for a received segment. + * + * Called by tcp_input() (if no matching local pcb was found) and + * tcp_listen_input() (if incoming segment has ACK flag set). + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param netif the netif on which to send the RST (since we have no pcb) + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst_netif(struct netif *netif, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) +{ + if (netif) { + struct pbuf *p = tcp_rst_common(NULL, seqno, ackno, local_ip, remote_ip, local_port, remote_port); + if (p != NULL) { + tcp_output_control_segment_netif(NULL, p, local_ip, remote_ip, netif); + } + } else { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_rst_netif: no netif given\n")); + } } /** diff --git a/src/core/timeouts.c b/src/core/timeouts.c index 60e2ea2..91657eb 100644 --- a/src/core/timeouts.c +++ b/src/core/timeouts.c @@ -51,7 +51,7 @@ #include "lwip/ip4_frag.h" #include "lwip/etharp.h" #include "lwip/dhcp.h" -#include "lwip/autoip.h" +#include "lwip/acd.h" #include "lwip/igmp.h" #include "lwip/dns.h" #include "lwip/nd6.h" @@ -61,8 +61,6 @@ #include "lwip/sys.h" #include "lwip/pbuf.h" -#if !LWIP_LOWPOWER - #if LWIP_DEBUG_TIMERNAMES #define HANDLER(x) x, #x #else /* LWIP_DEBUG_TIMERNAMES */ @@ -93,9 +91,9 @@ const struct lwip_cyclic_timer lwip_cyclic_timers[] = { {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, #endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, -#endif /* LWIP_AUTOIP */ +#if LWIP_ACD + {ACD_TMR_INTERVAL, HANDLER(acd_tmr)}, +#endif /* LWIP_ACD */ #if LWIP_IGMP {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, #endif /* LWIP_IGMP */ @@ -243,7 +241,7 @@ lwip_cyclic_timer(void *arg) cyclic->handler(); now = sys_now(); - next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ + next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ if (TIME_LESS_THAN(next_timeout_time, now)) { /* timer would immediately expire again -> "overload" -> restart without any correction */ #if LWIP_DEBUG_TIMERNAMES @@ -298,7 +296,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) LWIP_ASSERT("Timeout time too long, max is LWIP_UINT32_MAX/4 msecs", msecs <= (LWIP_UINT32_MAX / 4)); - next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ + next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ #if LWIP_DEBUG_TIMERNAMES sys_timeout_abs(next_timeout_time, handler, arg, handler_name); @@ -451,4 +449,3 @@ tcp_timer_needed(void) { } #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ -#endif /* !LWIP_LOWPOWER */ diff --git a/src/core/udp.c b/src/core/udp.c index a304dc7..c787ae0 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -1,12 +1,12 @@ /** * @file - * User Datagram Protocol module\n - * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n + * User Datagram Protocol module
    + * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
    * See also @ref udp_raw * * @defgroup udp_raw UDP * @ingroup callbackstyle_api - * User Datagram Protocol module\n + * User Datagram Protocol module
    * @see @ref api */ @@ -80,17 +80,6 @@ static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; /* exported in udp.h (was static) */ struct udp_pcb *udp_pcbs; -#ifdef LOSCFG_NET_CONTAINER -void set_udp_pcb_net_group(struct udp_pcb *pcb, struct net_group *group) -{ - set_ippcb_net_group((struct ip_pcb *)pcb, group); -} - -struct net_group *get_net_group_from_udp_pcb(struct udp_pcb *pcb) -{ - return get_net_group_from_ippcb((struct ip_pcb *)pcb); -} -#endif /** * Initialize this module. */ @@ -174,14 +163,14 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) { if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || - ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { + ip4_addr_net_eq(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { return 1; } } } else #endif /* LWIP_IPV4 */ /* Handle IPv4 and IPv6: all or exact match */ - if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + if (ip_addr_isany(&pcb->local_ip) || ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { return 1; } } @@ -207,9 +196,6 @@ udp_input(struct pbuf *p, struct netif *inp) struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; -#ifdef LOSCFG_NET_CONTAINER - struct net_group *inp_net_group = get_net_group_from_netif(inp); -#endif u16_t src, dest; u8_t broadcast; u8_t for_us = 0; @@ -273,11 +259,7 @@ udp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ -#ifdef LOSCFG_NET_CONTAINER - if (inp_net_group == get_net_group_from_udp_pcb(pcb) && (pcb->local_port == dest) && -#else if ((pcb->local_port == dest) && -#endif (udp_input_local_match(pcb, inp, broadcast) != 0)) { if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) { if (uncon_pcb == NULL) { @@ -286,9 +268,9 @@ udp_input(struct pbuf *p, struct netif *inp) #if LWIP_IPV4 } else if (broadcast && ip4_current_dest_addr()->addr == IPADDR_BROADCAST) { /* global broadcast address (only valid for IPv4; match was checked before) */ - if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_cmp(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) { + if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_eq(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) { /* uncon_pcb does not match the input netif, check this pcb */ - if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) { + if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_eq(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) { /* better match */ uncon_pcb = pcb; } @@ -306,7 +288,7 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB remote addr+port to UDP source addr+port */ if ((pcb->remote_port == src) && (ip_addr_isany_val(pcb->remote_ip) || - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -339,7 +321,7 @@ udp_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_IPV6 */ #if LWIP_IPV4 if (!ip_current_is_v6()) { - for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); + for_us = ip4_addr_eq(netif_ip4_addr(inp), ip4_current_dest_addr()); } #endif /* LWIP_IPV4 */ } @@ -383,7 +365,7 @@ udp_input(struct pbuf *p, struct netif *inp) #endif /* CHECKSUM_CHECK_UDP */ if (pbuf_remove_header(p, UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpinerrors); pbuf_free(p); @@ -399,22 +381,14 @@ udp_input(struct pbuf *p, struct netif *inp) if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { -#ifdef LOSCFG_NET_CONTAINER - if (mpcb != pcb && inp_net_group == get_net_group_from_udp_pcb(mpcb)) { -#else if (mpcb != pcb) { -#endif /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && (udp_input_local_match(mpcb, inp, broadcast) != 0)) { /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; -#if USE_PBUF_RAM_UDP_INPUT - q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); -#else q = pbuf_clone(PBUF_RAW, PBUF_POOL, p); -#endif if (q != NULL) { mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } @@ -569,16 +543,8 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); -#ifdef LOSCFG_NET_CONTAINER - struct net_group *group = get_net_group_from_udp_pcb(pcb); - LWIP_ERROR("udp_sendto: invalid net group", group != NULL, return ERR_VAL); -#endif if (pcb->netif_idx != NETIF_NO_INDEX) { -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index(pcb->netif_idx, group); -#else netif = netif_get_by_index(pcb->netif_idx); -#endif } else { #if LWIP_MULTICAST_TX_OPTIONS netif = NULL; @@ -590,11 +556,7 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, * list, but by doing so we skip a route lookup. If the interface index has * gone stale, we fall through and do the regular route lookup after all. */ if (pcb->mcast_ifindex != NETIF_NO_INDEX) { -#ifdef LOSCFG_NET_CONTAINER - netif = netif_get_by_index(pcb->mcast_ifindex, group); -#else netif = netif_get_by_index(pcb->mcast_ifindex); -#endif } #if LWIP_IPV4 else @@ -608,12 +570,8 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, in pcb->mcast_ip4 that is used for routing. If this routing lookup fails, we try regular routing as though no override was set. */ if (!ip4_addr_isany_val(pcb->mcast_ip4) && - !ip4_addr_cmp(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { -#ifdef LOSCFG_NET_CONTAINER - netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4, group); -#else + !ip4_addr_eq(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4); -#endif } } #endif /* LWIP_IPV4 */ @@ -623,11 +581,7 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, #endif /* LWIP_MULTICAST_TX_OPTIONS */ { /* find the outgoing network interface for this packet */ -#ifdef LOSCFG_NET_CONTAINER - netif = ip_route(&pcb->local_ip, dst_ip, group); -#else netif = ip_route(&pcb->local_ip, dst_ip); -#endif } } @@ -724,7 +678,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_i } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ - if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { + if (!ip4_addr_eq(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { /* local_ip doesn't match, drop the packet */ return ERR_RTE; } @@ -957,7 +911,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d /** * @ingroup udp_raw * Bind an UDP PCB. - * + * * @param pcb UDP PCB to be bound with a local address ipaddr and port. * @param ipaddr local IP address to bind with. Use IP_ANY_TYPE to * bind to all local interfaces. @@ -1032,13 +986,9 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) } } else { for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { -#ifdef LOSCFG_NET_CONTAINER - if (pcb != ipcb && (get_net_group_from_udp_pcb(pcb) == get_net_group_from_udp_pcb(ipcb))) { -#else if (pcb != ipcb) { -#endif /* By default, we don't allow to bind to a port that any other udp - PCB is already bound to, unless *all* PCBs with that port have tha + PCB is already bound to, unless *all* PCBs with that port have the REUSEADDR flag set. */ #if SO_REUSE if (!ip_get_option(pcb, SOF_REUSEADDR) || @@ -1049,7 +999,7 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) if ((ipcb->local_port == port) && (((IP_GET_TYPE(&ipcb->local_ip) == IP_GET_TYPE(ipaddr)) && /* IP address matches or any IP used? */ - (ip_addr_cmp(&ipcb->local_ip, ipaddr) || + (ip_addr_eq(&ipcb->local_ip, ipaddr) || ip_addr_isany(ipaddr) || ip_addr_isany(&ipcb->local_ip))) || (IP_GET_TYPE(&ipcb->local_ip) == IPADDR_TYPE_ANY) || @@ -1222,8 +1172,8 @@ udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) /** * @ingroup udp_raw - * Removes and deallocates the pcb. - * + * Removes and deallocates the pcb. + * * @param pcb UDP PCB to be removed. The PCB is removed from the list of * UDP PCB's and the data structure is freed from memory. * @@ -1288,6 +1238,7 @@ udp_new(void) #if LWIP_MULTICAST_TX_OPTIONS udp_set_multicast_ttl(pcb, UDP_TTL); #endif /* LWIP_MULTICAST_TX_OPTIONS */ + pcb_tci_init(pcb); } return pcb; } @@ -1338,7 +1289,7 @@ void udp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_a if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&upcb->local_ip, old_addr)) { + if (ip_addr_eq(&upcb->local_ip, old_addr)) { /* The PCB is bound to the old ipaddr and * is set to bound to the new one instead */ ip_addr_copy(upcb->local_ip, *new_addr); diff --git a/src/include/compat/posix/net/if.h b/src/include/compat/posix/net/if.h index 6b8e63a..8b8e481 100644 --- a/src/include/compat/posix/net/if.h +++ b/src/include/compat/posix/net/if.h @@ -7,7 +7,7 @@ * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, @@ -16,17 +16,17 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. diff --git a/src/include/lwip/acd.h b/src/include/lwip/acd.h new file mode 100644 index 0000000..e2e6cdd --- /dev/null +++ b/src/include/lwip/acd.h @@ -0,0 +1,109 @@ +/** + * @file + * + * ACD IPv4 Address Conflict Detection + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * Copyright (c) 2018 Jasper Verschueren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Jasper Verschueren + * Author: Dominik Spies + */ + +#ifndef LWIP_HDR_ACD_H +#define LWIP_HDR_ACD_H + +#include "lwip/opt.h" + +/* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV4 && LWIP_ACD + +#include "lwip/netif.h" +#include "lwip/etharp.h" +#include "lwip/prot/acd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** ACD Timing + * ACD_TMR_INTERVAL msecs, I recommend a value of 100. + * The value must divide 1000 with a remainder almost 0. Possible values are + * 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + */ +#define ACD_TMR_INTERVAL 100 + +/** + * Callback function: Handle conflict information from ACD module + * + * @param netif network interface to handle conflict information on + * @param state acd_callback_enum_t + */ +typedef void (*acd_conflict_callback_t)(struct netif *netif, acd_callback_enum_t state); + +/** ACD state information per netif */ +struct acd +{ + /** next acd module */ + struct acd *next; + /** the currently selected, probed, announced or used IP-Address */ + ip4_addr_t ipaddr; + /** current ACD state machine state */ + acd_state_enum_t state; + /** sent number of probes or announces, dependent on state */ + u8_t sent_num; + /** ticks to wait, tick is ACD_TMR_INTERVAL long */ + u16_t ttw; + /** ticks until a conflict can again be solved by defending */ + u8_t lastconflict; + /** total number of probed/used IP-Addresses that resulted in a conflict */ + u8_t num_conflicts; + /** callback function -> let's the acd user know if the address is good or + if a conflict is detected */ + acd_conflict_callback_t acd_conflict_callback; +}; + +err_t acd_add(struct netif *netif, struct acd *acd, + acd_conflict_callback_t acd_conflict_callback); +void acd_remove(struct netif *netif, struct acd *acd); +err_t acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr); +err_t acd_stop(struct acd *acd); +void acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr); +void acd_tmr(void); +void acd_network_changed_link_down(struct netif *netif); +void acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr, + const ip_addr_t *new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_ACD */ + +#endif /* LWIP_HDR_ACD_H */ diff --git a/src/include/lwip/altcp.h b/src/include/lwip/altcp.h index 1b24544..11acaff 100644 --- a/src/include/lwip/altcp.h +++ b/src/include/lwip/altcp.h @@ -1,6 +1,6 @@ /** * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n + * Application layered TCP connection API (to be used from TCPIP thread) * * This file contains the generic API. * For more details see @ref altcp_api. @@ -80,7 +80,8 @@ struct altcp_pcb { u8_t pollinterval; }; -/** @ingroup altcp */ +/** @ingroup altcp + * Struct containing an allocator and its state. */ typedef struct altcp_allocator_s { /** Allocator function */ altcp_new_fn alloc; diff --git a/src/include/lwip/altcp_tcp.h b/src/include/lwip/altcp_tcp.h index dbde584..ca47379 100644 --- a/src/include/lwip/altcp_tcp.h +++ b/src/include/lwip/altcp_tcp.h @@ -1,6 +1,6 @@ /** * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n + * Application layered TCP connection API (to be used from TCPIP thread)
    * This interface mimics the tcp callback API to the application while preventing * direct linking (much like virtual functions). * This way, an application can make use of other application layer protocols diff --git a/src/include/lwip/altcp_tls.h b/src/include/lwip/altcp_tls.h index ff797f2..fcb784d 100644 --- a/src/include/lwip/altcp_tls.h +++ b/src/include/lwip/altcp_tls.h @@ -51,6 +51,13 @@ #include "lwip/altcp.h" +/* check if mbedtls port is enabled */ +#include "lwip/apps/altcp_tls_mbedtls_opts.h" +/* allow session structure to be fully defined when using mbedtls port */ +#if LWIP_ALTCP_TLS_MBEDTLS +#include "mbedtls/ssl.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -63,7 +70,7 @@ struct altcp_tls_config; /** @ingroup altcp_tls * Create an ALTCP_TLS server configuration handle prepared for multiple certificates */ -struct altcp_tls_config *altcp_tls_create_config_server(uint8_t cert_count); +struct altcp_tls_config *altcp_tls_create_config_server(u8_t cert_count); /** @ingroup altcp_tls * Add a certificate to an ALTCP_TLS server configuration handle @@ -94,6 +101,15 @@ struct altcp_tls_config *altcp_tls_create_config_client_2wayauth(const u8_t *ca, const u8_t *privkey_pass, size_t privkey_pass_len, const u8_t *cert, size_t cert_len); +/** @ingroup altcp_tls + * Configure ALPN TLS extension + * Example:
    + * static const char *g_alpn_protocols[] = { "x-amzn-mqtt-ca", NULL };
    + * tls_config = altcp_tls_create_config_client(ca, ca_len);
    + * altcp_tls_conf_alpn_protocols(tls_config, g_alpn_protocols);
    + */ +int altcp_tls_configure_alpn_protocols(struct altcp_tls_config *conf, const char **protos); + /** @ingroup altcp_tls * Free an ALTCP_TLS configuration handle */ @@ -123,7 +139,7 @@ struct altcp_pcb *altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type); /** @ingroup altcp_tls * Create new ALTCP_TLS layer pcb and its inner tcp pcb. * Same as @ref altcp_tls_new but this allocator function fits to - * @ref altcp_allocator_t / @ref altcp_new.\n + * @ref altcp_allocator_t / @ref altcp_new.
    'arg' must contain a struct altcp_tls_config *. */ struct altcp_pcb *altcp_tls_alloc(void *arg, u8_t ip_type); @@ -134,6 +150,43 @@ struct altcp_pcb *altcp_tls_alloc(void *arg, u8_t ip_type); */ void *altcp_tls_context(struct altcp_pcb *conn); +/** @ingroup altcp_tls + * ALTCP_TLS session handle, content depends on port (e.g. mbedtls) + */ +struct altcp_tls_session +#if LWIP_ALTCP_TLS_MBEDTLS +{ + mbedtls_ssl_session data; +} +#endif +; + +/** @ingroup altcp_tls + * Initialise a TLS session buffer. + * Real type depends on port (e.g. mbedtls use mbedtls_ssl_session) + */ +void altcp_tls_init_session(struct altcp_tls_session *dest); + +/** @ingroup altcp_tls + * Save current connected session to reuse it later. Should be called after altcp_connect() succeeded. + * Return error if saving session fail. + * Real type depends on port (e.g. mbedtls use mbedtls_ssl_session) + */ +err_t altcp_tls_get_session(struct altcp_pcb *conn, struct altcp_tls_session *dest); + +/** @ingroup altcp_tls + * Restore a previously saved session. Must be called before altcp_connect(). + * Return error if cannot restore session. + * Real type depends on port (e.g. mbedtls use mbedtls_ssl_session) + */ +err_t altcp_tls_set_session(struct altcp_pcb *conn, struct altcp_tls_session *from); + +/** @ingroup altcp_tls + * Free allocated data inside a TLS session buffer. + * Real type depends on port (e.g. mbedtls use mbedtls_ssl_session) + */ +void altcp_tls_free_session(struct altcp_tls_session *dest); + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index c2afaf2..be8c22a 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -153,27 +153,27 @@ enum netconn_state { }; /** Used to inform the callback function about changes - * + * * Event explanation: - * + * * In the netconn implementation, there are three ways to block a client: - * + * * - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept()) * - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data()) * - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write()) - * + * * The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking * connections, you need to know in advance whether a call to a netconn function call would block or not, * and these events tell you about that. - * - * RCVPLUS events say: Safe to perform a potentially blocking call call once more. + * + * RCVPLUS events say: Safe to perform a potentially blocking call call once more. * They are counted in sockets - three RCVPLUS events for accept mbox means you are safe * to call netconn_accept 3 times without being blocked. * Same thing for receive mbox. - * + * * RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged". * Socket implementation decrements the counter. - * + * * For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something. * SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again. * A SENDMINUS event occurs when the next call to a netconn_send() would be blocking. @@ -246,10 +246,10 @@ struct netconn { all threads when closing while threads are waiting. */ int mbox_threads_waiting; #endif - /** only used for socket layer */ -#if LWIP_SOCKET - int socket; -#endif /* LWIP_SOCKET */ + union { + int socket; + void *ptr; + } callback_arg; #if LWIP_SO_SNDTIMEO /** timeout to wait for sending data (which means enqueueing data for sending in internal buffers) in milliseconds */ @@ -373,6 +373,9 @@ err_t netconn_err(struct netconn *conn); #define netconn_clear_flags(conn, clr_flags) do { (conn)->flags = (u8_t)((conn)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) #define netconn_is_flag_set(conn, flag) (((conn)->flags & (flag)) != 0) +#define netconn_set_callback_arg(conn, arg) do { (conn)->callback_arg.ptr = (arg); } while(0) +#define netconn_get_callback_arg(conn) ((conn)->callback_arg.ptr) + /** Set the blocking status of netconn calls (@todo: write/send is missing) */ #define netconn_set_nonblocking(conn, val) do { if(val) { \ netconn_set_flags(conn, NETCONN_FLAG_NON_BLOCKING); \ diff --git a/src/include/lwip/apps/altcp_tls_mbedtls_opts.h b/src/include/lwip/apps/altcp_tls_mbedtls_opts.h index 71aa599..e41301c 100644 --- a/src/include/lwip/apps/altcp_tls_mbedtls_opts.h +++ b/src/include/lwip/apps/altcp_tls_mbedtls_opts.h @@ -100,6 +100,12 @@ #define ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS (60 * 60 * 24) #endif +/** Certificate verification mode: MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL (default), + * MBEDTLS_SSL_VERIFY_REQUIRED (recommended)*/ +#ifndef ALTCP_MBEDTLS_AUTHMODE +#define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_OPTIONAL +#endif + #endif /* LWIP_ALTCP */ #endif /* LWIP_HDR_ALTCP_TLS_OPTS_H */ diff --git a/src/include/lwip/apps/fs.h b/src/include/lwip/apps/fs.h index 67b9a60..82b219a 100644 --- a/src/include/lwip/apps/fs.h +++ b/src/include/lwip/apps/fs.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, @@ -11,21 +11,21 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. - * + * * Author: Adam Dunkels * */ @@ -54,6 +54,7 @@ struct fsdata_chksum { #define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02 #define FS_FILE_FLAGS_HEADER_HTTPVER_1_1 0x04 #define FS_FILE_FLAGS_SSI 0x08 +#define FS_FILE_FLAGS_CUSTOM 0x10 /** Define FS_FILE_EXTENSION_T_DEFINED if you have typedef'ed to your private * pointer type (defaults to 'void' so the default usage is 'void*') @@ -66,17 +67,16 @@ struct fs_file { const char *data; int len; int index; +#if LWIP_HTTPD_FILE_EXTENSION /* pextension is free for implementations to hold private (extensional) arbitrary data, e.g. holding some file state or file system handle */ fs_file_extension *pextension; +#endif /* LWIP_HTTPD_FILE_EXTENSION */ #if HTTPD_PRECALCULATED_CHECKSUM const struct fsdata_chksum *chksum; u16_t chksum_count; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ u8_t flags; -#if LWIP_HTTPD_CUSTOM_FILES - u8_t is_custom_file; -#endif /* LWIP_HTTPD_CUSTOM_FILES */ #if LWIP_HTTPD_FILE_STATE void *state; #endif /* LWIP_HTTPD_FILE_STATE */ @@ -119,6 +119,19 @@ struct fsdata_file { #endif /* HTTPD_PRECALCULATED_CHECKSUM */ }; +#if LWIP_HTTPD_CUSTOM_FILES +/* Prototypes required to implement custom files as fs addon */ +int fs_open_custom(struct fs_file *file, const char *name); +void fs_close_custom(struct fs_file *file); +#if LWIP_HTTPD_FS_ASYNC_READ +u8_t fs_canread_custom(struct fs_file *file); +u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); +int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_read_custom(struct fs_file *file, char *buffer, int count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_CUSTOM_FILES */ + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/apps/http_client.h b/src/include/lwip/apps/http_client.h index 8a06308..3ba6d80 100644 --- a/src/include/lwip/apps/http_client.h +++ b/src/include/lwip/apps/http_client.h @@ -52,8 +52,8 @@ extern "C" { #endif /** - * @ingroup httpc - * HTTPC_HAVE_FILE_IO: define this to 1 to have functions dowloading directly + * @ingroup httpc + * HTTPC_HAVE_FILE_IO: define this to 1 to have functions downloading directly * to disk via fopen/fwrite. * These functions are example implementations of the interface only. */ @@ -62,13 +62,13 @@ extern "C" { #endif /** - * @ingroup httpc + * @ingroup httpc * The default TCP port used for HTTP */ #define HTTP_DEFAULT_PORT LWIP_IANA_PORT_HTTP /** - * @ingroup httpc + * @ingroup httpc * HTTP client result codes */ typedef enum ehttpc_result { @@ -97,7 +97,7 @@ typedef enum ehttpc_result { typedef struct _httpc_state httpc_state_t; /** - * @ingroup httpc + * @ingroup httpc * Prototype of a http client callback function * * @param arg argument specified when initiating the request @@ -110,13 +110,13 @@ typedef struct _httpc_state httpc_state_t; typedef void (*httpc_result_fn)(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err); /** - * @ingroup httpc + * @ingroup httpc * Prototype of http client callback: called when the headers are received * * @param connection http client connection * @param arg argument specified when initiating the request * @param hdr header pbuf(s) (may contain data also) - * @param hdr_len length of the heders in 'hdr' + * @param hdr_len length of the headers in 'hdr' * @param content_len content length as received in the headers (-1 if not received) * @return if != ERR_OK is returned, the connection is aborted */ diff --git a/src/include/lwip/apps/httpd.h b/src/include/lwip/apps/httpd.h index e872429..1ecdd74 100644 --- a/src/include/lwip/apps/httpd.h +++ b/src/include/lwip/apps/httpd.h @@ -95,6 +95,7 @@ typedef struct tCGIHandler pfnCGIHandler; } tCGI; +/** Set the array of cgi handlers. */ void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); #endif /* LWIP_HTTPD_CGI */ diff --git a/src/include/lwip/apps/httpd_opts.h b/src/include/lwip/apps/httpd_opts.h index 8723961..2b66e67 100644 --- a/src/include/lwip/apps/httpd_opts.h +++ b/src/include/lwip/apps/httpd_opts.h @@ -94,7 +94,7 @@ * * To save memory, the maximum tag length is limited (@see LWIP_HTTPD_MAX_TAG_NAME_LEN). * To save memory, the maximum insertion string length is limited (@see - * LWIP_HTTPD_MAX_TAG_INSERT_LEN). If this is not enought, @ref LWIP_HTTPD_SSI_MULTIPART + * LWIP_HTTPD_MAX_TAG_INSERT_LEN). If this is not enough, @ref LWIP_HTTPD_SSI_MULTIPART * can be used. */ #if !defined LWIP_HTTPD_SSI || defined __DOXYGEN__ @@ -112,7 +112,9 @@ /** Set this to 0 to prevent parsing the file extension at runtime to decide * if a file should be scanned for SSI tags or not. * Default is 1 (file extensions are checked using the g_pcSSIExtensions array) - * Set to 2 to override this runtime test function. + * Set to 2 to override this runtime test function. In this case, you have to + * provide an external function that does the check: + * u8_t http_uri_is_ssi(struct fs_file *file, const char *uri) * * This is enabled by default, but if you only use a newer version of makefsdata * supporting the "-ssi" option, this info is already present in @@ -121,6 +123,14 @@ #define LWIP_HTTPD_SSI_BY_FILE_EXTENSION 1 #endif +/** This is a list of file extensions handled as SSI files. This define + * is used to initialize a 'const char *const[]'. It is only used if + * LWIP_HTTPD_SSI_BY_FILE_EXTENSION != 0. + */ +#if !defined LWIP_HTTPD_SSI_EXTENSIONS || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_EXTENSIONS ".shtml", ".shtm", ".ssi", ".xml", ".json" +#endif + /** Set this to 1 to support HTTP POST */ #if !defined LWIP_HTTPD_SUPPORT_POST || defined __DOXYGEN__ #define LWIP_HTTPD_SUPPORT_POST 0 @@ -175,7 +185,7 @@ #define HTTPD_DEBUG LWIP_DBG_OFF #endif -/** Set this to 1 to use a memp pool for allocating +/** Set this to 1 to use a memp pool for allocating * struct http_state instead of the heap. * If enabled, you'll need to define MEMP_NUM_PARALLEL_HTTPD_CONNS * (and MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS for SSI) to set the size of @@ -365,6 +375,16 @@ #define LWIP_HTTPD_FILE_STATE 0 #endif +/** Set this to 1 to add the pextension field to the fs_file structure. + * This is included here to retain compatibility with legacy code that + * relies on the presence of the pextension field. + * New code should use LWIP_HTTPD_FILE_STATE instead. + * This option may be removed in a future version of lwip. + */ +#if !defined LWIP_HTTPD_FILE_EXTENSION || defined __DOXYGEN__ +#define LWIP_HTTPD_FILE_EXTENSION 0 +#endif + /** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for * predefined (MSS-sized) chunks of the files to prevent having to calculate * the checksums at runtime. */ diff --git a/src/include/lwip/apps/lwiperf.h b/src/include/lwip/apps/lwiperf.h index cc86e7f..e6f4476 100644 --- a/src/include/lwip/apps/lwiperf.h +++ b/src/include/lwip/apps/lwiperf.h @@ -76,7 +76,16 @@ enum lwiperf_client_type /** Prototype of a report function that is called when a session is finished. This report function can show the test results. - @param report_type contains the test result */ + @param arg Report_arg from when the test was started. + @param report_type contains the test result + @param local_addr The local address from the session + @param local_port The local port + @param remote_addr The remote address from the session + @param remote_port The remote port + @param bytes_transferred Total transferred bytes + @param ms_duration Total session duration, in milliseconds + @param bandwidth_kbitpsec Average bandwidth during the session, in kbps +*/ typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); diff --git a/src/include/lwip/apps/mdns.h b/src/include/lwip/apps/mdns.h index 20d7ee2..33da4a3 100644 --- a/src/include/lwip/apps/mdns.h +++ b/src/include/lwip/apps/mdns.h @@ -32,6 +32,7 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Erik Ekman + * Author: Jasper Verschueren * */ @@ -56,10 +57,41 @@ enum mdns_sd_proto { #define MDNS_PROBING_SUCCESSFUL 1 #define MDNS_LABEL_MAXLEN 63 +#define MDNS_DOMAIN_MAXLEN 256 struct mdns_host; struct mdns_service; +/* Domain structs */ +struct mdns_domain { + /* Encoded domain name */ + u8_t name[MDNS_DOMAIN_MAXLEN]; + /* Total length of domain name, including zero */ + u16_t length; + /* Set if compression of this domain is not allowed */ + u8_t skip_compression; +}; + +/** Domain, type and class. + * Shared between questions and answers */ +struct mdns_rr_info { + struct mdns_domain domain; + u16_t type; + u16_t klass; +}; + +struct mdns_answer { + struct mdns_rr_info info; + /** cache flush command bit */ + u16_t cache_flush; + /* Validity time in seconds */ + u32_t ttl; + /** Length of variable answer */ + u16_t rd_length; + /** Offset of start of variable answer in packet */ + u16_t rd_offset; +}; + /** Callback function to add text to a reply, called when generating the reply */ typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata); @@ -67,22 +99,26 @@ typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_use * uniqueness, called with result MDNS_PROBING_SUCCESSFUL if no other node claimed * use for the name for the netif or a service and is safe to use, or MDNS_PROBING_CONFLICT * if another node is already using it and mdns is disabled on this interface */ -typedef void (*mdns_name_result_cb_t)(struct netif* netif, u8_t result); +typedef void (*mdns_name_result_cb_t)(struct netif* netif, u8_t result, s8_t slot); + +void *mdns_get_service_txt_userdata(struct netif *netif, s8_t slot); void mdns_resp_init(void); void mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb); -err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); +err_t mdns_resp_add_netif(struct netif *netif, const char *hostname); err_t mdns_resp_remove_netif(struct netif *netif); err_t mdns_resp_rename_netif(struct netif *netif, const char *hostname); +int mdns_resp_netif_active(struct netif *netif); -s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); -err_t mdns_resp_del_service(struct netif *netif, s8_t slot); -err_t mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name); +s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_userdata); +err_t mdns_resp_del_service(struct netif *netif, u8_t slot); +err_t mdns_resp_rename_service(struct netif *netif, u8_t slot, const char *name); err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len); +void mdns_resp_restart_delay(struct netif *netif, uint32_t delay); void mdns_resp_restart(struct netif *netif); void mdns_resp_announce(struct netif *netif); @@ -96,6 +132,19 @@ void mdns_resp_announce(struct netif *netif); */ #define mdns_resp_netif_settings_changed(netif) mdns_resp_announce(netif) +#if LWIP_MDNS_SEARCH +typedef void (*search_result_fn_t)(struct mdns_answer *answer, const char *varpart, int varlen, int flags, void *arg); +/* flags bits, both can be set! */ +#define MDNS_SEARCH_RESULT_FIRST 1 /* First answer in received frame. */ +#define MDNS_SEARCH_RESULT_LAST 2 /* Last answer. */ + +err_t mdns_search_service(const char *name, const char *service, enum mdns_sd_proto proto, + struct netif *netif, search_result_fn_t result_fn, void *arg, + u8_t *request_id); +void mdns_search_stop(u8_t request_id); + +#endif /* LWIP_MDNS_SEARCH */ + #endif /* LWIP_MDNS_RESPONDER */ #ifdef __cplusplus diff --git a/src/include/lwip/apps/mdns_domain.h b/src/include/lwip/apps/mdns_domain.h new file mode 100644 index 0000000..9fa804e --- /dev/null +++ b/src/include/lwip/apps/mdns_domain.h @@ -0,0 +1,80 @@ +/** + * @file + * MDNS responder - domain related functionalities + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Author: Jasper Verschueren + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_DOMAIN_H +#define LWIP_HDR_APPS_MDNS_DOMAIN_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/apps/mdns_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MDNS_RESPONDER + +/* Domain methods - also visible for unit tests */ + +err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); +err_t mdns_domain_add_domain(struct mdns_domain *domain, struct mdns_domain *source); +err_t mdns_domain_add_string(struct mdns_domain *domain, const char *source); +u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); +void mdns_domain_debug_print(struct mdns_domain *domain); +int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); +#if LWIP_IPV4 +err_t mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t *addr); +#endif +#if LWIP_IPV6 +err_t mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr); +#endif +err_t mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns); +err_t mdns_build_dnssd_domain(struct mdns_domain *domain); +err_t mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name); +#if LWIP_MDNS_SEARCH +err_t mdns_build_request_domain(struct mdns_domain *domain, struct mdns_request *request, int include_name); +#endif +u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); +err_t mdns_write_domain(struct mdns_outpacket *outpkt, struct mdns_domain *domain); + +#endif /* LWIP_MDNS_RESPONDER */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MDNS_DOMAIN_H */ diff --git a/src/include/lwip/apps/mdns_opts.h b/src/include/lwip/apps/mdns_opts.h index 45f2c50..1eee3e3 100644 --- a/src/include/lwip/apps/mdns_opts.h +++ b/src/include/lwip/apps/mdns_opts.h @@ -32,6 +32,7 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Erik Ekman + * Author: Jasper Verschueren * */ @@ -59,6 +60,34 @@ #define MDNS_MAX_SERVICES 1 #endif +/** The minimum delay between probes in ms. RFC 6762 require 250ms. + * In noisy WiFi environment, adding 30-50ms to this value help a lot for + * a successful Apple BCT tests. + */ +#ifndef MDNS_PROBE_DELAY_MS +#define MDNS_PROBE_DELAY_MS 250 +#endif + +/** The maximum number of received packets stored in chained list of known + * answers for pending truncated questions. This value define the size of + * the MDNS_PKTS mempool. + * Up to MDNS_MAX_STORED_PKTS pbuf can be stored in addition to TC questions + * that are pending. + */ +#ifndef MDNS_MAX_STORED_PKTS +#define MDNS_MAX_STORED_PKTS 4 +#endif + +/** Payload size allocated for each outgoing UDP packet. Will be allocated with + * PBUF_RAM and freed after packet was sent. + * According to RFC 6762, there is no reason to retain the 512 bytes restriction + * for link-local multicast packet. + * 512 bytes isn't enough when 2 services need to be probed. + */ +#ifndef MDNS_OUTPUT_PACKET_SIZE +#define MDNS_OUTPUT_PACKET_SIZE ((MDNS_MAX_SERVICES == 1) ? 512 : 1450) +#endif + /** MDNS_RESP_USENETIF_EXTCALLBACK==1: register an ext_callback on the netif * to automatically restart probing/announcing on status or address change. */ @@ -66,6 +95,18 @@ #define MDNS_RESP_USENETIF_EXTCALLBACK LWIP_NETIF_EXT_STATUS_CALLBACK #endif +/** + * LWIP_MDNS_SEARCH==1: Turn on search over multicast DNS module. + */ +#ifndef LWIP_MDNS_SEARCH +#define LWIP_MDNS_SEARCH 1 +#endif + +/** The maximum number of running requests */ +#ifndef MDNS_MAX_REQUESTS +#define MDNS_MAX_REQUESTS 2 +#endif + /** * MDNS_DEBUG: Enable debugging for multicast DNS. */ @@ -78,4 +119,3 @@ */ #endif /* LWIP_HDR_APPS_MDNS_OPTS_H */ - diff --git a/src/include/lwip/apps/mdns_out.h b/src/include/lwip/apps/mdns_out.h new file mode 100644 index 0000000..e6a7e38 --- /dev/null +++ b/src/include/lwip/apps/mdns_out.h @@ -0,0 +1,138 @@ +/** + * @file + * MDNS responder - output related functionalities + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Author: Jasper Verschueren + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_OUT_H +#define LWIP_HDR_APPS_MDNS_OUT_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/apps/mdns_priv.h" +#include "lwip/netif.h" +#include "lwip/timeouts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MDNS_RESPONDER + +/** Bitmasks outmsg generation */ +/* Probe for ALL types with hostname */ +#define QUESTION_PROBE_HOST_ANY 0x10 +/* Probe for ALL types with service instance name */ +#define QUESTION_PROBE_SERVICE_NAME_ANY 0x10 + +/* Lookup from hostname -> IPv4 */ +#define REPLY_HOST_A 0x01 +/* Lookup from IPv4/v6 -> hostname */ +#define REPLY_HOST_PTR_V4 0x02 +/* Lookup from hostname -> IPv6 */ +#define REPLY_HOST_AAAA 0x04 +/* Lookup from hostname -> IPv6 */ +#define REPLY_HOST_PTR_V6 0x08 + +/* Lookup for service types */ +#define REPLY_SERVICE_TYPE_PTR 0x10 +/* Lookup for instances of service */ +#define REPLY_SERVICE_NAME_PTR 0x20 +/* Lookup for location of service instance */ +#define REPLY_SERVICE_SRV 0x40 +/* Lookup for text info on service instance */ +#define REPLY_SERVICE_TXT 0x80 + +/* RFC6762 section 6: + * To protect the network against excessive packet flooding due to software bugs + * or malicious attack, a Multicast DNS responder MUST NOT (except in the one + * special case of answering probe queries) multicast a record on a given + * interface until at least one second has elapsed since the last time that + * record was multicast on that particular interface. + */ +#define MDNS_MULTICAST_TIMEOUT 1000 + +/* RFC6762 section 6: + * In this special case only, when responding via multicast to a probe, a + * Multicast DNS responder is only required to delay its transmission as + * necessary to ensure an interval of at least 250 ms since the last time the + * record was multicast on that interface. + */ +#define MDNS_MULTICAST_PROBE_TIMEOUT 250 + +/* RFC6762 section 5.4: + * When receiving a question with the unicast-response bit set, a responder + * SHOULD usually respond with a unicast packet directed back to the querier. + * However, if the responder has not multicast that record recently (within one + * quarter of its TTL), then the responder SHOULD instead multicast the response + * so as to keep all the peer caches up to date, and to permit passive conflict + * detection. + * -> we implement a stripped down version. Depending on a timeout of 30s + * (25% of 120s) all QU questions are send via multicast or unicast. + */ +#define MDNS_MULTICAST_TIMEOUT_25TTL 30000 + +err_t mdns_create_outpacket(struct netif *netif, struct mdns_outmsg *msg, + struct mdns_outpacket *outpkt); +err_t mdns_send_outpacket(struct mdns_outmsg *msg, struct netif *netif); +void mdns_set_timeout(struct netif *netif, u32_t msecs, + sys_timeout_handler handler, u8_t *busy_flag); +#if LWIP_IPV4 +void mdns_multicast_timeout_reset_ipv4(void *arg); +void mdns_multicast_probe_timeout_reset_ipv4(void *arg); +void mdns_multicast_timeout_25ttl_reset_ipv4(void *arg); +void mdns_send_multicast_msg_delayed_ipv4(void *arg); +void mdns_send_unicast_msg_delayed_ipv4(void *arg); +void mdns_start_multicast_timeouts_ipv4(struct netif *netif); +#endif +#if LWIP_IPV6 +void mdns_multicast_timeout_reset_ipv6(void *arg); +void mdns_multicast_probe_timeout_reset_ipv6(void *arg); +void mdns_multicast_timeout_25ttl_reset_ipv6(void *arg); +void mdns_send_multicast_msg_delayed_ipv6(void *arg); +void mdns_send_unicast_msg_delayed_ipv6(void *arg); +void mdns_start_multicast_timeouts_ipv6(struct netif *netif); +#endif +void mdns_prepare_txtdata(struct mdns_service *service); +#ifdef LWIP_MDNS_SEARCH +err_t mdns_send_request(struct mdns_request *req, struct netif *netif, const ip_addr_t *destination); +#endif + +#endif /* LWIP_MDNS_RESPONDER */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MDNS_OUT_H */ diff --git a/src/include/lwip/apps/mdns_priv.h b/src/include/lwip/apps/mdns_priv.h index 9635b5b..5209ba0 100644 --- a/src/include/lwip/apps/mdns_priv.h +++ b/src/include/lwip/apps/mdns_priv.h @@ -32,11 +32,13 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Erik Ekman + * Author: Jasper Verschueren * */ #ifndef LWIP_HDR_MDNS_PRIV_H #define LWIP_HDR_MDNS_PRIV_H +#include "lwip/apps/mdns.h" #include "lwip/apps/mdns_opts.h" #include "lwip/pbuf.h" @@ -46,24 +48,185 @@ extern "C" { #if LWIP_MDNS_RESPONDER -/* Domain struct and methods - visible for unit tests */ - -#define MDNS_DOMAIN_MAXLEN 256 #define MDNS_READNAME_ERROR 0xFFFF +#define NUM_DOMAIN_OFFSETS 10 + +#define SRV_PRIORITY 0 +#define SRV_WEIGHT 0 + +/* mDNS TTL: (RFC6762 section 10) + * - 120 seconds if the hostname appears somewhere in the RR + * - 75 minutes if not (4500 seconds) + * - 10 seconds if responding to a legacy query + */ +#define MDNS_TTL_10 10 +#define MDNS_TTL_120 120 +#define MDNS_TTL_4500 4500 + +/* RFC6762 section 8.1: If fifteen conflicts occur within any ten-second period, + * then the host MUST wait at least five seconds before each successive + * additional probe attempt. + */ +#define MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT 15 +#define MDNS_PROBE_MAX_CONFLICTS_TIME_WINDOW 10000 +#define MDNS_PROBE_MAX_CONFLICTS_TIMEOUT 5000 + +#if LWIP_MDNS_SEARCH +/** Description of a search request */ +struct mdns_request { + /** Name of service, like 'myweb' */ + char name[MDNS_LABEL_MAXLEN + 1]; + /** Type of service, like '_http' or '_services._dns-sd' */ + struct mdns_domain service; + /** Callback function called for each response */ + search_result_fn_t result_fn; + void *arg; + /** Protocol, TCP or UDP */ + u16_t proto; + /** Query type (PTR, SRV, ...) */ + u8_t qtype; + /** PTR only request. */ + u16_t only_ptr; +}; +#endif + +/** Description of a service */ +struct mdns_service { + /** TXT record to answer with */ + struct mdns_domain txtdata; + /** Name of service, like 'myweb' */ + char name[MDNS_LABEL_MAXLEN + 1]; + /** Type of service, like '_http' */ + char service[MDNS_LABEL_MAXLEN + 1]; + /** Callback function and userdata + * to update txtdata buffer */ + service_get_txt_fn_t txt_fn; + void *txt_userdata; + /** Protocol, TCP or UDP */ + u16_t proto; + /** Port of the service */ + u16_t port; +}; -struct mdns_domain { - /* Encoded domain name */ - u8_t name[MDNS_DOMAIN_MAXLEN]; - /* Total length of domain name, including zero */ - u16_t length; - /* Set if compression of this domain is not allowed */ - u8_t skip_compression; +/** mDNS output packet */ +struct mdns_outpacket { + /** Packet data */ + struct pbuf *pbuf; + /** Current write offset in packet */ + u16_t write_offset; + /** Number of questions written */ + u16_t questions; + /** Number of normal answers written */ + u16_t answers; + /** Number of authoritative answers written */ + u16_t authoritative; + /** Number of additional answers written */ + u16_t additional; + /** Offsets for written domain names in packet. + * Used for compression */ + u16_t domain_offsets[NUM_DOMAIN_OFFSETS]; +}; + +/** mDNS output message */ +struct mdns_outmsg { + /** Identifier. Used in legacy queries */ + u16_t tx_id; + /** dns flags */ + u8_t flags; + /** Destination IP/port if sent unicast */ + ip_addr_t dest_addr; + u16_t dest_port; + /** If all answers in packet should set cache_flush bit */ + u8_t cache_flush; + /** If reply should be sent unicast (as requested) */ + u8_t unicast_reply_requested; + /** If legacy query. (tx_id needed, and write + * question again in reply before answer) */ + u8_t legacy_query; + /** If the query is a probe msg we need to respond immediately. Independent of + * the QU or QM flag. */ + u8_t probe_query_recv; + /* Question bitmask for host information */ + u8_t host_questions; + /* Questions bitmask per service */ + u8_t serv_questions[MDNS_MAX_SERVICES]; + /* Reply bitmask for host information */ + u8_t host_replies; + /* Bitmask for which reverse IPv6 hosts to answer */ + u8_t host_reverse_v6_replies; + /* Reply bitmask per service */ + u8_t serv_replies[MDNS_MAX_SERVICES]; +#ifdef LWIP_MDNS_SEARCH + /** Search query to send */ + struct mdns_request *query; +#endif +}; + +/** Delayed msg info */ +struct mdns_delayed_msg { + /** Signals if a multicast msg needs to be send out */ + u8_t multicast_msg_waiting; + /** Multicast timeout for all multicast traffic except probe answers */ + u8_t multicast_timeout; + /** Multicast timeout only for probe answers */ + u8_t multicast_probe_timeout; + /** Output msg used for delayed multicast responses */ + struct mdns_outmsg delayed_msg_multicast; + /** Prefer multicast over unicast timeout -> 25% of TTL = we take 30s as + general delay. */ + u8_t multicast_timeout_25TTL; + /** Only send out new unicast message if previous was send */ + u8_t unicast_msg_in_use; + /** Output msg used for delayed unicast responses */ + struct mdns_outmsg delayed_msg_unicast; +}; + +/* MDNS states */ +typedef enum { + /* MDNS module is off */ + MDNS_STATE_OFF, + /* Waiting before probing can be started */ + MDNS_STATE_PROBE_WAIT, + /* Probing the unique records */ + MDNS_STATE_PROBING, + /* Waiting before announcing the probed unique records */ + MDNS_STATE_ANNOUNCE_WAIT, + /* Announcing all records */ + MDNS_STATE_ANNOUNCING, + /* Probing and announcing completed */ + MDNS_STATE_COMPLETE +} mdns_resp_state_enum_t; + +/** Description of a host/netif */ +struct mdns_host { + /** Hostname */ + char name[MDNS_LABEL_MAXLEN + 1]; + /** Pointer to services */ + struct mdns_service *services[MDNS_MAX_SERVICES]; + /** Number of probes/announces sent for the current name */ + u8_t sent_num; + /** State of the mdns responder */ + mdns_resp_state_enum_t state; +#if LWIP_IPV4 + /** delayed msg struct for IPv4 */ + struct mdns_delayed_msg ipv4; +#endif +#if LWIP_IPV6 + /** delayed msg struct for IPv6 */ + struct mdns_delayed_msg ipv6; +#endif + /** Timestamp of probe conflict saved in list */ + u32_t conflict_time[MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT]; + /** Rate limit flag */ + u8_t rate_limit_activated; + /** List index for timestamps */ + u8_t index; + /** number of conflicts since startup */ + u8_t num_conflicts; }; -err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); -u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); -int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); -u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); +struct mdns_host* netif_mdns_data(struct netif *netif); +struct udp_pcb* get_mdns_pcb(void); #endif /* LWIP_MDNS_RESPONDER */ diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index c2bb228..f1583fc 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -79,6 +79,8 @@ struct mqtt_connect_client_info_t { const char* will_topic; /** will_msg, see will_topic */ const char* will_msg; + /** will_msg length, 0 to compute length from will_msg string */ + u8_t will_msg_len; /** will_qos, see will_topic */ u8_t will_qos; /** will_retain, see will_topic */ @@ -134,7 +136,7 @@ enum { MQTT_DATA_FLAG_LAST = 1 }; -/** +/** * @ingroup mqtt * Function prototype for MQTT incoming publish data callback function. Called when data * arrives to a subscribed topic @see mqtt_subscribe @@ -149,7 +151,7 @@ enum { typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); -/** +/** * @ingroup mqtt * Function prototype for MQTT incoming publish function. Called when an incoming publish * arrives to a subscribed topic @see mqtt_subscribe @@ -183,7 +185,7 @@ void mqtt_client_free(mqtt_client_t* client); u8_t mqtt_client_is_connected(mqtt_client_t *client); -void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, +void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t pub_cb, mqtt_incoming_data_cb_t data_cb, void *arg); err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub); diff --git a/src/include/lwip/apps/netbiosns_opts.h b/src/include/lwip/apps/netbiosns_opts.h index 1f51ab0..cc0da95 100644 --- a/src/include/lwip/apps/netbiosns_opts.h +++ b/src/include/lwip/apps/netbiosns_opts.h @@ -42,7 +42,7 @@ /** NetBIOS name of lwip device * This must be uppercase until NETBIOS_STRCMP() is defined to a string - * comparision function that is case insensitive. + * comparison function that is case insensitive. * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") * diff --git a/src/include/lwip/apps/smtp_opts.h b/src/include/lwip/apps/smtp_opts.h index bc743f6..c588fb9 100644 --- a/src/include/lwip/apps/smtp_opts.h +++ b/src/include/lwip/apps/smtp_opts.h @@ -6,14 +6,14 @@ #ifdef __cplusplus extern "C" { #endif - + /** * @defgroup smtp_opts Options * @ingroup smtp - * + * * @{ */ - + /** Set this to 1 to enable data handler callback on BODY */ #ifndef SMTP_BODYDH #define SMTP_BODYDH 0 @@ -78,4 +78,3 @@ extern "C" { #endif #endif /* SMTP_OPTS_H */ - diff --git a/src/include/lwip/apps/snmp.h b/src/include/lwip/apps/snmp.h index a3f8eb1..d01f99b 100644 --- a/src/include/lwip/apps/snmp.h +++ b/src/include/lwip/apps/snmp.h @@ -50,13 +50,11 @@ extern "C" { #include "lwip/err.h" #include "lwip/apps/snmp_core.h" -/** SNMP variable binding descriptor (publically needed for traps) */ +/** SNMP variable binding descriptor (publicly needed for traps) */ struct snmp_varbind { /** pointer to next varbind, NULL for last in list */ struct snmp_varbind *next; - /** pointer to previous varbind, NULL for first in list */ - struct snmp_varbind *prev; /** object identifier */ struct snmp_obj_id oid; @@ -101,6 +99,16 @@ err_t snmp_send_trap_generic(s32_t generic_trap); err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds); err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); +err_t snmp_send_inform_generic(s32_t generic_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id); +err_t snmp_send_inform_specific(s32_t specific_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id); +err_t snmp_send_inform(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds, s32_t *ptr_request_id); +struct snmp_request; +typedef void (*snmp_inform_callback_fct)(struct snmp_request *request, void* callback_arg); +void snmp_set_inform_callback(snmp_inform_callback_fct inform_callback, void* callback_arg); + +void snmp_set_default_trap_version(u8_t snmp_version); +u8_t snmp_get_default_trap_version(void); + #define SNMP_AUTH_TRAPS_DISABLED 0 #define SNMP_AUTH_TRAPS_ENABLED 1 void snmp_set_auth_traps_enabled(u8_t enable); diff --git a/src/include/lwip/apps/snmp_core.h b/src/include/lwip/apps/snmp_core.h index 6021c72..5a8a49f 100644 --- a/src/include/lwip/apps/snmp_core.h +++ b/src/include/lwip/apps/snmp_core.h @@ -101,7 +101,7 @@ extern "C" { /** error codes predefined by SNMP prot. */ typedef enum { SNMP_ERR_NOERROR = 0, -/* +/* outdated v1 error codes. do not use anmore! #define SNMP_ERR_NOSUCHNAME 2 use SNMP_ERR_NOSUCHINSTANCE instead #define SNMP_ERR_BADVALUE 3 use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead diff --git a/src/include/lwip/apps/snmp_mib2.h b/src/include/lwip/apps/snmp_mib2.h index 2f4a689..453e519 100644 --- a/src/include/lwip/apps/snmp_mib2.h +++ b/src/include/lwip/apps/snmp_mib2.h @@ -60,7 +60,7 @@ extern struct snmp_threadsync_instance snmp_mib2_lwip_locks; #define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) #endif -void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */ +void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be definition */ void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen); void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); diff --git a/src/include/lwip/apps/snmp_threadsync.h b/src/include/lwip/apps/snmp_threadsync.h index a25dbf2..76f1118 100644 --- a/src/include/lwip/apps/snmp_threadsync.h +++ b/src/include/lwip/apps/snmp_threadsync.h @@ -72,7 +72,7 @@ struct threadsync_data struct snmp_node_instance proxy_instance; }; -/** Thread sync instance. Needed EXCATLY once for every thread to be synced into. */ +/** Thread sync instance. Needed EXACTLY once for every thread to be synced into. */ struct snmp_threadsync_instance { sys_sem_t sem; diff --git a/src/include/lwip/apps/sntp.h b/src/include/lwip/apps/sntp.h index c415253..11dacce 100644 --- a/src/include/lwip/apps/sntp.h +++ b/src/include/lwip/apps/sntp.h @@ -57,6 +57,7 @@ u8_t sntp_enabled(void); void sntp_setserver(u8_t idx, const ip_addr_t *addr); const ip_addr_t* sntp_getserver(u8_t idx); +u8_t sntp_getkodreceived(u8_t idx); #if SNTP_MONITOR_SERVER_REACHABILITY u8_t sntp_getreachability(u8_t idx); diff --git a/src/include/lwip/apps/sntp_opts.h b/src/include/lwip/apps/sntp_opts.h index cb62771..1fad9a8 100644 --- a/src/include/lwip/apps/sntp_opts.h +++ b/src/include/lwip/apps/sntp_opts.h @@ -158,14 +158,14 @@ /** SNTP receive timeout - in milliseconds * Also used as retry timeout - this shouldn't be too low. - * Default is 15 seconds. Must not be beolw 15 seconds by specification (i.e. 15000) + * Default is 15 seconds. Must not be below 15 seconds by specification (i.e. 15000) */ #if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ #define SNTP_RECV_TIMEOUT 15000 #endif /** SNTP update delay - in milliseconds - * Default is 1 hour. Must not be beolw 60 seconds by specification (i.e. 60000) + * Default is 1 hour. Must not be below 60 seconds by specification (i.e. 60000) */ #if !defined SNTP_UPDATE_DELAY || defined __DOXYGEN__ #define SNTP_UPDATE_DELAY 3600000 diff --git a/src/include/lwip/apps/tftp_client.h b/src/include/lwip/apps/tftp_client.h new file mode 100644 index 0000000..24dbda6 --- /dev/null +++ b/src/include/lwip/apps/tftp_client.h @@ -0,0 +1,50 @@ +/** + * + * @file tftp_client.h + * TFTP client header + * + */ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_CLIENT_H +#define LWIP_HDR_APPS_TFTP_CLIENT_H + +#include "lwip/apps/tftp_common.h" + +enum tftp_transfer_mode { + TFTP_MODE_OCTET, + TFTP_MODE_NETASCII, + TFTP_MODE_BINARY /* used in old versions only */ +}; + +err_t tftp_init_client(const struct tftp_context* ctx); +err_t tftp_get(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode); +err_t tftp_put(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode); + +#endif /* LWIP_HDR_APPS_TFTP_CLIENT_H */ diff --git a/src/include/lwip/apps/tftp_common.h b/src/include/lwip/apps/tftp_common.h new file mode 100644 index 0000000..4bc2c17 --- /dev/null +++ b/src/include/lwip/apps/tftp_common.h @@ -0,0 +1,108 @@ +/** + * + * @file tftp_common.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_COMMON_H +#define LWIP_HDR_APPS_TFTP_COMMON_H + +#include "lwip/apps/tftp_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup tftp + * TFTP context containing callback functions for TFTP transfers + */ +struct tftp_context { + /** + * Open file for read/write (server mode only). + * @param fname Filename + * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) + * @param write Flag indicating read (0) or write (!= 0) access + * @returns File handle supplied to other functions + */ + void* (*open)(const char* fname, const char* mode, u8_t write); + /** + * Close file handle + * @param handle File handle returned by open()/tftp_put()/tftp_get() + */ + void (*close)(void* handle); + /** + * Read from file + * @param handle File handle returned by open()/tftp_put()/tftp_get() + * @param buf Target buffer to copy read data to + * @param bytes Number of bytes to copy to buf + * @returns >= 0: Success; < 0: Error + */ + int (*read)(void* handle, void* buf, int bytes); + /** + * Write to file + * @param handle File handle returned by open()/tftp_put()/tftp_get() + * @param pbuf PBUF adjusted such that payload pointer points + * to the beginning of write data. In other words, + * TFTP headers are stripped off. + * @returns >= 0: Success; < 0: Error + */ + int (*write)(void* handle, struct pbuf* p); + /** + * Error indication from client or response from server + * @param handle File handle set by open()/tftp_get()/tftp_put() + * @param err error code from client or server + * @param msg error message from client or server + * @param size size of msg + */ + void (*error)(void* handle, int err, const char* msg, int size); +}; + +#define LWIP_TFTP_MODE_SERVER 0x01 +#define LWIP_TFTP_MODE_CLIENT 0x02 +#define LWIP_TFTP_MODE_CLIENTSERVER (LWIP_TFTP_MODE_SERVER | LWIP_TFTP_MODE_CLIENT) + +err_t tftp_init_common(u8_t mode, const struct tftp_context* ctx); +void tftp_cleanup(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_TFTP_COMMON_H */ diff --git a/src/include/lwip/apps/tftp_opts.h b/src/include/lwip/apps/tftp_opts.h index 198f632..509fabd 100644 --- a/src/include/lwip/apps/tftp_opts.h +++ b/src/include/lwip/apps/tftp_opts.h @@ -11,7 +11,7 @@ * */ -/* +/* * Redistribution and use in source and binary forms, with or without * modification,are permitted provided that the following conditions are met: * @@ -96,7 +96,7 @@ * Max. length of TFTP mode */ #if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__ -#define TFTP_MAX_MODE_LEN 7 +#define TFTP_MAX_MODE_LEN 10 #endif /** diff --git a/src/include/lwip/apps/tftp_server.h b/src/include/lwip/apps/tftp_server.h index 0a7fbee..a5769ce 100644 --- a/src/include/lwip/apps/tftp_server.h +++ b/src/include/lwip/apps/tftp_server.h @@ -1,17 +1,11 @@ /** * * @file tftp_server.h - * - * @author Logan Gunthorpe - * - * @brief Trivial File Transfer Protocol (RFC 1350) - * - * Copyright (c) Deltatee Enterprises Ltd. 2013 - * All rights reserved. + * TFTP server header * */ -/* +/* * Redistribution and use in source and binary forms, with or without * modification,are permitted provided that the following conditions are met: * @@ -34,62 +28,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Logan Gunthorpe + * This file is part of the lwIP TCP/IP stack. * */ #ifndef LWIP_HDR_APPS_TFTP_SERVER_H #define LWIP_HDR_APPS_TFTP_SERVER_H -#include "lwip/apps/tftp_opts.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @ingroup tftp - * TFTP context containing callback functions for TFTP transfers - */ -struct tftp_context { - /** - * Open file for read/write. - * @param fname Filename - * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) - * @param write Flag indicating read (0) or write (!= 0) access - * @returns File handle supplied to other functions - */ - void* (*open)(const char* fname, const char* mode, u8_t write); - /** - * Close file handle - * @param handle File handle returned by open() - */ - void (*close)(void* handle); - /** - * Read from file - * @param handle File handle returned by open() - * @param buf Target buffer to copy read data to - * @param bytes Number of bytes to copy to buf - * @returns >= 0: Success; < 0: Error - */ - int (*read)(void* handle, void* buf, int bytes); - /** - * Write to file - * @param handle File handle returned by open() - * @param pbuf PBUF adjusted such that payload pointer points - * to the beginning of write data. In other words, - * TFTP headers are stripped off. - * @returns >= 0: Success; < 0: Error - */ - int (*write)(void* handle, struct pbuf* p); -}; - -err_t tftp_init(const struct tftp_context* ctx); -void tftp_cleanup(void); +#include "lwip/apps/tftp_common.h" -#ifdef __cplusplus -} -#endif +err_t tftp_init_server(const struct tftp_context* ctx); #endif /* LWIP_HDR_APPS_TFTP_SERVER_H */ diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 58dae33..c659a80 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -72,9 +72,9 @@ #define LWIP_RAND() ((u32_t)rand()) #endif -/** Platform specific diagnostic output.\n +/** Platform specific diagnostic output.
    * Note the default implementation pulls in printf, which may - * in turn pull in a lot of standard libary code. In resource-constrained + * in turn pull in a lot of standard library code. In resource-constrained * systems, this should be defined to something less resource-consuming. */ #ifndef LWIP_PLATFORM_DIAG @@ -83,9 +83,9 @@ #include #endif -/** Platform specific assertion handling.\n +/** Platform specific assertion handling.
    * Note the default implementation pulls in printf, fflush and abort, which may - * in turn pull in a lot of standard libary code. In resource-constrained + * in turn pull in a lot of standard library code. In resource-constrained * systems, this should be defined to something less resource-consuming. */ #ifndef LWIP_PLATFORM_ASSERT @@ -261,10 +261,10 @@ typedef int ssize_t; * its start address using LWIP_MEM_ALIGN. * You can declare your own version here e.g. to enforce alignment without adding * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement - * requirements.\n - * e.g. if you use gcc and need 32 bit alignment:\n - * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n - * or more portable:\n + * requirements.
    + * e.g. if you use gcc and need 32 bit alignment:
    + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))
    + * or more portable:
    * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] */ #ifndef LWIP_DECLARE_MEMORY_ALIGNED @@ -299,8 +299,8 @@ extern "C" { #endif /** Packed structs support. - * Placed BEFORE declaration of a packed struct.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Placed BEFORE declaration of a packed struct.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_BEGIN @@ -308,8 +308,8 @@ extern "C" { #endif /* PACK_STRUCT_BEGIN */ /** Packed structs support. - * Placed AFTER declaration of a packed struct.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Placed AFTER declaration of a packed struct.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_END @@ -317,8 +317,8 @@ extern "C" { #endif /* PACK_STRUCT_END */ /** Packed structs support. - * Placed between end of declaration of a packed struct and trailing semicolon.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Placed between end of declaration of a packed struct and trailing semicolon.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_STRUCT @@ -330,8 +330,8 @@ extern "C" { #endif /* PACK_STRUCT_STRUCT */ /** Packed structs support. - * Wraps u32_t and u16_t members.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Wraps u32_t and u16_t members.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_FIELD @@ -339,8 +339,8 @@ extern "C" { #endif /* PACK_STRUCT_FIELD */ /** Packed structs support. - * Wraps u8_t members, where some compilers warn that packing is not necessary.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Wraps u8_t members, where some compilers warn that packing is not necessary.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_FLD_8 @@ -348,20 +348,20 @@ extern "C" { #endif /* PACK_STRUCT_FLD_8 */ /** Packed structs support. - * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.
    + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifndef PACK_STRUCT_FLD_S #define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) #endif /* PACK_STRUCT_FLD_S */ -/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.\n - * The file included BEFORE the struct is "arch/bpstruct.h".\n - * The file included AFTER the struct is "arch/epstruct.h".\n +/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.
    + * The file included BEFORE the struct is "arch/bpstruct.h".
    + * The file included AFTER the struct is "arch/epstruct.h".
    * This can be used to implement struct packing on MS Visual C compilers, see - * the Win32 port in the lwIP contrib repository for reference. - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * the Win32 port in the lwIP/contrib subdir for reference. + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.
    * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. */ #ifdef __DOXYGEN__ @@ -382,6 +382,15 @@ extern "C" { #define LWIP_PROVIDE_ERRNO #endif +/* Use a special, reproducible version of rand() for fuzz tests? */ +#ifdef LWIP_RAND_FOR_FUZZ +#ifdef LWIP_RAND +#undef LWIP_RAND +#endif +u32_t lwip_fuzz_rand(void); +#define LWIP_RAND() lwip_fuzz_rand() +#endif + /** * @} */ diff --git a/src/include/lwip/autoip.h b/src/include/lwip/autoip.h index a3f0b76..b3f9feb 100644 --- a/src/include/lwip/autoip.h +++ b/src/include/lwip/autoip.h @@ -48,15 +48,12 @@ #include "lwip/netif.h" /* #include "lwip/udp.h" */ #include "lwip/etharp.h" +#include "lwip/acd.h" #ifdef __cplusplus extern "C" { #endif -/** AutoIP Timing */ -#define AUTOIP_TMR_INTERVAL 100 -#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) - /** AutoIP state information per netif */ struct autoip { @@ -64,36 +61,26 @@ struct autoip ip4_addr_t llipaddr; /** current AutoIP state machine state */ u8_t state; - /** sent number of probes or announces, dependent on state */ - u8_t sent_num; - /** ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ - u16_t ttw; - /** ticks until a conflict can be solved by defending */ - u8_t lastconflict; /** total number of probed/used Link Local IP-Addresses */ u8_t tried_llipaddr; + /** acd struct */ + struct acd acd; }; void autoip_set_struct(struct netif *netif, struct autoip *autoip); -/** Remove a struct autoip previously set to the netif using autoip_set_struct() */ -#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) +void autoip_remove_struct(struct netif *netif); err_t autoip_start(struct netif *netif); err_t autoip_stop(struct netif *netif); -void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); -void autoip_tmr(void); -void autoip_network_changed(struct netif *netif); -u8_t autoip_supplied_address(const struct netif *netif); +void autoip_network_changed_link_up(struct netif *netif); +void autoip_network_changed_link_down(struct netif *netif); +u8_t autoip_supplied_address(struct netif *netif); /* for lwIP internal use by ip4.c */ u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); #define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) -#if LWIP_LOWPOWER -u32_t autoip_tmr_tick(void); -#endif - #ifdef __cplusplus } #endif diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h index 579fd24..0ec7e76 100644 --- a/src/include/lwip/debug.h +++ b/src/include/lwip/debug.h @@ -140,11 +140,12 @@ #endif #ifdef LWIP_DEBUG -#define LWIP_DEBUGF(debug, message) do { \ - if ( \ - ((debug) & LWIP_DBG_ON) && \ +#define LWIP_DEBUG_ENABLED(debug) (((debug) & LWIP_DBG_ON) && \ ((debug) & LWIP_DBG_TYPES_ON) && \ - ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) + +#define LWIP_DEBUGF(debug, message) do { \ + if (LWIP_DEBUG_ENABLED(debug)) { \ LWIP_PLATFORM_DIAG(message); \ if ((debug) & LWIP_DBG_HALT) { \ while(1); \ @@ -153,6 +154,7 @@ } while(0) #else /* LWIP_DEBUG */ +#define LWIP_DEBUG_ENABLED(debug) 0 #define LWIP_DEBUGF(debug, message) #endif /* LWIP_DEBUG */ diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h index dfb266d..fd7c6a2 100644 --- a/src/include/lwip/def.h +++ b/src/include/lwip/def.h @@ -144,6 +144,20 @@ int lwip_stricmp(const char* str1, const char* str2); /* This can be #defined to strnstr() depending on your platform */ char* lwip_strnstr(const char* buffer, const char* token, size_t n); #endif +#ifndef lwip_strnistr +/* This can be #defined to strnistr() depending on your platform */ +char* lwip_strnistr(const char* buffer, const char* token, size_t n); +#endif +#ifndef lwip_memcmp_consttime +/* This could be #defined to something existing on your platform + * The goal of this function is to compare memory with constant runtime in order to prevent + * timing attacks to various parts in the stack. + * To do that, in contrast to memcmp(), it only returns: + * 0: equal + * != 0: not equal + */ +int lwip_memcmp_consttime(const void* s1, const void* s2, size_t len); +#endif #ifdef __cplusplus } diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index 8d73455..b413fa6 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -45,12 +45,25 @@ #include "lwip/netif.h" #include "lwip/udp.h" +#if LWIP_DHCP_DOES_ACD_CHECK +#include "lwip/acd.h" +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ + #ifdef __cplusplus extern "C" { #endif +/** Define DHCP_TIMEOUT_SIZE_T in opt.h if you want use a different integer than u16_t. + * Especially useful if DHCP_COARSE_TIMER_SECS is in smaller units, so timeouts easily reach UINT16_MAX and more */ +#ifdef DHCP_TIMEOUT_SIZE_T +typedef DHCP_TIMEOUT_SIZE_T dhcp_timeout_t; +#else /* DHCP_TIMEOUT_SIZE_T */ +typedef u16_t dhcp_timeout_t; +#endif /* DHCP_TIMEOUT_SIZE_T*/ /** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#ifndef DHCP_COARSE_TIMER_SECS #define DHCP_COARSE_TIMER_SECS 60 +#endif /* DHCP_COARSE_TIMER_SECS */ /** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ #define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) /** period (in milliseconds) of the application calling dhcp_fine_tmr() */ @@ -58,40 +71,8 @@ extern "C" { #define DHCP_BOOT_FILE_LEN 128U -#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS -#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS -#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS -#else -#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS -#endif -#else -#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 -#endif - -/** Option handling: options are parsed in dhcp_parse_reply - * and saved in an array where other functions can load them from. - * This might be moved into the struct dhcp (not necessarily since - * lwIP is single-threaded and the array is only used while in recv - * callback). */ -enum dhcp_option_idx { - DHCP_OPTION_IDX_OVERLOAD = 0, - DHCP_OPTION_IDX_MSG_TYPE, - DHCP_OPTION_IDX_SERVER_ID, - DHCP_OPTION_IDX_LEASE_TIME, - DHCP_OPTION_IDX_T1, - DHCP_OPTION_IDX_T2, - DHCP_OPTION_IDX_SUBNET_MASK, - DHCP_OPTION_IDX_ROUTER, -#if LWIP_DHCP_PROVIDE_DNS_SERVERS - DHCP_OPTION_IDX_DNS_SERVER, - DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ -#if LWIP_DHCP_GET_NTP_SRV - DHCP_OPTION_IDX_NTP_SERVER, - DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, -#endif /* LWIP_DHCP_GET_NTP_SRV */ - DHCP_OPTION_IDX_MAX -}; +#define DHCP_FLAG_SUBNET_MASK_GIVEN 0x01 +#define DHCP_FLAG_EXTERNAL_MEM 0x02 /* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ typedef enum { @@ -109,18 +90,16 @@ struct dhcp u8_t state; /** retries of current request */ u8_t tries; -#if LWIP_DHCP_AUTOIP_COOP - u8_t autoip_coop_state; -#endif - u8_t subnet_mask_given; - - u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ - u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ - u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ - u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ - u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ - u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ - u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ + /** see DHCP_FLAG_* */ + u8_t flags; + + dhcp_timeout_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + dhcp_timeout_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + dhcp_timeout_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + dhcp_timeout_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ + dhcp_timeout_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ + dhcp_timeout_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ + dhcp_timeout_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ ip4_addr_t offered_ip_addr; ip4_addr_t offered_sn_mask; @@ -133,10 +112,10 @@ struct dhcp ip4_addr_t offered_si_addr; char boot_file_name[DHCP_BOOT_FILE_LEN]; #endif /* LWIP_DHCP_BOOTPFILE */ - /** Holds the decoded option values, only valid while in dhcp_recv. */ - u32_t rx_options_val[DHCP_OPTION_IDX_MAX]; - /** Holds a flag which option was received and is contained in dhcp_rx_options_val, only valid while in dhcp_recv. */ - u8_t rx_options_given[DHCP_OPTION_IDX_MAX]; +#if LWIP_DHCP_DOES_ACD_CHECK + /** acd struct */ + struct acd acd; +#endif /* LWIP_DHCP_DOES_ACD_CHECK */ }; @@ -150,21 +129,14 @@ err_t dhcp_release(struct netif *netif); void dhcp_stop(struct netif *netif); void dhcp_release_and_stop(struct netif *netif); void dhcp_inform(struct netif *netif); -void dhcp_network_changed(struct netif *netif); -#if DHCP_DOES_ARP_CHECK -void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); -#endif +void dhcp_network_changed_link_up(struct netif *netif); + u8_t dhcp_supplied_address(const struct netif *netif); /* to be called every minute */ void dhcp_coarse_tmr(void); /* to be called every half second */ void dhcp_fine_tmr(void); -#if LWIP_LOWPOWER -u32_t dhcp_coarse_tmr_tick(void); -u32_t dhcp_fine_tmr_tick(void); -#endif - #if LWIP_DHCP_GET_NTP_SRV /** This function must exist, in other to add offered NTP servers to * the NTP (or SNTP) engine. diff --git a/src/include/lwip/dhcp6.h b/src/include/lwip/dhcp6.h index 4f994a8..5cc4a01 100644 --- a/src/include/lwip/dhcp6.h +++ b/src/include/lwip/dhcp6.h @@ -95,10 +95,6 @@ extern void dhcp6_set_ntp_servers(u8_t num_ntp_servers, const ip_addr_t* ntp_ser #define netif_dhcp6_data(netif) ((struct dhcp6*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6)) -#if LWIP_LOWPOWER -u32_t dhcp6_tmr_tick(); -#endif - #ifdef __cplusplus } #endif diff --git a/src/include/lwip/distributed_net/distributed_net.h b/src/include/lwip/distributed_net/distributed_net.h deleted file mode 100644 index 6680b5b..0000000 --- a/src/include/lwip/distributed_net/distributed_net.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LWIP_HDR_DISTRIBUTED_NET_H -#define LWIP_HDR_DISTRIBUTED_NET_H - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/sockets.h" - -#define IP4_MAX_ADDR_LEN 16 /* strlen(255.255.255.255) + 1 */ - -#define LOCAL_SERVER_IP "127.0.0.1" - -#define SOCKET_TO_INDEX(socket) ((socket)-LWIP_SOCKET_OFFSET) - -#define INDEX_TO_SOCKET(index) ((index) + LWIP_SOCKET_OFFSET) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#define INIT_SOCK_ADDR(addr, ip_string, port) \ - do { \ - (addr)->sin_family = AF_INET; \ - (addr)->sin_port = lwip_htons(port); \ - (addr)->sin_addr.s_addr = ipaddr_addr(ip_string); \ - } while (0) - -#define SET_MSG_ADDR(hdr, addr, addr_len) \ - do { \ - ((struct msghdr *)(hdr))->msg_name = (void *)(addr); \ - ((struct msghdr *)(hdr))->msg_namelen = (addr_len); \ - } while (0) - -void set_distributed_net_socket(int sock); - -void reset_distributed_net_socket(int sock); - -u16_t get_local_tcp_server_port(void); - -u16_t get_local_udp_server_port(void); - -u8_t is_distributed_net_enabled(void); - -int enable_distributed_net(u16_t tcp_port, u16_t udp_port); - -int disable_distributed_net(void); - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ - -#endif /* LWIP_HDR_DISTRIBUTED_NET_H */ diff --git a/src/include/lwip/distributed_net/distributed_net_core.h b/src/include/lwip/distributed_net/distributed_net_core.h deleted file mode 100644 index 0adf24f..0000000 --- a/src/include/lwip/distributed_net/distributed_net_core.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LWIP_HDR_DISTRIBUTED_NET_CORE_H -#define LWIP_HDR_DISTRIBUTED_NET_CORE_H - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/distributed_net/distributed_net.h" -#include "lwip/sockets.h" - -#define DNS_PORT 53 - -#define CHECK_PARA(exp, err) \ - do { \ - if (!(exp)) { \ - set_errno(err); \ - return -1; \ - } \ - } while (0) - -#define IS_LOCAL_UDP_SERVER_ADDR(addr) \ - ((addr)->sin_addr.s_addr == ipaddr_addr(LOCAL_SERVER_IP) && (addr)->sin_port == ntohs(get_local_udp_server_port())) - -#define IS_DNS_PORT(addr) (ntohs((addr).sin_port) == DNS_PORT) - -typedef struct tcp_connect_data { - char dest_addr[IP4_MAX_ADDR_LEN]; - u32_t dest_port; -} tcp_connect_data; - -int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t addr_len); - -int distributed_net_close(int sock); - -#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL -ssize_t distributed_net_sendto(int sock, const void *buf, size_t buf_len, int flags, const struct sockaddr *addr, - socklen_t addr_len); - -#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG -ssize_t distributed_net_sendmsg(int sock, const struct msghdr *hdr, int flags); -#endif - -ssize_t distributed_net_recvfrom(int sock, void *buf, size_t buf_len, int flags, struct sockaddr *from, - socklen_t *from_len); -#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ - -#endif /* LWIP_HDR_DISTRIBUTED_NET_CORE_H */ diff --git a/src/include/lwip/distributed_net/distributed_net_utils.h b/src/include/lwip/distributed_net/distributed_net_utils.h deleted file mode 100644 index 27172b5..0000000 --- a/src/include/lwip/distributed_net/distributed_net_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LWIP_HDR_DISTRIBUTED_NET_UTILS_H -#define LWIP_HDR_DISTRIBUTED_NET_UTILS_H - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -#include "lwip/sockets.h" - -u8_t is_no_proxy_network_segment(const struct sockaddr_in *addr_in); - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ - -#endif /* LWIP_HDR_DISTRIBUTED_NET_UTILS_H */ diff --git a/src/include/lwip/distributed_net/udp_transmit.h b/src/include/lwip/distributed_net/udp_transmit.h deleted file mode 100644 index 27e13ab..0000000 --- a/src/include/lwip/distributed_net/udp_transmit.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LWIP_HDR_UDP_TRANSMIT_H -#define LWIP_HDR_UDP_TRANSMIT_H - -#include "lwip/sockets.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/prot/dhcp.h" -#include "lwip/dhcp.h" -#include "lwip/if_api.h" - -#if LWIP_ENABLE_DISTRIBUTED_NET - -typedef struct udp_data { - char dest_addr[IP4_MAX_ADDR_LEN]; - u32_t dest_port; - char payload[]; -} udp_data; - -#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL - -#include "lwip/distributed_net/distributed_net.h" -#include "lwip/sockets.h" - -#define MAX_UDP_PAYLOAD_LEN 1024 - -#define MAX_IOV_NUM 32 - -#define UDP_PAYLOAD_LEN(send_len) ((send_len) - (ssize_t)sizeof(udp_data)) - -ssize_t udp_transmit_sendto(int sock, const void *buf, size_t buf_len, const struct sockaddr_in *dest_addr); - -ssize_t udp_transmit_sendmsg(int sock, const struct msghdr *hdr); - -#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ - -#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ - -#endif /* LWIP_HDR_UDP_TRANSMIT_H */ diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 2bb7d71..0913415 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -86,10 +86,6 @@ struct local_hostlist_entry { #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #endif /* DNS_LOCAL_HOSTLIST */ -#if LWIP_LOWPOWER -u32_t dns_tmr_tick(void); -#endif - #if LWIP_IPV4 extern const ip_addr_t dns_mquery_v4group; #endif /* LWIP_IPV4 */ diff --git a/src/include/lwip/errno.h b/src/include/lwip/errno.h index 4099657..48d6b53 100644 --- a/src/include/lwip/errno.h +++ b/src/include/lwip/errno.h @@ -130,9 +130,7 @@ extern "C" { #define ELIBSCN 81 /* .lib section in a.out corrupted */ #define ELIBMAX 82 /* Attempting to link in too many shared libraries */ #define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#ifndef EILSEQ #define EILSEQ 84 /* Illegal byte sequence */ -#endif #define ERESTART 85 /* Interrupted system call should be restarted */ #define ESTRPIPE 86 /* Streams pipe error */ #define EUSERS 87 /* Too many users */ diff --git a/src/include/lwip/etharp.h b/src/include/lwip/etharp.h index ca58ce3..48a1d22 100644 --- a/src/include/lwip/etharp.h +++ b/src/include/lwip/etharp.h @@ -88,15 +88,16 @@ err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr); #define etharp_gratuitous(netif) etharp_request((netif), netif_ip4_addr(netif)) void etharp_cleanup_netif(struct netif *netif); +#if LWIP_ACD +err_t etharp_acd_probe(struct netif *netif, const ip4_addr_t *ipaddr); +err_t etharp_acd_announce(struct netif *netif, const ip4_addr_t *ipaddr); +#endif /* LWIP_ACD */ + #if ETHARP_SUPPORT_STATIC_ENTRIES err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr); err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ -#if LWIP_LOWPOWER -u32_t etharp_tmr_tick(void); -#endif /* LWIP_LOWPOWER */ - void etharp_input(struct pbuf *p, struct netif *netif); #ifdef __cplusplus diff --git a/src/include/lwip/if_api.h b/src/include/lwip/if_api.h index bbf679f..b7269e2 100644 --- a/src/include/lwip/if_api.h +++ b/src/include/lwip/if_api.h @@ -49,11 +49,10 @@ extern "C" { #endif -#ifndef LWIP_SOCKET_STDINCLUDE #ifndef IF_NAMESIZE #define IF_NAMESIZE NETIF_NAMESIZE #endif -#endif /* LWIP_SOCKET_STDINCLUDE */ + char * lwip_if_indextoname(unsigned int ifindex, char *ifname); unsigned int lwip_if_nametoindex(const char *ifname); diff --git a/src/include/lwip/igmp.h b/src/include/lwip/igmp.h index 32451c6..0a16db0 100644 --- a/src/include/lwip/igmp.h +++ b/src/include/lwip/igmp.h @@ -99,11 +99,7 @@ err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); void igmp_tmr(void); -#if LWIP_LOWPOWER -u32_t igmp_tmr_tick(void); -#endif - -/** @ingroup igmp +/** @ingroup igmp * Get list head of IGMP groups for netif. * Note: The allsystems group IP is contained in the list as first entry. * @see @ref netif_set_igmp_mac_filter() diff --git a/src/include/lwip/inet.h b/src/include/lwip/inet.h index 466f359..0970885 100644 --- a/src/include/lwip/inet.h +++ b/src/include/lwip/inet.h @@ -41,6 +41,11 @@ #define LWIP_HDR_INET_H #include "lwip/opt.h" + +#if LWIP_SOCKET_EXTERNAL_HEADERS +#include LWIP_SOCKET_EXTERNAL_HEADER_INET_H +#else /* LWIP_SOCKET_EXTERNAL_HEADERS */ + #include "lwip/def.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" @@ -48,7 +53,7 @@ #ifdef __cplusplus extern "C" { #endif -#ifndef LWIP_SOCKET_STDINCLUDE + /* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED to prevent this code from redefining it. */ #if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) @@ -120,6 +125,18 @@ extern const struct in6_addr in6addr_any; #define IN_LOOPBACKNET IP_LOOPBACKNET +#define IN6_IS_ADDR_UNSPECIFIED(a) ip6_addr_isany((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_LOOPBACK(a) ip6_addr_isloopback((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MULTICAST(a) ip6_addr_ismulticast((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_LINKLOCAL(a) ip6_addr_islinklocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_SITELOCAL(a) ip6_addr_issitelocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_V4MAPPED(a) ip6_addr_isipv4mappedipv6((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_V4COMPAT(a) ip6_addr_isipv4compat((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MC_NODELOCAL(a) ip6_addr_ismulticast_iflocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) ip6_addr_ismulticast_linklocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MC_SITELOCAL(a) ip6_addr_ismulticast_sitelocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) ip6_addr_ismulticast_orglocal((ip6_addr_t*)(a)) +#define IN6_IS_ADDR_MC_GLOBAL(a) ip6_addr_ismulticast_global((ip6_addr_t*)(a)) #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX @@ -160,10 +177,12 @@ extern const struct in6_addr in6addr_any; #define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) #endif /* LWIP_IPV6 */ -#endif /* LWIP_SOCKET_STDINCLUDE */ + #ifdef __cplusplus } #endif +#endif /* LWIP_SOCKET_EXTERNAL_HEADERS */ + #endif /* LWIP_HDR_INET_H */ diff --git a/src/include/lwip/inet_chksum.h b/src/include/lwip/inet_chksum.h index 76893ef..33296d2 100644 --- a/src/include/lwip/inet_chksum.h +++ b/src/include/lwip/inet_chksum.h @@ -102,4 +102,3 @@ u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, #endif #endif /* LWIP_HDR_INET_H */ - diff --git a/src/include/lwip/init.h b/src/include/lwip/init.h index 6cabfc8..f579da4 100644 --- a/src/include/lwip/init.h +++ b/src/include/lwip/init.h @@ -52,9 +52,9 @@ extern "C" { /** X.x.x: Major version of the stack */ #define LWIP_VERSION_MAJOR 2 /** x.X.x: Minor version of the stack */ -#define LWIP_VERSION_MINOR 1 +#define LWIP_VERSION_MINOR 2 /** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION 3 +#define LWIP_VERSION_REVISION 1 /** For release candidates, this is set to 1..254 * For official releases, this is set to 255 (LWIP_RC_RELEASE) * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 9ce2661..668d831 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -47,9 +47,6 @@ #include "lwip/ip4.h" #include "lwip/ip6.h" #include "lwip/prot/ip.h" -#ifdef LOSCFG_NET_CONTAINER -#include "lwip/net_group.h" -#endif #ifdef __cplusplus extern "C" { @@ -72,33 +69,10 @@ extern "C" { #define IP_PCB_NETIFHINT #endif /* LWIP_NETIF_USE_HINTS */ -#ifdef LOSCFG_NET_CONTAINER -#ifndef IP_PCB_NETGROUP -#define IP_PCB_NETGROUP -#endif -#endif - /** This is the common part of all PCB types. It needs to be at the beginning of a PCB type definition. It is located here so that changes to this common part are made in one location instead of having to change all PCB structs. */ -#ifdef LOSCFG_NET_CONTAINER -#define IP_PCB \ - /* ip addresses in network byte order */ \ - ip_addr_t local_ip; \ - ip_addr_t remote_ip; \ - /* Bound netif index */ \ - u8_t netif_idx; \ - /* Socket options */ \ - u8_t so_options; \ - /* Type Of Service */ \ - u8_t tos; \ - /* Time To Live */ \ - u8_t ttl \ - /* link layer address resolution hint */ \ - IP_PCB_NETIFHINT \ - IP_PCB_NETGROUP -#else #define IP_PCB \ /* ip addresses in network byte order */ \ ip_addr_t local_ip; \ @@ -113,13 +87,23 @@ extern "C" { u8_t ttl \ /* link layer address resolution hint */ \ IP_PCB_NETIFHINT -#endif struct ip_pcb { /* Common members of all PCB types */ IP_PCB; }; +#if LWIP_VLAN_PCP +#define pcb_has_tci(pcb) ((pcb)->netif_hints.tci >= 0) +#define pcb_tci_get(pcb) ((pcb)->netif_hints.tci) +#define pcb_tci_clear(pcb) do { (pcb)->netif_hints.tci = -1; } while(0) +#define pcb_tci_set(pcb, tci_val) do { (pcb)->netif_hints.tci = (tci_val) & 0xffff; } while(0) +#define pcb_tci_set_pcp_dei_vid(pcb, pcp, dei, vid) pcb_tci_set(pcb, (((pcp) & 7) << 13) | (((dei) & 1) << 12) | ((vid) & 0xFFF)) +#define pcb_tci_init(pcb) pcb_tci_clear(pcb) +#else +#define pcb_tci_init(pcb) +#endif + /* * Option flags per-socket. These are the same like SO_XXX in sockets.h */ @@ -286,17 +270,10 @@ extern struct ip_globals ip_data; * @ingroup ip * Get netif for address combination. See \ref ip6_route and \ref ip4_route */ -#ifdef LOSCFG_NET_CONTAINER -#define ip_route(src, dest, group) \ - (IP_IS_V6(dest) ? \ - ip6_route(ip_2_ip6(src), ip_2_ip6(dest), group) : \ - ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest), group)) -#else #define ip_route(src, dest) \ (IP_IS_V6(dest) ? \ ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest))) -#endif /** * @ingroup ip * Get netif for IP. @@ -355,14 +332,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp); (ipaddr) = ip_netif_get_local_ip(netif, dest); \ }while(0) -#ifdef LOSCFG_NET_CONTAINER -void set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group); -struct net_group *get_net_group_from_ippcb(struct ip_pcb *pcb); -#endif #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_H */ - - diff --git a/src/include/lwip/ip4.h b/src/include/lwip/ip4.h index dbadc14..4d7228d 100644 --- a/src/include/lwip/ip4.h +++ b/src/include/lwip/ip4.h @@ -62,19 +62,11 @@ extern "C" { #define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) #define ip_init() /* Compatibility define, no init needed. */ -#ifdef LOSCFG_NET_CONTAINER -struct netif *ip4_route(const ip4_addr_t *dest, struct net_group *group); -#else struct netif *ip4_route(const ip4_addr_t *dest); -#endif #if LWIP_IPV4_SRC_ROUTING struct netif *ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest); #else /* LWIP_IPV4_SRC_ROUTING */ -#ifdef LOSCFG_NET_CONTAINER -#define ip4_route_src(src, dest, group) ip4_route(dest, group) -#else #define ip4_route_src(src, dest) ip4_route(dest) -#endif #endif /* LWIP_IPV4_SRC_ROUTING */ err_t ip4_input(struct pbuf *p, struct netif *inp); err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, @@ -115,5 +107,3 @@ void ip4_debug_print(struct pbuf *p); #endif /* LWIP_IPV4 */ #endif /* LWIP_HDR_IP_H */ - - diff --git a/src/include/lwip/ip4_addr.h b/src/include/lwip/ip4_addr.h index f244c4f..9fd8a0a 100644 --- a/src/include/lwip/ip4_addr.h +++ b/src/include/lwip/ip4_addr.h @@ -130,6 +130,11 @@ struct netif; /** Get the network address by combining host address with netmask */ #define ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0) +/** + * Determine if two address are on the same network. + * @deprecated Renamed to @ref ip4_addr_net_eq + */ +#define ip4_addr_netcmp(addr1, addr2, mask) ip4_addr_net_eq(addr1, addr2, mask) /** * Determine if two address are on the same network. * @@ -138,11 +143,15 @@ struct netif; * @arg mask network identifier mask * @return !0 if the network identifiers of both address match */ -#define ip4_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ +#define ip4_addr_net_eq(addr1, addr2, mask) (((addr1)->addr & \ (mask)->addr) == \ ((addr2)->addr & \ (mask)->addr)) -#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) +/** + * @deprecated Renamed to ip4_addr_eq + */ +#define ip4_addr_cmp(addr1, addr2) ip4_addr_eq(addr1, addr2) +#define ip4_addr_eq(addr1, addr2) ((addr1)->addr == (addr2)->addr) #define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY) #define ip4_addr_isany(addr1) ((addr1) == NULL || ip4_addr_isany_val(*(addr1))) diff --git a/src/include/lwip/ip4_frag.h b/src/include/lwip/ip4_frag.h index 13744f2..ed5bf14 100644 --- a/src/include/lwip/ip4_frag.h +++ b/src/include/lwip/ip4_frag.h @@ -89,11 +89,6 @@ struct pbuf_custom_ref { #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); - -#if LWIP_LOWPOWER -u32_t ip_reass_tmr_tick(void); -#endif /* LWIP_LOWPOWER */ - #endif /* IP_FRAG */ #ifdef __cplusplus diff --git a/src/include/lwip/ip6.h b/src/include/lwip/ip6.h index 3a31bdf..f894e06 100644 --- a/src/include/lwip/ip6.h +++ b/src/include/lwip/ip6.h @@ -57,11 +57,7 @@ extern "C" { #endif -#ifdef LOSCFG_NET_CONTAINER -struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, struct net_group *group); -#else struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); -#endif const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); err_t ip6_input(struct pbuf *p, struct netif *inp); err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, diff --git a/src/include/lwip/ip6_addr.h b/src/include/lwip/ip6_addr.h index 29c2a34..5937fed 100644 --- a/src/include/lwip/ip6_addr.h +++ b/src/include/lwip/ip6_addr.h @@ -146,10 +146,17 @@ typedef struct ip6_addr ip6_addr_t; ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src));}while(0) +/** @deprecated Renamed to @ref ip6_addr_net_zoneless_eq */ +#define ip6_addr_netcmp_zoneless(addr1, addr2) ip6_addr_net_zoneless_eq(addr1, addr2) /** Compare IPv6 networks, ignoring zone information. To be used sparingly! */ -#define ip6_addr_netcmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ +#define ip6_addr_net_zoneless_eq(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ ((addr1)->addr[1] == (addr2)->addr[1])) +/** + * Determine if two IPv6 address are on the same network. + * @deprecated Renamed to @ref ip6_addr_net_eq + */ +#define ip6_addr_netcmp(addr1, addr2) ip6_addr_net_eq(addr1, addr2) /** * Determine if two IPv6 address are on the same network. * @@ -157,18 +164,23 @@ typedef struct ip6_addr ip6_addr_t; * @param addr2 IPv6 address 2 * @return 1 if the network identifiers of both address match, 0 if not */ -#define ip6_addr_netcmp(addr1, addr2) (ip6_addr_netcmp_zoneless((addr1), (addr2)) && \ - ip6_addr_cmp_zone((addr1), (addr2))) +#define ip6_addr_net_eq(addr1, addr2) (ip6_addr_net_zoneless_eq((addr1), (addr2)) && \ + ip6_addr_zone_eq((addr1), (addr2))) -/* Exact-host comparison *after* ip6_addr_netcmp() succeeded, for efficiency. */ -#define ip6_addr_nethostcmp(addr1, addr2) (((addr1)->addr[2] == (addr2)->addr[2]) && \ +#define ip6_addr_nethostcmp(addr1, addr2) ip6_addr_nethost_eq(addr1, addr2) +/* Exact-host comparison *after* ip6_addr_net_eq() succeeded, for efficiency. */ +#define ip6_addr_nethost_eq(addr1, addr2) (((addr1)->addr[2] == (addr2)->addr[2]) && \ ((addr1)->addr[3] == (addr2)->addr[3])) +/** @deprecated Renamed to @ref ip6_addr_zoneless_eq */ +#define ip6_addr_cmp_zoneless(addr1, addr2) ip6_addr_zoneless_eq(addr1, addr2) /** Compare IPv6 addresses, ignoring zone information. To be used sparingly! */ -#define ip6_addr_cmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ +#define ip6_addr_zoneless_eq(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ ((addr1)->addr[1] == (addr2)->addr[1]) && \ ((addr1)->addr[2] == (addr2)->addr[2]) && \ ((addr1)->addr[3] == (addr2)->addr[3])) +/** @deprecated Renamed to @ref ip6_addr_eq */ +#define ip6_addr_cmp(addr1, addr2) ip6_addr_eq(addr1, addr2) /** * Determine if two IPv6 addresses are the same. In particular, the address * part of both must be the same, and the zone must be compatible. @@ -177,11 +189,13 @@ typedef struct ip6_addr ip6_addr_t; * @param addr2 IPv6 address 2 * @return 1 if the addresses are considered equal, 0 if not */ -#define ip6_addr_cmp(addr1, addr2) (ip6_addr_cmp_zoneless((addr1), (addr2)) && \ - ip6_addr_cmp_zone((addr1), (addr2))) +#define ip6_addr_eq(addr1, addr2) (ip6_addr_zoneless_eq((addr1), (addr2)) && \ + ip6_addr_zone_eq((addr1), (addr2))) +/** @deprecated Renamed to @ref ip6_addr_packed_eq */ +#define ip6_addr_cmp_packed(ip6addr, paddr, zone_idx) ip6_addr_packed_eq(ip6addr, paddr, zone_idx) /** Compare IPv6 address to packed address and zone */ -#define ip6_addr_cmp_packed(ip6addr, paddr, zone_idx) (((ip6addr)->addr[0] == (paddr)->addr[0]) && \ +#define ip6_addr_packed_eq(ip6addr, paddr, zone_idx) (((ip6addr)->addr[0] == (paddr)->addr[0]) && \ ((ip6addr)->addr[1] == (paddr)->addr[1]) && \ ((ip6addr)->addr[2] == (paddr)->addr[2]) && \ ((ip6addr)->addr[3] == (paddr)->addr[3]) && \ @@ -210,6 +224,11 @@ typedef struct ip6_addr ip6_addr_t; #define ip6_addr_isipv4mappedipv6(ip6addr) (((ip6addr)->addr[0] == 0) && ((ip6addr)->addr[1] == 0) && (((ip6addr)->addr[2]) == PP_HTONL(0x0000FFFFUL))) +#define ip6_addr_isipv4compat(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + (htonl((ip6addr)->addr[3]) > 1)) + #define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) #define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) #define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) @@ -274,7 +293,8 @@ typedef struct ip6_addr ip6_addr_t; (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id)); \ ip6_addr_clear_zone(ip6addr); }while(0) -#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ +#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) ip6_addr_solicitednode_eq(ip6addr, sn_addr) +#define ip6_addr_solicitednode_eq(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[1] == 0) && \ ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) diff --git a/src/include/lwip/ip6_frag.h b/src/include/lwip/ip6_frag.h index b278ddd..87e0e86 100644 --- a/src/include/lwip/ip6_frag.h +++ b/src/include/lwip/ip6_frag.h @@ -115,10 +115,6 @@ struct ip6_reassdata { void ip6_reass_tmr(void); struct pbuf *ip6_reass(struct pbuf *p); -#if LWIP_LOWPOWER -u32_t ip6_reass_tmr_tick(void); -#endif - #endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ #if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ diff --git a/src/include/lwip/ip6_zone.h b/src/include/lwip/ip6_zone.h index 2e254ff..834c32f 100644 --- a/src/include/lwip/ip6_zone.h +++ b/src/include/lwip/ip6_zone.h @@ -123,9 +123,11 @@ extern "C" { /** Is the zone field of the given IPv6 address equal to the given zone index? (0/1) */ #define ip6_addr_equals_zone(ip6addr, zone_idx) ((ip6addr)->zone == (zone_idx)) +/** @deprecated Renamed to @ref ip6_addr_zone_eq */ +#define ip6_addr_cmp_zone(addr1, addr2) ip6_addr_zone_eq(ip6addr1, ip6addr2) /** Are the zone fields of the given IPv6 addresses equal? (0/1) * This macro must only be used on IPv6 addresses of the same scope. */ -#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone) +#define ip6_addr_zone_eq(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone) /** Symbolic constants for the 'type' parameters in some of the macros. * These exist for efficiency only, allowing the macros to avoid certain tests @@ -246,20 +248,12 @@ enum lwip_ipv6_scope_type * @param dest the IPv6 address for which to select and set a zone. * @param src source IPv6 address (const); may be equal to dest. */ -#ifdef LOSCFG_NET_CONTAINER -#define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ - selected_netif = ip6_route((src), (dest), get_root_net_group()); \ - if (selected_netif != NULL) { \ - ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ - } } while (0) -#else #define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ selected_netif = ip6_route((src), (dest)); \ if (selected_netif != NULL) { \ ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ } } while (0) -#endif /** * @} */ @@ -273,7 +267,7 @@ enum lwip_ipv6_scope_type #define ip6_addr_clear_zone(ip6addr) #define ip6_addr_copy_zone(ip6addr1, ip6addr2) #define ip6_addr_equals_zone(ip6addr, zone_idx) (1) -#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) (1) +#define ip6_addr_zone_eq(ip6addr1, ip6addr2) (1) #define IPV6_CUSTOM_SCOPES 0 #define ip6_addr_has_scope(ip6addr, type) (0) #define ip6_addr_assign_zone(ip6addr, type, netif) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 2f97770..06454a4 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -194,39 +194,63 @@ extern const ip_addr_t ip_addr_any_type; #define ip_addr_get_network(target, host, netmask) do{if(IP_IS_V6(host)){ \ ip4_addr_set_zero(ip_2_ip4(target)); IP_SET_TYPE(target, IPADDR_TYPE_V6); } else { \ ip4_addr_get_network(ip_2_ip4(target), ip_2_ip4(host), ip_2_ip4(netmask)); IP_SET_TYPE(target, IPADDR_TYPE_V4); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_netcmp(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ +/** + * @ingroup ipaddr + * @deprecated Renamed to @ref ip_addr_net_eq + */ +#define ip_addr_netcmp(addr1, addr2, mask) ip_addr_net_eq((addr1), (addr2), (mask)) +/** @ingroup ipaddr + * Check if two ip addresses are share the same network, for a specific netmask. */ +#define ip_addr_net_eq(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ 0 : \ - ip4_addr_netcmp(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) -/** @ingroup ipaddr */ -#define ip_addr_cmp(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ - ip6_addr_cmp(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ - ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) -/** @ingroup ipaddr */ -#define ip_addr_cmp_zoneless(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ - ip6_addr_cmp_zoneless(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ - ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) -/** @ingroup ipaddr */ + ip4_addr_net_eq(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) +/** + * @ingroup ipaddr + * @deprecated Renamed to @ref ip_addr_eq + */ +#define ip_addr_cmp(addr1, addr2) ip_addr_eq((addr1), (addr2)) +/** @ingroup ipaddr + * Check if two ip addresses are equal. */ +#define ip_addr_eq(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_eq(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_eq(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** + * @ingroup ipaddr + * @deprecated Renamed to @ref ip_addr_zoneless_eq + */ +#define ip_addr_cmp_zoneless(addr1, addr2) ip_addr_zoneless_eq((addr1), (addr2)) +/** @ingroup ipaddr + * Check if two ip addresses are equal, ignoring the zone. */ +#define ip_addr_zoneless_eq(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_zoneless_eq(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_eq(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** @ingroup ipaddr + * Check if an ip address is the 'any' address. */ #define ip_addr_isany(ipaddr) (((ipaddr) == NULL) ? 1 : ((IP_IS_V6(ipaddr)) ? \ ip6_addr_isany(ip_2_ip6(ipaddr)) : \ ip4_addr_isany(ip_2_ip4(ipaddr)))) -/** @ingroup ipaddr */ +/** @ingroup ipaddr + * Check if an ip address is the 'any' address, by value. */ #define ip_addr_isany_val(ipaddr) ((IP_IS_V6_VAL(ipaddr)) ? \ ip6_addr_isany_val(*ip_2_ip6(&(ipaddr))) : \ ip4_addr_isany_val(*ip_2_ip4(&(ipaddr)))) -/** @ingroup ipaddr */ +/** @ingroup ipaddr + * Check if an ip address is a broadcast address. */ #define ip_addr_isbroadcast(ipaddr, netif) ((IP_IS_V6(ipaddr)) ? \ 0 : \ ip4_addr_isbroadcast(ip_2_ip4(ipaddr), netif)) -/** @ingroup ipaddr */ +/** @ingroup ipaddr + * Check inf an ip address is a multicast address. */ #define ip_addr_ismulticast(ipaddr) ((IP_IS_V6(ipaddr)) ? \ ip6_addr_ismulticast(ip_2_ip6(ipaddr)) : \ ip4_addr_ismulticast(ip_2_ip4(ipaddr))) -/** @ingroup ipaddr */ +/** @ingroup ipaddr + * Check inf an ip address is a loopback address. */ #define ip_addr_isloopback(ipaddr) ((IP_IS_V6(ipaddr)) ? \ ip6_addr_isloopback(ip_2_ip6(ipaddr)) : \ ip4_addr_isloopback(ip_2_ip4(ipaddr))) -/** @ingroup ipaddr */ +/** @ingroup ipaddr + * Check inf an ip address is a link-local address. */ #define ip_addr_islinklocal(ipaddr) ((IP_IS_V6(ipaddr)) ? \ ip6_addr_islinklocal(ip_2_ip6(ipaddr)) : \ ip4_addr_islinklocal(ip_2_ip4(ipaddr))) @@ -295,8 +319,10 @@ typedef ip4_addr_t ip_addr_t; #define ip_addr_set_loopback(is_ipv6, ipaddr) ip4_addr_set_loopback(ipaddr) #define ip_addr_set_hton(dest, src) ip4_addr_set_hton(dest, src) #define ip_addr_get_network(target, host, mask) ip4_addr_get_network(target, host, mask) -#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_netcmp(addr1, addr2, mask) -#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2) +#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_net_eq(addr1, addr2, mask) +#define ip_addr_net_eq(addr1, addr2, mask) ip4_addr_net_eq(addr1, addr2, mask) +#define ip_addr_cmp(addr1, addr2) ip4_addr_eq(addr1, addr2) +#define ip_addr_eq(addr1, addr2) ip4_addr_eq(addr1, addr2) #define ip_addr_isany(ipaddr) ip4_addr_isany(ipaddr) #define ip_addr_isany_val(ipaddr) ip4_addr_isany_val(ipaddr) #define ip_addr_isloopback(ipaddr) ip4_addr_isloopback(ipaddr) @@ -343,8 +369,11 @@ typedef ip6_addr_t ip_addr_t; #define ip_addr_set_hton(dest, src) ip6_addr_set_hton(dest, src) #define ip_addr_get_network(target, host, mask) ip6_addr_set_zero(target) #define ip_addr_netcmp(addr1, addr2, mask) 0 -#define ip_addr_cmp(addr1, addr2) ip6_addr_cmp(addr1, addr2) -#define ip_addr_cmp_zoneless(addr1, addr2) ip6_addr_cmp_zoneless(addr1, addr2) +#define ip_addr_net_eq(addr1, addr2, mask) 0 +#define ip_addr_cmp(addr1, addr2) ip6_addr_eq(addr1, addr2) +#define ip_addr_eq(addr1, addr2) ip6_addr_eq(addr1, addr2) +#define ip_addr_cmp_zoneless(addr1, addr2) ip6_addr_zoneless_eq(addr1, addr2) +#define ip_addr_zoneless_eq(addr1, addr2) ip6_addr_zoneless_eq(addr1, addr2) #define ip_addr_isany(ipaddr) ip6_addr_isany(ipaddr) #define ip_addr_isany_val(ipaddr) ip6_addr_isany_val(ipaddr) #define ip_addr_isloopback(ipaddr) ip6_addr_isloopback(ipaddr) @@ -404,7 +433,7 @@ extern const ip_addr_t ip_addr_broadcast; extern const ip_addr_t ip6_addr_any; -/** +/** * @ingroup ip6addr * IP6_ADDR_ANY can be used as a fixed ip_addr_t * for the IPv6 wildcard address @@ -424,8 +453,9 @@ extern const ip_addr_t ip6_addr_any; #endif +/** @ingroup ipaddr + * Macro representing the 'any' address. */ #if LWIP_IPV4 && LWIP_IPV6 -/** @ingroup ipaddr */ #define IP_ANY_TYPE (&ip_addr_any_type) #else #define IP_ANY_TYPE IP_ADDR_ANY diff --git a/src/include/lwip/lowpower.h b/src/include/lwip/lowpower.h deleted file mode 100644 index eab2c46..0000000 --- a/src/include/lwip/lowpower.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef LWIP_HDR_LOWPOWER_H -#define LWIP_HDR_LOWPOWER_H - -#include "lwip/opt.h" - -#if LWIP_LOWPOWER -#include "lwip/err.h" -#if !NO_SYS -#include "lwip/sys.h" -#endif - -#define LOWPOWER_TIMER_DEBUG 0 -#define TIMEOUT_TICK 100 /* 100ms */ -#define TIMEOUT_CHECK 30 - -#if LOWPOWER_TIMER_DEBUG -#define TCP_FASTTMR_NAME , "tcp_fasttmr" -#define TCP_SLOWTMR_NAME , "tcp_slowtmr" -#define IP_REASSTRM_NAME , "ip_reass_tmr" -#define ETHARPTMR_NAME , "etharp_tmr" -#define DHCP_COARSETMR_NAME , "dhcp_coarse_tmr" -#define DHCP_FINETMR_NAME , "dhcp_fine_tmr" -#define AUTOIPTMR_NAME , "autoip_tmr" -#define IGMPTMR_NAME , "igmp_tmr" -#define DNSTMR_NAME , "dns_tmr" -#define NAT64TMR_NAME , "nat64_tmr" -#define ND6TMR_NAME , "nd6_tmr" -#define IP6_TREASSTMR_NAME , "ip6_reass_tmr" -#define MLD6TMR_NAME , "mld6_tmr" -#define DHCP6TMR_NAME , "dhcp6_tmr" -#define LOWPAN6TMR_NAME , "lowpan6_tmr" -#else -#define TCP_FASTTMR_NAME -#define TCP_SLOWTMR_NAME -#define IP_REASSTRM_NAME -#define ETHARPTMR_NAME -#define DHCP_COARSETMR_NAME -#define DHCP_FINETMR_NAME -#define AUTOIPTMR_NAME -#define IGMPTMR_NAME -#define DNSTMR_NAME -#define NAT64TMR_NAME -#define ND6TMR_NAME -#define IP6_TREASSTMR_NAME -#define MLD6TMR_NAME -#define DHCP6TMR_NAME -#define LOWPAN6TMR_NAME -#endif - -#define SET_TMR_TICK(tick, val) do { \ - if ((val) > 0) { \ - if ((tick) == 0) { \ - (tick) = (val); \ - } else { \ - (tick) = (tick) > (val) ? (val) : (tick); \ - } \ - } \ -} while (0) - -typedef void (*lwip_timer_handler)(void); -typedef void (*sys_timeout_handler)(void *args); - -/* get time count to trigger */ -typedef u32_t (*get_next_timeout)(void); - -struct timer_handler { - u32_t interval; - lwip_timer_handler handler; - get_next_timeout next_tick; -#if LOWPOWER_TIMER_DEBUG - char *name; -#endif -}; - -struct timer_entry { - u32_t clock_max; /* tmr interval */ - u32_t timeout; - sys_timeout_handler handler; - void *args; - get_next_timeout next_tick; - struct timer_entry *next; -#if LOWPOWER_TIMER_DEBUG - char *name; -#endif - u8_t enable; -}; - -enum timer_state { - LOW_TMR_GETING_TICKS = 0, - LOW_TMR_TIMER_WAITING, - LOW_TMR_TIMER_HANDLING, -}; - -struct timer_mng { - enum timer_state state; - u32_t waiting_time; -}; - -enum lowpower_msg_type { - LOW_NON_BLOCK = 0, - LOW_BLOCK = 1, - LOW_FORCE_NON_BLOCK = 2, -}; - -enum lowpower_mod { - LOW_TMR_LOWPOWER_MOD = 0, - LOW_TMR_NORMAL_MOD = 1, -}; - -#define lowpower_sem_t sys_sem_t -#define LOWPOWER_SEM_WAIT(lock) sys_sem_wait(&(lock)) -#define LOWPOWER_SIGNAL(lock) sys_sem_signal(&(lock)) -#define LOWPOWER_SEM_NEW(lock, val) \ - do { \ - (val) = sys_sem_new(&(lock), 0); \ - } while (0) -#define LOWPOWER_SEM_FREE(lock) sys_sem_free(&(lock)) - -/* all timer use the same timeout step */ -#define STEP_TIMEOUT_TO_TICK(step, type) (((step) * lwip_cyclic_timers[(type)].interval_ms) / TIMEOUT_TICK) -#define STEP_TICK_TO_TIMEOUT(tick, type) (((tick) * TIMEOUT_TICK) / lwip_cyclic_timers[(type)].interval_ms) - -#define LOW_TMR_DELAY 20 -void sys_timeout_set_wake_time(u32_t val); -u32_t sys_timeout_get_wake_time(void); - -void sys_untimeout(sys_timeout_handler handler, void *arg); -void sys_restart_timeouts(void); -void tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); -void sys_timeouts_init(void); -err_t sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); -u8_t sys_timeout_waiting_long(void); - -void set_lowpower_mod(enum lowpower_mod sw); -enum lowpower_mod get_lowpowper_mod(void); - -#endif /* LOWEPOWER */ - -#endif /* LWIP_HDR_LOWPOWER_H */ diff --git a/src/include/lwip/mem.h b/src/include/lwip/mem.h index ff208d2..6819ee4 100644 --- a/src/include/lwip/mem.h +++ b/src/include/lwip/mem.h @@ -43,7 +43,7 @@ extern "C" { #endif -#if MEM_LIBC_MALLOC +#if MEM_CUSTOM_ALLOCATOR #include "lwip/arch.h" diff --git a/src/include/lwip/mld6.h b/src/include/lwip/mld6.h index 77ec0cb..2764fdd 100644 --- a/src/include/lwip/mld6.h +++ b/src/include/lwip/mld6.h @@ -82,13 +82,9 @@ err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); -#if LWIP_LOWPOWER -u32_t mld6_tmr_tick(void); -#endif - /** @ingroup mld6 * Get list head of MLD6 groups for netif. - * Note: The allnodes group IP is NOT in the list, since it must always + * Note: The allnodes group IP is NOT in the list, since it must always * be received for correct IPv6 operation. * @see @ref netif_set_mld_mac_filter() */ diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index e262ff6..c30e624 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -81,10 +81,6 @@ void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_stat #endif /* LWIP_IPV6_MLD */ void nd6_restart_netif(struct netif *netif); -#ifdef LWIP_LOWPOWER -u32_t nd6_tmr_tick(void); -#endif - #ifdef __cplusplus } #endif diff --git a/src/include/lwip/net_group.h b/src/include/lwip/net_group.h deleted file mode 100644 index bfec088..0000000 --- a/src/include/lwip/net_group.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef LOSCFG_NET_CONTAINER -#ifndef _NET_GROUP_H -#define _NET_GROUP_H -#include "lwip/arch.h" - -struct netif; -struct ip_pcb; - -struct net_group { - u8_t netif_num; - /** The default network interface. */ - struct netif *netif_default; - /** The list of network interfaces. */ - struct netif *netif_list; - struct netif *loop_netif; -}; - -struct net_group_ops { - struct net_group *(*get_curr_process_net_group)(void); - void (*set_netif_net_group)(struct netif *, struct net_group *); - struct net_group *(*get_net_group_from_netif)(struct netif *); - void (*set_ippcb_net_group)(struct ip_pcb *, struct net_group *); - struct net_group *(*get_net_group_from_ippcb)(struct ip_pcb *); -}; - -struct net_group *get_root_net_group(void); -struct net_group *get_curr_process_net_group(void); -struct net_group_ops *get_default_net_group_ops(void); -void set_default_net_group_ops(struct net_group_ops *ops); -#endif -#endif /* _NET_GROUP_H */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 627614b..0cde2c2 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -48,9 +48,6 @@ #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/stats.h" -#ifdef LOSCFG_NET_CONTAINER -#include "lwip/net_group.h" -#endif #ifdef __cplusplus extern "C" { @@ -122,6 +119,9 @@ enum lwip_internal_netif_client_data_index #if LWIP_AUTOIP LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, #endif +#if LWIP_ACD + LWIP_NETIF_CLIENT_DATA_INDEX_ACD, +#endif #if LWIP_IGMP LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, #endif @@ -248,14 +248,20 @@ typedef u8_t netif_addr_idx_t; #define NETIF_ADDR_IDX_MAX 0x7F #endif +#if LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP + #define LWIP_NETIF_USE_HINTS 1 + struct netif_hint { #if LWIP_NETIF_HWADDRHINT -#define LWIP_NETIF_USE_HINTS 1 -struct netif_hint { - netif_addr_idx_t addr_hint; -}; -#else /* LWIP_NETIF_HWADDRHINT */ -#define LWIP_NETIF_USE_HINTS 0 -#endif /* LWIP_NETIF_HWADDRHINT */ + u8_t addr_hint; +#endif +#if LWIP_VLAN_PCP + /** VLAN hader is set if this is >= 0 (but must be <= 0xFFFF) */ + s32_t tci; +#endif + }; +#else /* LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP */ + #define LWIP_NETIF_USE_HINTS 0 +#endif /* LWIP_NETIF_HWADDRHINT || LWIP_VLAN_PCP*/ /** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization @@ -348,7 +354,7 @@ struct netif { u8_t flags; /** descriptive abbreviation */ char name[2]; - /** number of this interface. Used for @ref if_api and @ref netifapi_netif, + /** number of this interface. Used for @ref if_api and @ref netifapi_netif, * as well as for IPv6 zones */ u8_t num; #if LWIP_IPV6_AUTOCONFIG @@ -379,6 +385,9 @@ struct netif { filter table of the ethernet MAC. */ netif_mld_mac_filter_fn mld_mac_filter; #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if LWIP_ACD + struct acd *acd_list; +#endif /* LWIP_ACD */ #if LWIP_NETIF_USE_HINTS struct netif_hint *hints; #endif /* LWIP_NETIF_USE_HINTS */ @@ -399,53 +408,30 @@ struct netif { #if LWIP_CHECKSUM_CTRL_PER_NETIF #define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ (netif)->chksum_flags = chksumflags; } while(0) -#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#define NETIF_CHECKSUM_ENABLED(netif, chksumflag) (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if NETIF_CHECKSUM_ENABLED(netif, chksumflag) #else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_CHECKSUM_ENABLED(netif, chksumflag) 0 #define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) #define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ #if LWIP_SINGLE_NETIF -#ifdef LOSCFG_NET_CONTAINER -#define NETIF_FOREACH(netif, group) if (((netif) = group->netif_default) != NULL) -#else #define NETIF_FOREACH(netif) if (((netif) = netif_default) != NULL) -#endif #else /* LWIP_SINGLE_NETIF */ -#ifdef LOSCFG_NET_CONTAINER -#define NETIF_FOREACH(netif, group) for ((netif) = group->netif_list; (netif) != NULL; (netif) = (netif)->next) -#else /** The list of network interfaces. */ extern struct netif *netif_list; #define NETIF_FOREACH(netif) for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) -#endif - #endif /* LWIP_SINGLE_NETIF */ -#ifndef LOSCFG_NET_CONTAINER /** The default network interface. */ extern struct netif *netif_default; -#endif -#ifdef LOSCFG_NET_CONTAINER -struct net_group *get_net_group_from_netif(struct netif *netif); -void netif_init(struct net_group *group); -#else void netif_init(void); -#endif -#ifdef LOSCFG_NET_CONTAINER -struct netif *netif_add_noaddr(struct netif *netif, struct net_group *group, - void *state, netif_init_fn init, netif_input_fn input); -#else struct netif *netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); -#endif #if LWIP_IPV4 -#ifdef LOSCFG_NET_CONTAINER -struct netif *netif_add(struct netif *netif, struct net_group *group, -#else struct netif *netif_add(struct netif *netif, -#endif const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, @@ -461,12 +447,7 @@ void netif_remove(struct netif * netif); structure. */ struct netif *netif_find(const char *name); -#ifdef LOSCFG_NET_CONTAINER -void netif_set_default(struct netif *netif, struct net_group *group); -void netif_set_default2(struct netif *netif); -#else void netif_set_default(struct netif *netif); -#endif #if LWIP_IPV4 void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); @@ -521,14 +502,18 @@ void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_ #endif /* LWIP_NETIF_HOSTNAME */ #if LWIP_IGMP -/** @ingroup netif */ +/** @ingroup netif + * Set igmp mac filter function for a netif. */ #define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +/** Get the igmp mac filter function for a netif. */ #define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD -/** @ingroup netif */ +/** @ingroup netif + * Set mld mac filter function for a netif. */ #define netif_set_mld_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->mld_mac_filter = function; }}while(0) +/** Get the mld mac filter function for a netif. */ #define netif_get_mld_mac_filter(netif) (((netif) != NULL) ? ((netif)->mld_mac_filter) : NULL) #define netif_mld_mac_filter(netif, addr, action) do { if((netif) && (netif)->mld_mac_filter) { (netif)->mld_mac_filter((netif), (addr), (action)); }}while(0) #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ @@ -586,13 +571,8 @@ err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t #endif /* LWIP_NETIF_USE_HINTS */ u8_t netif_name_to_index(const char *name); -#ifdef LOSCFG_NET_CONTAINER -char * netif_index_to_name(u8_t idx, char *name, struct net_group *group); -struct netif* netif_get_by_index(u8_t idx, struct net_group *group); -#else char * netif_index_to_name(u8_t idx, char *name); struct netif* netif_get_by_index(u8_t idx); -#endif /* Interface indexes always start at 1 per RFC 3493, section 4, num starts at 0 (internal index is 0..254)*/ #define netif_get_index(netif) ((u8_t)((netif)->num + 1)) @@ -613,8 +593,8 @@ typedef u16_t netif_nsc_reason_t; #define LWIP_NSC_NETIF_REMOVED 0x0002 /** link changed */ #define LWIP_NSC_LINK_CHANGED 0x0004 -/** netif administrative status changed.\n - * up is called AFTER netif is set up.\n +/** netif administrative status changed.
    + * up is called AFTER netif is set up.
    * down is called BEFORE the netif is actually set down. */ #define LWIP_NSC_STATUS_CHANGED 0x0008 /** IPv4 address has changed */ @@ -629,6 +609,8 @@ typedef u16_t netif_nsc_reason_t; #define LWIP_NSC_IPV6_SET 0x0100 /** IPv6 address state has changed */ #define LWIP_NSC_IPV6_ADDR_STATE_CHANGED 0x0200 +/** IPv4 settings: valid address set, application may start to communicate */ +#define LWIP_NSC_IPV4_ADDR_VALID 0x0400 /** @ingroup netif * Argument supplied to netif_ext_callback_fn. @@ -704,6 +686,11 @@ void netif_invoke_ext_callback(struct netif* netif, netif_nsc_reason_t reason, c #define netif_invoke_ext_callback(netif, reason, args) #endif +#if LWIP_TESTMODE && LWIP_HAVE_LOOPIF +struct netif* netif_get_loopif(void); +#endif + + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/netifapi.h b/src/include/lwip/netifapi.h index df05065..e063179 100644 --- a/src/include/lwip/netifapi.h +++ b/src/include/lwip/netifapi.h @@ -96,11 +96,7 @@ err_t netifapi_netif_index_to_name(u8_t index, char *name); /** @ingroup netifapi_netif * @see netif_set_default() */ -#ifdef LOSCFG_NET_CONTAINER -#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default2, NULL) -#else #define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) -#endif /** @ingroup netifapi_netif * @see netif_set_link_up() */ @@ -156,11 +152,6 @@ err_t netifapi_netif_index_to_name(u8_t index, char *name); */ #define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) -#if LWIP_LOWPOWER -err_t netifapi_enable_lowpower(void); -err_t netifapi_disable_lowpower(void); -#endif - #ifdef __cplusplus } #endif diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 53a20b7..2573285 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -227,14 +227,7 @@ #define LWIP_ASSERT_CORE_LOCKED() #endif -/** - * Called as first thing in the lwIP TCPIP thread. Can be used in conjunction - * with @ref LWIP_ASSERT_CORE_LOCKED to check core locking. - * @see @ref multithreading - */ -#if !defined LWIP_MARK_TCPIP_THREAD || defined __DOXYGEN__ -#define LWIP_MARK_TCPIP_THREAD() -#endif + /** * @} */ @@ -252,10 +245,28 @@ /** * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library * instead of the lwip internal allocator. Can save code size if you - * already use it. + * already use it. Specialized case of MEM_CUSTOM_ALLOCATOR. + * @see MEM_CUSTOM_ALLOCATOR */ #if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ #define MEM_LIBC_MALLOC 0 +#elif MEM_LIBC_MALLOC +#define MEM_CUSTOM_ALLOCATOR 1 +#define MEM_CUSTOM_FREE free +#define MEM_CUSTOM_MALLOC malloc +#define MEM_CUSTOM_CALLOC calloc +#endif + +/** + * MEM_CUSTOM_ALLOCATOR==1: Use malloc/free/realloc provided by a custom + * implementation instead of the lwip internal allocator. Can save code size if + * you already use it. If enabled, you have to define those functions: + * \#define MEM_CUSTOM_FREE my_free + * \#define MEM_CUSTOM_MALLOC my_malloc + * \#define MEM_CUSTOM_CALLOC my_calloc + */ +#if !defined MEM_CUSTOM_ALLOCATOR || defined __DOXYGEN__ +#define MEM_CUSTOM_ALLOCATOR 0 #endif /** @@ -505,7 +516,7 @@ * The number of sys timeouts used by the core stack (not apps) * The default number of timeouts is calculated here for all enabled modules. */ -#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD))) +#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_ACD + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD + LWIP_IPV6_DHCP6))) /** * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. @@ -677,6 +688,20 @@ #define ETHARP_SUPPORT_VLAN 0 #endif +/** + * LWIP_VLAN_PCP==1: Enable outgoing VLAN tagging of frames on a per-PCB basis + * for QoS purposes. With this feature enabled, each PCB has a new variable: + * "netif_hints.tci" (Tag Control Identifier). + * The TCI contains three fields: VID, CFI and PCP. + * - VID is the VLAN ID, which should be set to zero. + * - The "CFI" bit is used to enable or disable VLAN tags for the PCB. + * - PCP (Priority Code Point) is a 3 bit field used for Ethernet level QoS. + * See pcb_tci_*() functions to get/set/clear this. + */ +#ifndef LWIP_VLAN_PCP +#define LWIP_VLAN_PCP 0 +#endif + /** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled */ #if !defined LWIP_ETHERNET || defined __DOXYGEN__ @@ -924,10 +949,10 @@ #endif /* !LWIP_IPV4 */ /** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + * LWIP_DHCP_DOES_ACD_CHECK==1: Perform address conflict detection on the dhcp address. */ -#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ -#define DHCP_DOES_ARP_CHECK (LWIP_DHCP && LWIP_ARP) +#if !defined LWIP_DHCP_DOES_ACD_CHECK || defined __DOXYGEN__ +#define LWIP_DHCP_DOES_ACD_CHECK LWIP_DHCP #endif /** @@ -961,6 +986,14 @@ #if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ #define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS #endif + +/** LWIP_DHCP_DISCOVER_ADD_HOSTNAME: Set to 0 to not include hostname opt in discover packets. + * If the hostname is not set in the DISCOVER packet, then some servers might issue an OFFER with hostname + * configured and consequently reject the REQUEST with any other hostname. + */ +#if !defined LWIP_DHCP_DISCOVER_ADD_HOSTNAME || defined __DOXYGEN__ +#define LWIP_DHCP_DISCOVER_ADD_HOSTNAME 1 +#endif /* LWIP_DHCP_DISCOVER_ADD_HOSTNAME */ /** * @} */ @@ -1009,6 +1042,31 @@ * @} */ +/* + ------------------------------------ + ----------- ACD options ------------ + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_acd ACD + * @ingroup lwip_opts_ipv4 + * @{ + */ + /** + * LWIP_ACD==1: Enable ACD module. ACD module is needed when using AUTOIP. + */ +#if !defined LWIP_ACD || defined __DOXYGEN__ +#define LWIP_ACD (LWIP_AUTOIP || LWIP_DHCP_DOES_ACD_CHECK) +#endif +#if !LWIP_IPV4 +/* disable ACD when IPv4 is disabled */ +#undef LWIP_ACD +#define LWIP_ACD 0 +#endif /* !LWIP_IPV4 */ +/** + * @} + */ + /* ---------------------------------- ----- SNMP MIB2 support ----- @@ -1141,7 +1199,9 @@ * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} * * Instead, you can also use an external function: - * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * \#define DNS_LOOKUP_LOCAL_EXTERN(name, namelen, addr, dns_addrtype) my_lookup_function(name, namelen, addr, dns_addrtype) + * with function signature: + * extern err_t my_lookup_function(const char *name, size_t namelen, ip_addr_t *addr, u8_t dns_addrtype) * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). */ #if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ @@ -1305,6 +1365,15 @@ #define TCP_CALCULATE_EFF_SEND_MSS 1 #endif +/** + * LWIP_TCP_RTO_TIME: Initial TCP retransmission timeout (ms). + * This defaults to 3 seconds as traditionally defined in the TCP protocol. + * For improving timely recovery on faster networks, this value could + * be lowered down to 1 second (RFC 6298) + */ +#if !defined LWIP_TCP_RTO_TIME || defined __DOXYGEN__ +#define LWIP_TCP_RTO_TIME 3000 +#endif /** * TCP_SND_BUF: TCP sender buffer space (bytes). @@ -1523,13 +1592,13 @@ * link level header. The default is 14, the standard value for * Ethernet. */ -#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ -#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ -#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) -#else /* LWIP_HOOK_VLAN_SET */ -#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -#endif /* LWIP_HOOK_VLAN_SET */ -#endif + #if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if (defined LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP) && !defined __DOXYGEN__ + #define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP */ + #define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET || LWIP_VLAN_PCP */ + #endif /** * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated @@ -1559,10 +1628,22 @@ /** * LWIP_PBUF_CUSTOM_DATA: Store private data on pbufs (e.g. timestamps) * This extends struct pbuf so user can store custom data on every pbuf. + * e.g.: + * \#define LWIP_PBUF_CUSTOM_DATA u32_t myref; */ #if !defined LWIP_PBUF_CUSTOM_DATA || defined __DOXYGEN__ #define LWIP_PBUF_CUSTOM_DATA #endif + +/** + * LWIP_PBUF_CUSTOM_DATA_INIT: Initialize private data on pbufs. + * e.g. for the above example definition: + * \#define LWIP_PBUF_CUSTOM_DATA(p) (p)->myref = 0 + */ +#if !defined LWIP_PBUF_CUSTOM_DATA_INIT || defined __DOXYGEN__ +#define LWIP_PBUF_CUSTOM_DATA_INIT(p) +#endif + /** * @} */ @@ -1609,7 +1690,7 @@ #endif /** - * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function * for several netif related event that supports multiple subscribers. * @see netif_ext_status_callback */ @@ -1977,6 +2058,17 @@ #define LWIP_SOCKET_OFFSET 0 #endif +/** + * LWIP_SOCKET_EXTERNAL_HEADERS==1: Use external headers instead of sockets.h + * and inet.h. In this case, user must provide its own headers by setting the + * values for LWIP_SOCKET_EXTERNAL_HEADER_SOCKETS_H and + * LWIP_SOCKET_EXTERNAL_HEADER_INET_H to appropriate include file names and the + * whole content of the default sockets.h and inet.h is skipped. + */ +#if !defined LWIP_SOCKET_EXTERNAL_HEADERS || defined __DOXYGEN__ +#define LWIP_SOCKET_EXTERNAL_HEADERS 0 +#endif + /** * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set @@ -2176,7 +2268,7 @@ * MEM_STATS==1: Enable mem.c stats. */ #if !defined MEM_STATS || defined __DOXYGEN__ -#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#define MEM_STATS ((MEM_CUSTOM_ALLOCATOR == 0) && (MEM_USE_POOLS == 0)) #endif /** @@ -2394,7 +2486,7 @@ * All addresses that have a scope according to the default policy (link-local * unicast addresses, interface-local and link-local multicast addresses) should * now have a zone set on them before being passed to the core API, although - * lwIP will currently attempt to select a zone on the caller's behalf when + * lwIP will currently attempt to select a zone on the caller's behalf when * necessary. Applications that directly assign IPv6 addresses to interfaces * (which is NOT recommended) must now ensure that link-local addresses carry * the netif's zone. See the new ip6_zone.h header file for more information and @@ -2756,16 +2848,16 @@ * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), * or any other desired algorithm as a replacement. * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for - * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.
    * Signature:\code{.c} * u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); * \endcode - * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations
    * Arguments: * - local_ip: pointer to the local IP address of the connection * - local_port: local port number of the connection (host-byte order) * - remote_ip: pointer to the remote IP address of the connection - * - remote_port: remote port number of the connection (host-byte order)\n + * - remote_port: remote port number of the connection (host-byte order)
    * Return value: * - the 32-bit Initial Sequence Number to use for the new TCP connection. */ @@ -2791,7 +2883,7 @@ * the first 'opt1len' bytes and the rest starts at 'opt2'. opt2len can * be simply calculated: 'opt2len = optlen - opt1len;' * - p: input packet, p->payload points to application data (that's why tcp hdr - * and options are passed in seperately) + * and options are passed in separately) * Return value: * - ERR_OK: continue input of this packet as normal * - != ERR_OK: drop this packet for input (don't continue input processing) @@ -3024,18 +3116,18 @@ * LWIP_HOOK_VLAN_SET: * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data * on per-netif basis to implement this callback, see @ref netif_cd. - * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.
    * Signature:\code{.c} - * s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type); * \endcode * Arguments: * - netif: struct netif that the packet will be sent through * - p: struct pbuf packet to be sent * - src: source eth address * - dst: destination eth address - * - eth_type: ethernet type to packet to be sent\n - * - * + * - eth_type: ethernet type to packet to be sent
    + * + * * Return values: * - <0: Packet shall not contain VLAN header. * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. @@ -3471,6 +3563,13 @@ #define AUTOIP_DEBUG LWIP_DBG_OFF #endif +/** + * ACD_DEBUG: Enable debugging in acd.c. + */ +#if !defined ACD_DEBUG || defined __DOXYGEN__ +#define ACD_DEBUG LWIP_DBG_OFF +#endif + /** * DNS_DEBUG: Enable debugging for DNS. */ @@ -3523,38 +3622,4 @@ * @} */ -/** - * enable LWIP_LOWPOWER macro to use lowpower function - */ -#undef LWIP_LOWPOWER -#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM -#if defined (CONFIG_LWIP_LOWPOWER) -#define LWIP_LOWPOWER 1 -#else -#define LWIP_LOWPOWER 0 -#endif -#else -#define LWIP_LOWPOWER 0 -#endif - -#if LWIP_LOWPOWER - -/** - * LOWPOWER_DEBUG: Enable debugging in lowpower.c. - */ -#if !defined LOWPOWER_DEBUG || defined __DOXYGEN__ -#define LOWPOWER_DEBUG LWIP_DBG_OFF -#endif - -#ifndef MEMP_NUM_TCPIP_MSG_LOWPOWER -#define MEMP_NUM_TCPIP_MSG_LOWPOWER 10 -#endif - -#define LWIP_SNTP_TIMER 2 - -#define LOWPOWER_TCP_TIMER 1 - -#define MEMP_NUM_SYS_TIMEOUT_LOW (MEMP_NUM_SYS_TIMEOUT + LWIP_SNTP_TIMER + LOWPOWER_TCP_TIMER) -#endif /* LWIP_LOWPOWER */ - #endif /* LWIP_HDR_OPT_H */ diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index e5daf96..5a4fc88 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -55,7 +55,7 @@ extern "C" { #define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) #endif -/** @ingroup pbuf +/** @ingroup pbuf * PBUF_NEEDS_COPY(p): return a boolean value indicating whether the given * pbuf needs to be copied in order to be kept around beyond the current call * stack without risking being corrupted. The default setting provides safety: diff --git a/src/include/lwip/priv/altcp_priv.h b/src/include/lwip/priv/altcp_priv.h index d1de9b1..50e6b97 100644 --- a/src/include/lwip/priv/altcp_priv.h +++ b/src/include/lwip/priv/altcp_priv.h @@ -1,6 +1,6 @@ /** * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n + * Application layered TCP connection API (to be used from TCPIP thread)
    * This interface mimics the tcp callback API to the application while preventing * direct linking (much like virtual functions). * This way, an application can make use of other application layer protocols diff --git a/src/include/lwip/priv/api_msg.h b/src/include/lwip/priv/api_msg.h index 77e4fdb..9e8ffc9 100644 --- a/src/include/lwip/priv/api_msg.h +++ b/src/include/lwip/priv/api_msg.h @@ -187,11 +187,6 @@ struct dns_api_msg { }; #endif /* LWIP_DNS */ -#if LWIP_LOWPOWER -/* check wether need to poll tcp */ -u8_t poll_tcp_needed(void *arg, struct tcp_pcb *pcb); -#endif - #if LWIP_NETCONN_FULLDUPLEX int lwip_netconn_is_deallocated_msg(void *msg); #endif @@ -265,11 +260,6 @@ struct netifapi_msg { #endif /* LWIP_MPU_COMPATIBLE */ u8_t index; } ifs; -#if LWIP_LOWPOWER - struct { - enum lowpower_mod mod; - } lp; -#endif } msg; }; diff --git a/src/include/lwip/priv/memp_std.h b/src/include/lwip/priv/memp_std.h index 3c2f9e6..669ad4d 100644 --- a/src/include/lwip/priv/memp_std.h +++ b/src/include/lwip/priv/memp_std.h @@ -99,12 +99,7 @@ LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group) #endif /* LWIP_IGMP */ #if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM -#if LWIP_LOWPOWER -LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT_LOW, sizeof(struct timer_entry), "SYS_TIMEOUT") -LWIP_MEMPOOL(TCPIP_MSG_LOWPOWER, MEMP_NUM_TCPIP_MSG_LOWPOWER, sizeof(struct tcpip_msg), "TCPIP_MSG_NA") -#else LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") -#endif /* LWIP_LOWPOWER */ #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ #if LWIP_DNS && LWIP_SOCKET diff --git a/src/include/lwip/priv/nd6_priv.h b/src/include/lwip/priv/nd6_priv.h index cc3007d..75d5f02 100644 --- a/src/include/lwip/priv/nd6_priv.h +++ b/src/include/lwip/priv/nd6_priv.h @@ -94,6 +94,7 @@ struct nd6_destination_cache_entry { ip6_addr_t destination_addr; ip6_addr_t next_hop_addr; u16_t pmtu; + u8_t cached_neighbor_idx; u32_t age; }; diff --git a/src/include/lwip/priv/sockets_priv.h b/src/include/lwip/priv/sockets_priv.h index d8f9904..c604734 100644 --- a/src/include/lwip/priv/sockets_priv.h +++ b/src/include/lwip/priv/sockets_priv.h @@ -99,7 +99,7 @@ struct lwip_sock { /** Maximum optlen used by setsockopt/getsockopt */ #define LWIP_SETGETSOCKOPT_MAXOPTLEN LWIP_MAX(16, sizeof(struct ifreq)) -/** This struct is used to pass data to the set/getsockopt_internal +/** This struct is used to pass data to the set/getsockopt_impl * functions running in tcpip_thread context (only a void* is allowed) */ struct lwip_setgetsockopt_data { /** socket index for which to change options */ diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index 25e78d0..a8e87e5 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.h @@ -106,14 +106,11 @@ err_t tcp_process_refused_data(struct tcp_pcb *pcb); #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) -#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) -#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) -#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) -#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) +#define TCP_SEQ_LT(a,b) (((u32_t)((u32_t)(a) - (u32_t)(b)) & 0x80000000u) != 0) +#define TCP_SEQ_LEQ(a,b) (!(TCP_SEQ_LT(b,a))) +#define TCP_SEQ_GT(a,b) TCP_SEQ_LT(b,a) +#define TCP_SEQ_GEQ(a,b) TCP_SEQ_LEQ(b,a) /* is b<=a<=c? */ -#if 0 /* see bug #10548 */ -#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) -#endif #define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) #ifndef TCP_TMR_INTERVAL @@ -361,7 +358,7 @@ extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; for (tcp_tmp_pcb = *(pcbs); \ tcp_tmp_pcb != NULL; \ tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + LWIP_ASSERT("TCP_REG: already registered", tcp_tmp_pcb != (npcb)); \ } \ LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ (npcb)->next = *(pcbs); \ @@ -467,6 +464,9 @@ void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); void tcp_rst(const struct tcp_pcb* pcb, u32_t seqno, u32_t ackno, const ip_addr_t *local_ip, const ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port); +void tcp_rst_netif(struct netif *netif, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port); u32_t tcp_next_iss(struct tcp_pcb *pcb); @@ -478,13 +478,8 @@ void tcp_trigger_input_pcb_close(void); #if TCP_CALCULATE_EFF_SEND_MSS u16_t tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest); -#ifdef LOSCFG_NET_CONTAINER -#define tcp_eff_send_mss(sendmss, src, dest, group) \ - tcp_eff_send_mss_netif(sendmss, ip_route(src, dest, group), dest) -#else #define tcp_eff_send_mss(sendmss, src, dest) \ tcp_eff_send_mss_netif(sendmss, ip_route(src, dest), dest) -#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if LWIP_CALLBACK_API diff --git a/src/include/lwip/priv/tcpip_priv.h b/src/include/lwip/priv/tcpip_priv.h index 23c6d37..bfa88ff 100644 --- a/src/include/lwip/priv/tcpip_priv.h +++ b/src/include/lwip/priv/tcpip_priv.h @@ -124,9 +124,7 @@ enum tcpip_msg_type { #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ TCPIP_MSG_CALLBACK, TCPIP_MSG_CALLBACK_STATIC, -#if LWIP_LOWPOWER - TCPIP_MSG_NA, -#endif + TCPIP_MSG_CALLBACK_STATIC_WAIT }; struct tcpip_msg { @@ -142,6 +140,11 @@ struct tcpip_msg { struct tcpip_api_call_data *arg; sys_sem_t *sem; } api_call; + struct { + tcpip_callback_fn function; + void *ctx; + sys_sem_t *sem; + } cb_wait; #endif /* LWIP_TCPIP_CORE_LOCKING */ #if !LWIP_TCPIP_CORE_LOCKING_INPUT struct { @@ -161,12 +164,6 @@ struct tcpip_msg { void *arg; } tmo; #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ -#if LWIP_LOWPOWER - struct { - enum lowpower_msg_type type; - lowpower_sem_t wait_up; - } lowpower; -#endif } msg; }; diff --git a/src/include/lwip/prot/acd.h b/src/include/lwip/prot/acd.h new file mode 100644 index 0000000..860cae5 --- /dev/null +++ b/src/include/lwip/prot/acd.h @@ -0,0 +1,91 @@ +/** + * @file + * ACD protocol definitions + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * Copyright (c) 2018 Jasper Verschueren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Jasper Verschueren + * Author: Dominik Spies + */ + +#ifndef LWIP_HDR_PROT_ACD_H +#define LWIP_HDR_PROT_ACD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* RFC 5227 and RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (minimum interval between defensive ARPs) */ + +/* ACD states */ +typedef enum { + /* ACD is module is off */ + ACD_STATE_OFF, + /* Waiting before probing can be started */ + ACD_STATE_PROBE_WAIT, + /* Probing the ipaddr */ + ACD_STATE_PROBING, + /* Waiting before announcing the probed ipaddr */ + ACD_STATE_ANNOUNCE_WAIT, + /* Announcing the new ipaddr */ + ACD_STATE_ANNOUNCING, + /* Performing ongoing conflict detection with one defend within defend inferval */ + ACD_STATE_ONGOING, + /* Performing ongoing conflict detection but immediately back off and Release + * the address when a conflict occurs. This state is used for LL addresses + * that stay active even if the netif has a routable address selected. + * In such a case, we cannot defend our address */ + ACD_STATE_PASSIVE_ONGOING, + /* To many conflicts occurred, we need to wait before restarting the selection + * process */ + ACD_STATE_RATE_LIMIT +} acd_state_enum_t; + +typedef enum { + ACD_IP_OK, /* IP address is good, no conflicts found in checking state */ + ACD_RESTART_CLIENT, /* Conflict found -> the client should try again */ + ACD_DECLINE /* Decline the received IP address (rate limiting)*/ +} acd_callback_enum_t; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ACD_H */ diff --git a/src/include/lwip/prot/autoip.h b/src/include/lwip/prot/autoip.h index fd3af8a..adbb166 100644 --- a/src/include/lwip/prot/autoip.h +++ b/src/include/lwip/prot/autoip.h @@ -51,24 +51,11 @@ extern "C" { /* 169.254.254.255 */ #define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) -/* RFC 3927 Constants */ -#define PROBE_WAIT 1 /* second (initial random delay) */ -#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ -#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ -#define PROBE_NUM 3 /* (number of probe packets) */ -#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ -#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ -#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ -#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ -#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ -#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ - /* AutoIP client states */ typedef enum { - AUTOIP_STATE_OFF = 0, - AUTOIP_STATE_PROBING = 1, - AUTOIP_STATE_ANNOUNCING = 2, - AUTOIP_STATE_BOUND = 3 + AUTOIP_STATE_OFF, + AUTOIP_STATE_CHECKING, + AUTOIP_STATE_BOUND } autoip_state_enum_t; #ifdef __cplusplus diff --git a/src/include/lwip/prot/ethernet.h b/src/include/lwip/prot/ethernet.h index 309e574..d16b604 100644 --- a/src/include/lwip/prot/ethernet.h +++ b/src/include/lwip/prot/ethernet.h @@ -116,7 +116,9 @@ PACK_STRUCT_END #define LL_IP6_MULTICAST_ADDR_0 0x33 #define LL_IP6_MULTICAST_ADDR_1 0x33 -#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) +/* eth_addr_cmp is deprecated, use eth_addr_eq */ +#define eth_addr_cmp(addr1, addr2) eth_addr_eq((addr1), (addr2)) +#define eth_addr_eq(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) #ifdef __cplusplus } diff --git a/src/include/lwip/prot/icmp.h b/src/include/lwip/prot/icmp.h index 7d19385..1fe12d9 100644 --- a/src/include/lwip/prot/icmp.h +++ b/src/include/lwip/prot/icmp.h @@ -60,18 +60,13 @@ extern "C" { #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif -/** This is the standard ICMP header only that the u32_t data - * is split to two u16_t like ICMP echo needs it. - * This header is also used for other ICMP types that do not - * use the data part. - */ +/** The standard ICMP header (unspecified 32 bit data) */ PACK_STRUCT_BEGIN -struct icmp_echo_hdr { +struct icmp_hdr { PACK_STRUCT_FLD_8(u8_t type); PACK_STRUCT_FLD_8(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u16_t seqno); + PACK_STRUCT_FIELD(u32_t data); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES @@ -84,6 +79,25 @@ PACK_STRUCT_END #define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) #define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is split to two u16_t like ICMP echo needs it. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/prot/ieee.h b/src/include/lwip/prot/ieee.h index abbb9e3..cd4d2de 100644 --- a/src/include/lwip/prot/ieee.h +++ b/src/include/lwip/prot/ieee.h @@ -53,7 +53,7 @@ enum lwip_ieee_eth_type { /** Internet protocol v4 */ ETHTYPE_IP = 0x0800U, /** Address resolution protocol */ - ETHTYPE_ARP = 0x0806U, + ETHTYPE_ARP = 0x0806U, /** Wake on lan */ ETHTYPE_WOL = 0x0842U, /** RARP */ diff --git a/src/include/lwip/prot/ip4.h b/src/include/lwip/prot/ip4.h index eb18cf5..9347461 100644 --- a/src/include/lwip/prot/ip4.h +++ b/src/include/lwip/prot/ip4.h @@ -81,12 +81,10 @@ struct ip_hdr { PACK_STRUCT_FIELD(u16_t _id); /* fragment offset field */ PACK_STRUCT_FIELD(u16_t _offset); -#ifndef LWIP_SOCKET_STDINCLUDE #define IP_RF 0x8000U /* reserved fragment flag */ #define IP_DF 0x4000U /* don't fragment flag */ #define IP_MF 0x2000U /* more fragments flag */ #define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ -#endif /* LWIP_SOCKET_STDINCLUDE */ /* time to live */ PACK_STRUCT_FLD_8(u8_t _ttl); /* protocol*/ diff --git a/src/include/lwip/prot/nd6.h b/src/include/lwip/prot/nd6.h index c270d07..a92d34d 100644 --- a/src/include/lwip/prot/nd6.h +++ b/src/include/lwip/prot/nd6.h @@ -153,6 +153,7 @@ PACK_STRUCT_END /** Link-layer address option. */ #define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) #define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) +#define ND6_LLADDR_OPTION_MIN_LENGTH (2) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index 08fff99..f916ff6 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -1,6 +1,6 @@ /** * @file - * raw API (to be used from TCPIP thread)\n + * raw API (to be used from TCPIP thread)
    * See also @ref raw_raw */ @@ -101,10 +101,6 @@ struct raw_pcb { /* The following functions is the application layer interface to the RAW code. */ -#ifdef LOSCFG_NET_CONTAINER -void set_raw_pcb_net_group(struct raw_pcb *pcb, struct net_group *group); -struct net_group *get_net_group_from_raw_pcb(struct raw_pcb *pcb); -#endif struct raw_pcb * raw_new (u8_t proto); struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); void raw_remove (struct raw_pcb *pcb); diff --git a/src/include/lwip/sio.h b/src/include/lwip/sio.h index 7643e19..12d2a7e 100644 --- a/src/include/lwip/sio.h +++ b/src/include/lwip/sio.h @@ -123,7 +123,7 @@ u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); * * @note This function will block until all data can be sent. */ -u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); +u32_t sio_write(sio_fd_t fd, const u8_t *data, u32_t len); #endif #ifndef sio_read_abort diff --git a/src/include/lwip/snmp.h b/src/include/lwip/snmp.h index 8704d0b..2431589 100644 --- a/src/include/lwip/snmp.h +++ b/src/include/lwip/snmp.h @@ -1,6 +1,6 @@ /** * @file - * SNMP support API for implementing netifs and statitics for MIB2 + * SNMP support API for implementing netifs and statistics for MIB2 */ /* diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 7d089b7..b6f3d52 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -43,6 +43,10 @@ #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +#if LWIP_SOCKET_EXTERNAL_HEADERS +#include LWIP_SOCKET_EXTERNAL_HEADER_SOCKETS_H +#else /* LWIP_SOCKET_EXTERNAL_HEADERS */ + #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/err.h" @@ -54,7 +58,10 @@ #ifdef __cplusplus extern "C" { #endif -#ifndef LWIP_SOCKET_STDINCLUDE + +/* sockaddr and pals include length fields */ +#define LWIP_SOCKET_HAVE_SA_LEN 1 + /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED to prevent this code from redefining it. */ #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) @@ -124,11 +131,13 @@ struct iovec { }; #endif +typedef int msg_iovlen_t; + struct msghdr { void *msg_name; socklen_t msg_namelen; struct iovec *msg_iov; - int msg_iovlen; + msg_iovlen_t msg_iovlen; void *msg_control; socklen_t msg_controllen; int msg_flags; @@ -400,7 +409,7 @@ typedef struct ipv6_mreq { * we restrict parameters to at most 128 bytes. */ #if !defined(FIONREAD) || !defined(FIONBIO) -#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOCPARM_MASK 0x7fUL /* parameters must be < 128 bytes */ #define IOC_VOID 0x20000000UL /* no parameters */ #define IOC_OUT 0x40000000UL /* copy out parameters */ #define IOC_IN 0x80000000UL /* copy in parameters */ @@ -524,7 +533,17 @@ struct timeval { long tv_usec; /* and microseconds */ }; #endif /* LWIP_TIMEVAL_PRIVATE */ -#endif /* LWIP_SOCKET_STDINCLUDE */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET_EXTERNAL_HEADERS */ + +#ifdef __cplusplus +extern "C" { +#endif + #define lwip_socket_init() /* Compatibility define, no init needed. */ void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ @@ -608,25 +627,6 @@ int lwip_fcntl(int s, int cmd, int val); const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); int lwip_inet_pton(int af, const char *src, void *dst); -#if LWIP_ENABLE_DISTRIBUTED_NET - -int lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen); - -int lwip_close_internal(int s); - -#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL -ssize_t lwip_sendto_internal(int s, const void *data, size_t size, int flags, const struct sockaddr *to, - socklen_t tolen); - -#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG -ssize_t lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags); -#endif - -ssize_t lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); -#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ - -#endif - #if LWIP_COMPAT_SOCKETS #if LWIP_COMPAT_SOCKETS != 2 /** @ingroup socket */ diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h index b570dba..8c94320 100644 --- a/src/include/lwip/stats.h +++ b/src/include/lwip/stats.h @@ -122,7 +122,7 @@ struct stats_sys { /** SNMP MIB2 stats */ struct stats_mib2 { - /* IP */ + /* IPv4 */ u32_t ipinhdrerrors; u32_t ipinaddrerrors; u32_t ipinunknownprotos; @@ -140,6 +140,9 @@ struct stats_mib2 { u32_t ipforwdatagrams; u32_t ipinreceives; + /* IPv6 */ + u32_t ip6reasmoks; + /* TCP */ u32_t tcpactiveopens; u32_t tcppassiveopens; diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h index 168e465..4bfdb13 100644 --- a/src/include/lwip/sys.h +++ b/src/include/lwip/sys.h @@ -130,7 +130,7 @@ typedef void (*lwip_thread_fn)(void *arg); * If the mutex has been created, ERR_OK should be returned. Returning any * other error will provide a hint what went wrong, but except for assertions, * no real error handling is implemented. - * + * * @param mutex pointer to the mutex to create * @return ERR_OK if successful, another err_t otherwise */ @@ -205,13 +205,13 @@ void sys_sem_signal(sys_sem_t *sem); * "timeout" argument is non-zero, the thread should only be blocked for the * specified time (measured in milliseconds). If the "timeout" argument is zero, * the thread should be blocked until the semaphore is signalled. - * + * * The return value is SYS_ARCH_TIMEOUT if the semaphore wasn't signaled within * the specified time or any other value if it was signaled (with or without * waiting). * Notice that lwIP implements a function with a similar name, * sys_sem_wait(), that uses the sys_arch_sem_wait() function. - * + * * @param sem the semaphore to wait for * @param timeout timeout in milliseconds to wait (0 = wait forever) * @return SYS_ARCH_TIMEOUT on timeout, any other value on success @@ -277,7 +277,7 @@ void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ * If the mailbox has been created, ERR_OK should be returned. Returning any * other error will provide a hint what went wrong, but except for assertions, * no real error handling is implemented. - * + * * @param mbox pointer to the mbox to create * @param size (minimum) number of messages in this mbox * @return ERR_OK if successful, another err_t otherwise @@ -287,7 +287,7 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int size); * @ingroup sys_mbox * Post a message to an mbox - may not fail * -> blocks if full, only to be used from tasks NOT from ISR! - * + * * @param mbox mbox to posts the message * @param msg message to post (ATTENTION: can be NULL) */ @@ -297,7 +297,7 @@ void sys_mbox_post(sys_mbox_t *mbox, void *msg); * Try to post a message to an mbox - may fail if full. * Can be used from ISR (if the sys arch layer allows this). * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. - * + * * @param mbox mbox to posts the message * @param msg message to post (ATTENTION: can be NULL) */ @@ -307,7 +307,7 @@ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); * Try to post a message to an mbox - may fail if full. * To be be used from ISR. * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. - * + * * @param mbox mbox to posts the message * @param msg message to post (ATTENTION: can be NULL) */ @@ -324,10 +324,10 @@ err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg); * The return values are the same as for the sys_arch_sem_wait() function: * SYS_ARCH_TIMEOUT if there was a timeout, any other value if a messages * is received. - * + * * Note that a function with a similar name, sys_mbox_fetch(), is - * implemented by lwIP. - * + * implemented by lwIP. + * * @param mbox mbox to get a message from * @param msg pointer where the message is stored * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) @@ -346,7 +346,7 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); * example, a naive implementation could be: * \#define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1) * although this would introduce unnecessary delays. - * + * * @param mbox mbox to get a message from * @param msg pointer where the message is stored * @return 0 (milliseconds) if a message has been received @@ -363,7 +363,7 @@ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); * Deallocates a mailbox. If there are messages still present in the * mailbox when the mailbox is deallocated, it is an indication of a * programming error in lwIP and the developer should be notified. - * + * * @param mbox mbox to delete */ void sys_mbox_free(sys_mbox_t *mbox); @@ -411,7 +411,7 @@ void sys_mbox_set_invalid(sys_mbox_t *mbox); * the "stacksize" parameter. The id of the new thread is returned. Both the id * and the priority are system dependent. * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) - * + * * @param name human-readable name for the thread (used for debugging purposes) * @param thread thread-function * @param arg parameter passed to 'thread' @@ -421,6 +421,16 @@ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, #endif /* NO_SYS */ +/** + * @ingroup lwip_opts_lock + * Called as first thing in the lwIP TCPIP thread. Can be used in conjunction + * with @ref LWIP_ASSERT_CORE_LOCKED to check core locking. + * @see @ref multithreading + */ +#if !defined LWIP_MARK_TCPIP_THREAD || defined __DOXYGEN__ +#define LWIP_MARK_TCPIP_THREAD() +#endif + /** * @ingroup sys_misc * sys_init() must be called before anything else. @@ -435,6 +445,11 @@ void sys_init(void); u32_t sys_jiffies(void); #endif +#ifdef LWIP_FUZZ_SYS_NOW +/* This offset should be added to the time 'sys_now()' returns */ +extern u32_t sys_now_offset; +#endif + /** * @ingroup sys_time * Returns the current time in milliseconds, diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 6138548..3991fd6 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -1,6 +1,6 @@ /** * @file - * TCP API (to be used from TCPIP thread)\n + * TCP API (to be used from TCPIP thread)
    * See also @ref tcp_raw */ @@ -408,10 +408,6 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, #endif /* LWIP_EVENT_API */ /* Application program's interface: */ -#ifdef LOSCFG_NET_CONTAINER -void set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group); -struct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb); -#endif struct tcp_pcb * tcp_new (void); struct tcp_pcb * tcp_new_ip_type (u8_t type); @@ -424,11 +420,6 @@ void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); #endif /* LWIP_CALLBACK_API */ void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); -#if LWIP_LOWPOWER -u32_t tcp_fast_tmr_tick(void); -u32_t tcp_slow_tmr_tick(void); -#endif - #define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0) #define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0) #define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) @@ -495,9 +486,9 @@ err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_add #if LWIP_TCP_PCB_NUM_EXT_ARGS u8_t tcp_ext_arg_alloc_id(void); -void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks); -void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg); -void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id); +void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, u8_t id, const struct tcp_ext_arg_callbacks * const callbacks); +void tcp_ext_arg_set(struct tcp_pcb *pcb, u8_t id, void *arg); +void *tcp_ext_arg_get(const struct tcp_pcb *pcb, u8_t id); #endif #ifdef __cplusplus diff --git a/src/include/lwip/tcpbase.h b/src/include/lwip/tcpbase.h index 0023074..018790f 100644 --- a/src/include/lwip/tcpbase.h +++ b/src/include/lwip/tcpbase.h @@ -1,6 +1,6 @@ /** * @file - * Base TCP API definitions shared by TCP and ALTCP\n + * Base TCP API definitions shared by TCP and ALTCP
    * See also @ref tcp_raw */ diff --git a/src/include/lwip/tcpip.h b/src/include/lwip/tcpip.h index c17693d..30ce4fe 100644 --- a/src/include/lwip/tcpip.h +++ b/src/include/lwip/tcpip.h @@ -81,6 +81,7 @@ err_t tcpip_input(struct pbuf *p, struct netif *inp); err_t tcpip_try_callback(tcpip_callback_fn function, void *ctx); err_t tcpip_callback(tcpip_callback_fn function, void *ctx); +err_t tcpip_callback_wait(tcpip_callback_fn function, void *ctx); /** @ingroup lwip_os * @deprecated use tcpip_try_callback() or tcpip_callback() instead */ @@ -104,10 +105,6 @@ err_t tcpip_untimeout(sys_timeout_handler h, void *arg); int tcpip_thread_poll_one(void); #endif -#if LWIP_LOWPOWER -void tcpip_send_msg_na(enum lowpower_msg_type type); -#endif - #ifdef __cplusplus } #endif diff --git a/src/include/lwip/timeouts.h b/src/include/lwip/timeouts.h index 10a34f3..b601f9e 100644 --- a/src/include/lwip/timeouts.h +++ b/src/include/lwip/timeouts.h @@ -43,15 +43,11 @@ #if !NO_SYS #include "lwip/sys.h" #endif -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -#endif #ifdef __cplusplus extern "C" { #endif -#if !LWIP_LOWPOWER #ifndef LWIP_DEBUG_TIMERNAMES #ifdef LWIP_DEBUG #define LWIP_DEBUG_TIMERNAMES SYS_DEBUG @@ -124,7 +120,7 @@ void lwip_cyclic_timer(void *arg); #endif #endif /* LWIP_TIMERS */ -#endif /* !LWIP_LOWPOWER */ + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 25a1066..f1deae3 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -1,6 +1,6 @@ /** * @file - * UDP API (to be used from TCPIP thread)\n + * UDP API (to be used from TCPIP thread)
    * See also @ref udp_raw */ @@ -116,10 +116,6 @@ extern struct udp_pcb *udp_pcbs; /* The following functions is the application layer interface to the UDP code. */ -#ifdef LOSCFG_NET_CONTAINER -void set_udp_pcb_net_group(struct udp_pcb *pcb, struct net_group *group); -struct net_group *get_net_group_from_udp_pcb(struct udp_pcb *pcb); -#endif struct udp_pcb * udp_new (void); struct udp_pcb * udp_new_ip_type(u8_t type); void udp_remove (struct udp_pcb *pcb); diff --git a/src/include/netif/lowpan6.h b/src/include/netif/lowpan6.h index 06a2c95..ecff24b 100644 --- a/src/include/netif/lowpan6.h +++ b/src/include/netif/lowpan6.h @@ -60,9 +60,6 @@ extern "C" { #define LOWPAN6_TMR_INTERVAL 1000 void lowpan6_tmr(void); -#if LWIP_LOWPOWER -u32_t lowpan6_tmr_tick(void); -#endif err_t lowpan6_set_context(u8_t idx, const ip6_addr_t * context); err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); diff --git a/src/include/netif/lowpan6_ble.h b/src/include/netif/lowpan6_ble.h index 01896a7..ff35fcd 100644 --- a/src/include/netif/lowpan6_ble.h +++ b/src/include/netif/lowpan6_ble.h @@ -6,7 +6,7 @@ /* * Copyright (c) 2017 Benjamin Aigner * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer - * + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,10 +32,10 @@ * OF SUCH DAMAGE. * * Author: Benjamin Aigner - * + * * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c) */ - + #ifndef LWIP_HDR_LOWPAN6_BLE_H #define LWIP_HDR_LOWPAN6_BLE_H @@ -66,8 +66,8 @@ err_t rfc7668_if_init(struct netif *netif); err_t tcpip_rfc7668_input(struct pbuf *p, struct netif *inp); #endif -void ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr); -void eui64_to_ble_addr(uint8_t *dst, const uint8_t *src); +void ble_addr_to_eui64(u8_t *dst, const u8_t *src, int public_addr); +void eui64_to_ble_addr(u8_t *dst, const u8_t *src); #ifdef __cplusplus } diff --git a/src/include/netif/lowpan6_opts.h b/src/include/netif/lowpan6_opts.h index 17d46cd..32e5c5e 100644 --- a/src/include/netif/lowpan6_opts.h +++ b/src/include/netif/lowpan6_opts.h @@ -109,7 +109,7 @@ #define LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG LWIP_DBG_OFF #endif -/** LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS: +/** LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS: * Currently, the linux kernel driver for 6lowpan sets/clears a bit in * the address, depending on the BD address (either public or not). * Might not be RFC7668 conform, so you may select to do that (=1) or diff --git a/src/include/netif/ppp/eap.h b/src/include/netif/ppp/eap.h index 3ee9aaf..32434ed 100644 --- a/src/include/netif/ppp/eap.h +++ b/src/include/netif/ppp/eap.h @@ -13,7 +13,7 @@ * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Original version by James Carlson * diff --git a/src/include/netif/ppp/magic.h b/src/include/netif/ppp/magic.h index a165e18..12a002c 100644 --- a/src/include/netif/ppp/magic.h +++ b/src/include/netif/ppp/magic.h @@ -94,7 +94,7 @@ extern "C" { void magic_init(void); /* - * Randomize our random seed value. To be called for truely random events + * Randomize our random seed value. To be called for truly random events * such as user operations and network traffic. */ void magic_randomize(void); diff --git a/src/include/netif/ppp/ppp.h b/src/include/netif/ppp/ppp.h index 3d73c36..f93747f 100644 --- a/src/include/netif/ppp/ppp.h +++ b/src/include/netif/ppp/ppp.h @@ -266,9 +266,9 @@ typedef struct ppp_settings_s { #endif /* PAP_SUPPPORT */ #if CHAP_SUPPORT +#if PPP_SERVER u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ u8_t chap_max_transmits; /* max # times to send challenge */ -#if PPP_SERVER u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ #endif /* PPP_SERVER */ #endif /* CHAP_SUPPPORT */ diff --git a/src/include/netif/ppp/ppp_impl.h b/src/include/netif/ppp/ppp_impl.h index 40843d5..2282831 100644 --- a/src/include/netif/ppp/ppp_impl.h +++ b/src/include/netif/ppp/ppp_impl.h @@ -60,16 +60,10 @@ extern "C" { /* * Memory used for control packets. * - * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we + * PPP_CTRL_PBUF_UNKNOWN_SIZE is the amount of memory we allocate when we * cannot figure out how much we are going to use before filling the buffer. */ -#if PPP_USE_PBUF_RAM -#define PPP_CTRL_PBUF_TYPE PBUF_RAM -#define PPP_CTRL_PBUF_MAX_SIZE 512 -#else /* PPP_USE_PBUF_RAM */ -#define PPP_CTRL_PBUF_TYPE PBUF_POOL -#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE -#endif /* PPP_USE_PBUF_RAM */ +#define PPP_CTRL_PBUF_UNKNOWN_SIZE 512 /* * The basic PPP frame. @@ -87,10 +81,18 @@ extern "C" { #define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ #define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ +/* + * PPP_DEFMRU: MRU value used prior negotiation and unless negotiated later. + * Must be 1500. + */ +#define PPP_DEFMRU 1500 + /* * Protocol field values. */ +#if PPP_IPV4_SUPPORT #define PPP_IP 0x21 /* Internet Protocol */ +#endif /* PPP_IPV4_SUPPORT */ #if 0 /* UNUSED */ #define PPP_AT 0x29 /* AppleTalk Protocol */ #define PPP_IPX 0x2b /* IPX protocol */ @@ -265,7 +267,7 @@ extern int maxoctets_timeout; /* Timeout for check of octets limit */ #define PPP_OCTETS_DIRECTION_IN 1 #define PPP_OCTETS_DIRECTION_OUT 2 #define PPP_OCTETS_DIRECTION_MAXOVERAL 3 -/* same as previos, but little different on RADIUS side */ +/* same as previous, but little different on RADIUS side */ #define PPP_OCTETS_DIRECTION_MAXSESSION 4 #endif @@ -456,8 +458,8 @@ int sif6down (ppp_pcb *pcb); int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); #endif /* DEMAND_SUPPORt */ -void netif_set_mtu(ppp_pcb *pcb, int mtu); -int netif_get_mtu(ppp_pcb *pcb); +void ppp_netif_set_mtu(ppp_pcb *pcb, int mtu); +int ppp_netif_get_mtu(ppp_pcb *pcb); #if CCP_SUPPORT #if 0 /* unused */ @@ -539,7 +541,7 @@ void update_link_stats(int u); /* Get stats at link termination */ #define BZERO(s, n) memset(s, 0, n) #define BCMP(s1, s2, l) memcmp(s1, s2, l) -#define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } +#define PRINTMSG(m, l) { ppp_info(("Remote message: %0.*v", l, m)); } /* * MAKEHEADER - Add Header fields to a packet. @@ -559,7 +561,7 @@ void start_networks(ppp_pcb *pcb); /* start all the network control protos */ void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ #if PPP_AUTH_SUPPORT #if PPP_SERVER -int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen); +int auth_check_passwd(ppp_pcb *pcb, char *auser, unsigned int userlen, char *apasswd, unsigned int passwdlen, const char **msg, int *msglen); /* check the user name and passwd against configuration */ void auth_peer_fail(ppp_pcb *pcb, int protocol); /* peer failed to authenticate itself */ @@ -614,12 +616,19 @@ int ppp_slprintf(char *buf, int buflen, const char *fmt, ...); /* spr int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args); /* vsprintf++ */ size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ -void ppp_dbglog(const char *fmt, ...); /* log a debug message */ -void ppp_info(const char *fmt, ...); /* log an informational message */ -void ppp_notice(const char *fmt, ...); /* log a notice-level message */ -void ppp_warn(const char *fmt, ...); /* log a warning message */ -void ppp_error(const char *fmt, ...); /* log an error message */ -void ppp_fatal(const char *fmt, ...); /* log an error message and die(1) */ +void ppp_dbglog_impl(const char *fmt, ...); /* log a debug message */ +void ppp_info_impl(const char *fmt, ...); /* log an informational message */ +void ppp_notice_impl(const char *fmt, ...); /* log a notice-level message */ +void ppp_warn_impl(const char *fmt, ...); /* log a warning message */ +void ppp_error_impl(const char *fmt, ...); /* log an error message */ +void ppp_fatal_impl(const char *fmt, ...); /* log an error message and die(1) */ +/* wrap all the above functions so they will only be linked when enabled */ +#define ppp_dbglog(x) do { if (LWIP_DEBUG_ENABLED(LOG_DEBUG)) { ppp_dbglog_impl x; }} while(0) +#define ppp_info(x) do { if (LWIP_DEBUG_ENABLED(LOG_INFO)) { ppp_info_impl x; }} while(0) +#define ppp_notice(x) do { if (LWIP_DEBUG_ENABLED(LOG_NOTICE)) { ppp_notice_impl x; }} while(0) +#define ppp_warn(x) do { if (LWIP_DEBUG_ENABLED(LOG_WARNING)) { ppp_warn_impl x; }} while(0) +#define ppp_error(x) do { if (LWIP_DEBUG_ENABLED(LOG_ERR)) { ppp_error_impl x; }} while(0) +#define ppp_fatal(x) do { if (LWIP_DEBUG_ENABLED(LOG_CRITICAL)) { ppp_fatal_impl x; }} while(0) #if PRINTPKT_SUPPORT void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); /* dump packet to debug log if interesting */ @@ -665,11 +674,10 @@ void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); * |. . . * | . . * PPP_PHASE_AUTHENTICATE - * | . . * || . . * PPP_PHASE_NETWORK - * | || . . - * | ||| . + * |||| . . + * || ||| . * PPP_PHASE_RUNNING * | .||||| * | . |||| @@ -685,33 +693,39 @@ void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); * 1 * * If authentication is enabled one timer is necessary during authentication. + * This timer might still be running up to network phase for any necessary + * rechallenge, mostly for PPP server support. * 1 + PPP_AUTH_SUPPORT * * If ECP is enabled one timer is necessary before IPCP and/or IP6CP, one more * is necessary if CCP is enabled (only with MPPE support but we don't care much * up to this detail level). - * 1 + ECP_SUPPORT + CCP_SUPPORT + * 1 + PPP_AUTH_SUPPORT + ECP_SUPPORT + CCP_SUPPORT * * If CCP is enabled it might consume a timer during IPCP or IP6CP, thus - * we might use IPCP, IP6CP and CCP timers simultaneously. - * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT + * we might use AUTH, IPCP, IP6CP and CCP timers simultaneously. + * 1 + PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT * * When entering running phase, IPCP or IP6CP is still running. If idle time limit * is enabled one more timer is necessary. Same for max connect time and max * octets features. Furthermore CCP RACK might be used past this point. * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT * - * IPv4 or IPv6 must be enabled, therefore we don't need to take care the authentication - * and the CCP + ECP case, thus reducing overall complexity. - * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT) + * Then the maximum number of simultaneously running timers is given by: + * 1 + MAX(PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, + * PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT) * - * We don't support PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features - * and adding those defines to ppp_opts.h just for having the value always - * defined to 0 isn't worth it. - * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT) + * We don't support ECP_SUPPORT + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features + * and adding those defines to ppp_opts.h just for having the value always defined to 0 + * is not worth it, thus reducing the overall complexity. + * 1 + MAX(PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, + * PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT) * - * Thus, the following is enough for now. - * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT + * PPP_AUTH_SUPPORT is not available in ppp_opts.h because it is defined later in ppp.h, + * but we do not need to be that picky about the real number of simultaneously running + * timers so we just set the base number of timeouts to 2, thus the following is enough + * for now. + * 2 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT */ #ifdef __cplusplus diff --git a/src/include/netif/ppp/ppp_opts.h b/src/include/netif/ppp/ppp_opts.h index 479a006..be22c4c 100644 --- a/src/include/netif/ppp/ppp_opts.h +++ b/src/include/netif/ppp/ppp_opts.h @@ -95,7 +95,7 @@ * timers analysis. */ #ifndef PPP_NUM_TIMEOUTS_PER_PCB -#define PPP_NUM_TIMEOUTS_PER_PCB (1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT) +#define PPP_NUM_TIMEOUTS_PER_PCB (2 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT) #endif /* The number of sys_timeouts required for the PPP module */ @@ -184,20 +184,6 @@ #define PPP_NOTIFY_PHASE 0 #endif -/** - * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets. - * - * Memory allocated must be single buffered for PPP to works, it requires pbuf - * that are not going to be chained when allocated. This requires setting - * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. - * - * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous - * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. - */ -#ifndef PPP_USE_PBUF_RAM -#define PPP_USE_PBUF_RAM 0 -#endif - /** * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS */ @@ -311,9 +297,11 @@ /** * VJ_SUPPORT==1: Support VJ header compression. + * + * BEWARE: It is known to be broken when built with some compiler optimizations enabled. */ #ifndef VJ_SUPPORT -#define VJ_SUPPORT 1 +#define VJ_SUPPORT 0 #endif /* VJ compression is only supported for TCP over IPv4 over PPPoS. */ #if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP @@ -507,28 +495,33 @@ */ /** - * PPP_MRU: Default MRU + * PPP_MRU: MRU value we want to negotiate (peer MTU) + * + * It only affects PPPoS because PPPoE value is derived from the + * Ethernet interface MTU and PPPoL2TP have a separate setting. */ #ifndef PPP_MRU #define PPP_MRU 1500 #endif /** - * PPP_DEFMRU: Default MRU to try - */ -#ifndef PPP_DEFMRU -#define PPP_DEFMRU 1500 -#endif - -/** - * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384) + * PPP_MAXMRU: Normally limit peer MRU to this + * + * This is the upper limit value to which we set our interface MTU. + * If the peer sends a larger number, we will just ignore it as we + * are not required to maximize the use of the peer capacity. + * + * It only affects PPPoS because PPPoE value is derived from the + * Ethernet interface MTU and PPPoL2TP have a separate setting. */ #ifndef PPP_MAXMRU #define PPP_MAXMRU 1500 #endif /** - * PPP_MINMRU: No MRUs below this + * PPP_MINMRU: No peer MRUs below this + * + * Peer must be able to receive at least our minimum MTU. */ #ifndef PPP_MINMRU #define PPP_MINMRU 128 diff --git a/src/include/netif/ppp/pppoe.h b/src/include/netif/ppp/pppoe.h index 8994d38..b5f7ed1 100644 --- a/src/include/netif/ppp/pppoe.h +++ b/src/include/netif/ppp/pppoe.h @@ -128,7 +128,7 @@ PACK_STRUCT_END #define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ #define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ #define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ -#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* generic error */ #define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ #define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ diff --git a/src/include/netif/ppp/pppos.h b/src/include/netif/ppp/pppos.h index 380a965..f587498 100644 --- a/src/include/netif/ppp/pppos.h +++ b/src/include/netif/ppp/pppos.h @@ -50,7 +50,6 @@ extern "C" { * completed. */ enum { PDIDLE = 0, /* Idle state - waiting. */ - PDSTART, /* Process start flag. */ PDADDRESS, /* Process address field. */ PDCONTROL, /* Process control field. */ PDPROTOCOL1, /* Process protocol field 1. */ @@ -59,7 +58,7 @@ enum { }; /* PPPoS serial output callback function prototype */ -typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx); +typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, const void *data, u32_t len, void *ctx); /* * Extended asyncmap - allows any character to be escaped. @@ -103,11 +102,11 @@ ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, #if !NO_SYS && !PPP_INPROC_IRQ_SAFE /* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */ -err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l); +err_t pppos_input_tcpip(ppp_pcb *ppp, const void *s, int l); #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ /* PPP over Serial: this is the input function to be called for received data. */ -void pppos_input(ppp_pcb *ppp, u8_t* data, int len); +void pppos_input(ppp_pcb *ppp, const void* data, int len); /* diff --git a/src/include/netif/ppp/vj.h b/src/include/netif/ppp/vj.h index 77d9976..a9ba786 100644 --- a/src/include/netif/ppp/vj.h +++ b/src/include/netif/ppp/vj.h @@ -16,7 +16,7 @@ * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. @@ -53,7 +53,7 @@ extern "C" { * * There are 5 numbers which can change (they are always inserted * in the following order): TCP urgent pointer, window, - * acknowlegement, sequence number and IP ID. (The urgent pointer + * acknowledgement, sequence number and IP ID. (The urgent pointer * is different from the others in that its value is sent, not the * change in value.) Since typical use of SLIP links is biased * toward small packets (see comments on MTU/MSS below), changes diff --git a/src/include/netif/slipif.h b/src/include/netif/slipif.h index 65ba31f..46d2010 100644 --- a/src/include/netif/slipif.h +++ b/src/include/netif/slipif.h @@ -84,4 +84,3 @@ void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); #endif #endif /* LWIP_HDR_NETIF_SLIPIF_H */ - diff --git a/src/netif/bridgeif.c b/src/netif/bridgeif.c index 8a97bce..2dc88fc 100644 --- a/src/netif/bridgeif.c +++ b/src/netif/bridgeif.c @@ -120,7 +120,7 @@ typedef struct bridgeif_private_s { } bridgeif_private_t; /* netif data index to get the bridge on input */ -u8_t bridgeif_netif_client_id = 0xff; +static u8_t bridgeif_netif_client_id = 0xff; /** * @ingroup bridgeif @@ -421,7 +421,7 @@ bridgeif_init(struct netif *netif) LWIP_ASSERT("bridgeif needs an input callback", (netif->input != NULL)); #if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT if (netif->input == tcpip_input) { - LWIP_DEBUGF(BRIDGEIF_DEBUG | LWIP_DBG_ON, ("bridgeif does not need tcpip_input, use netif_input/ethernet_input instead")); + LWIP_DEBUGF(BRIDGEIF_DEBUG | LWIP_DBG_ON, ("bridgeif does not need tcpip_input, use netif_input/ethernet_input instead\n")); } #endif diff --git a/src/netif/bridgeif_fdb.c b/src/netif/bridgeif_fdb.c index 6739fc2..2f052ec 100644 --- a/src/netif/bridgeif_fdb.c +++ b/src/netif/bridgeif_fdb.c @@ -69,7 +69,7 @@ typedef struct bridgeif_dfdb_s { * remembers known src mac addresses to know which port to send frames destined for that * mac address. * - * ATTENTION: This is meant as an example only, in real-world use, you should + * ATTENTION: This is meant as an example only, in real-world use, you should * provide a better implementation :-) */ void @@ -120,9 +120,9 @@ bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx) /* not found, no free entry -> flood */ } -/** +/** * @ingroup bridgeif_fdb - * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown + * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown */ bridgeif_portmask_t bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr) diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c index dd171e2..db5c514 100644 --- a/src/netif/ethernet.c +++ b/src/netif/ethernet.c @@ -67,7 +67,7 @@ const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}}; * @ingroup lwip_nosys * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, - * the ARP cache is protected from concurrent access.\n + * the ARP cache is protected from concurrent access.
    * Don't call directly, pass to netif_add() and call netif->input(). * * @param p the received packet, p->payload pointing to the ethernet header @@ -96,10 +96,6 @@ ethernet_input(struct pbuf *p, struct netif *netif) goto free_and_return; } - if (p->if_idx == NETIF_NO_INDEX) { - p->if_idx = netif_get_index(netif); - } - /* points to packet payload, which starts with an Ethernet header */ ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, @@ -143,6 +139,10 @@ ethernet_input(struct pbuf *p, struct netif *netif) netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ + if (p->if_idx == NETIF_NO_INDEX) { + p->if_idx = netif_get_index(netif); + } + if (ethhdr->dest.addr[0] & 1) { /* this might be a multicast or broadcast packet */ if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { @@ -179,7 +179,7 @@ ethernet_input(struct pbuf *p, struct netif *netif) LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n", p->tot_len, next_hdr_offset)); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet\n")); goto free_and_return; } else { /* pass to IP layer */ @@ -196,7 +196,7 @@ ethernet_input(struct pbuf *p, struct netif *netif) LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n", p->tot_len, next_hdr_offset)); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet\n")); ETHARP_STATS_INC(etharp.lenerr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; @@ -273,8 +273,16 @@ ethernet_output(struct netif * netif, struct pbuf * p, struct eth_hdr *ethhdr; u16_t eth_type_be = lwip_htons(eth_type); -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); +#if ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) + s32_t vlan_prio_vid; +#ifdef LWIP_HOOK_VLAN_SET + vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); +#elif LWIP_VLAN_PCP + vlan_prio_vid = -1; + if (netif->hints && (netif->hints->tci >= 0)) { + vlan_prio_vid = (u16_t)netif->hints->tci; + } +#endif if (vlan_prio_vid >= 0) { struct eth_vlan_hdr *vlanhdr; @@ -289,7 +297,7 @@ ethernet_output(struct netif * netif, struct pbuf * p, eth_type_be = PP_HTONS(ETHTYPE_VLAN); } else -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ +#endif /* ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) */ { if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) { goto pbuf_header_failed; diff --git a/src/netif/lowpan6.c b/src/netif/lowpan6.c index 428aac2..8eb751c 100644 --- a/src/netif/lowpan6.c +++ b/src/netif/lowpan6.c @@ -63,9 +63,6 @@ #include "lwip/snmp.h" #include "netif/ieee802154.h" -#if LWIP_LOWPOWER -#include "lwip/lowpower.h" -#endif #include #if LWIP_6LOWPAN_802154_HW_CRC @@ -121,28 +118,6 @@ static const struct lowpan6_link_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; static struct lowpan6_link_addr short_mac_addr = {2, {0, 0}}; #endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ -#if LWIP_LOWPOWER -u32_t -lowpan6_tmr_tick() -{ - struct lowpan6_reass_helper *lrh = NULL; - struct lowpan6_reass_helper *lrh_temp = NULL; - u32_t tick = 0; - - lrh = lowpan6_data.reass_list; - while (lrh != NULL) { - lrh_temp = lrh->next_packet; - if (lrh->timer > 0) { - SET_TMR_TICK(tick, lrh->timer); - } - lrh = lrh_temp; - } - - LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "lowpan6_tmr_tick", tick)); - return tick; -} -#endif /* LWIP_LOWPOWER */ - /* IEEE 802.15.4 specific functions: */ /** Write the IEEE 802.15.4 header that encapsulates the 6LoWPAN frame. @@ -408,6 +383,7 @@ lowpan6_frag(struct netif *netif, struct pbuf *p, const struct lowpan6_link_addr #else /* LWIP_6LOWPAN_IPHC */ /* Send uncompressed IPv6 header with appropriate dispatch byte. */ lowpan6_header_len = 1; + hidden_header_len = 0; buffer[ieee_header_len] = 0x41; /* IPv6 dispatch */ #endif /* LWIP_6LOWPAN_IPHC */ @@ -629,12 +605,12 @@ lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) #if LWIP_6LOWPAN_INFER_SHORT_ADDRESS if (src.addr_len == 2) { - /* If source address was compressable to short_mac_addr, and dest has same subnet and - * is also compressable to 2-bytes, assume we can infer dest as a short address too. */ + /* If source address was compressible to short_mac_addr, and dest has same subnet and + * is also compressible to 2-bytes, assume we can infer dest as a short address too. */ dest.addr_len = 2; dest.addr[0] = ((u8_t *)q->payload)[38]; dest.addr[1] = ((u8_t *)q->payload)[39]; - if ((src.addr_len == 2) && (ip6_addr_netcmp_zoneless(&ip6_hdr->src, &ip6_hdr->dest)) && + if ((src.addr_len == 2) && (ip6_addr_net_zoneless_eq(&ip6_hdr->src, &ip6_hdr->dest)) && (lowpan6_get_address_mode(ip6addr, &dest) == 3)) { MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); return lowpan6_frag(netif, q, &src, &dest); @@ -704,7 +680,7 @@ lowpan6_input(struct pbuf *p, struct netif *netif) /* check for duplicate */ lrh = lowpan6_data.reass_list; while (lrh != NULL) { - uint8_t discard = 0; + u8_t discard = 0; lrh_next = lrh->next_packet; if ((lrh->sender_addr.addr_len == src.addr_len) && (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0)) { diff --git a/src/netif/lowpan6_ble.c b/src/netif/lowpan6_ble.c index 6de0ae3..cca8bb1 100644 --- a/src/netif/lowpan6_ble.c +++ b/src/netif/lowpan6_ble.c @@ -6,7 +6,7 @@ /* * Copyright (c) 2017 Benjamin Aigner * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer - * + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,7 +32,7 @@ * OF SUCH DAMAGE. * * Author: Benjamin Aigner - * + * * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c) */ @@ -95,19 +95,19 @@ static struct lowpan6_link_addr rfc7668_peer_addr; /** * @ingroup rfc7668if * convert BT address to EUI64 addr - * + * * This method converts a Bluetooth MAC address to an EUI64 address, * which is used within IPv6 communication - * + * * @param dst IPv6 destination space * @param src BLE MAC address source * @param public_addr If the LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS * option is set, bit 0x02 will be set if param=0 (no public addr); cleared otherwise - * + * * @see LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS */ void -ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr) +ble_addr_to_eui64(u8_t *dst, const u8_t *src, int public_addr) { /* according to RFC7668 ch 3.2.2. */ memcpy(dst, src, 3); @@ -128,15 +128,15 @@ ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr) /** * @ingroup rfc7668if * convert EUI64 address to Bluetooth MAC addr - * + * * This method converts an EUI64 address to a Bluetooth MAC address, - * + * * @param dst BLE MAC address destination * @param src IPv6 source - * + * */ void -eui64_to_ble_addr(uint8_t *dst, const uint8_t *src) +eui64_to_ble_addr(u8_t *dst, const u8_t *src) { /* according to RFC7668 ch 3.2.2. */ memcpy(dst,src,3); @@ -214,16 +214,16 @@ rfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t p } /** Encapsulate IPv6 frames for BLE transmission - * + * * This method implements the IPv6 header compression: * *) According to RFC6282 * *) See Figure 2, contains base format of bit positions * *) Fragmentation not necessary (done at L2CAP layer of BLE) * @note Currently the pbuf allocation uses 256 bytes. If longer packets are used (possible due to MTU=1480Bytes), increase it here! - * + * * @param p Pbuf struct, containing the payload data * @param netif Output network interface. Should be of RFC7668 type - * + * * @return Same as netif->output. */ static err_t @@ -340,7 +340,7 @@ rfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) * @param p the received packet, p->payload pointing to the * IPv6 header (maybe compressed) * @param netif the network interface on which the packet was received - * + * * @return ERR_OK if everything was fine */ err_t @@ -352,7 +352,7 @@ rfc7668_input(struct pbuf * p, struct netif *netif) /* Load first header byte */ puc = (u8_t*)p->payload; - + /* no IP header compression */ if (*puc == 0x41) { LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, removing dispatch: 0x%2x \n", *puc)); @@ -386,7 +386,7 @@ rfc7668_input(struct pbuf * p, struct netif *netif) if ((i%4)==0) { LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\n")); } - LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("%2X ", *((uint8_t *)p->payload+i))); + LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("%2X ", *((u8_t *)p->payload+i))); } LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\np->len: %d\n", p->len)); } @@ -398,12 +398,12 @@ rfc7668_input(struct pbuf * p, struct netif *netif) /** * @ingroup rfc7668if * Initialize the netif - * + * * No flags are used (broadcast not possible, not ethernet, ...) * The shortname for this netif is "BT" * * @param netif the network interface to be initialized as RFC7668 netif - * + * * @return ERR_OK if everything went fine */ err_t @@ -433,7 +433,7 @@ rfc7668_if_init(struct netif *netif) * @param p the received packet, p->payload pointing to the * IEEE 802.15.4 header. * @param inp the network interface on which the packet was received - * + * * @return see @ref tcpip_inpkt, same return values */ err_t diff --git a/src/netif/lowpan6_common.c b/src/netif/lowpan6_common.c index 4db1ebb..9f50658 100644 --- a/src/netif/lowpan6_common.c +++ b/src/netif/lowpan6_common.c @@ -117,7 +117,7 @@ lowpan6_context_lookup(const ip6_addr_t *lowpan6_contexts, const ip6_addr_t *ip6 s8_t i; for (i = 0; i < LWIP_6LOWPAN_NUM_CONTEXTS; i++) { - if (ip6_addr_netcmp(&lowpan6_contexts[i], ip6addr)) { + if (ip6_addr_net_eq(&lowpan6_contexts[i], ip6addr)) { return i; } } @@ -424,13 +424,13 @@ lowpan6_decompress_hdr(u8_t *lowpan6_buffer, size_t lowpan6_bufsize, } LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("%2X ", lowpan6_buffer[j])); } - LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("\np->len: %d", lowpan6_bufsize)); + LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("\np->len: %d\n", lowpan6_bufsize)); } #endif /* offset for inline IP headers (RFC 6282 ch3)*/ lowpan6_offset = 2; - /* if CID is set (context identifier), the context byte + /* if CID is set (context identifier), the context byte * follows immediately after the header, so other IPHC fields are @+3 */ if (lowpan6_buffer[1] & 0x80) { lowpan6_offset++; @@ -523,7 +523,7 @@ lowpan6_decompress_hdr(u8_t *lowpan6_buffer, size_t lowpan6_bufsize, lowpan6_offset += 2; } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 11, src compression, 0bits inline, using other headers\n")); - /* no information avalaible, using other layers, see RFC6282 ch 3.2.2 */ + /* no information available, using other layers, see RFC6282 ch 3.2.2 */ ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); ip6hdr->src.addr[1] = 0; if (src->addr_len == 2) { @@ -667,7 +667,7 @@ lowpan6_decompress_hdr(u8_t *lowpan6_buffer, size_t lowpan6_bufsize, /* M=0, DAC=0, determining destination address length via DAM=xx */ if ((lowpan6_buffer[1] & 0x03) == 0x00) { - LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 00, no dst compression, fetching 128bits inline")); + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 00, no dst compression, fetching 128bits inline\n")); /* DAM=00, copy full address */ MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); lowpan6_offset += 16; diff --git a/src/netif/ppp/auth.c b/src/netif/ppp/auth.c index c8673ad..1f27175 100644 --- a/src/netif/ppp/auth.c +++ b/src/netif/ppp/auth.c @@ -591,9 +591,9 @@ void start_link(unit) * incoming events (reply, timeout, etc.). */ if (ifunit >= 0) - ppp_notice("Connect: %s <--> %s", ifname, ppp_devnam); + ppp_notice(("Connect: %s <--> %s", ifname, ppp_devnam)); else - ppp_notice("Starting negotiation on %s", ppp_devnam); + ppp_notice(("Starting negotiation on %s", ppp_devnam)); add_fd(fd_ppp); new_phase(pcb, PPP_PHASE_ESTABLISH); @@ -634,12 +634,12 @@ void link_terminated(ppp_pcb *pcb) { #endif /* UNUSED */ if (!doing_multilink) { - ppp_notice("Connection terminated."); + ppp_notice(("Connection terminated.")); #if PPP_STATS_SUPPORT print_link_stats(); #endif /* PPP_STATS_SUPPORT */ } else - ppp_notice("Link terminated."); + ppp_notice(("Link terminated.")); lcp_lowerdown(pcb); @@ -791,7 +791,7 @@ void link_established(ppp_pcb *pcb) { || !wo->neg_upap #endif /* PAP_SUPPORT */ ) { - ppp_warn("peer refused to authenticate: terminating link"); + ppp_warn(("peer refused to authenticate: terminating link")); #if 0 /* UNUSED */ status = EXIT_PEER_AUTH_FAILED; #endif /* UNUSED */ @@ -868,7 +868,7 @@ static void network_phase(ppp_pcb *pcb) { #if 0 /* UNUSED */ /* Log calling number. */ if (*remote_number) - ppp_notice("peer from calling number %q authorized", remote_number); + ppp_notice(("peer from calling number %q authorized", remote_number)); #endif /* UNUSED */ #if PPP_NOTIFY @@ -1003,17 +1003,17 @@ void continue_networks(ppp_pcb *pcb) { * 1: Authentication succeeded. * In either case, msg points to an appropriate message and msglen to the message len. */ -int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen) { - int secretuserlen; - int secretpasswdlen; +int auth_check_passwd(ppp_pcb *pcb, char *auser, unsigned int userlen, char *apasswd, unsigned int passwdlen, const char **msg, int *msglen) { + size_t secretuserlen; + size_t secretpasswdlen; if (pcb->settings.user && pcb->settings.passwd) { - secretuserlen = (int)strlen(pcb->settings.user); - secretpasswdlen = (int)strlen(pcb->settings.passwd); + secretuserlen = strlen(pcb->settings.user); + secretpasswdlen = strlen(pcb->settings.passwd); if (secretuserlen == userlen && secretpasswdlen == passwdlen - && !memcmp(auser, pcb->settings.user, userlen) - && !memcmp(apasswd, pcb->settings.passwd, passwdlen) ) { + && !lwip_memcmp_consttime(auser, pcb->settings.user, userlen) + && !lwip_memcmp_consttime(apasswd, pcb->settings.passwd, passwdlen) ) { *msg = "Login ok"; *msglen = sizeof("Login ok")-1; return 1; @@ -1049,6 +1049,7 @@ void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char * LWIP_UNUSED_ARG(name); LWIP_UNUSED_ARG(namelen); #endif /* HAVE_MULTILINK */ + LWIP_UNUSED_ARG(prot_flavor); /* if CHAP_SUPPORT is disabled */ switch (protocol) { #if CHAP_SUPPORT @@ -1082,7 +1083,7 @@ void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char * break; #endif /* EAP_SUPPORT */ default: - ppp_warn("auth_peer_success: unknown protocol %x", protocol); + ppp_warn(("auth_peer_success: unknown protocol %x", protocol)); return; } @@ -1136,6 +1137,7 @@ void auth_withpeer_fail(ppp_pcb *pcb, int protocol) { void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { int bit; const char *prot = ""; + LWIP_UNUSED_ARG(prot_flavor); /* if CHAP_SUPPORT is disabled */ switch (protocol) { #if CHAP_SUPPORT @@ -1172,12 +1174,12 @@ void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { break; #endif /* EAP_SUPPORT */ default: - ppp_warn("auth_withpeer_success: unknown protocol %x", protocol); + ppp_warn(("auth_withpeer_success: unknown protocol %x", protocol)); bit = 0; /* no break */ } - ppp_notice("%s authentication succeeded", prot); + ppp_notice(("%s authentication succeeded", prot)); /* Save the authentication method for later. */ pcb->auth_done |= bit; @@ -1300,7 +1302,7 @@ check_maxoctets(arg) break; } if (used > maxoctets) { - ppp_notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); + ppp_notice(("Traffic limit reached. Limit: %u Used: %u", maxoctets, used)); status = EXIT_TRAFFIC_LIMIT; lcp_close(pcb, "Traffic limit"); #if 0 /* UNUSED */ @@ -1338,7 +1340,7 @@ static void check_idle(void *arg) { #endif /* UNUSED */ if (tlim <= 0) { /* link is idle: shut it down. */ - ppp_notice("Terminating connection due to lack of activity."); + ppp_notice(("Terminating connection due to lack of activity.")); pcb->err_code = PPPERR_IDLETIMEOUT; lcp_close(pcb, "Link inactive"); #if 0 /* UNUSED */ @@ -1356,7 +1358,7 @@ static void check_idle(void *arg) { */ static void connect_time_expired(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; - ppp_info("Connect time expired"); + ppp_info(("Connect time expired")); pcb->err_code = PPPERR_CONNECTTIME; lcp_close(pcb, "Connect time expired"); /* Close connection */ } @@ -1495,7 +1497,7 @@ auth_check_options() * Early check for remote number authorization. */ if (!auth_number()) { - ppp_warn("calling number %q is not authorized", remote_number); + ppp_warn(("calling number %q is not authorized", remote_number)); exit(EXIT_CNID_AUTH_FAILED); } } @@ -1609,12 +1611,12 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) ret = UPAP_AUTHNAK; f = fopen(filename, "r"); if (f == NULL) { - ppp_error("Can't open PAP password file %s: %m", filename); + ppp_error(("Can't open PAP password file %s: %m", filename)); } else { check_access(f, filename); if (scan_authfile(f, ppp_settings.user, our_name, secret, &addrs, &opts, filename, 0) < 0) { - ppp_warn("no PAP secret found for %s", user); + ppp_warn(("no PAP secret found for %s", user)); } else { /* * If the secret is "@login", it means to check @@ -1629,7 +1631,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) } } else if (session_mgmt) { if (session_check(ppp_settings.user, NULL, devnam, NULL) == 0) { - ppp_warn("Peer %q failed PAP Session verification", user); + ppp_warn(("Peer %q failed PAP Session verification", user)); ret = UPAP_AUTHNAK; } } @@ -1653,7 +1655,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) * On 10'th, drop the connection. */ if (attempts++ >= 10) { - ppp_warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); + ppp_warn(("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user)); lcp_close(pcb, "login failed"); } if (attempts > 3) @@ -1902,7 +1904,7 @@ have_srp_secret(client, server, need_ip, lacks_ipp) * (We could be either client or server). */ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server) { - int len; + size_t len; LWIP_UNUSED_ARG(server); LWIP_UNUSED_ARG(am_server); @@ -1910,9 +1912,9 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre return 0; } - len = (int)strlen(pcb->settings.passwd); + len = strlen(pcb->settings.passwd); if (len > MAXSECRETLEN) { - ppp_error("Secret for %s on %s is too long", client, server); + ppp_error(("Secret for %s on %s is too long", client, server)); len = MAXSECRETLEN; } @@ -1922,7 +1924,8 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre #if 0 /* UNUSED */ FILE *f; - int ret, len; + int ret; + size_t len; char *filename; struct wordlist *addrs, *opts; char secbuf[MAXWORDLEN]; @@ -1933,8 +1936,8 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre strlcpy(secbuf, ppp_settings.passwd, sizeof(secbuf)); } else if (!am_server && chap_passwd_hook) { if ( (*chap_passwd_hook)(client, secbuf) < 0) { - ppp_error("Unable to obtain CHAP password for %s on %s from plugin", - client, server); + ppp_error(("Unable to obtain CHAP password for %s on %s from plugin", + client, server)); return 0; } } else { @@ -1944,7 +1947,7 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre f = fopen(filename, "r"); if (f == NULL) { - ppp_error("Can't open chap secret file %s: %m", filename); + ppp_error(("Can't open chap secret file %s: %m", filename)); return 0; } check_access(f, filename); @@ -1964,7 +1967,7 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre len = strlen(secbuf); if (len > MAXSECRETLEN) { - ppp_error("Secret for %s on %s is too long", client, server); + ppp_error(("Secret for %s on %s is too long", client, server)); len = MAXSECRETLEN; } MEMCPY(secret, secbuf, len); @@ -2004,7 +2007,7 @@ get_srp_secret(unit, client, server, secret, am_server) fp = fopen(filename, "r"); if (fp == NULL) { - ppp_error("Can't open srp secret file %s: %m", filename); + ppp_error(("Can't open srp secret file %s: %m", filename)); return 0; } check_access(fp, filename); @@ -2098,8 +2101,8 @@ set_allowed_addrs(unit, addrs, opts) bit_count = (int) strtol (ptr_mask+1, &endp, 10); if (bit_count <= 0 || bit_count > 32) { - ppp_warn("invalid address length %v in auth. address list", - ptr_mask+1); + ppp_warn(("invalid address length %v in auth. address list", + ptr_mask+1)); continue; } bit_count = 32 - bit_count; /* # bits in host part */ @@ -2108,7 +2111,7 @@ set_allowed_addrs(unit, addrs, opts) ++endp; } if (*endp != 0) { - ppp_warn("invalid address length syntax: %v", ptr_mask+1); + ppp_warn(("invalid address length syntax: %v", ptr_mask+1)); continue; } *ptr_mask = '\0'; @@ -2141,13 +2144,13 @@ set_allowed_addrs(unit, addrs, opts) *ptr_mask = '/'; if (a == (u32_t)-1L) { - ppp_warn("unknown host %s in auth. address list", ap->word); + ppp_warn(("unknown host %s in auth. address list", ap->word)); continue; } if (offset != 0) { if (offset >= ~mask) { - ppp_warn("interface unit %d too large for subnet %v", - ifunit, ptr_word); + ppp_warn(("interface unit %d too large for subnet %v", + ifunit, ptr_word)); continue; } a = lwip_htonl((lwip_ntohl(a) & mask) + offset); @@ -2295,10 +2298,10 @@ check_access(f, filename) struct stat sbuf; if (fstat(fileno(f), &sbuf) < 0) { - ppp_warn("cannot stat secret file %s: %m", filename); + ppp_warn(("cannot stat secret file %s: %m", filename)); } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { - ppp_warn("Warning - secret file %s has world and/or group access", - filename); + ppp_warn(("Warning - secret file %s has world and/or group access", + filename)); } } @@ -2408,12 +2411,12 @@ scan_authfile(f, client, server, secret, addrs, opts, filename, flags) if (word[0] == '@' && word[1] == '/') { strlcpy(atfile, word+1, sizeof(atfile)); if ((sf = fopen(atfile, "r")) == NULL) { - ppp_warn("can't open indirect secret file %s", atfile); + ppp_warn(("can't open indirect secret file %s", atfile)); continue; } check_access(sf, atfile); if (!getword(sf, word, &xxx, atfile)) { - ppp_warn("no secret in indirect secret file %s", atfile); + ppp_warn(("no secret in indirect secret file %s", atfile)); fclose(sf); continue; } diff --git a/src/netif/ppp/ccp.c b/src/netif/ppp/ccp.c index f8519eb..86ecb9f 100644 --- a/src/netif/ppp/ccp.c +++ b/src/netif/ppp/ccp.c @@ -463,10 +463,10 @@ static void ccp_input(ppp_pcb *pcb, u_char *p, int len) { oldstate = f->state; fsm_input(f, p, len); if (oldstate == PPP_FSM_OPENED && p[0] == TERMREQ && f->state != PPP_FSM_OPENED) { - ppp_notice("Compression disabled by peer."); + ppp_notice(("Compression disabled by peer.")); #if MPPE_SUPPORT if (go->mppe) { - ppp_error("MPPE disabled, closing LCP"); + ppp_error(("MPPE disabled, closing LCP")); lcp_close(pcb, "MPPE disabled by peer"); } #endif /* MPPE_SUPPORT */ @@ -528,7 +528,7 @@ static void ccp_protrej(ppp_pcb *pcb) { #if MPPE_SUPPORT if (go->mppe) { - ppp_error("MPPE required but peer negotiation failed"); + ppp_error(("MPPE required but peer negotiation failed")); lcp_close(pcb, "MPPE required but peer negotiation failed"); } #endif /* MPPE_SUPPORT */ @@ -589,20 +589,20 @@ static void ccp_resetci(fsm *f) { auth_mschap_bits >>= 1; } while (auth_mschap_bits); if (numbits > 1) { - ppp_error("MPPE required, but auth done in both directions."); + ppp_error(("MPPE required, but auth done in both directions.")); lcp_close(pcb, "MPPE required but not available"); return; } if (!numbits) { - ppp_error("MPPE required, but MS-CHAP[v2] auth not performed."); + ppp_error(("MPPE required, but MS-CHAP[v2] auth not performed.")); lcp_close(pcb, "MPPE required but not available"); return; } /* A plugin (eg radius) may not have obtained key material. */ if (!pcb->mppe_keys_set) { - ppp_error("MPPE required, but keys are not available. " - "Possible plugin problem?"); + ppp_error(("MPPE required, but keys are not available. " + "Possible plugin problem?")); lcp_close(pcb, "MPPE required but not available"); return; } @@ -611,7 +611,7 @@ static void ccp_resetci(fsm *f) { if (pcb->auth_done & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { /* This might be noise */ if (go->mppe & MPPE_OPT_40) { - ppp_notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); + ppp_notice(("Disabling 40-bit MPPE; MS-CHAP LM not supported")); go->mppe &= ~MPPE_OPT_40; wo->mppe &= ~MPPE_OPT_40; } @@ -620,7 +620,7 @@ static void ccp_resetci(fsm *f) { /* Last check: can we actually negotiate something? */ if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { /* Could be misconfig, could be 40-bit disabled above. */ - ppp_error("MPPE required, but both 40-bit and 128-bit disabled."); + ppp_error(("MPPE required, but both 40-bit and 128-bit disabled.")); lcp_close(pcb, "MPPE required but not available"); return; } @@ -949,7 +949,7 @@ static int ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { */ MPPE_CI_TO_OPTS(&p[2], try_.mppe); if ((try_.mppe & MPPE_OPT_STATEFUL) && pcb->settings.refuse_mppe_stateful) { - ppp_error("Refusing MPPE stateful mode offered by peer"); + ppp_error(("Refusing MPPE stateful mode offered by peer")); try_.mppe = 0; } else if (((go->mppe | MPPE_OPT_STATEFUL) & try_.mppe) != try_.mppe) { /* Peer must have set options we didn't request (suggest) */ @@ -957,7 +957,7 @@ static int ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { } if (!try_.mppe) { - ppp_error("MPPE required but peer negotiation failed"); + ppp_error(("MPPE required but peer negotiation failed")); lcp_close(pcb, "MPPE required but peer negotiation failed"); } } @@ -1035,7 +1035,7 @@ static int ccp_rejci(fsm *f, u_char *p, int len) { #if MPPE_SUPPORT if (go->mppe && len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { - ppp_error("MPPE required but peer refused"); + ppp_error(("MPPE required but peer refused")); lcp_close(pcb, "MPPE required but peer refused"); p += CILEN_MPPE; len -= CILEN_MPPE; @@ -1164,7 +1164,7 @@ static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { * the Internet -- which is where we expect MPPE. */ if (pcb->settings.refuse_mppe_stateful) { - ppp_error("Refusing MPPE stateful mode offered by peer"); + ppp_error(("Refusing MPPE stateful mode offered by peer")); newret = CONFREJ; break; } @@ -1213,9 +1213,9 @@ static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { * because MPPE frames **grow**. The kernel [must] * allocate MPPE_PAD extra bytes in xmit buffers. */ - mtu = netif_get_mtu(pcb); + mtu = ppp_netif_get_mtu(pcb); if (mtu) - netif_set_mtu(pcb, mtu - MPPE_PAD); + ppp_netif_set_mtu(pcb, mtu - MPPE_PAD); else newret = CONFREJ; } @@ -1375,7 +1375,7 @@ static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { } #if MPPE_SUPPORT if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) { - ppp_error("MPPE required but peer negotiation failed"); + ppp_error(("MPPE required but peer negotiation failed")); lcp_close(pcb, "MPPE required but peer negotiation failed"); } #endif /* MPPE_SUPPORT */ @@ -1466,16 +1466,16 @@ static void ccp_up(fsm *f) { if (ccp_anycompress(go)) { if (ccp_anycompress(ho)) { if (go->method == ho->method) { - ppp_notice("%s compression enabled", method_name(go, ho)); + ppp_notice(("%s compression enabled", method_name(go, ho))); } else { ppp_strlcpy(method1, method_name(go, NULL), sizeof(method1)); - ppp_notice("%s / %s compression enabled", - method1, method_name(ho, NULL)); + ppp_notice(("%s / %s compression enabled", + method1, method_name(ho, NULL))); } } else - ppp_notice("%s receive compression enabled", method_name(go, NULL)); + ppp_notice(("%s receive compression enabled", method_name(go, NULL))); } else if (ccp_anycompress(ho)) - ppp_notice("%s transmit compression enabled", method_name(ho, NULL)); + ppp_notice(("%s transmit compression enabled", method_name(ho, NULL))); #if MPPE_SUPPORT if (go->mppe) { continue_networks(pcb); /* Bring up IP et al */ @@ -1501,7 +1501,7 @@ static void ccp_down(fsm *f) { go->mppe = 0; if (pcb->lcp_fsm.state == PPP_FSM_OPENED) { /* If LCP is not already going down, make sure it does. */ - ppp_error("MPPE disabled"); + ppp_error(("MPPE disabled")); lcp_close(pcb, "MPPE disabled"); } } @@ -1671,14 +1671,14 @@ static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len) { /* * Disable compression by taking CCP down. */ - ppp_error("Lost compression sync: disabling compression"); + ppp_error(("Lost compression sync: disabling compression")); ccp_close(pcb, "Lost compression sync"); #if MPPE_SUPPORT /* * If we were doing MPPE, we must also take the link down. */ if (go->mppe) { - ppp_error("Too many MPPE errors, closing LCP"); + ppp_error(("Too many MPPE errors, closing LCP")); lcp_close(pcb, "Too many MPPE errors"); } #endif /* MPPE_SUPPORT */ diff --git a/src/netif/ppp/chap-new.c b/src/netif/ppp/chap-new.c index 485122d..da12430 100644 --- a/src/netif/ppp/chap-new.c +++ b/src/netif/ppp/chap-new.c @@ -166,15 +166,15 @@ void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { int i; if (pcb->chap_server.flags & AUTH_STARTED) { - ppp_error("CHAP: peer authentication already started!"); + ppp_error(("CHAP: peer authentication already started!")); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) if (dp->code == digest_code) break; if (dp == NULL) - ppp_fatal("CHAP digest 0x%x requested but not available", - digest_code); + ppp_fatal(("CHAP digest 0x%x requested but not available", + digest_code)); pcb->chap_server.digest = dp; pcb->chap_server.name = our_name; @@ -198,7 +198,7 @@ void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { return; if (pcb->chap_client.flags & AUTH_STARTED) { - ppp_error("CHAP: authentication with peer already started!"); + ppp_error(("CHAP: authentication with peer already started!")); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) @@ -206,8 +206,8 @@ void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { break; if (dp == NULL) - ppp_fatal("CHAP digest 0x%x requested but not available", - digest_code); + ppp_fatal(("CHAP digest 0x%x requested but not available", + digest_code)); pcb->chap_client.digest = dp; pcb->chap_client.name = our_name; @@ -236,7 +236,7 @@ static void chap_timeout(void *arg) { return; } - p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -337,7 +337,7 @@ static void chap_handle_response(ppp_pcb *pcb, int id, #endif /* UNUSED */ if (!ok) { pcb->chap_server.flags |= AUTH_FAILED; - ppp_warn("Peer %q failed CHAP authentication", name); + ppp_warn(("Peer %q failed CHAP authentication", name)); } } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) return; @@ -345,7 +345,7 @@ static void chap_handle_response(ppp_pcb *pcb, int id, /* send the response */ mlen = strlen(message); len = CHAP_HDRLEN + mlen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -381,7 +381,7 @@ static void chap_handle_response(ppp_pcb *pcb, int id, if (session_mgmt && session_check(name, NULL, devnam, NULL) == 0) { pcb->chap_server.flags |= AUTH_FAILED; - ppp_warn("Peer %q failed CHAP Session verification", name); + ppp_warn(("Peer %q failed CHAP Session verification", name)); } #endif /* UNUSED */ @@ -418,7 +418,7 @@ static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourn /* Get the secret that the peer is supposed to know */ if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { - ppp_error("No CHAP secret found for authenticating %q", name); + ppp_error(("No CHAP secret found for authenticating %q", name)); return 0; } ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, @@ -441,7 +441,7 @@ static void chap_respond(ppp_pcb *pcb, int id, char rname[MAXNAMELEN+1]; char secret[MAXSECRETLEN+1]; - p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -468,7 +468,7 @@ static void chap_respond(ppp_pcb *pcb, int id, /* get secret for authenticating ourselves with the specified host */ if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { secret_len = 0; /* assume null secret if can't find one */ - ppp_warn("No CHAP secret found for authenticating us to %q", rname); + ppp_warn(("No CHAP secret found for authenticating us to %q", rname)); } outp = (u_char*)p->payload; @@ -519,15 +519,15 @@ static void chap_handle_status(ppp_pcb *pcb, int code, int id, } if (msg) { if (len > 0) - ppp_info("%s: %.*v", msg, len, pkt); + ppp_info(("%s: %.*v", msg, len, pkt)); else - ppp_info("%s", msg); + ppp_info(("%s", msg)); } if (code == CHAP_SUCCESS) auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); else { pcb->chap_client.flags |= AUTH_FAILED; - ppp_error("CHAP authentication failed"); + ppp_error(("CHAP authentication failed")); auth_withpeer_fail(pcb, PPP_CHAP); } } @@ -577,7 +577,7 @@ static void chap_protrej(ppp_pcb *pcb) { #endif /* PPP_SERVER */ if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { pcb->chap_client.flags &= ~AUTH_STARTED; - ppp_error("CHAP authentication failed due to protocol-reject"); + ppp_error(("CHAP authentication failed due to protocol-reject")); auth_withpeer_fail(pcb, PPP_CHAP); } } diff --git a/src/netif/ppp/chap_ms.c b/src/netif/ppp/chap_ms.c index 5a989c9..0639e7d 100644 --- a/src/netif/ppp/chap_ms.c +++ b/src/netif/ppp/chap_ms.c @@ -33,7 +33,7 @@ * * Implemented LANManager type password response to MS-CHAP challenges. * Now pppd provides both NT style and LANMan style blocks, and the - * prefered is set by option "ms-lanman". Default is to use NT. + * preferred is set by option "ms-lanman". Default is to use NT. * The hash text (StdText) was taken from Win95 RASAPI32.DLL. * * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 @@ -264,7 +264,7 @@ static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name, #ifndef MSLANMAN if (!response[MS_CHAP_USENT]) { /* Should really propagate this into the error packet. */ - ppp_notice("Peer request for LANMAN auth not supported"); + ppp_notice(("Peer request for LANMAN auth not supported")); goto bad; } #endif @@ -404,7 +404,7 @@ static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsi if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp((char *)msg, "S=", 2) != 0) { /* Packet does not start with "S=" */ - ppp_error("MS-CHAPv2 Success packet is badly formed."); + ppp_error(("MS-CHAPv2 Success packet is badly formed.")); return 0; } msg += 2; @@ -412,7 +412,7 @@ static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsi if (len < MS_AUTH_RESPONSE_LENGTH || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) { /* Authenticator Response did not match expected. */ - ppp_error("MS-CHAPv2 mutual authentication failed."); + ppp_error(("MS-CHAPv2 mutual authentication failed.")); return 0; } /* Authenticator Response matches. */ @@ -422,7 +422,7 @@ static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsi msg += 3; /* Eat the delimiter */ } else if (len) { /* Packet has extra text which does not begin " M=" */ - ppp_error("MS-CHAPv2 Success packet is badly formed."); + ppp_error(("MS-CHAPv2 Success packet is badly formed.")); return 0; } return 1; @@ -483,14 +483,14 @@ static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) { break; default: - ppp_error("Unknown MS-CHAP authentication failure: %.*v", - len, inp); + ppp_error(("Unknown MS-CHAP authentication failure: %.*v", + len, inp)); return; } } print_msg: if (p != NULL) - ppp_error("MS-CHAP authentication failed: %v", p); + ppp_error(("MS-CHAP authentication failed: %v", p)); } static void ChallengeResponse(const u_char *challenge, diff --git a/src/netif/ppp/demand.c b/src/netif/ppp/demand.c index 26c6c30..709e5ea 100644 --- a/src/netif/ppp/demand.c +++ b/src/netif/ppp/demand.c @@ -86,8 +86,8 @@ demand_conf() const struct protent *protp; /* framemax = lcp_allowoptions[0].mru; - if (framemax < PPP_MRU) */ - framemax = PPP_MRU; + if (framemax < PPP_DEFMRU) */ + framemax = PPP_DEFMRU; framemax += PPP_HDRLEN + PPP_FCSLEN; frame = malloc(framemax); if (frame == NULL) @@ -98,9 +98,9 @@ demand_conf() flush_flag = 0; fcs = PPP_INITFCS; - netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU)); - if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0 - || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0) + ppp_netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_DEFMRU)); + if (ppp_send_config(pcb, PPP_DEFMRU, (u32_t) 0, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_DEFMRU, (u32_t) 0, 0, 0) < 0) fatal("Couldn't set up demand-dialled PPP interface: %m"); #ifdef PPP_FILTER diff --git a/src/netif/ppp/eap.c b/src/netif/ppp/eap.c index 8fb5636..ea684bf 100644 --- a/src/netif/ppp/eap.c +++ b/src/netif/ppp/eap.c @@ -13,7 +13,7 @@ * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Original version by James Carlson * @@ -211,7 +211,7 @@ static void eap_client_timeout(void *arg) { if (!eap_client_active(pcb)) return; - ppp_error("EAP: timeout waiting for Request from peer"); + ppp_error(("EAP: timeout waiting for Request from peer")); auth_withpeer_fail(pcb, PPP_EAP); pcb->eap.es_client.ea_state = eapBadAuth; } @@ -251,7 +251,7 @@ static void eap_send_failure(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -282,7 +282,7 @@ static void eap_send_success(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -471,8 +471,8 @@ static void eap_figure_next_state(ppp_pcb *pcb, int status) { toffs -= 86400; /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ if (!DesDecrypt(secbuf, clear)) { - ppp_dbglog("no DES here; cannot decode " - "pseudonym"); + ppp_dbglog(("no DES here; cannot decode " + "pseudonym")); return; } id = *(unsigned char *)clear; @@ -502,11 +502,11 @@ static void eap_figure_next_state(ppp_pcb *pcb, int status) { } pcb->eap.es_server.ea_peer[ pcb->eap.es_server.ea_peerlen] = '\0'; - ppp_dbglog("decoded pseudonym to \"%.*q\"", + ppp_dbglog(("decoded pseudonym to \"%.*q\"", pcb->eap.es_server.ea_peerlen, - pcb->eap.es_server.ea_peer); + pcb->eap.es_server.ea_peer)); } else { - ppp_dbglog("failed to decode real name"); + ppp_dbglog(("failed to decode real name")); /* Stay in eapIdentfy state; requery */ break; } @@ -676,14 +676,14 @@ static void eap_send_request(ppp_pcb *pcb) { if (pcb->settings.eap_max_transmits > 0 && pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) { if (pcb->eap.es_server.ea_responses > 0) - ppp_error("EAP: too many Requests sent"); + ppp_error(("EAP: too many Requests sent")); else - ppp_error("EAP: no response to Requests"); + ppp_error(("EAP: no response to Requests")); eap_send_failure(pcb); return; } - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_UNKNOWN_SIZE), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -786,7 +786,7 @@ static void eap_send_request(ppp_pcb *pcb) { cp += j; /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ if (!DesEncrypt(clear, cipher)) { - ppp_dbglog("no DES here; not generating pseudonym"); + ppp_dbglog(("no DES here; not generating pseudonym")); break; } BZERO(&b64, sizeof (b64)); @@ -997,12 +997,12 @@ static void eap_lowerdown(ppp_pcb *pcb) { static void eap_protrej(ppp_pcb *pcb) { if (eap_client_active(pcb)) { - ppp_error("EAP authentication failed due to Protocol-Reject"); + ppp_error(("EAP authentication failed due to Protocol-Reject")); auth_withpeer_fail(pcb, PPP_EAP); } #if PPP_SERVER if (eap_server_active(pcb)) { - ppp_error("EAP authentication of peer failed on Protocol-Reject"); + ppp_error(("EAP authentication of peer failed on Protocol-Reject")); auth_peer_fail(pcb, PPP_EAP); } #endif /* PPP_SERVER */ @@ -1018,7 +1018,7 @@ static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_c int msglen; msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -1052,7 +1052,7 @@ static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE + namelen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -1097,7 +1097,7 @@ int lenstr; int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -1139,7 +1139,7 @@ u_char *str; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) + SHA_DIGESTSIZE; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -1170,7 +1170,7 @@ static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) { int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char); - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -1213,7 +1213,7 @@ name_of_pn_file() return (NULL); (void) slprintf(path, pl, "%s/%s", user, file); if (!pnlogged) { - ppp_dbglog("pseudonym file: %s", path); + ppp_dbglog(("pseudonym file: %s", path)); pnlogged = 1; } return (path); @@ -1284,22 +1284,22 @@ int len, id; /* Now check that the result is sane */ if (olen <= 0 || *inp + 1 > olen) { - ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); + ppp_dbglog(("EAP: decoded pseudonym is unusable <%.*B>", olen, inp)); return; } /* Save it away */ fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); if (fd < 0) { - ppp_dbglog("EAP: error saving pseudonym: %m"); + ppp_dbglog(("EAP: error saving pseudonym: %m")); return; } len = write(fd, inp + 1, *inp); if (close(fd) != -1 && len == *inp) { - ppp_dbglog("EAP: saved pseudonym"); + ppp_dbglog(("EAP: saved pseudonym")); pcb->eap.es_usedpseudo = 0; } else { - ppp_dbglog("EAP: failed to save pseudonym"); + ppp_dbglog(("EAP: failed to save pseudonym")); remove_pn_file(); } } @@ -1325,6 +1325,12 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { int fd; #endif /* USE_SRP */ + /* + * Ignore requests if we're not open + */ + if (pcb->eap.es_client.ea_state <= eapClosed) + return; + /* * Note: we update es_client.ea_id *only if* a Response * message is being generated. Otherwise, we leave it the @@ -1334,7 +1340,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { pcb->eap.es_client.ea_requests++; if (pcb->settings.eap_allow_req != 0 && pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) { - ppp_info("EAP: received too many Request messages"); + ppp_info(("EAP: received too many Request messages")); if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); } @@ -1343,7 +1349,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { } if (len <= 0) { - ppp_error("EAP: empty Request message discarded"); + ppp_error(("EAP: empty Request message discarded")); return; } @@ -1353,7 +1359,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { switch (typenum) { case EAPT_IDENTITY: if (len > 0) - ppp_info("EAP: Identity prompt \"%.*q\"", len, inp); + ppp_info(("EAP: Identity prompt \"%.*q\"", len, inp)); #ifdef USE_SRP if (pcb->eap.es_usepseudo && (pcb->eap.es_usedpseudo == 0 || @@ -1387,7 +1393,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPT_NOTIFICATION: if (len > 0) - ppp_info("EAP: Notification \"%.*q\"", len, inp); + ppp_info(("EAP: Notification \"%.*q\"", len, inp)); eap_send_response(pcb, id, typenum, NULL, 0); break; @@ -1396,29 +1402,29 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { * Avoid the temptation to send Response Nak in reply * to Request Nak here. It can only lead to trouble. */ - ppp_warn("EAP: unexpected Nak in Request; ignored"); + ppp_warn(("EAP: unexpected Nak in Request; ignored")); /* Return because we're waiting for something real. */ return; case EAPT_MD5CHAP: if (len < 1) { - ppp_error("EAP: received MD5-Challenge with no data"); + ppp_error(("EAP: received MD5-Challenge with no data")); /* Bogus request; wait for something real. */ return; } GETCHAR(vallen, inp); len--; if (vallen < 8 || vallen > len) { - ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)", - vallen, len); + ppp_error(("EAP: MD5-Challenge with bad length %d (8..%d)", + vallen, len)); /* Try something better. */ eap_send_nak(pcb, id, EAPT_SRP); break; } /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { - ppp_dbglog("EAP: trimming really long peer name down"); + if (len - vallen >= (int)sizeof (rhostname)) { + ppp_dbglog(("EAP: trimming really long peer name down")); MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; } else { @@ -1439,7 +1445,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { */ if (!get_secret(pcb, pcb->eap.es_client.ea_name, rhostname, secret, &secret_len, 0)) { - ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname); + ppp_dbglog(("EAP: no MD5 secret for auth to %q", rhostname)); eap_send_nak(pcb, id, EAPT_SRP); break; } @@ -1459,7 +1465,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { #ifdef USE_SRP case EAPT_SRP: if (len < 1) { - ppp_error("EAP: received empty SRP Request"); + ppp_error(("EAP: received empty SRP Request")); /* Bogus request; wait for something real. */ return; } @@ -1492,8 +1498,8 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { GETCHAR(vallen, inp); len--; if (vallen >= len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (name)"); + ppp_error(("EAP: badly-formed SRP Challenge" + " (name)")); /* Ignore badly-formed messages */ return; } @@ -1523,8 +1529,8 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { GETCHAR(vallen, inp); len--; if (vallen >= len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (s)"); + ppp_error(("EAP: badly-formed SRP Challenge" + " (s)")); /* Ignore badly-formed messages */ return; } @@ -1536,8 +1542,8 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { GETCHAR(vallen, inp); len--; if (vallen > len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (g)"); + ppp_error(("EAP: badly-formed SRP Challenge" + " (g)")); /* Ignore badly-formed messages */ return; } @@ -1584,7 +1590,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_SKEY: tc = (struct t_client *)pcb->eap.es_client.ea_session; if (tc == NULL) { - ppp_warn("EAP: peer sent Subtype 2 without 1"); + ppp_warn(("EAP: peer sent Subtype 2 without 1")); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } @@ -1594,9 +1600,9 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { * if it does (but otherwise ignore). */ if (id != pcb->eap.es_client.ea_id) { - ppp_warn("EAP: ID changed from %d to %d " + ppp_warn(("EAP: ID changed from %d to %d " "in SRP Subtype 2 rexmit", - pcb->eap.es_client.ea_id, id); + pcb->eap.es_client.ea_id, id)); } } else { if (get_srp_secret(pcb->eap.es_unit, @@ -1618,7 +1624,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { t_clientgetkey(tc, &Bval); if (pcb->eap.es_client.ea_skey == NULL) { /* Server is rogue; stop now */ - ppp_error("EAP: SRP server is rogue"); + ppp_error(("EAP: SRP server is rogue")); goto client_failure; } } @@ -1629,7 +1635,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_SVALIDATOR: tc = (struct t_client *)pcb->eap.es_client.ea_session; if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) { - ppp_warn("EAP: peer sent Subtype 3 without 1/2"); + ppp_warn(("EAP: peer sent Subtype 3 without 1/2")); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } @@ -1640,16 +1646,16 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { */ if (pcb->eap.es_client.ea_state == eapOpen) { if (id != pcb->eap.es_client.ea_id) { - ppp_warn("EAP: ID changed from %d to %d " + ppp_warn(("EAP: ID changed from %d to %d " "in SRP Subtype 3 rexmit", - pcb->eap.es_client.ea_id, id); + pcb->eap.es_client.ea_id, id)); } } else { len -= sizeof (u32_t) + SHA_DIGESTSIZE; if (len < 0 || t_clientverify(tc, inp + sizeof (u32_t)) != 0) { - ppp_error("EAP: SRP server verification " - "failed"); + ppp_error(("EAP: SRP server verification " + "failed")); goto client_failure; } GETLONG(pcb->eap.es_client.ea_keyflags, inp); @@ -1669,7 +1675,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_LWRECHALLENGE: if (len < 4) { - ppp_warn("EAP: malformed Lightweight rechallenge"); + ppp_warn(("EAP: malformed Lightweight rechallenge")); return; } SHA1Init(&ctxt); @@ -1686,7 +1692,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { break; default: - ppp_error("EAP: unknown SRP Subtype %d", vallen); + ppp_error(("EAP: unknown SRP Subtype %d", vallen)); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } @@ -1694,7 +1700,7 @@ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { #endif /* USE_SRP */ default: - ppp_info("EAP: unknown authentication type %d; Naking", typenum); + ppp_info(("EAP: unknown authentication type %d; Naking", typenum)); eap_send_nak(pcb, id, EAPT_SRP); break; } @@ -1737,16 +1743,22 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char dig[SHA_DIGESTSIZE]; #endif /* USE_SRP */ + /* + * Ignore responses if we're not open + */ + if (pcb->eap.es_server.ea_state <= eapClosed) + return; + if (pcb->eap.es_server.ea_id != id) { - ppp_dbglog("EAP: discarding Response %d; expected ID %d", id, - pcb->eap.es_server.ea_id); + ppp_dbglog(("EAP: discarding Response %d; expected ID %d", id, + pcb->eap.es_server.ea_id)); return; } pcb->eap.es_server.ea_responses++; if (len <= 0) { - ppp_error("EAP: empty Response message discarded"); + ppp_error(("EAP: empty Response message discarded")); return; } @@ -1756,11 +1768,11 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { switch (typenum) { case EAPT_IDENTITY: if (pcb->eap.es_server.ea_state != eapIdentify) { - ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len, - inp); + ppp_dbglog(("EAP discarding unwanted Identify \"%.q\"", len, + inp)); break; } - ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp); + ppp_info(("EAP: unauthenticated peer name \"%.*q\"", len, inp)); if (len > MAXNAMELEN) { len = MAXNAMELEN; } @@ -1771,12 +1783,12 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { break; case EAPT_NOTIFICATION: - ppp_dbglog("EAP unexpected Notification; response discarded"); + ppp_dbglog(("EAP unexpected Notification; response discarded")); break; case EAPT_NAK: if (len < 1) { - ppp_info("EAP: Nak Response with no suggested protocol"); + ppp_info(("EAP: Nak Response with no suggested protocol")); eap_figure_next_state(pcb, 1); break; } @@ -1806,7 +1818,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { break; default: - ppp_dbglog("EAP: peer requesting unknown Type %d", vallen); + ppp_dbglog(("EAP: peer requesting unknown Type %d", vallen)); switch (pcb->eap.es_server.ea_state) { case eapSRP1: case eapSRP2: @@ -1827,26 +1839,26 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPT_MD5CHAP: if (pcb->eap.es_server.ea_state != eapMD5Chall) { - ppp_error("EAP: unexpected MD5-Response"); + ppp_error(("EAP: unexpected MD5-Response")); eap_figure_next_state(pcb, 1); break; } if (len < 1) { - ppp_error("EAP: received MD5-Response with no data"); + ppp_error(("EAP: received MD5-Response with no data")); eap_figure_next_state(pcb, 1); break; } GETCHAR(vallen, inp); len--; if (vallen != 16 || vallen > len) { - ppp_error("EAP: MD5-Response with bad length %d", vallen); + ppp_error(("EAP: MD5-Response with bad length %d", vallen)); eap_figure_next_state(pcb, 1); break; } /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { - ppp_dbglog("EAP: trimming really long peer name down"); + if (len - vallen >= (int)sizeof (rhostname)) { + ppp_dbglog(("EAP: trimming really long peer name down")); MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; } else { @@ -1867,7 +1879,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { */ if (!get_secret(pcb, rhostname, pcb->eap.es_server.ea_name, secret, &secret_len, 1)) { - ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname); + ppp_dbglog(("EAP: no MD5 secret for auth of %q", rhostname)); eap_send_failure(pcb); break; } @@ -1893,7 +1905,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { #ifdef USE_SRP case EAPT_SRP: if (len < 1) { - ppp_error("EAP: empty SRP Response"); + ppp_error(("EAP: empty SRP Response")); eap_figure_next_state(pcb, 1); break; } @@ -1902,7 +1914,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { switch (typenum) { case EAPSRP_CKEY: if (pcb->eap.es_server.ea_state != eapSRP1) { - ppp_error("EAP: unexpected SRP Subtype 1 Response"); + ppp_error(("EAP: unexpected SRP Subtype 1 Response")); eap_figure_next_state(pcb, 1); break; } @@ -1913,7 +1925,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A); if (pcb->eap.es_server.ea_skey == NULL) { /* Client's A value is bogus; terminate now */ - ppp_error("EAP: bogus A value from client"); + ppp_error(("EAP: bogus A value from client")); eap_send_failure(pcb); } else { eap_figure_next_state(pcb, 0); @@ -1922,13 +1934,13 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_CVALIDATOR: if (pcb->eap.es_server.ea_state != eapSRP2) { - ppp_error("EAP: unexpected SRP Subtype 2 Response"); + ppp_error(("EAP: unexpected SRP Subtype 2 Response")); eap_figure_next_state(pcb, 1); break; } if (len < sizeof (u32_t) + SHA_DIGESTSIZE) { - ppp_error("EAP: M1 length %d < %d", len, - sizeof (u32_t) + SHA_DIGESTSIZE); + ppp_error(("EAP: M1 length %d < %d", len, + sizeof (u32_t) + SHA_DIGESTSIZE)); eap_figure_next_state(pcb, 1); break; } @@ -1936,7 +1948,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); if (t_serververify(ts, inp)) { - ppp_info("EAP: unable to validate client identity"); + ppp_info(("EAP: unable to validate client identity")); eap_send_failure(pcb); break; } @@ -1945,7 +1957,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_ACK: if (pcb->eap.es_server.ea_state != eapSRP3) { - ppp_error("EAP: unexpected SRP Subtype 3 Response"); + ppp_error(("EAP: unexpected SRP Subtype 3 Response")); eap_send_failure(esp); break; } @@ -1962,12 +1974,12 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { case EAPSRP_LWRECHALLENGE: if (pcb->eap.es_server.ea_state != eapSRP4) { - ppp_info("EAP: unexpected SRP Subtype 4 Response"); + ppp_info(("EAP: unexpected SRP Subtype 4 Response")); return; } if (len != SHA_DIGESTSIZE) { - ppp_error("EAP: bad Lightweight rechallenge " - "response"); + ppp_error(("EAP: bad Lightweight rechallenge " + "response")); return; } SHA1Init(&ctxt); @@ -1980,7 +1992,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { pcb->eap.es_server.ea_peerlen); SHA1Final(dig, &ctxt); if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { - ppp_error("EAP: failed Lightweight rechallenge"); + ppp_error(("EAP: failed Lightweight rechallenge")); eap_send_failure(pcb); break; } @@ -1995,7 +2007,7 @@ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { default: /* This can't happen. */ - ppp_error("EAP: unknown Response type %d; ignored", typenum); + ppp_error(("EAP: unknown Response type %d; ignored", typenum)); return; } @@ -2018,9 +2030,9 @@ static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { LWIP_UNUSED_ARG(id); if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) { - ppp_dbglog("EAP unexpected success message in state %s (%d)", + ppp_dbglog(("EAP unexpected success message in state %s (%d)", eap_state_name(pcb->eap.es_client.ea_state), - pcb->eap.es_client.ea_state); + pcb->eap.es_client.ea_state)); return; } @@ -2043,10 +2055,16 @@ static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { LWIP_UNUSED_ARG(id); + /* + * Ignore failure messages if we're not open + */ + if (pcb->eap.es_client.ea_state <= eapClosed) + return; + if (!eap_client_active(pcb)) { - ppp_dbglog("EAP unexpected failure message in state %s (%d)", + ppp_dbglog(("EAP unexpected failure message in state %s (%d)", eap_state_name(pcb->eap.es_client.ea_state), - pcb->eap.es_client.ea_state); + pcb->eap.es_client.ea_state)); } if (pcb->settings.eap_req_time > 0) { @@ -2060,7 +2078,7 @@ static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { pcb->eap.es_client.ea_state = eapBadAuth; - ppp_error("EAP: peer reports authentication failure"); + ppp_error(("EAP: peer reports authentication failure")); auth_withpeer_fail(pcb, PPP_EAP); } @@ -2076,15 +2094,15 @@ static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { * drop it. */ if (inlen < EAP_HEADERLEN) { - ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); + ppp_error(("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < EAP_HEADERLEN || len > inlen) { - ppp_error("EAP: packet has illegal length field %d (%d..%d)", len, - EAP_HEADERLEN, inlen); + ppp_error(("EAP: packet has illegal length field %d (%d..%d)", len, + EAP_HEADERLEN, inlen)); return; } len -= EAP_HEADERLEN; @@ -2111,7 +2129,7 @@ static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { default: /* XXX Need code reject */ /* Note: it's not legal to send EAP Nak here. */ - ppp_warn("EAP: unknown code %d received", code); + ppp_warn(("EAP: unknown code %d received", code)); break; } } diff --git a/src/netif/ppp/fsm.c b/src/netif/ppp/fsm.c index b1f08af..90a227c 100644 --- a/src/netif/ppp/fsm.c +++ b/src/netif/ppp/fsm.c @@ -290,7 +290,7 @@ static void fsm_timeout(void *arg) { case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: if (f->retransmits <= 0) { - ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f)); + ppp_warn(("%s: timeout sending Config-Requests", PROTO_NAME(f))); f->state = PPP_FSM_STOPPED; if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) (*f->callbacks->finished)(f); @@ -464,7 +464,7 @@ static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){ /* Ack is bad - ignore it */ - ppp_error("Received bad configure-ack: %P", inp, len); + ppp_error(("Received bad configure-ack: %P", inp, len)); return; } f->seen_ack = 1; @@ -524,14 +524,14 @@ static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { treat_as_reject = (f->rnakloops >= f->maxnakloops); if (f->callbacks->nakci == NULL || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { - ppp_error("Received bad configure-nak: %P", inp, len); + ppp_error(("Received bad configure-nak: %P", inp, len)); return; } } else { f->rnakloops = 0; if (f->callbacks->rejci == NULL || !(ret = f->callbacks->rejci(f, inp, len))) { - ppp_error("Received bad configure-rej: %P", inp, len); + ppp_error(("Received bad configure-rej: %P", inp, len)); return; } } @@ -588,9 +588,9 @@ static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { case PPP_FSM_OPENED: if (len > 0) { - ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); + ppp_info(("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p)); } else - ppp_info("%s terminated by peer", PROTO_NAME(f)); + ppp_info(("%s terminated by peer", PROTO_NAME(f))); f->retransmits = 0; f->state = PPP_FSM_STOPPING; if (f->callbacks->down) @@ -651,7 +651,7 @@ static void fsm_rcoderej(fsm *f, u_char *inp, int len) { } GETCHAR(code, inp); GETCHAR(id, inp); - ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); + ppp_warn(("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id)); if( f->state == PPP_FSM_ACKRCVD ) f->state = PPP_FSM_REQSENT; @@ -735,7 +735,7 @@ static void fsm_sconfreq(fsm *f, int retransmit) { } else cilen = 0; - p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -778,7 +778,7 @@ void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) datalen = pcb->peer_mru - HEADERLEN; outlen = datalen + HEADERLEN; - p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -787,8 +787,9 @@ void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) } outp = (u_char*)p->payload; - if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ - MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); + if (datalen && data != NULL) { /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ + MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); + } MAKEHEADER(outp, f->protocol); PUTCHAR(code, outp); PUTCHAR(id, outp); diff --git a/src/netif/ppp/ipcp.c b/src/netif/ppp/ipcp.c index b7c766e..b033cde 100644 --- a/src/netif/ppp/ipcp.c +++ b/src/netif/ppp/ipcp.c @@ -1067,7 +1067,7 @@ bad: * ipcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPCP is in the OPENED state. - * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + * Callback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. * * Returns: * 0 - Nak was bad. @@ -1537,7 +1537,7 @@ static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { next = inp; while (l) { orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ + cip = p = next; /* Remember beginning of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ @@ -1589,7 +1589,7 @@ static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { * If he doesn't know our address, or if we both have our address * but disagree about it, then NAK it with our idea. */ - GETLONG(tl, p); /* Parse desination address (ours) */ + GETLONG(tl, p); /* Parse destination address (ours) */ ciaddr2 = lwip_htonl(tl); if (ciaddr2 != wo->ouraddr) { if (ciaddr2 == 0 || !wo->accept_local) { @@ -1739,7 +1739,7 @@ static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { } endswitch: if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ + rc != CONFACK) /* but prior CI wasn't? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ @@ -1869,9 +1869,9 @@ ip_demand_conf(u) proxy_arp_set[u] = 1; #endif /* UNUSED - PROXY ARP */ - ppp_notice("local IP address %I", wo->ouraddr); + ppp_notice(("local IP address %I", wo->ouraddr)); if (wo->hisaddr) - ppp_notice("remote IP address %I", wo->hisaddr); + ppp_notice(("remote IP address %I", wo->hisaddr)); return 1; } @@ -1899,19 +1899,19 @@ static void ipcp_up(fsm *f) { if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) && wo->ouraddr != 0) { - ppp_error("Peer refused to agree to our IP address"); + ppp_error(("Peer refused to agree to our IP address")); ipcp_close(f->pcb, "Refused our IP address"); return; } if (go->ouraddr == 0) { - ppp_error("Could not determine local IP address"); + ppp_error(("Could not determine local IP address")); ipcp_close(f->pcb, "Could not determine local IP address"); return; } if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { ho->hisaddr = lwip_htonl(0x0a404040); - ppp_warn("Could not determine remote IP address: defaulting to %I", - ho->hisaddr); + ppp_warn(("Could not determine remote IP address: defaulting to %I", + ho->hisaddr)); } #if 0 /* UNUSED */ script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); @@ -1955,7 +1955,7 @@ static void ipcp_up(fsm *f) { || (pcb->settings.auth_required && wo->hisaddr != ho->hisaddr) #endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ ) { - ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ppp_error(("Peer is not authorized to use remote address %I", ho->hisaddr)); ipcp_close(pcb, "Unauthorized remote IP address"); return; } @@ -1963,7 +1963,7 @@ static void ipcp_up(fsm *f) { #if 0 /* Unused */ /* Upstream checking code */ if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { - ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ppp_error(("Peer is not authorized to use remote address %I", ho->hisaddr)); ipcp_close(f->unit, "Unauthorized remote IP address"); return; } @@ -1985,13 +1985,13 @@ static void ipcp_up(fsm *f) { ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, wo->replace_default_route); if (go->ouraddr != wo->ouraddr) { - ppp_warn("Local IP address changed to %I", go->ouraddr); + ppp_warn(("Local IP address changed to %I", go->ouraddr)); script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); wo->ouraddr = go->ouraddr; } else script_unsetenv("OLDIPLOCAL"); if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { - ppp_warn("Remote IP address changed to %I", ho->hisaddr); + ppp_warn(("Remote IP address changed to %I", ho->hisaddr)); script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); wo->hisaddr = ho->hisaddr; } else @@ -2001,7 +2001,7 @@ static void ipcp_up(fsm *f) { mask = get_mask(go->ouraddr); if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG - ppp_warn("Interface configuration failed"); + ppp_warn(("Interface configuration failed")); #endif /* PPP_DEBUG */ ipcp_close(f->unit, "Interface configuration failed"); return; @@ -2035,7 +2035,7 @@ static void ipcp_up(fsm *f) { #if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG - ppp_warn("Interface configuration failed"); + ppp_warn(("Interface configuration failed")); #endif /* PPP_DEBUG */ ipcp_close(f->pcb, "Interface configuration failed"); return; @@ -2045,7 +2045,7 @@ static void ipcp_up(fsm *f) { /* bring the interface up for IP */ if (!sifup(pcb)) { #if PPP_DEBUG - ppp_warn("Interface failed to come up"); + ppp_warn(("Interface failed to come up")); #endif /* PPP_DEBUG */ ipcp_close(f->pcb, "Interface configuration failed"); return; @@ -2054,7 +2054,7 @@ static void ipcp_up(fsm *f) { #if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG - ppp_warn("Interface configuration failed"); + ppp_warn(("Interface configuration failed")); #endif /* PPP_DEBUG */ ipcp_close(f->unit, "Interface configuration failed"); return; @@ -2081,14 +2081,14 @@ static void ipcp_up(fsm *f) { wo->ouraddr = go->ouraddr; - ppp_notice("local IP address %I", go->ouraddr); + ppp_notice(("local IP address %I", go->ouraddr)); if (ho->hisaddr != 0) - ppp_notice("remote IP address %I", ho->hisaddr); + ppp_notice(("remote IP address %I", ho->hisaddr)); #if LWIP_DNS if (go->dnsaddr[0]) - ppp_notice("primary DNS address %I", go->dnsaddr[0]); + ppp_notice(("primary DNS address %I", go->dnsaddr[0])); if (go->dnsaddr[1]) - ppp_notice("secondary DNS address %I", go->dnsaddr[1]); + ppp_notice(("secondary DNS address %I", go->dnsaddr[1])); #endif /* LWIP_DNS */ } diff --git a/src/netif/ppp/ipv6cp.c b/src/netif/ppp/ipv6cp.c index 11c18df..2035ef9 100644 --- a/src/netif/ppp/ipv6cp.c +++ b/src/netif/ppp/ipv6cp.c @@ -67,7 +67,7 @@ L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant - sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + sept laboratoires don't le laboratoire Logiciels, Systèmes, Réseaux (LSR). This work has been done in the context of GIE DYADE (joint R & D venture between BULL S.A. and INRIA). @@ -913,7 +913,7 @@ static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { next = inp; while (l) { orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ + cip = p = next; /* Remember beginning of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ @@ -1006,7 +1006,7 @@ endswitch: IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ + rc != CONFACK) /* but prior CI wasn't? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ @@ -1134,9 +1134,9 @@ static int ipv6_demand_conf(int u) { if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) return 0; - ppp_notice("ipv6_demand_conf"); - ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); - ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); + ppp_notice(("ipv6_demand_conf")); + ppp_notice(("local LL address %s", llv6_ntoa(wo->ourid))); + ppp_notice(("remote LL address %s", llv6_ntoa(wo->hisid))); return 1; } @@ -1166,17 +1166,17 @@ static void ipv6cp_up(fsm *f) { if(!no_ifaceid_neg) { #endif /* UNUSED */ if (eui64_iszero(ho->hisid)) { - ppp_error("Could not determine remote LL address"); + ppp_error(("Could not determine remote LL address")); ipv6cp_close(f->pcb, "Could not determine remote LL address"); return; } if (eui64_iszero(go->ourid)) { - ppp_error("Could not determine local LL address"); + ppp_error(("Could not determine local LL address")); ipv6cp_close(f->pcb, "Could not determine local LL address"); return; } if (eui64_equals(go->ourid, ho->hisid)) { - ppp_error("local and remote LL addresses are equal"); + ppp_error(("local and remote LL addresses are equal")); ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); return; } @@ -1244,8 +1244,8 @@ static void ipv6cp_up(fsm *f) { sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); #endif /* DEMAND_SUPPORT */ - ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); - ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); + ppp_notice(("local LL address %s", llv6_ntoa(go->ourid))); + ppp_notice(("remote LL address %s", llv6_ntoa(ho->hisid))); } np_up(f->pcb, PPP_IPV6); diff --git a/src/netif/ppp/lcp.c b/src/netif/ppp/lcp.c index 90ed183..3bc0092 100644 --- a/src/netif/ppp/lcp.c +++ b/src/netif/ppp/lcp.c @@ -373,7 +373,7 @@ static void lcp_init(ppp_pcb *pcb) { BZERO(wo, sizeof(*wo)); wo->neg_mru = 1; - wo->mru = PPP_DEFMRU; + wo->mru = PPP_MRU; wo->neg_asyncmap = 1; wo->neg_magicnumber = 1; wo->neg_pcompression = 1; @@ -462,11 +462,11 @@ void lcp_lowerup(ppp_pcb *pcb) { * but accept A/C and protocol compressed packets * if we are going to ask for A/C and protocol compression. */ - if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0 - || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff), + if (ppp_send_config(pcb, PPP_DEFMRU, 0xffffffff, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_DEFMRU, (pcb->settings.lax_recv? 0: 0xffffffff), wo->neg_pcompression, wo->neg_accompression) < 0) return; - pcb->peer_mru = PPP_MRU; + pcb->peer_mru = PPP_DEFMRU; if (pcb->settings.listen_time != 0) { f->flags |= DELAYED_UP; @@ -594,22 +594,22 @@ static void lcp_rprotrej(fsm *f, u_char *inp, int len) { if (protp->protocol == prot) { #if PPP_PROTOCOLNAME if (pname != NULL) - ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname, - prot); + ppp_dbglog(("Protocol-Reject for '%s' (0x%x) received", pname, + prot)); else #endif /* PPP_PROTOCOLNAME */ - ppp_dbglog("Protocol-Reject for 0x%x received", prot); + ppp_dbglog(("Protocol-Reject for 0x%x received", prot)); (*protp->protrej)(f->pcb); return; } #if PPP_PROTOCOLNAME if (pname != NULL) - ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, - prot); + ppp_warn(("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, + prot)); else #endif /* #if PPP_PROTOCOLNAME */ - ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot); + ppp_warn(("Protocol-Reject for unsupported protocol 0x%x", prot)); } @@ -621,7 +621,7 @@ static void lcp_protrej(ppp_pcb *pcb) { /* * Can't reject LCP! */ - ppp_error("Received Protocol-Reject for LCP!"); + ppp_error(("Received Protocol-Reject for LCP!")); fsm_protreject(&pcb->lcp_fsm); } @@ -757,7 +757,7 @@ static void lcp_resetci(fsm *f) { #endif /* HAVE_MULTILINK */ if (pcb->settings.noendpoint) ao->neg_endpoint = 0; - pcb->peer_mru = PPP_MRU; + pcb->peer_mru = PPP_DEFMRU; #if 0 /* UNUSED */ auth_reset(pcb); #endif /* UNUSED */ @@ -931,7 +931,7 @@ static void lcp_addci(fsm *f, u_char *ucp, int *lenp) { if (ucp - start_ucp != *lenp) { /* this should never happen, because peer_mtu should be 1500 */ - ppp_error("Bug in lcp_addci: wrong length"); + ppp_error(("Bug in lcp_addci: wrong length")); } } @@ -1363,7 +1363,7 @@ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { * well, that's just strange. Nobody should do that. */ if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap) - ppp_dbglog("Unexpected Conf-Nak for EAP"); + ppp_dbglog(("Unexpected Conf-Nak for EAP")); /* * We don't recognize what they're suggesting. @@ -1498,7 +1498,11 @@ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { goto bad; break; case CI_AUTHTYPE: - if (0 + /* This is potentially dead code (#if !PPP_AUTH_SUPPORT) + * Thus the double parentheses to mark the code explicitly + * disabled when building with clang + */ + if ((0 #if CHAP_SUPPORT || go->neg_chap || no.neg_chap #endif /* CHAP_SUPPORT */ @@ -1508,7 +1512,7 @@ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { #if EAP_SUPPORT || go->neg_eap || no.neg_eap #endif /* EAP_SUPPORT */ - ) + )) goto bad; break; case CI_MAGICNUMBER: @@ -1560,7 +1564,7 @@ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { if (f->state != PPP_FSM_OPENED) { if (looped_back) { if (++try_.numloops >= pcb->settings.lcp_loopbackfail) { - ppp_notice("Serial line is looped back."); + ppp_notice(("Serial line is looped back.")); pcb->err_code = PPPERR_LOOPBACK; lcp_close(f->pcb, "Loopback detected"); } @@ -1843,7 +1847,7 @@ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { * Process all his options. */ next = inp; - nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_UNKNOWN_SIZE), PBUF_RAM); if(NULL == nakp) return 0; if(nakp->tot_len != nakp->len) { @@ -1855,7 +1859,7 @@ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { rejp = inp; while (l) { orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ + cip = p = next; /* Remember beginning of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ @@ -1935,7 +1939,7 @@ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { /* * Reject the option if we're not willing to authenticate. */ - ppp_dbglog("No auth is possible"); + ppp_dbglog(("No auth is possible")); orc = CONFREJ; break; } @@ -2232,7 +2236,7 @@ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { endswitch: if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ + rc != CONFACK) /* but prior CI wasn't? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ @@ -2309,12 +2313,12 @@ static void lcp_up(fsm *f) { * the interface MTU is set to the lowest of that, the * MTU we want to use, and our link MRU. */ - mtu = ho->neg_mru? ho->mru: PPP_MRU; - mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU; + mtu = ho->neg_mru? ho->mru: PPP_DEFMRU; + mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_DEFMRU; #ifdef HAVE_MULTILINK if (!(multilink && go->neg_mrru && ho->neg_mrru)) #endif /* HAVE_MULTILINK */ - netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); + ppp_netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); ppp_send_config(pcb, mtu, (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), ho->neg_pcompression, ho->neg_accompression); @@ -2344,11 +2348,11 @@ static void lcp_down(fsm *f) { link_down(pcb); - ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0); - ppp_recv_config(pcb, PPP_MRU, + ppp_send_config(pcb, PPP_DEFMRU, 0xffffffff, 0, 0); + ppp_recv_config(pcb, PPP_DEFMRU, (go->neg_asyncmap? go->asyncmap: 0xffffffff), go->neg_pcompression, go->neg_accompression); - pcb->peer_mru = PPP_MRU; + pcb->peer_mru = PPP_DEFMRU; } @@ -2639,8 +2643,8 @@ static int lcp_printpkt(const u_char *p, int plen, static void LcpLinkFailure(fsm *f) { ppp_pcb *pcb = f->pcb; if (f->state == PPP_FSM_OPENED) { - ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending); - ppp_notice("Serial link appears to be disconnected."); + ppp_info(("No response to %d echo-requests", pcb->lcp_echos_pending)); + ppp_notice(("Serial link appears to be disconnected.")); pcb->err_code = PPPERR_PEERDEAD; lcp_close(pcb, "Peer not responding"); } @@ -2661,7 +2665,7 @@ static void LcpEchoCheck(fsm *f) { * Start the timer for the next interval. */ if (pcb->lcp_echo_timer_running) - ppp_warn("assertion lcp_echo_timer_running==0 failed"); + ppp_warn(("assertion lcp_echo_timer_running==0 failed")); TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval); pcb->lcp_echo_timer_running = 1; } @@ -2691,13 +2695,13 @@ static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) { /* Check the magic number - don't count replies from ourselves. */ if (len < 4) { - ppp_dbglog("lcp: received short Echo-Reply, length %d", len); + ppp_dbglog(("lcp: received short Echo-Reply, length %d", len)); return; } GETLONG(magic_val, inp); if (go->neg_magicnumber && magic_val == go->magicnumber) { - ppp_warn("appear to have received our own echo-reply!"); + ppp_warn(("appear to have received our own echo-reply!")); return; } diff --git a/src/netif/ppp/magic.c b/src/netif/ppp/magic.c index d0d87c5..ce21326 100644 --- a/src/netif/ppp/magic.c +++ b/src/netif/ppp/magic.c @@ -114,12 +114,12 @@ static void magic_churnrand(char *rand_data, u32_t rand_len) { u32_t rand; #endif /* LWIP_RAND */ } sys_data; + /* Load sys_data fields here. */ magic_randomseed += sys_jiffies(); sys_data.jiffies = magic_randomseed; #ifdef LWIP_RAND sys_data.rand = LWIP_RAND(); #endif /* LWIP_RAND */ - /* Load sys_data fields here. */ lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data)); } lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool); @@ -142,7 +142,7 @@ void magic_randomize(void) { } /* - * magic_random_bytes - Fill a buffer with random bytes. + * Fill a buffer with random bytes. * * Use the random pool to generate random data. This degrades to pseudo * random when used faster than randomness is supplied using magic_churnrand(). @@ -180,58 +180,47 @@ void magic_random_bytes(unsigned char *buf, u32_t buf_len) { } /* - * Return a new random number. + * Return a new 32-bit random number. */ u32_t magic(void) { u32_t new_rand; magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand)); - return new_rand; } #else /* PPP_MD5_RANDM */ -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ #ifndef LWIP_RAND -static int magic_randomized; /* Set when truely randomized. */ +static int magic_randomized; /* Set when truly randomized. */ #endif /* LWIP_RAND */ static u32_t magic_randomseed; /* Seed used for random number generation. */ - -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ - /* * Initialize the random number generator. * * Here we attempt to compute a random number seed but even if * it isn't random, we'll randomize it later. * - * The current method uses the fields from the real time clock, - * the idle process counter, the millisecond counter, and the - * hardware timer tick counter. When this is invoked - * in startup(), then the idle counter and timer values may - * repeat after each boot and the real time clock may not be - * operational. Thus we call it again on the first random - * event. + * The current method uses the jiffies counter. When this is + * invoked at startup the jiffies counter value may repeat + * after each boot. Thus we call it again on the first + * random event. + * + * If LWIP_RAND if available, we do not call srand() as we are + * not going to call rand(). */ void magic_init(void) { magic_randomseed += sys_jiffies(); #ifndef LWIP_RAND - /* Initialize the Borland random number generator. */ + /* Initialize the random number generator. */ srand((unsigned)magic_randomseed); #endif /* LWIP_RAND */ } /* - * magic_init - Initialize the magic number generator. - * * Randomize our random seed value. Here we use the fact that - * this function is called at *truely random* times by the polling + * this function is called at *truly random* times by the polling * and network functions. Here we only get 16 bits of new random * value but we use the previous value to randomize the other 16 * bits. @@ -242,34 +231,37 @@ void magic_randomize(void) { magic_randomized = !0; magic_init(); /* The initialization function also updates the seed. */ - } else { -#endif /* LWIP_RAND */ - magic_randomseed += sys_jiffies(); -#ifndef LWIP_RAND + return; } #endif /* LWIP_RAND */ + magic_randomseed += sys_jiffies(); } /* - * Return a new random number. + * Return a new 32-bit random number. * - * Here we use the Borland rand() function to supply a pseudo random - * number which we make truely random by combining it with our own - * seed which is randomized by truely random events. - * Thus the numbers will be truely random unless there have been no + * Here we use the rand() function to supply a pseudo random + * number which we make truly random by combining it with our own + * seed which is randomized by truly random events. + * Thus the numbers will be truly random unless there have been no * operator or network events in which case it will be pseudo random - * seeded by the real time clock. + * seeded by srand(). + * + * Alternatively, use LWIP_RAND if available, but we do not assume + * it is returning 32 bits of random data because it is probably + * going to be defined to directly return the rand() value. For + * example, LCP magic numbers are 32-bit random values. */ u32_t magic(void) { #ifdef LWIP_RAND - return LWIP_RAND() + magic_randomseed; + return (LWIP_RAND() << 16) + LWIP_RAND() + magic_randomseed; #else /* LWIP_RAND */ return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed; #endif /* LWIP_RAND */ } /* - * magic_random_bytes - Fill a buffer with random bytes. + * Fill a buffer with random bytes. */ void magic_random_bytes(unsigned char *buf, u32_t buf_len) { u32_t new_rand, n; diff --git a/src/netif/ppp/multilink.c b/src/netif/ppp/multilink.c index 62014e8..795d6b5 100644 --- a/src/netif/ppp/multilink.c +++ b/src/netif/ppp/multilink.c @@ -142,18 +142,18 @@ mp_join_bundle() /* not doing multilink */ if (go->neg_mrru) notice("oops, multilink negotiated only for receive"); - mtu = ho->neg_mru? ho->mru: PPP_MRU; + mtu = ho->neg_mru? ho->mru: PPP_DEFMRU; if (mtu > ao->mru) mtu = ao->mru; if (demand) { /* already have a bundle */ cfg_bundle(0, 0, 0, 0); - netif_set_mtu(pcb, mtu); + ppp_netif_set_mtu(pcb, mtu); return 0; } make_new_bundle(0, 0, 0, 0); set_ifunit(1); - netif_set_mtu(pcb, mtu); + ppp_netif_set_mtu(pcb, mtu); return 0; } @@ -198,7 +198,7 @@ mp_join_bundle() mtu = LWIP_MIN(ho->mrru, ao->mru); if (demand) { cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); - netif_set_mtu(pcb, mtu); + ppp_netif_set_mtu(pcb, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); return 0; } @@ -245,7 +245,7 @@ mp_join_bundle() /* we have to make a new bundle */ make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); set_ifunit(1); - netif_set_mtu(pcb, mtu); + ppp_netif_set_mtu(pcb, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); make_bundle_links(pcb); unlock_db(); diff --git a/src/netif/ppp/ppp.c b/src/netif/ppp/ppp.c index be58553..1cd5958 100644 --- a/src/netif/ppp/ppp.c +++ b/src/netif/ppp/ppp.c @@ -255,6 +255,7 @@ void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) { #if PPP_NOTIFY_PHASE void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { + LWIP_ASSERT_CORE_LOCKED(); pcb->notify_phase_cb = notify_phase_cb; notify_phase_cb(pcb, pcb->phase, pcb->ctx_cb); } @@ -476,7 +477,6 @@ static err_t ppp_netif_init_cb(struct netif *netif) { #if PPP_IPV6_SUPPORT netif->output_ip6 = ppp_netif_output_ip6; #endif /* PPP_IPV6_SUPPORT */ - netif->flags = NETIF_FLAG_UP; #if LWIP_NETIF_HOSTNAME /* @todo: Initialize interface hostname */ /* netif_set_hostname(netif, "lwip"); */ @@ -674,9 +674,9 @@ ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, vo #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT +#if PPP_SERVER pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT; pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS; -#if PPP_SERVER pcb->settings.chap_rechallenge_time = CHAP_DEFRECHALLENGETIME; #endif /* PPP_SERVER */ #endif /* CHAP_SUPPPORT */ @@ -710,6 +710,9 @@ ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, vo PPPDEBUG(LOG_ERR, ("ppp_new: netif_add failed\n")); return NULL; } + /* FIXME: user application should be responsible to call netif_set_up(), + * remove it for next release with allowed behavior break */ + netif_set_up(pcb->netif); pcb->link_cb = callbacks; pcb->link_ctx_cb = link_ctx_cb; @@ -776,8 +779,10 @@ void ppp_link_end(ppp_pcb *pcb) { void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { u16_t protocol; #if PPP_DEBUG && PPP_PROTOCOLNAME - const char *pname; + const char *pname; #endif /* PPP_DEBUG && PPP_PROTOCOLNAME */ + LWIP_ASSERT("pcb->phase >= PPP_PHASE_ESTABLISH && pcb->phase <= PPP_PHASE_TERMINATE", + pcb->phase >= PPP_PHASE_ESTABLISH && pcb->phase <= PPP_PHASE_TERMINATE); magic_randomize(); @@ -801,7 +806,7 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { * Toss all non-LCP packets unless LCP is OPEN. */ if (protocol != PPP_LCP && pcb->lcp_fsm.state != PPP_FSM_OPENED) { - ppp_dbglog("Discarded non-LCP packet when LCP not open"); + ppp_dbglog(("Discarded non-LCP packet when LCP not open")); goto drop; } @@ -824,7 +829,7 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { || protocol == PPP_EAP #endif /* EAP_SUPPORT */ )) { - ppp_dbglog("discarding proto 0x%x in phase %d", protocol, pcb->phase); + ppp_dbglog(("discarding proto 0x%x in phase %d", protocol, pcb->phase)); goto drop; } @@ -875,7 +880,7 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { } #endif /* CCP_SUPPORT */ - switch(protocol) { + switch (protocol) { #if PPP_IPV4_SUPPORT case PPP_IP: /* Internet Protocol */ @@ -931,6 +936,10 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (protp->protocol == protocol) { pb = pbuf_coalesce(pb, PBUF_RAW); + if (pb->next != NULL) { + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_coalesce failed), len=%d\n", pcb->netif->num, pb->tot_len)); + goto drop; + } (*protp->input)(pcb, (u8_t*)pb->payload, pb->len); goto out; } @@ -959,18 +968,19 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { #if PPP_PROTOCOLNAME pname = protocol_name(protocol); if (pname != NULL) { - ppp_warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); + ppp_warn(("Unsupported protocol '%s' (0x%x) received", pname, protocol)); } else #endif /* PPP_PROTOCOLNAME */ - ppp_warn("Unsupported protocol 0x%x received", protocol); + ppp_warn(("Unsupported protocol 0x%x received", protocol)); #endif /* PPP_DEBUG */ - if (pbuf_add_header(pb, sizeof(protocol))) { - PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_add_header failed)\n", pcb->netif->num)); - goto drop; - } - lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len); + + if (pbuf_add_header(pb, sizeof(protocol))) { + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_add_header failed)\n", pcb->netif->num)); + goto drop; } - break; + lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len); + } + break; } drop: @@ -1027,13 +1037,13 @@ void new_phase(ppp_pcb *pcb, int p) { */ int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { LWIP_UNUSED_ARG(mtu); - /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */ + + PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num)); if (pcb->link_cb->send_config) { pcb->link_cb->send_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); } - PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num) ); return 0; } @@ -1044,11 +1054,12 @@ int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) { LWIP_UNUSED_ARG(mru); + PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num)); + if (pcb->link_cb->recv_config) { pcb->link_cb->recv_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); } - PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num)); return 0; } @@ -1129,12 +1140,12 @@ int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { nsa = dns_getserver(0); ip_addr_set_ip4_u32_val(nsb, ns1); - if (ip_addr_cmp(nsa, &nsb)) { + if (ip_addr_eq(nsa, &nsb)) { dns_setserver(0, IP_ADDR_ANY); } nsa = dns_getserver(1); ip_addr_set_ip4_u32_val(nsb, ns2); - if (ip_addr_cmp(nsa, &nsb)) { + if (ip_addr_eq(nsa, &nsb)) { dns_setserver(1, IP_ADDR_ANY); } return 1; @@ -1313,18 +1324,21 @@ int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) { #endif /* DEMAND_SUPPORT */ /* - * netif_set_mtu - set the MTU on the PPP network interface. + * ppp_netif_set_mtu - set the MTU on the PPP network interface. */ -void netif_set_mtu(ppp_pcb *pcb, int mtu) { +void ppp_netif_set_mtu(ppp_pcb *pcb, int mtu) { pcb->netif->mtu = mtu; - PPPDEBUG(LOG_INFO, ("netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu)); +#if PPP_IPV6_SUPPORT && LWIP_ND6_ALLOW_RA_UPDATES + pcb->netif->mtu6 = mtu; +#endif /* PPP_IPV6_SUPPORT && LWIP_ND6_ALLOW_RA_UPDATES */ + PPPDEBUG(LOG_INFO, ("ppp_netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu)); } /* - * netif_get_mtu - get PPP interface MTU + * ppp_netif_get_mtu - get PPP interface MTU */ -int netif_get_mtu(ppp_pcb *pcb) { +int ppp_netif_get_mtu(ppp_pcb *pcb) { return pcb->netif->mtu; } diff --git a/src/netif/ppp/pppoe.c b/src/netif/ppp/pppoe.c index 971b36b..9e4f346 100644 --- a/src/netif/ppp/pppoe.c +++ b/src/netif/ppp/pppoe.c @@ -132,7 +132,7 @@ static void pppoe_clear_softc(struct pppoe_softc *, const char *); /* internal timeout handling */ static void pppoe_timeout(void *); -/* sending actual protocol controll packets */ +/* sending actual protocol control packets */ static err_t pppoe_send_padi(struct pppoe_softc *); static err_t pppoe_send_padr(struct pppoe_softc *); #ifdef PPPOE_SERVER @@ -175,12 +175,29 @@ ppp_pcb *pppoe_create(struct netif *pppif, { ppp_pcb *ppp; struct pppoe_softc *sc; -#if !PPPOE_SCNAME_SUPPORT +#if PPPOE_SCNAME_SUPPORT + size_t l; +#else /* PPPOE_SCNAME_SUPPORT */ LWIP_UNUSED_ARG(service_name); LWIP_UNUSED_ARG(concentrator_name); -#endif /* !PPPOE_SCNAME_SUPPORT */ +#endif /* PPPOE_SCNAME_SUPPORT */ LWIP_ASSERT_CORE_LOCKED(); +#if PPPOE_SCNAME_SUPPORT + /* + * Check that service_name and concentrator_name strings length will + * not trigger integer overflows when computing packets length. + */ + l = strlen(service_name); + if (l > 1024) { + return NULL; + } + l = strlen(concentrator_name); + if (l > 1024) { + return NULL; + } +#endif /* PPPOE_SCNAME_SUPPORT */ + sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF); if (sc == NULL) { return NULL; @@ -393,6 +410,10 @@ pppoe_disc_input(struct netif *netif, struct pbuf *pb) } pb = pbuf_coalesce(pb, PBUF_RAW); + if (pb->next != NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: pbuf_coalesce failed: %d\n", pb->tot_len)); + goto done; + } ethhdr = (struct eth_hdr *)pb->payload; @@ -753,20 +774,20 @@ pppoe_send_padi(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; - int len; + size_t len; #if PPPOE_SCNAME_SUPPORT - int l1 = 0, l2 = 0; /* XXX: gcc */ + size_t l1 = 0, l2 = 0; /* XXX: gcc */ #endif /* PPPOE_SCNAME_SUPPORT */ /* calculate length of frame (excluding ethernet header + pppoe header) */ len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ #if PPPOE_SCNAME_SUPPORT if (sc->sc_service_name != NULL) { - l1 = (int)strlen(sc->sc_service_name); + l1 = strlen(sc->sc_service_name); len += l1; } if (sc->sc_concentrator_name != NULL) { - l2 = (int)strlen(sc->sc_concentrator_name); + l2 = strlen(sc->sc_concentrator_name); len += 2 + 2 + l2; } #endif /* PPPOE_SCNAME_SUPPORT */ @@ -848,7 +869,6 @@ pppoe_timeout(void *arg) /* initialize for quick retry mode */ retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); if ((err = pppoe_send_padi(sc)) != 0) { - sc->sc_padi_retried--; PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ } @@ -869,7 +889,6 @@ pppoe_timeout(void *arg) return; } if ((err = pppoe_send_padr(sc)) != 0) { - sc->sc_padr_retried--; PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ } diff --git a/src/netif/ppp/pppol2tp.c b/src/netif/ppp/pppol2tp.c index 4c4557f..2a9a9b1 100644 --- a/src/netif/ppp/pppol2tp.c +++ b/src/netif/ppp/pppol2tp.c @@ -172,6 +172,9 @@ static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { LWIP_UNUSED_ARG(ppp); #endif /* MIB2_STATS */ + /* skip address & flags */ + pbuf_remove_header(p, 2); + ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); if(!ph) { LINK_STATS_INC(link.memerr); @@ -353,7 +356,7 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const goto free_and_return; } - if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { + if (!ip_addr_eq(&l2tp->remote_ip, addr)) { goto free_and_return; } @@ -440,7 +443,7 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", - len, tunnel_id, session_id, ns, nr)); + p->tot_len, tunnel_id, session_id, ns, nr)); /* Control packet */ if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { @@ -463,8 +466,16 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const /* * skip address & flags if necessary * - * RFC 2661 does not specify whether the PPP frame in the L2TP payload should - * have a HDLC header or not. We handle both cases for compatibility. + * RFC 2661 (L2TPv2) does not specify whether the PPP frame in the L2TP payload + * should have a HDLC header or not, both behaviors are seen in the wild. + * + * On the other hand, L2TPv3 draft-ietf-l2tpext-l2tp-ppp versions 00 and 01 say + * it must be included, versions 02 to 05 say it must be omitted, and versions + * 06 and onwards say it should be omitted so it changed along the path when + * L2TPv3 was designed. Latest versions state that receivers must handle both + * cases. + * + * We handle both cases for compatibility. */ if (p->len >= 2) { GETSHORT(hflags, inp); @@ -530,6 +541,11 @@ static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, str l2tp->peer_ns = ns+1; p = pbuf_coalesce(p, PBUF_RAW); + if (p->next != NULL) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: pbuf_coalesce failed: %d\n", p->tot_len)); + return; + } + inp = (u8_t*)p->payload; /* Decode AVPs */ while (p->len > 0) { @@ -749,7 +765,6 @@ static void pppol2tp_timeout(void *arg) { retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { - l2tp->sccrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ } @@ -765,7 +780,6 @@ static void pppol2tp_timeout(void *arg) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); if ((s16_t)(l2tp->peer_nr - l2tp->our_ns) < 0) { /* the SCCCN was not acknowledged */ if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { - l2tp->icrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); @@ -773,7 +787,6 @@ static void pppol2tp_timeout(void *arg) { } } if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { - l2tp->icrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ } @@ -788,7 +801,6 @@ static void pppol2tp_timeout(void *arg) { } PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { - l2tp->iccn_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ } diff --git a/src/netif/ppp/pppos.c b/src/netif/ppp/pppos.c index dff0255..8847536 100644 --- a/src/netif/ppp/pppos.c +++ b/src/netif/ppp/pppos.c @@ -207,10 +207,9 @@ pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) err_t err; LWIP_UNUSED_ARG(ppp); - /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf - gets freed by 'pppos_output_last' before this function returns and thus - cannot starve rx. */ - nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + /* Grab an output buffer. Assume PBUF_POOL_BUFSIZE is an acceptable + * chunk size for Tx as well. */ + nb = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_RAM); if (nb == NULL) { PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num)); LINK_STATS_INC(link.memerr); @@ -220,6 +219,8 @@ pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) return ERR_MEM; } + /* Empty the buffer */ + nb->len = 0; /* Set nb->tot_len to actual payload length */ nb->tot_len = p->len; @@ -258,10 +259,9 @@ pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) err_t err; LWIP_UNUSED_ARG(ppp); - /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf - gets freed by 'pppos_output_last' before this function returns and thus - cannot starve rx. */ - nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + /* Grab an output buffer. Assume PBUF_POOL_BUFSIZE is an acceptable + * chunk size for Tx as well. */ + nb = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_RAM); if (nb == NULL) { PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num)); LINK_STATS_INC(link.memerr); @@ -270,6 +270,8 @@ pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) return ERR_MEM; } + /* Empty the buffer */ + nb->len = 0; /* Set nb->tot_len to actual payload length */ nb->tot_len = pb->tot_len; @@ -420,7 +422,7 @@ pppos_destroy(ppp_pcb *ppp, void *ctx) * @param l length of received data */ err_t -pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l) +pppos_input_tcpip(ppp_pcb *ppp, const void *s, int l) { struct pbuf *p; err_t err; @@ -445,7 +447,7 @@ err_t pppos_input_sys(struct pbuf *p, struct netif *inp) { LWIP_ASSERT_CORE_LOCKED(); for (n = p; n; n = n->next) { - pppos_input(ppp, (u8_t*)n->payload, n->len); + pppos_input(ppp, n->payload, n->len); } pbuf_free(p); return ERR_OK; @@ -475,10 +477,11 @@ PACK_STRUCT_END * @param l length of received data */ void -pppos_input(ppp_pcb *ppp, u8_t *s, int l) +pppos_input(ppp_pcb *ppp, const void *s, int l) { pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; struct pbuf *next_pbuf; + const u8_t *s_u8 = (const u8_t *)s; u8_t cur_char; u8_t escaped; PPPOS_DECL_PROTECT(lev); @@ -486,22 +489,24 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) LWIP_ASSERT_CORE_LOCKED(); #endif + /* Don't even bother parsing data if we are disconnected. + * Added to that, ppp_input must never be called if the upper layer is down. + */ + PPPOS_PROTECT(lev); + if (!pppos->open) { + PPPOS_UNPROTECT(lev); + return; + } + PPPOS_UNPROTECT(lev); + PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l)); while (l-- > 0) { - cur_char = *s++; + cur_char = *s_u8++; PPPOS_PROTECT(lev); - /* ppp_input can disconnect the interface, we need to abort to prevent a memory - * leak if there are remaining bytes because pppos_connect and pppos_listen - * functions expect input buffer to be free. Furthermore there are no real - * reason to continue reading bytes if we are disconnected. - */ - if (!pppos->open) { - PPPOS_UNPROTECT(lev); - return; - } escaped = ESCAPE_P(pppos->in_accm, cur_char); PPPOS_UNPROTECT(lev); + /* Handle special characters. */ if (escaped) { /* Check for escape sequences. */ @@ -531,6 +536,12 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ LINK_STATS_INC(link.chkerr); pppos_input_drop(pppos); + } else if (!pppos->in_tail) { + PPPDEBUG(LOG_INFO, + ("pppos_input[%d]: Dropping null in_tail\n", + ppp->netif->num)); + LINK_STATS_INC(link.drop); + pppos_input_drop(pppos); /* Otherwise it's a good packet so pass it on. */ } else { struct pbuf *inp; @@ -558,7 +569,16 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) pppos->in_tail = NULL; #if IP_FORWARD || LWIP_IPV6_FORWARD /* hide the room for Ethernet forwarding header */ - pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN); + if (0 +#if PPP_IPV4_SUPPORT + || pppos->in_protocol == PPP_IP +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || pppos->in_protocol == PPP_IPV6 +#endif /* PPP_IPV6_SUPPORT */ + ) { + pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN); + } #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ #if PPP_INPROC_IRQ_SAFE if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) { @@ -569,6 +589,14 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) } #else /* PPP_INPROC_IRQ_SAFE */ ppp_input(ppp, inp); + /* ppp_input can disconnect the interface, we need to abort to prevent a memory + * leak if there are remaining bytes because pppos_connect and pppos_listen + * functions expect input buffer to be free. Furthermore there are no real + * reason to continue reading bytes if we are disconnected. + */ + if (!pppos->open) { + break; + } #endif /* PPP_INPROC_IRQ_SAFE */ } @@ -591,50 +619,24 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) } /* Process character relative to current state. */ - switch(pppos->in_state) { - case PDIDLE: /* Idle state - waiting. */ - /* Drop the character if it's not 0xff - * we would have processed a flag character above. */ - if (cur_char != PPP_ALLSTATIONS) { - break; - } - /* no break */ - /* Fall through */ - - case PDSTART: /* Process start flag. */ - /* Prepare for a new packet. */ - pppos->in_fcs = PPP_INITFCS; - /* no break */ - /* Fall through */ - + switch (pppos->in_state) { + case PDIDLE: /* Idle state - wait for flag character. */ + break; case PDADDRESS: /* Process address field. */ if (cur_char == PPP_ALLSTATIONS) { pppos->in_state = PDCONTROL; break; } - /* no break */ - /* Else assume compressed address and control fields so * fall through to get the protocol... */ /* Fall through */ case PDCONTROL: /* Process control field. */ - /* If we don't get a valid control code, restart. */ if (cur_char == PPP_UI) { pppos->in_state = PDPROTOCOL1; break; } - /* no break */ - -#if 0 - else { - PPPDEBUG(LOG_WARNING, - ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char)); - pppos->in_state = PDSTART; - } -#endif /* Fall through */ - - case PDPROTOCOL1: /* Process protocol field 1. */ + case PDPROTOCOL1: /* Process protocol field 1. */ /* If the lower bit is set, this is the end of the protocol * field. */ if (cur_char & 1) { @@ -654,12 +656,37 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) { u16_t pbuf_alloc_len; if (pppos->in_tail != NULL) { + u16_t mru; pppos->in_tail->tot_len = pppos->in_tail->len; if (pppos->in_tail != pppos->in_head) { pbuf_cat(pppos->in_head, pppos->in_tail); /* give up the in_tail reference now */ pppos->in_tail = NULL; } + /* Compute MRU including headers length. If smaller packets are + * requested, we must still be able to receive packets of the + * default MRU for control packets. */ + mru = LWIP_MAX(PPP_MRU, PPP_DEFMRU) + /* Add 10% more. We only want to avoid filling all PBUFs with garbage, + * we don't have to be pedantic. */ + + LWIP_MAX(PPP_MRU, PPP_DEFMRU)/10 +#if IP_FORWARD || LWIP_IPV6_FORWARD + + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN +#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ +#if PPP_INPROC_IRQ_SAFE + + sizeof(struct pppos_input_header) +#endif /* PPP_INPROC_IRQ_SAFE */ + + sizeof(pppos->in_protocol); + if (pppos->in_head->tot_len > mru) { + /* Packet too big. Drop the input packet and let the + * higher layers deal with it. Continue processing + * received characters in case a new packet starts. */ + PPPDEBUG(LOG_ERR, ("pppos_input[%d]: packet too big, max_len=%d, dropping packet\n", ppp->netif->num, mru)); + LINK_STATS_INC(link.lenerr); + pppos_input_drop(pppos); + pppos->in_state = PDIDLE; /* Wait for flag character. */ + break; + } } /* If we haven't started a packet, we need a packet header. */ pbuf_alloc_len = 0; @@ -668,7 +695,14 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header * space to be forwarded (to Ethernet for example). */ - if (pppos->in_head == NULL) { + if (pppos->in_head == NULL && (0 +#if PPP_IPV4_SUPPORT + || pppos->in_protocol == PPP_IP +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || pppos->in_protocol == PPP_IPV6 +#endif /* PPP_IPV6_SUPPORT */ + )) { pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; } #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ @@ -676,11 +710,11 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) if (next_pbuf == NULL) { /* No free buffers. Drop the input packet and let the * higher layers deal with it. Continue processing - * the received pbuf chain in case a new packet starts. */ + * received characters in case a new packet starts. */ PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num)); LINK_STATS_INC(link.memerr); pppos_input_drop(pppos); - pppos->in_state = PDSTART; /* Wait for flag sequence. */ + pppos->in_state = PDIDLE; /* Wait for flag character. */ break; } if (pppos->in_head == NULL) { @@ -716,10 +750,21 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l) static void pppos_input_callback(void *arg) { struct pbuf *pb = (struct pbuf*)arg; ppp_pcb *ppp; + pppos_pcb *pppos; ppp = ((struct pppos_input_header*)pb->payload)->ppp; if(pbuf_remove_header(pb, sizeof(struct pppos_input_header))) { - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); + goto drop; + } + + /* A previous call to ppp_input might have disconnected the session + * while there were still packets in flight in the tcpip mailbox. + * Drop incoming packets because ppp_input must never be called if + * the upper layer is down. + */ + pppos = (pppos_pcb *)ppp->link_ctx_cb; + if (!pppos->open) { goto drop; } @@ -830,7 +875,7 @@ pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t a * Sure we don't quite fill the buffer if the character doesn't * get escaped but is one character worth complicating this? */ if ((PBUF_POOL_BUFSIZE - nb->len) < 2) { - u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb); + u32_t l = pppos->output_cb(pppos->ppp, nb->payload, nb->len, pppos->ppp->ctx_cb); if (l != nb->len) { return ERR_IF; } @@ -869,7 +914,7 @@ pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs) /* Send remaining buffer if not empty */ if (nb->len > 0) { - u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb); + u32_t l = pppos->output_cb(ppp, nb->payload, nb->len, ppp->ctx_cb); if (l != nb->len) { err = ERR_IF; goto failed; diff --git a/src/netif/ppp/upap.c b/src/netif/ppp/upap.c index 3b2399d..c8cd394 100644 --- a/src/netif/ppp/upap.c +++ b/src/netif/ppp/upap.c @@ -206,7 +206,7 @@ static void upap_timeout(void *arg) { if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) { /* give up in disgust */ - ppp_error("No response to PAP authenticate-requests"); + ppp_error(("No response to PAP authenticate-requests")); pcb->upap.us_clientstate = UPAPCS_BADAUTH; auth_withpeer_fail(pcb, PPP_PAP); return; @@ -286,12 +286,12 @@ static void upap_lowerdown(ppp_pcb *pcb) { static void upap_protrej(ppp_pcb *pcb) { if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) { - ppp_error("PAP authentication failed due to protocol-reject"); + ppp_error(("PAP authentication failed due to protocol-reject")); auth_withpeer_fail(pcb, PPP_PAP); } #if PPP_SERVER if (pcb->upap.us_serverstate == UPAPSS_LISTEN) { - ppp_error("PAP authentication of peer failed (protocol-reject)"); + ppp_error(("PAP authentication of peer failed (protocol-reject)")); auth_peer_fail(pcb, PPP_PAP); } #endif /* PPP_SERVER */ @@ -439,11 +439,11 @@ static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) { if (retcode == UPAP_AUTHACK) { pcb->upap.us_serverstate = UPAPSS_OPEN; - ppp_notice("PAP peer authentication succeeded for %q", rhostname); + ppp_notice(("PAP peer authentication succeeded for %q", rhostname)); auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen); } else { pcb->upap.us_serverstate = UPAPSS_BADAUTH; - ppp_warn("PAP peer authentication failed for %q", rhostname); + ppp_warn(("PAP peer authentication failed for %q", rhostname)); auth_peer_fail(pcb, PPP_PAP); } @@ -481,6 +481,7 @@ static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) { } } + UNTIMEOUT(upap_timeout, pcb); pcb->upap.us_clientstate = UPAPCS_OPEN; auth_withpeer_success(pcb, PPP_PAP, 0); @@ -516,9 +517,10 @@ static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) { } } + UNTIMEOUT(upap_timeout, pcb); pcb->upap.us_clientstate = UPAPCS_BADAUTH; - ppp_error("PAP authentication failed"); + ppp_error(("PAP authentication failed")); auth_withpeer_fail(pcb, PPP_PAP); } @@ -533,7 +535,7 @@ static void upap_sauthreq(ppp_pcb *pcb) { outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + pcb->upap.us_userlen + pcb->upap.us_passwdlen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { @@ -570,7 +572,7 @@ static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, in int outlen; outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM); if(NULL == p) return; if(p->tot_len != p->len) { diff --git a/src/netif/ppp/utils.c b/src/netif/ppp/utils.c index f1366da..99a5fb1 100644 --- a/src/netif/ppp/utils.c +++ b/src/netif/ppp/utils.c @@ -629,7 +629,7 @@ static void ppp_log_write(int level, char *buf) { /* * ppp_fatal - log an error message and die horribly. */ -void ppp_fatal(const char *fmt, ...) { +void ppp_fatal_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -642,7 +642,7 @@ void ppp_fatal(const char *fmt, ...) { /* * ppp_error - log an error message. */ -void ppp_error(const char *fmt, ...) { +void ppp_error_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -656,7 +656,7 @@ void ppp_error(const char *fmt, ...) { /* * ppp_warn - log a warning message. */ -void ppp_warn(const char *fmt, ...) { +void ppp_warn_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -667,7 +667,7 @@ void ppp_warn(const char *fmt, ...) { /* * ppp_notice - log a notice-level message. */ -void ppp_notice(const char *fmt, ...) { +void ppp_notice_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -678,7 +678,7 @@ void ppp_notice(const char *fmt, ...) { /* * ppp_info - log an informational message. */ -void ppp_info(const char *fmt, ...) { +void ppp_info_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -689,7 +689,7 @@ void ppp_info(const char *fmt, ...) { /* * ppp_dbglog - log a debug message. */ -void ppp_dbglog(const char *fmt, ...) { +void ppp_dbglog_impl(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); @@ -724,7 +724,7 @@ void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) { return; } - ppp_dbglog("%s %P", tag, p, len); + ppp_dbglog(("%s %P", tag, p, len)); } #endif /* PRINTPKT_SUPPORT */ @@ -788,9 +788,9 @@ lock(dev) } if (result > 0) - ppp_notice("Device %s is locked by pid %d", dev, result); + ppp_notice(("Device %s is locked by pid %d", dev, result)); else - ppp_error("Can't create lock file %s", lock_file); + ppp_error(("Can't create lock file %s", lock_file)); return -1; #else /* LOCKLIB */ @@ -802,11 +802,11 @@ lock(dev) struct stat sbuf; if (stat(dev, &sbuf) < 0) { - ppp_error("Can't get device number for %s: %m", dev); + ppp_error(("Can't get device number for %s: %m", dev)); return -1; } if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { - ppp_error("Can't lock %s: not a character device", dev); + ppp_error(("Can't lock %s: not a character device", dev)); return -1; } ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", @@ -833,7 +833,7 @@ lock(dev) while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { if (errno != EEXIST) { - ppp_error("Can't create lock file %s: %m", lock_file); + ppp_error(("Can't create lock file %s: %m", lock_file)); break; } @@ -842,7 +842,7 @@ lock(dev) if (fd < 0) { if (errno == ENOENT) /* This is just a timing problem. */ continue; - ppp_error("Can't open existing lock file %s: %m", lock_file); + ppp_error(("Can't open existing lock file %s: %m", lock_file)); break; } #ifndef LOCK_BINARY @@ -853,7 +853,7 @@ lock(dev) close(fd); fd = -1; if (n <= 0) { - ppp_error("Can't read pid from lock file %s", lock_file); + ppp_error(("Can't read pid from lock file %s", lock_file)); break; } @@ -867,12 +867,12 @@ lock(dev) if (pid == 0 || (kill(pid, 0) == -1 && errno == ESRCH)) { if (unlink (lock_file) == 0) { - ppp_notice("Removed stale lock on %s (pid %d)", dev, pid); + ppp_notice(("Removed stale lock on %s (pid %d)", dev, pid)); continue; } - ppp_warn("Couldn't remove stale lock on %s", dev); + ppp_warn(("Couldn't remove stale lock on %s", dev)); } else - ppp_notice("Device %s is locked by pid %d", dev, pid); + ppp_notice(("Device %s is locked by pid %d", dev, pid)); break; } @@ -919,7 +919,7 @@ relock(pid) return -1; fd = open(lock_file, O_WRONLY, 0); if (fd < 0) { - ppp_error("Couldn't reopen lock file %s: %m", lock_file); + ppp_error(("Couldn't reopen lock file %s: %m", lock_file)); lock_file[0] = 0; return -1; } diff --git a/src/netif/ppp/vj.c b/src/netif/ppp/vj.c index 3fecba6..7b6f8ea 100644 --- a/src/netif/ppp/vj.c +++ b/src/netif/ppp/vj.c @@ -15,7 +15,7 @@ * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * Initial distribution. @@ -218,8 +218,8 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) * again & we don't have to do any reordering if it's used. */ INCR(vjs_packets); - if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src) - || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + if (!ip4_addr_eq(&ip->src, &cs->cs_ip.src) + || !ip4_addr_eq(&ip->dest, &cs->cs_ip.dest) || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { /* * Wasn't the first -- search for it. @@ -239,8 +239,8 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) do { lcs = cs; cs = cs->cs_next; INCR(vjs_searches); - if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src) - && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + if (ip4_addr_eq(&ip->src, &cs->cs_ip.src) + && ip4_addr_eq(&ip->dest, &cs->cs_ip.dest) && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { goto found; } @@ -409,7 +409,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) hlen -= deltaS + 4; if (pbuf_remove_header(np, hlen)){ /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); } cp = (u8_t*)np->payload; *cp++ = (u8_t)(changes | NEW_C); @@ -418,7 +418,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) hlen -= deltaS + 3; if (pbuf_remove_header(np, hlen)) { /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); } cp = (u8_t*)np->payload; *cp++ = (u8_t)changes; @@ -621,7 +621,7 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) /* Remove the compressed header and prepend the uncompressed header. */ if (pbuf_remove_header(n0, vjlen)) { /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); goto bad; } @@ -644,7 +644,7 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) if (pbuf_remove_header(np, cs->cs_hlen)) { /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); + LWIP_ASSERT("pbuf_remove_header failed", 0); goto bad; } diff --git a/src/netif/slipif.c b/src/netif/slipif.c index 9b175dc..c8e4eb3 100644 --- a/src/netif/slipif.c +++ b/src/netif/slipif.c @@ -46,12 +46,12 @@ * This is an arch independent SLIP netif. The specific serial hooks must be * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send * - * Usage: This netif can be used in three ways:\n - * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() - * until data is received.\n - * 2) In your main loop, call slipif_poll() to check for new RX bytes, - * completed packets are fed into netif->input().\n - * 3) Call slipif_received_byte[s]() from your serial RX ISR and + * Usage: This netif can be used in three ways: + * 1. For NO_SYS==0, an RX thread can be used which blocks on sio_read() + * until data is received. + * 2. In your main loop, call slipif_poll() to check for new RX bytes, + * completed packets are fed into netif->input(). + * 3. Call slipif_received_byte[s]() from your serial RX ISR and * slipif_process_rxqueue() from your main loop. ISR level decodes * packets and puts completed packets on a queue which is fed into * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile index ccbe956..05a4f63 100644 --- a/test/fuzz/Makefile +++ b/test/fuzz/Makefile @@ -29,26 +29,45 @@ # Author: Adam Dunkels # -all compile: lwip_fuzz +all compile: lwip_fuzz lwip_fuzz2 lwip_fuzz3 .PHONY: all clean +ifeq ($(origin CC), default) CC=afl-gcc +endif + LDFLAGS=-lm # use 'make D=-DUSER_DEFINE' to pass a user define to gcc -CFLAGS=-O0 $(D) +CFLAGS=-O2 $(D) -CONTRIBDIR=../../../lwip-contrib +LWIPDIR=../../src +CONTRIBDIR=../../contrib include $(CONTRIBDIR)/ports/unix/Common.mk +DEPFILES=.depend_fuzz .depend_lwip .depend_app + clean: - rm -f *.o $(LWIPLIBCOMMON) $(APPLIB) lwip_fuzz *.s .depend* *.core core + rm -f *.o $(LWIPLIBCOMMON) $(APPLIB) lwip_fuzz lwip_fuzz2 lwip_fuzz3 *.s $(DEPFILES) *.core core + +depend dep: $(DEPFILES) + @true + +ifneq ($(MAKECMDGOALS),clean) +include $(DEPFILES) +endif -depend dep: .depend +.depend_fuzz: fuzz.c fuzz2.c fuzz3.c fuzz_common.c + $(CCDEP) $(CFLAGS) -MM $^ > .depend_fuzz || rm -f .depend_fuzz +.depend_lwip: $(LWIPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend_lwip || rm -f .depend_lwip +.depend_app: $(APPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend_app || rm -f .depend_app -include .depend +lwip_fuzz: $(DEPFILES) $(LWIPLIBCOMMON) $(APPLIB) fuzz.o fuzz_common.o + $(CC) $(CFLAGS) -o lwip_fuzz fuzz.o fuzz_common.o $(APPLIB) $(LWIPLIBCOMMON) $(LDFLAGS) -.depend: fuzz.c $(LWIPFILES) $(APPFILES) - $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend +lwip_fuzz2: $(DEPFILES) $(LWIPLIBCOMMON) $(APPLIB) fuzz2.o fuzz_common.o + $(CC) $(CFLAGS) -o lwip_fuzz2 fuzz2.o fuzz_common.o $(APPLIB) $(LWIPLIBCOMMON) $(LDFLAGS) -lwip_fuzz: .depend $(LWIPLIBCOMMON) $(APPLIB) fuzz.o - $(CC) $(CFLAGS) -o lwip_fuzz fuzz.o $(APPLIB) $(LWIPLIBCOMMON) $(LDFLAGS) +lwip_fuzz3: $(DEPFILES) $(LWIPLIBCOMMON) $(APPLIB) fuzz3.o fuzz_common.o + $(CC) $(CFLAGS) -o lwip_fuzz3 fuzz3.o fuzz_common.o $(APPLIB) $(LWIPLIBCOMMON) $(LDFLAGS) diff --git a/test/fuzz/README b/test/fuzz/README index de6fb75..a3b2eee 100644 --- a/test/fuzz/README +++ b/test/fuzz/README @@ -1,17 +1,15 @@ Fuzzing the lwIP stack (afl-fuzz requires linux/unix or similar) -This directory contains a small app that reads Ethernet frames from stdin and -processes them. It is used together with the 'american fuzzy lop' tool (found -at http://lcamtuf.coredump.cx/afl/) and the sample inputs to test how +This directory contains small apps that read Ethernet frames from stdin and +process them. They are used together with the 'american fuzzy lop' tool (found +at https://lcamtuf.coredump.cx/afl/) or its successor AFL++ +(https://github.com/AFLplusplus/AFLplusplus) and the sample inputs to test how unexpected inputs are handled. The afl tool will read the known inputs, and try to modify them to exercise as many code paths as possible, by instrumenting the code and keeping track of which code is executed. -Just running make will produce the test program. - -Running make with parameter 'D=-DLWIP_FUZZ_MULTI_PACKET' will produce a binary -that parses the input data as multiple packets (experimental!). +Just running make will produce the test programs. Then run afl with: @@ -34,4 +32,3 @@ file to simplify viewing in wireshark. The lwipopts.h file needs to have checksum checking off, otherwise almost every packet will be discarded because of that. The other options can be tuned to expose different parts of the code. - diff --git a/test/fuzz/fuzz.c b/test/fuzz/fuzz.c index 8aa07ec..8eb453f 100644 --- a/test/fuzz/fuzz.c +++ b/test/fuzz/fuzz.c @@ -27,163 +27,13 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Erik Ekman + * Simon Goldschmidt * */ -#include "lwip/init.h" -#include "lwip/netif.h" -#include "lwip/dns.h" -#include "netif/etharp.h" -#if LWIP_IPV6 -#include "lwip/ethip6.h" -#include "lwip/nd6.h" -#endif - -#include "lwip/apps/httpd.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/lwiperf.h" -#include "lwip/apps/mdns.h" - -#include -#include - -/* This define enables multi packet processing. - * For this, the input is interpreted as 2 byte length + data + 2 byte length + data... - * #define LWIP_FUZZ_MULTI_PACKET -*/ -#ifdef LWIP_FUZZ_MULTI_PACKET -u8_t pktbuf[20000]; -#else -u8_t pktbuf[2000]; -#endif - -/* no-op send function */ -static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) -{ - LWIP_UNUSED_ARG(netif); - LWIP_UNUSED_ARG(p); - return ERR_OK; -} - -static err_t testif_init(struct netif *netif) -{ - netif->name[0] = 'f'; - netif->name[1] = 'z'; - netif->output = etharp_output; - netif->linkoutput = lwip_tx_func; - netif->mtu = 1500; - netif->hwaddr_len = 6; - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; - - netif->hwaddr[0] = 0x00; - netif->hwaddr[1] = 0x23; - netif->hwaddr[2] = 0xC1; - netif->hwaddr[3] = 0xDE; - netif->hwaddr[4] = 0xD0; - netif->hwaddr[5] = 0x0D; - -#if LWIP_IPV6 - netif->output_ip6 = ethip6_output; - netif->ip6_autoconfig_enabled = 1; - netif_create_ip6_linklocal_address(netif, 1); - netif->flags |= NETIF_FLAG_MLD6; -#endif - - return ERR_OK; -} - -static void input_pkt(struct netif *netif, const u8_t *data, size_t len) -{ - struct pbuf *p, *q; - err_t err; - - LWIP_ASSERT("pkt too big", len <= 0xFFFF); - p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); - LWIP_ASSERT("alloc failed", p); - for(q = p; q != NULL; q = q->next) { - MEMCPY(q->payload, data, q->len); - data += q->len; - } - err = netif->input(p, netif); - if (err != ERR_OK) { - pbuf_free(p); - } -} - -static void input_pkts(struct netif *netif, const u8_t *data, size_t len) -{ -#ifdef LWIP_FUZZ_MULTI_PACKET - const u16_t max_packet_size = 1514; - const u8_t *ptr = data; - size_t rem_len = len; - - while (rem_len > sizeof(u16_t)) { - u16_t frame_len; - memcpy(&frame_len, ptr, sizeof(u16_t)); - ptr += sizeof(u16_t); - rem_len -= sizeof(u16_t); - frame_len = htons(frame_len) & 0x7FF; - frame_len = LWIP_MIN(frame_len, max_packet_size); - if (frame_len > rem_len) { - frame_len = (u16_t)rem_len; - } - if (frame_len != 0) { - input_pkt(netif, ptr, frame_len); - } - ptr += frame_len; - rem_len -= frame_len; - } -#else /* LWIP_FUZZ_MULTI_PACKET */ - input_pkt(netif, data, len); -#endif /* LWIP_FUZZ_MULTI_PACKET */ -} +#include "fuzz_common.h" int main(int argc, char** argv) { - struct netif net_test; - ip4_addr_t addr; - ip4_addr_t netmask; - ip4_addr_t gw; - size_t len; - - lwip_init(); - - IP4_ADDR(&addr, 172, 30, 115, 84); - IP4_ADDR(&netmask, 255, 255, 255, 0); - IP4_ADDR(&gw, 172, 30, 115, 1); - - netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); - netif_set_up(&net_test); - netif_set_link_up(&net_test); - -#if LWIP_IPV6 - nd6_tmr(); /* tick nd to join multicast groups */ -#endif - dns_setserver(0, &net_test.gw); - - /* initialize apps */ - httpd_init(); - lwiperf_start_tcp_server_default(NULL, NULL); - mdns_resp_init(); - mdns_resp_add_netif(&net_test, "hostname", 255); - snmp_init(); - - if(argc > 1) { - FILE* f; - const char* filename; - printf("reading input from file... "); - fflush(stdout); - filename = argv[1]; - LWIP_ASSERT("invalid filename", filename != NULL); - f = fopen(filename, "rb"); - LWIP_ASSERT("open failed", f != NULL); - len = fread(pktbuf, 1, sizeof(pktbuf), f); - fclose(f); - printf("testing file: \"%s\"...\r\n", filename); - } else { - len = fread(pktbuf, 1, sizeof(pktbuf), stdin); - } - input_pkts(&net_test, pktbuf, len); - - return 0; + return lwip_fuzztest(argc, argv, LWIP_FUZZ_SINGLE, LWIP_FUZZ_DEFAULT); } diff --git a/test/fuzz/fuzz2.c b/test/fuzz/fuzz2.c new file mode 100644 index 0000000..b6a9ceb --- /dev/null +++ b/test/fuzz/fuzz2.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Simon Goldschmidt + * + */ + +#include "fuzz_common.h" + +int main(int argc, char** argv) +{ + return lwip_fuzztest(argc, argv, LWIP_FUZZ_MULTIPACKET, LWIP_FUZZ_DEFAULT); +} diff --git a/test/fuzz/fuzz3.c b/test/fuzz/fuzz3.c new file mode 100644 index 0000000..fc22991 --- /dev/null +++ b/test/fuzz/fuzz3.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Simon Goldschmidt + * + */ + +#include "fuzz_common.h" + +int main(int argc, char** argv) +{ + return lwip_fuzztest(argc, argv, LWIP_FUZZ_MULTIPACKET_TIME, + LWIP_FUZZ_STATICARP|LWIP_FUZZ_TCP_SERVER|LWIP_FUZZ_TCP_CLIENT|LWIP_FUZZ_UDP_SERVER|LWIP_FUZZ_UDP_CLIENT); +} diff --git a/test/fuzz/fuzz_common.c b/test/fuzz/fuzz_common.c new file mode 100644 index 0000000..ef00e9d --- /dev/null +++ b/test/fuzz/fuzz_common.c @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * Simon Goldschmidt + * + */ + +#include "fuzz_common.h" + +#include "lwip/altcp_tcp.h" +#include "lwip/dns.h" +#include "lwip/init.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/udp.h" +#include "netif/etharp.h" +#if LWIP_IPV6 +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#endif + +#include "lwip/apps/httpd.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/lwiperf.h" +#include "lwip/apps/mdns.h" + +#include +#include + +static u8_t pktbuf[200000]; +static const u8_t *remfuzz_ptr; /* remaining fuzz pointer */ +static size_t remfuzz_len; /* remaining fuzz length */ + +#ifndef FUZZ_DEBUG +#define FUZZ_DEBUG LWIP_DBG_OFF +#endif + +#ifdef LWIP_FUZZ_SYS_NOW +/* This offset should be added to the time 'sys_now()' returns */ +u32_t sys_now_offset; +#endif + +/** Set this to 1 and define FUZZ_DUMP_PCAP_FILE to dump tx and rx packets into + * a pcap file. At the same time, packet info is written via LWIP_DEBUGF so + * packets can be matched to other events for debugging them. + */ +#ifndef FUZZ_DUMP_PCAP +#define FUZZ_DUMP_PCAP 0 +#endif + +#if FUZZ_DUMP_PCAP +const u8_t pcap_file_header[24] = { + 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00 +}; + +static FILE* fpcap; +static u32_t pcap_packet; + +static void pcap_dump_init(void) +{ + fpcap = fopen(FUZZ_DUMP_PCAP_FILE, "wb"); + if (fpcap != NULL) { + /* write header */ + fwrite(pcap_file_header, 1, sizeof(pcap_file_header), fpcap); + } +} + +/* This function might have to be called from LWIP_PLATFORM_ASSERT() + * in order to produce correct pcap results on crash. + * Define this global so that for a test, we can call this from anywhere... + */ +void pcap_dump_stop(void); +void pcap_dump_stop(void) +{ + if (fpcap != NULL) { + fclose(fpcap); + fpcap = NULL; + } +} + +static void pcap_dump_packet(struct pbuf *p, int is_tx) +{ + if (fpcap != NULL) { + struct pbuf *q; + u32_t data; + pcap_packet++; + if (is_tx) { + LWIP_DEBUGF(FUZZ_DEBUG, ("> %d fuzz: netif: send %u bytes\n", pcap_packet, p->tot_len)); + } else { + LWIP_DEBUGF(FUZZ_DEBUG, ("< %d fuzz: RX packet of %u bytes\n", pcap_packet, p->tot_len)); + if (pcap_packet == 50 || pcap_packet == 33 || pcap_packet == 29) { + pcap_packet++; + pcap_packet--; + } + } + /* write packet header */ + fwrite(&pcap_packet, 1, sizeof(pcap_packet), fpcap); + data = 0; + fwrite(&data, 1, sizeof(data), fpcap); + data = p->tot_len; + fwrite(&data, 1, sizeof(data), fpcap); + fwrite(&data, 1, sizeof(data), fpcap); + /* write packet data */ + for(q = p; q != NULL; q = q->next) { + fwrite(q->payload, 1, q->len, fpcap); + } + } +} + +static void pcap_dump_rx_packet(struct pbuf *p) +{ + pcap_dump_packet(p, 0); +} + +static void pcap_dump_tx_packet(struct pbuf *p) +{ + pcap_dump_packet(p, 1); +} +#else /* FUZZ_DUMP_PCAP */ +#define pcap_dump_rx_packet(p) +#define pcap_dump_tx_packet(p) +#define pcap_dump_init() +#define pcap_dump_stop() +#endif /* FUZZ_DUMP_PCAP */ + +/* no-op send function */ +static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) +{ + pcap_dump_tx_packet(p); + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(p); + return ERR_OK; +} + +static err_t testif_init(struct netif *netif) +{ + netif->name[0] = 'f'; + netif->name[1] = 'z'; + netif->output = etharp_output; + netif->linkoutput = lwip_tx_func; + netif->mtu = 1500; + netif->hwaddr_len = 6; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; + + netif->hwaddr[0] = 0x00; + netif->hwaddr[1] = 0x23; + netif->hwaddr[2] = 0xC1; + netif->hwaddr[3] = 0xDE; + netif->hwaddr[4] = 0xD0; + netif->hwaddr[5] = 0x0D; + +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; + netif_create_ip6_linklocal_address(netif, 1); + netif->flags |= NETIF_FLAG_MLD6; +#endif + + return ERR_OK; +} + +static void input_pkt(struct netif *netif, const u8_t *data, size_t len) +{ + struct pbuf *p, *q; + err_t err; + + if (len > 0xFFFF) { + printf("pkt too big (%#zX bytes)\n", len); + return; + } + + p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); + LWIP_ASSERT("alloc failed", p); + for(q = p; q != NULL; q = q->next) { + MEMCPY(q->payload, data, q->len); + data += q->len; + } + remfuzz_ptr += len; + remfuzz_len -= len; + pcap_dump_rx_packet(p); + err = netif->input(p, netif); + if (err != ERR_OK) { + pbuf_free(p); + } +} + +static void input_pkts(enum lwip_fuzz_type type, struct netif *netif, const u8_t *data, size_t len) +{ + size_t packet_nr = 0; + remfuzz_ptr = data; + remfuzz_len = len; + + if (type == LWIP_FUZZ_SINGLE) { + input_pkt(netif, data, len); + } else { + const u16_t max_packet_size = 1514; + const size_t minlen = sizeof(u16_t) + (type == LWIP_FUZZ_MULTIPACKET_TIME ? sizeof(u32_t) : 0); + + while (remfuzz_len > minlen) { + u16_t frame_len; +#ifdef LWIP_FUZZ_SYS_NOW + u32_t external_delay = 0; +#endif + packet_nr++; + if (type == LWIP_FUZZ_MULTIPACKET_TIME) { +#ifdef LWIP_FUZZ_SYS_NOW + /* Extract external delay time from fuzz pool */ + memcpy(&external_delay, remfuzz_ptr, sizeof(u32_t)); + external_delay = ntohl(external_delay); +#endif + remfuzz_ptr += sizeof(u32_t); + remfuzz_len -= sizeof(u32_t); + } + memcpy(&frame_len, remfuzz_ptr, sizeof(u16_t)); + remfuzz_ptr += sizeof(u16_t); + remfuzz_len -= sizeof(u16_t); + frame_len = ntohs(frame_len) & 0x7FF; + frame_len = LWIP_MIN(frame_len, max_packet_size); + if (frame_len > remfuzz_len) { + frame_len = (u16_t)remfuzz_len; + } + if (frame_len != 0) { + if (type == LWIP_FUZZ_MULTIPACKET_TIME) { +#ifdef LWIP_FUZZ_SYS_NOW + /* Update total external delay time, and check timeouts */ + sys_now_offset += external_delay; + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: sys_now_offset += %u -> %u\n", external_delay, sys_now_offset)); +#endif + sys_check_timeouts(); + } + input_pkt(netif, remfuzz_ptr, frame_len); + /* Check timeouts again */ + sys_check_timeouts(); + } + } + } +} + +#if LWIP_TCP +static struct altcp_pcb *tcp_client_pcb; /* a pcb for the TCP client */ +static struct altcp_pcb *tcp_server_pcb; /* a pcb for the TCP server */ +static u16_t tcp_remote_port; /* a TCP port number of the destination */ +static u16_t tcp_local_port; /* a TCP port number of the local server */ + +/** + * tcp_app_fuzz_input + * Input fuzz with a write function for TCP. + */ +static void +tcp_app_fuzz_input(struct altcp_pcb *pcb) +{ + if (remfuzz_len > sizeof(u16_t)) { + /* + * (max IP packet size) - ((minimum IP header size) + (minimum TCP header size)) + * = 65535 - (20 + 20) + * = 65495 + */ + const u16_t max_data_size = 65495; + u16_t data_len; + + memcpy(&data_len, remfuzz_ptr, sizeof(u16_t)); + remfuzz_ptr += sizeof(u16_t); + remfuzz_len -= sizeof(u16_t); + data_len = ntohs(data_len); + data_len = LWIP_MIN(data_len, max_data_size); + if (data_len > remfuzz_len) { + data_len = (u16_t)remfuzz_len; + } + + if (data_len != 0) { + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: tcp: write %u bytes\n", data_len)); + altcp_write(pcb, remfuzz_ptr, data_len, TCP_WRITE_FLAG_COPY); + altcp_output(pcb); + } else { + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: tcp: close\n")); + altcp_close(pcb); + } + + remfuzz_ptr += data_len; + remfuzz_len -= data_len; + } +} + +/** + * tcp_client_connected + * A connected callback function (for the TCP client) + */ +static err_t +tcp_client_connected(void *arg, struct altcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: tcp: tcp_client_connected\n")); + tcp_app_fuzz_input(pcb); + + return ERR_OK; +} + +/** + * tcp_client_recv + * A recv callback function (for the TCP client) + */ +static err_t +tcp_client_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + if (p == NULL) { + altcp_close(pcb); + } else { + altcp_recved(pcb, p->tot_len); + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: tcp: tcp_client_recv: %d\n", p->tot_len)); + tcp_app_fuzz_input(pcb); + pbuf_free(p); + } + + return ERR_OK; +} + +/** + * tcp_client_sent + * A sent callback function (for the TCP client) + */ +static err_t +tcp_client_sent(void *arg, struct altcp_pcb *pcb, u16_t len) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(len); + return ERR_OK; +} + +/** + * tcp_client_poll + * A poll callback function (for the TCP client) + */ +static err_t +tcp_client_poll(void *arg, struct altcp_pcb *pcb) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + return ERR_OK; +} + +/** + * tcp_client_err + * An err callback function (for the TCP client) + */ +static void +tcp_client_err(void *arg, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); +} + +/** + * tcp_server_recv + * A recv callback function (for the TCP server) + */ +static err_t +tcp_server_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + if (p == NULL) { + altcp_close(pcb); + } else { + altcp_recved(pcb, p->tot_len); + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: tcp: tcp_server_recv: %d\n", p->tot_len)); + tcp_app_fuzz_input(pcb); + pbuf_free(p); + } + + return ERR_OK; +} + +/** + * tcp_server_sent + * A sent callback function (for the TCP server) + */ +static err_t +tcp_server_sent(void *arg, struct altcp_pcb *pcb, u16_t len) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(len); + return ERR_OK; +} + +/** + * tcp_server_poll + * A poll callback function (for the TCP server) + */ +static err_t +tcp_server_poll(void *arg, struct altcp_pcb *pcb) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + return ERR_OK; +} + +/** + * tcp_server_err + * An err callbuck function (for the TCP server) + */ +static void +tcp_server_err(void *arg, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); +} + +/** + * tcp_server_accept + * An accept callbuck function (for the TCP server) + */ +static err_t +tcp_server_accept(void *arg, struct altcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + if ((err != ERR_OK) || (pcb == NULL)) { + return ERR_VAL; + } + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: accept from remote\n")); + + altcp_setprio(pcb, TCP_PRIO_MIN); + + altcp_recv(pcb, tcp_server_recv); + altcp_err(pcb, tcp_server_err); + altcp_poll(pcb, tcp_server_poll, 10); + altcp_sent(pcb, tcp_server_sent); + + return ERR_OK; +} +#endif /* LWIP_TCP */ + +#if LWIP_UDP +static struct udp_pcb *udp_client_pcb; /* a pcb for the UDP client */ +static struct udp_pcb *udp_server_pcb; /* a pcb for the UDP server */ +static u16_t udp_remote_port; /* a UDP port number of the destination */ +static u16_t udp_local_port; /* a UDP port number of the local server*/ + +/** + * udp_app_fuzz_input + * Input fuzz with write functions for UDP. + */ +static void +udp_app_fuzz_input(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port) +{ + if (remfuzz_len > sizeof(u16_t)) { + /* + * (max IP packet size) - ((minimum IP header size) - (minimum UDP header size)) + * = 65535 - (20 + 8) + * = 65507 + */ + const u16_t max_data_size = 65507; + u16_t data_len; + + memcpy(&data_len, remfuzz_ptr, sizeof(u16_t)); + remfuzz_ptr += sizeof(u16_t); + remfuzz_len -= sizeof(u16_t); + data_len = ntohs(data_len); + data_len = LWIP_MIN(data_len, max_data_size); + if (data_len > remfuzz_len) { + data_len = (u16_t)remfuzz_len; + } + + LWIP_DEBUGF(FUZZ_DEBUG, ("fuzz: udp: send %u bytes\n", data_len)); + if (data_len != 0) { + struct pbuf *p, *q; + + p = pbuf_alloc(PBUF_RAW, (u16_t)data_len, PBUF_POOL); + LWIP_ASSERT("alloc failed", p); + + for (q = p; q != NULL; q = q->next) { + MEMCPY(q->payload, remfuzz_ptr, q->len); + remfuzz_ptr += q->len; + } + remfuzz_len -= data_len; + + /* + * Trying input from ... + * + * client: + * The pcb has information about the destination. + * We use udp_send(). + * + * server: + * The pcb does NOT have information about the destination. + * We use udp_sendto(). + */ + if (addr == NULL) { + udp_send(pcb, p); + } else { + udp_sendto(pcb, p, addr, port); + } + pbuf_free(p); + } + } +} + +/** + * udp_client_recv + * A recv callback function (for the UDP client) + */ +static void +udp_client_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + if (p == NULL) { + udp_disconnect(pcb); + } else { + /* + * We call the function with 2nd argument set to NULL + * to input fuzz from udp_send. + */ + udp_app_fuzz_input(pcb, NULL, port); + pbuf_free(p); + } +} + +/** + * udp_server_recv + * A recv callback functyion (for the UDP server) + */ +static void +udp_server_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + if (p != NULL) { + udp_app_fuzz_input(pcb, addr, port); + pbuf_free(p); + } +} +#endif /* LWIP_UDP */ + +int lwip_fuzztest(int argc, char** argv, enum lwip_fuzz_type type, u32_t test_apps) +{ + struct netif net_test; + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + size_t len; + err_t err; + ip_addr_t remote_addr; /* a IPv4 addr of the destination */ + struct eth_addr remote_mac = ETH_ADDR(0x28, 0x00, 0x00, 0x22, 0x2b, 0x38); /* a MAC addr of the destination */ + + pcap_dump_init(); + lwip_init(); + + IP4_ADDR(&addr, 172, 30, 115, 84); + IP4_ADDR(&netmask, 255, 255, 255, 0); + IP4_ADDR(&gw, 172, 30, 115, 1); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + netif_set_link_up(&net_test); + + if (test_apps & LWIP_FUZZ_STATICARP) { + /* Add the ARP entry */ + IP_ADDR4(&remote_addr, 172, 30, 115, 37); + etharp_add_static_entry(&(remote_addr.u_addr.ip4), &remote_mac); + } + +#if LWIP_IPV6 + nd6_tmr(); /* tick nd to join multicast groups */ +#endif + dns_setserver(0, &net_test.gw); + + if (test_apps & LWIP_FUZZ_DEFAULT) { + /* initialize apps */ + httpd_init(); + lwiperf_start_tcp_server_default(NULL, NULL); + mdns_resp_init(); + mdns_resp_add_netif(&net_test, "hostname"); + snmp_init(); + } + if (test_apps & LWIP_FUZZ_TCP_CLIENT) { + tcp_client_pcb = altcp_tcp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("Error: altcp_new() failed", tcp_client_pcb != NULL); + tcp_remote_port = 80; + err = altcp_connect(tcp_client_pcb, &remote_addr, tcp_remote_port, tcp_client_connected); + LWIP_ASSERT("Error: altcp_connect() failed", err == ERR_OK); + altcp_recv(tcp_client_pcb, tcp_client_recv); + altcp_err(tcp_client_pcb, tcp_client_err); + altcp_poll(tcp_client_pcb, tcp_client_poll, 10); + altcp_sent(tcp_client_pcb, tcp_client_sent); + } + if (test_apps & LWIP_FUZZ_TCP_SERVER) { + tcp_server_pcb = altcp_tcp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("Error: altcp_new() failed", tcp_server_pcb != NULL); + altcp_setprio(tcp_server_pcb, TCP_PRIO_MIN); + tcp_local_port = 80; + err = altcp_bind(tcp_server_pcb, IP_ANY_TYPE, tcp_local_port); + LWIP_ASSERT("Error: altcp_bind() failed", err == ERR_OK); + tcp_server_pcb = altcp_listen(tcp_server_pcb); + LWIP_ASSERT("Error: altcp_listen() failed", err == ERR_OK); + altcp_accept(tcp_server_pcb, tcp_server_accept); + } + if (test_apps & LWIP_FUZZ_UDP_CLIENT) { + udp_client_pcb = udp_new(); + udp_new_ip_type(IPADDR_TYPE_ANY); + udp_recv(udp_client_pcb, udp_client_recv, NULL); + udp_remote_port = 161; + udp_connect(udp_client_pcb, &remote_addr, udp_remote_port); + } + if (test_apps & LWIP_FUZZ_UDP_SERVER) { + udp_server_pcb = udp_new(); + udp_new_ip_type(IPADDR_TYPE_ANY); + udp_local_port = 161; + udp_bind(udp_server_pcb, IP_ANY_TYPE, udp_local_port); + udp_recv(udp_server_pcb, udp_server_recv, NULL); + } + + if(argc > 1) { + FILE* f; + const char* filename; + printf("reading input from file... "); + fflush(stdout); + filename = argv[1]; + LWIP_ASSERT("invalid filename", filename != NULL); + f = fopen(filename, "rb"); + LWIP_ASSERT("open failed", f != NULL); + len = fread(pktbuf, 1, sizeof(pktbuf), f); + fclose(f); + printf("testing file: \"%s\"...\r\n", filename); + } else { + len = fread(pktbuf, 1, sizeof(pktbuf), stdin); + } + input_pkts(type, &net_test, pktbuf, len); + + pcap_dump_stop(); + return 0; +} + +#ifdef LWIP_RAND_FOR_FUZZ +u32_t lwip_fuzz_rand(void) +{ +#ifdef LWIP_RAND_FOR_FUZZ_SIMULATE_GLIBC + /* this is what glibc rand() returns (first 20 numbers) */ + static u32_t rand_nrs[] = {0x6b8b4567, 0x327b23c6, 0x643c9869, 0x66334873, 0x74b0dc51, + 0x19495cff, 0x2ae8944a, 0x625558ec, 0x238e1f29, 0x46e87ccd, + 0x3d1b58ba, 0x507ed7ab, 0x2eb141f2, 0x41b71efb, 0x79e2a9e3, + 0x7545e146, 0x515f007c, 0x5bd062c2, 0x12200854, 0x4db127f8}; + static unsigned idx = 0; + u32_t ret = rand_nrs[idx]; + idx++; + if (idx >= sizeof(rand_nrs)/sizeof((rand_nrs)[0])) { + idx = 0; + } + return ret; +#else + /* a simple LCG, unsafe but should give the same result for every execution (best for fuzzing) */ + u32_t result; + static s32_t state[1] = {0xdeadbeef}; + uint64_t val = state[0] & 0xffffffff; + val = ((val * 1103515245) + 12345) & 0x7fffffff; + state[0] = (s32_t)val; + result = (u32_t)val; + return result; +#endif +} +#endif diff --git a/test/fuzz/fuzz_common.h b/test/fuzz/fuzz_common.h new file mode 100644 index 0000000..79784e7 --- /dev/null +++ b/test/fuzz/fuzz_common.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_FUZZ_COMMON_H +#define LWIP_HDR_FUZZ_COMMON_H + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum lwip_fuzz_type { + LWIP_FUZZ_SINGLE = 0, + LWIP_FUZZ_MULTIPACKET = 1, + LWIP_FUZZ_MULTIPACKET_TIME = 2 +}; + +/* bitmask of what to test: */ +#define LWIP_FUZZ_DEFAULT 0x01 +#define LWIP_FUZZ_STATICARP 0x02 +#define LWIP_FUZZ_TCP_SERVER 0x04 +#define LWIP_FUZZ_TCP_CLIENT 0x08 +#define LWIP_FUZZ_UDP_SERVER 0x10 +#define LWIP_FUZZ_UDP_CLIENT 0x20 + +int lwip_fuzztest(int argc, char** argv, enum lwip_fuzz_type type, u32_t test_apps); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_FUZZ_COMMON_H */ diff --git a/test/fuzz/lwipopts.h b/test/fuzz/lwipopts.h index 4ab26f2..1492fd9 100644 --- a/test/fuzz/lwipopts.h +++ b/test/fuzz/lwipopts.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, @@ -11,27 +11,31 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. - * + * * Author: Simon Goldschmidt * */ #ifndef LWIP_HDR_LWIPOPTS_H__ #define LWIP_HDR_LWIPOPTS_H__ +#define MEMP_NUM_SYS_TIMEOUT 17 +#define LWIP_FUZZ_SYS_NOW +#define LWIP_RAND_FOR_FUZZ + /* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ #define NO_SYS 1 #define LWIP_NETCONN 0 diff --git a/test/unit/Filelists.cmake b/test/unit/Filelists.cmake index e1f40bc..b3db893 100644 --- a/test/unit/Filelists.cmake +++ b/test/unit/Filelists.cmake @@ -5,15 +5,20 @@ # # This file is NOT designed (on purpose) to be used as cmake # subdir via add_subdirectory() -# The intention is to provide greater flexibility to users to +# The intention is to provide greater flexibility to users to # create their own targets using the *_SRCS variables. +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + include_guard(GLOBAL) +endif() + set(LWIP_TESTDIR ${LWIP_DIR}/test/unit) set(LWIP_TESTFILES ${LWIP_TESTDIR}/lwip_unittests.c ${LWIP_TESTDIR}/api/test_sockets.c ${LWIP_TESTDIR}/arch/sys_arch.c ${LWIP_TESTDIR}/core/test_def.c + ${LWIP_TESTDIR}/core/test_dns.c ${LWIP_TESTDIR}/core/test_mem.c ${LWIP_TESTDIR}/core/test_netif.c ${LWIP_TESTDIR}/core/test_pbuf.c @@ -26,6 +31,8 @@ set(LWIP_TESTFILES ${LWIP_TESTDIR}/mqtt/test_mqtt.c ${LWIP_TESTDIR}/tcp/tcp_helper.c ${LWIP_TESTDIR}/tcp/test_tcp_oos.c + ${LWIP_TESTDIR}/tcp/test_tcp_state.c ${LWIP_TESTDIR}/tcp/test_tcp.c ${LWIP_TESTDIR}/udp/test_udp.c + ${LWIP_TESTDIR}/ppp/test_pppos.c ) diff --git a/test/unit/Filelists.mk b/test/unit/Filelists.mk index 4b77078..c33e1b0 100644 --- a/test/unit/Filelists.mk +++ b/test/unit/Filelists.mk @@ -34,6 +34,7 @@ TESTFILES=$(TESTDIR)/lwip_unittests.c \ $(TESTDIR)/api/test_sockets.c \ $(TESTDIR)/arch/sys_arch.c \ $(TESTDIR)/core/test_def.c \ + $(TESTDIR)/core/test_dns.c \ $(TESTDIR)/core/test_mem.c \ $(TESTDIR)/core/test_netif.c \ $(TESTDIR)/core/test_pbuf.c \ @@ -46,6 +47,8 @@ TESTFILES=$(TESTDIR)/lwip_unittests.c \ $(TESTDIR)/mqtt/test_mqtt.c \ $(TESTDIR)/tcp/tcp_helper.c \ $(TESTDIR)/tcp/test_tcp_oos.c \ + $(TESTDIR)/tcp/test_tcp_state.c \ $(TESTDIR)/tcp/test_tcp.c \ - $(TESTDIR)/udp/test_udp.c + $(TESTDIR)/udp/test_udp.c \ + $(TESTDIR)/ppp/test_pppos.c diff --git a/test/unit/Makefile b/test/unit/Makefile new file mode 100644 index 0000000..a27c72c --- /dev/null +++ b/test/unit/Makefile @@ -0,0 +1,11 @@ +# Shortcuts to building and running tests on unix platforms. +# Output files will be written to the directory listed below. + +all: + cd ../../contrib/ports/unix/check/ && $(MAKE) + +check: + cd ../../contrib/ports/unix/check/ && $(MAKE) check + +clean: + cd ../../contrib/ports/unix/check/ && $(MAKE) clean diff --git a/test/unit/api/test_sockets.c b/test/unit/api/test_sockets.c index 472fa48..1bcce34 100644 --- a/test/unit/api/test_sockets.c +++ b/test/unit/api/test_sockets.c @@ -153,7 +153,7 @@ static void test_sockets_allfunctions_basic_domain(int domain) fail_unless(errno == EISCONN); /* write from server to client */ - ret = write(s3, "test", 4); + ret = lwip_write(s3, "test", 4); fail_unless(ret == 4); ret = lwip_shutdown(s3, SHUT_WR); @@ -250,11 +250,11 @@ static void test_sockets_init_loopback_addr(int domain, struct sockaddr_storage static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes) { - int i; + msg_iovlen_t i; - /* note: this modifies the underyling iov_base and iov_len for a partial + /* note: this modifies the underlying iov_base and iov_len for a partial read for an individual vector. This updates the msg->msg_iov pointer - to skip fully consumed vecotrs */ + to skip fully consumed vectors */ /* process fully consumed vectors */ for (i = 0; i < msg->msg_iovlen; i++) { @@ -330,7 +330,7 @@ static void test_sockets_msgapi_tcp(int domain) /* set s2 to non-blocking, not inherited from listener */ opt = lwip_fcntl(s2, F_GETFL, 0); - fail_unless(opt == 6); + fail_unless(opt == O_RDWR); opt = O_NONBLOCK; ret = lwip_fcntl(s2, F_SETFL, opt); fail_unless(ret == 0); diff --git a/test/unit/core/test_dns.c b/test/unit/core/test_dns.c new file mode 100644 index 0000000..6789d24 --- /dev/null +++ b/test/unit/core/test_dns.c @@ -0,0 +1,52 @@ +#include "test_dns.h" + +#include "lwip/dns.h" + +/* Setups/teardown functions */ + +static void +dns_setup(void) +{ +} + +static void +dns_teardown(void) +{ +} + +/* Test functions */ + +START_TEST(test_dns_set_get_server) +{ + int n; + LWIP_UNUSED_ARG(_i); + + for (n = 0; n < 256; n++) { + u8_t i = (u8_t)n; + ip_addr_t server; + /* Should return a zeroed address for any index */ + fail_unless(dns_getserver(i)); + fail_unless(ip_addr_isany(dns_getserver(i))); + + /* Should accept setting address for any index, and ignore if out of range */ + IP_ADDR4(&server, 10, 0, 0, i); + dns_setserver(i, &server); + fail_unless(dns_getserver(i)); + if (i < DNS_MAX_SERVERS) { + fail_unless(ip_addr_eq(dns_getserver(i), &server) == 1); + } else { + fail_unless(ip_addr_isany(dns_getserver(i))); + } + } +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +dns_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_dns_set_get_server) + }; + return create_suite("DNS", tests, sizeof(tests)/sizeof(testfunc), dns_setup, dns_teardown); +} diff --git a/test/unit/core/test_dns.h b/test/unit/core/test_dns.h new file mode 100644 index 0000000..eaad0ca --- /dev/null +++ b/test/unit/core/test_dns.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_DNS_H +#define LWIP_HDR_TEST_DNS_H + +#include "../lwip_check.h" + +Suite *dns_suite(void); + +#endif diff --git a/test/unit/core/test_mem.c b/test/unit/core/test_mem.c index 2aeb20c..601bfc7 100644 --- a/test/unit/core/test_mem.c +++ b/test/unit/core/test_mem.c @@ -6,9 +6,6 @@ #if !LWIP_STATS || !MEM_STATS #error "This tests needs MEM-statistics enabled" #endif -#if LWIP_DNS -#error "This test needs DNS turned off (as it mallocs on init)" -#endif /* Setups/teardown functions */ diff --git a/test/unit/core/test_netif.c b/test/unit/core/test_netif.c index c5fa75d..a51a479 100644 --- a/test/unit/core/test_netif.c +++ b/test/unit/core/test_netif.c @@ -166,7 +166,8 @@ START_TEST(test_netif_extcallbacks) IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 1, 2, 3, 254); expected_reasons = (netif_nsc_reason_t)(LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_NETMASK_CHANGED | - LWIP_NSC_IPV4_GATEWAY_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED); + LWIP_NSC_IPV4_GATEWAY_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED | + LWIP_NSC_IPV4_ADDR_VALID); callback_ctr = 0; netif_set_addr(&net_test, &addr, &netmask, &gw); fail_unless(callback_ctr == 1); @@ -185,13 +186,16 @@ START_TEST(test_netif_extcallbacks) netif_set_gw(&net_test, &gw); fail_unless(callback_ctr == 0); + /* netif_set_addr() always issues at least LWIP_NSC_IPV4_ADDR_VALID */ + expected_reasons = LWIP_NSC_IPV4_ADDR_VALID; callback_ctr = 0; netif_set_addr(&net_test, &addr, &netmask, &gw); - fail_unless(callback_ctr == 0); + fail_unless(callback_ctr == 1); /* check for single-events */ IP4_ADDR(&addr, 1, 2, 3, 5); - expected_reasons = (netif_nsc_reason_t)(LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED); + expected_reasons = (netif_nsc_reason_t)(LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED | + LWIP_NSC_IPV4_ADDR_VALID); callback_ctr = 0; netif_set_addr(&net_test, &addr, &netmask, &gw); fail_unless(callback_ctr == 1); diff --git a/test/unit/core/test_pbuf.c b/test/unit/core/test_pbuf.c index 57087d2..9c5df33 100644 --- a/test/unit/core/test_pbuf.c +++ b/test/unit/core/test_pbuf.c @@ -6,9 +6,6 @@ #if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS #error "This tests needs MEM- and MEMP-statistics enabled" #endif -#if LWIP_DNS -#error "This test needs DNS turned off (as it mallocs on init)" -#endif #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE #error "This test needs TCP OOSEQ queueing and window scaling enabled" #endif @@ -77,9 +74,6 @@ START_TEST(test_pbuf_copy_zero_pbuf) err_t err; LWIP_UNUSED_ARG(_i); - fail_unless(lwip_stats.mem.used == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); - p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM); fail_unless(p1 != NULL); fail_unless(p1->ref == 1); @@ -94,15 +88,108 @@ START_TEST(test_pbuf_copy_zero_pbuf) fail_unless(p2->ref == 1); p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL); + fail_unless(p3 != NULL); err = pbuf_copy(p3, p1); fail_unless(err == ERR_VAL); pbuf_free(p1); pbuf_free(p3); - fail_unless(lwip_stats.mem.used == 0); +} +END_TEST + +/** Call pbuf_copy on pbufs with chains of different sizes */ +START_TEST(test_pbuf_copy_unmatched_chains) +{ + uint16_t i, j; + err_t err; + struct pbuf *source, *dest, *p; + LWIP_UNUSED_ARG(_i); + + source = NULL; + /* Build source pbuf from linked 16 byte parts, + * with payload bytes containing their offset */ + for (i = 0; i < 8; i++) { + p = pbuf_alloc(PBUF_RAW, 16, PBUF_RAM); + fail_unless(p != NULL); + for (j = 0; j < p->len; j++) { + ((u8_t*)p->payload)[j] = (u8_t)((i << 4) | j); + } + if (source) { + pbuf_cat(source, p); + } else { + source = p; + } + } + for (i = 0; i < source->tot_len; i++) { + fail_unless(pbuf_get_at(source, i) == i); + } + + /* Build dest pbuf from other lengths */ + dest = pbuf_alloc(PBUF_RAW, 35, PBUF_RAM); + fail_unless(dest != NULL); + p = pbuf_alloc(PBUF_RAW, 81, PBUF_RAM); + fail_unless(p != NULL); + pbuf_cat(dest, p); + p = pbuf_alloc(PBUF_RAW, 27, PBUF_RAM); + fail_unless(p != NULL); + pbuf_cat(dest, p); - fail_unless(lwip_stats.mem.used == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); + /* Copy contents and verify data */ + err = pbuf_copy(dest, source); + fail_unless(err == ERR_OK); + for (i = 0; i < source->tot_len; i++) { + fail_unless(pbuf_get_at(dest, i) == i); + } + + pbuf_free(source); + pbuf_free(dest); +} +END_TEST + +START_TEST(test_pbuf_copy_partial_pbuf) +{ + struct pbuf *a, *b, *dest; + char lwip[] = "lwip "; + char packet[] = "packet"; + err_t err; + LWIP_UNUSED_ARG(_i); + + a = pbuf_alloc(PBUF_RAW, 5, PBUF_REF); + fail_unless(a != NULL); + a->payload = lwip; + b = pbuf_alloc(PBUF_RAW, 7, PBUF_REF); + fail_unless(b != NULL); + b->payload = packet; + pbuf_cat(a, b); + dest = pbuf_alloc(PBUF_RAW, 14, PBUF_RAM); + fail_unless(dest != NULL); + memset(dest->payload, 0, dest->len); + + /* Don't copy if data will not fit */ + err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 4); + fail_unless(err == ERR_ARG); + /* Don't copy if length is longer than source */ + err = pbuf_copy_partial_pbuf(dest, a, a->tot_len + 1, 0); + fail_unless(err == ERR_ARG); + /* Normal copy */ + err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 0); + fail_unless(err == ERR_OK); + fail_unless(strcmp("lwip packet", (char*)dest->payload) == 0); + /* Copy at offset */ + err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 1); + fail_unless(err == ERR_OK); + fail_unless(strcmp("llwip packet", (char*)dest->payload) == 0); + /* Copy at offset with shorter length */ + err = pbuf_copy_partial_pbuf(dest, a, 6, 6); + fail_unless(err == ERR_OK); + fail_unless(strcmp("llwip lwip p", (char*)dest->payload) == 0); + /* Copy with shorter length */ + err = pbuf_copy_partial_pbuf(dest, a, 5, 0); + fail_unless(err == ERR_OK); + fail_unless(strcmp("lwip lwip p", (char*)dest->payload) == 0); + + pbuf_free(dest); + pbuf_free(a); } END_TEST @@ -112,6 +199,7 @@ START_TEST(test_pbuf_split_64k_on_small_pbufs) LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL); + fail_unless(p != NULL); pbuf_split_64k(p, &rest); fail_unless(p->tot_len == 1); pbuf_free(p); @@ -181,9 +269,14 @@ START_TEST(test_pbuf_take_at_edge) u8_t *out; int i; u8_t testdata[] = { 0x01, 0x08, 0x82, 0x02 }; - struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); - struct pbuf *q = p->next; + struct pbuf *p; + struct pbuf *q; LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); + fail_unless(p != NULL); + q = p->next; + /* alloc big enough to get a chain of pbufs */ fail_if(p->tot_len == p->len); memset(p->payload, 0, p->len); @@ -233,9 +326,14 @@ START_TEST(test_pbuf_get_put_at_edge) u8_t *out; u8_t testdata = 0x01; u8_t getdata; - struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); - struct pbuf *q = p->next; + struct pbuf *p; + struct pbuf *q; LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); + fail_unless(p != NULL); + q = p->next; + /* alloc big enough to get a chain of pbufs */ fail_if(p->tot_len == p->len); memset(p->payload, 0, p->len); @@ -262,6 +360,8 @@ pbuf_suite(void) testfunc tests[] = { TESTFUNC(test_pbuf_alloc_zero_pbufs), TESTFUNC(test_pbuf_copy_zero_pbuf), + TESTFUNC(test_pbuf_copy_unmatched_chains), + TESTFUNC(test_pbuf_copy_partial_pbuf), TESTFUNC(test_pbuf_split_64k_on_small_pbufs), TESTFUNC(test_pbuf_queueing_bigger_than_64k), TESTFUNC(test_pbuf_take_at_edge), diff --git a/test/unit/dhcp/test_dhcp.c b/test/unit/dhcp/test_dhcp.c index d84900d..0a75e54 100644 --- a/test/unit/dhcp/test_dhcp.c +++ b/test/unit/dhcp/test_dhcp.c @@ -4,8 +4,20 @@ #include "lwip/dhcp.h" #include "lwip/prot/dhcp.h" #include "lwip/etharp.h" +#include "lwip/inet.h" #include "netif/ethernet.h" +#if LWIP_ACD +#if LWIP_DHCP_DOES_ACD_CHECK +#define DHCP_TEST_NUM_ARP_FRAMES 5 +#else +#define DHCP_TEST_NUM_ARP_FRAMES 0 +#endif +#else +#define DHCP_TEST_NUM_ARP_FRAMES 1 +#endif + + static struct netif net_test; static const u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -132,6 +144,9 @@ static int tick = 0; static void tick_lwip(void) { tick++; +#if LWIP_DHCP_DOES_ACD_CHECK + acd_tmr(); +#endif if (tick % 5 == 0) { dhcp_fine_tmr(); } @@ -140,6 +155,11 @@ static void tick_lwip(void) } } +static u32_t get_bad_xid(const struct netif *netif) +{ + return ~netif_dhcp_data(netif)->xid; +} + static void send_pkt(struct netif *netif, const u8_t *data, size_t len) { struct pbuf *p, *q; @@ -282,7 +302,7 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - /* Check dchp message type, can be at different positions */ + /* Check dhcp message type, can be at different positions */ if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); @@ -295,9 +315,20 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) } break; } +#if DHCP_TEST_NUM_ARP_FRAMES > 0 case 3: +#if DHCP_TEST_NUM_ARP_FRAMES > 1 case 4: +#if DHCP_TEST_NUM_ARP_FRAMES > 2 case 5: +#if DHCP_TEST_NUM_ARP_FRAMES > 3 + case 6: +#if DHCP_TEST_NUM_ARP_FRAMES > 4 + case 7: +#endif +#endif +#endif +#endif { const u8_t arpproto[] = { 0x08, 0x06 }; @@ -307,7 +338,8 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ break; } - default: +#endif + default: fail(); break; } @@ -363,7 +395,7 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - /* Check dchp message type, can be at different positions */ + /* Check dhcp message type, can be at different positions */ if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); @@ -377,9 +409,20 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) break; } case 3: +#if DHCP_TEST_NUM_ARP_FRAMES > 0 case 4: +#if DHCP_TEST_NUM_ARP_FRAMES > 1 case 5: +#if DHCP_TEST_NUM_ARP_FRAMES > 2 case 6: +#if DHCP_TEST_NUM_ARP_FRAMES > 3 + case 7: +#if DHCP_TEST_NUM_ARP_FRAMES > 4 + case 8: +#endif +#endif +#endif +#endif { const u8_t arpproto[] = { 0x08, 0x06 }; @@ -389,7 +432,8 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ break; } - case 7: +#endif + case 4 + DHCP_TEST_NUM_ARP_FRAMES: { const u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab }; const u8_t ipproto[] = { 0x08, 0x00 }; @@ -410,7 +454,7 @@ static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - /* Check dchp message type, can be at different positions */ + /* Check dhcp message type, can be at different positions */ check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); break; } @@ -454,7 +498,7 @@ START_TEST(test_dhcp) dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + xid = get_bad_xid(&net_test); memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); @@ -469,7 +513,7 @@ START_TEST(test_dhcp) send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); /* DHCP request sent */ - xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + xid = get_bad_xid(&net_test); memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); @@ -478,10 +522,12 @@ START_TEST(test_dhcp) memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - for (i = 0; i < 20; i++) { + fail_unless(txpacket == 2); + + for (i = 0; i < 200; i++) { tick_lwip(); } - fail_unless(txpacket == 5, "TX %d packets, expected 5", txpacket); /* ARP requests sent */ + fail_unless(txpacket == (2 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (2 + DHCP_TEST_NUM_ARP_FRAMES)); /* Interface up */ fail_unless(netif_is_up(&net_test)); @@ -527,7 +573,7 @@ START_TEST(test_dhcp_nak) dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + xid = get_bad_xid(&net_test); memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); @@ -542,7 +588,7 @@ START_TEST(test_dhcp_nak) send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2); /* DHCP request sent */ - xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + xid = get_bad_xid(&net_test); memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); @@ -551,7 +597,12 @@ START_TEST(test_dhcp_nak) memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - fail_unless(txpacket == 3); /* ARP request sent */ + fail_unless(txpacket == 2); /* ARP request sent */ + + while (txpacket == 2) { + tick_lwip(); + } + fail_unless(txpacket == 3); tcase = TEST_LWIP_DHCP_NAK; /* Switch testcase */ @@ -766,10 +817,10 @@ START_TEST(test_dhcp_relayed) memcpy(&relay_ack1[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, relay_ack1, sizeof(relay_ack1)); - for (i = 0; i < 25; i++) { + for (i = 0; i < 200; i++) { tick_lwip(); } - fail_unless(txpacket == 5, "txpkt should be 5, is %d", txpacket); /* ARP requests sent */ + fail_unless(txpacket == (2 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (2 + DHCP_TEST_NUM_ARP_FRAMES)); /* Interface up */ fail_unless(netif_is_up(&net_test)); @@ -782,20 +833,20 @@ START_TEST(test_dhcp_relayed) fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - fail_unless(txpacket == 5, "txpacket = %d", txpacket); + fail_unless(txpacket == (2 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (2 + DHCP_TEST_NUM_ARP_FRAMES)); for (i = 0; i < 108000 - 25; i++) { tick_lwip(); } fail_unless(netif_is_up(&net_test)); - fail_unless(txpacket == 6, "txpacket = %d", txpacket); + fail_unless(txpacket == (3 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (3 + DHCP_TEST_NUM_ARP_FRAMES)); /* We need to send arp response here.. */ send_pkt(&net_test, arp_resp, sizeof(arp_resp)); - fail_unless(txpacket == 7, "txpacket = %d", txpacket); + fail_unless(txpacket == (4 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (4 + DHCP_TEST_NUM_ARP_FRAMES)); fail_unless(netif_is_up(&net_test)); xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ @@ -806,7 +857,7 @@ START_TEST(test_dhcp_relayed) tick_lwip(); } - fail_unless(txpacket == 7, "txpacket = %d", txpacket); + fail_unless(txpacket == (4 + DHCP_TEST_NUM_ARP_FRAMES), "TX %d packets, expected %d", txpacket, (5 + DHCP_TEST_NUM_ARP_FRAMES)); tcase = TEST_NONE; dhcp_stop(&net_test); @@ -895,7 +946,7 @@ START_TEST(test_dhcp_nak_no_endmarker) dhcp = netif_dhcp_data(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = dhcp->xid; /* Write bad xid, not using htonl! */ + xid = get_bad_xid(&net_test); memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); diff --git a/test/unit/etharp/test_etharp.c b/test/unit/etharp/test_etharp.c index 8eb506c..aeaacb2 100644 --- a/test/unit/etharp/test_etharp.c +++ b/test/unit/etharp/test_etharp.c @@ -2,6 +2,7 @@ #include "lwip/udp.h" #include "lwip/etharp.h" +#include "lwip/inet.h" #include "netif/ethernet.h" #include "lwip/stats.h" #include "lwip/prot/iana.h" diff --git a/test/unit/ip4/test_ip4.c b/test/unit/ip4/test_ip4.c index a5a7fd9..64ec1c4 100644 --- a/test/unit/ip4/test_ip4.c +++ b/test/unit/ip4/test_ip4.c @@ -1,6 +1,8 @@ #include "test_ip4.h" +#include "lwip/icmp.h" #include "lwip/ip4.h" +#include "lwip/etharp.h" #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/prot/ip.h" @@ -12,6 +14,61 @@ #error "This tests needs LWIP_IPV4, IP_REASSEMBLY; MIB2- and IPFRAG-statistics enabled" #endif +static struct netif test_netif; +static ip4_addr_t test_ipaddr, test_netmask, test_gw; +static int linkoutput_ctr; +static int linkoutput_byte_ctr; +static u16_t linkoutput_pkt_len; +static u8_t linkoutput_pkt[100]; + +/* reference internal lwip variable in netif.c */ + +static err_t +test_netif_linkoutput(struct netif *netif, struct pbuf *p) +{ + fail_unless(netif == &test_netif); + fail_unless(p != NULL); + linkoutput_ctr++; + linkoutput_byte_ctr += p->tot_len; + /* Copy start of packet into buffer */ + linkoutput_pkt_len = pbuf_copy_partial(p, linkoutput_pkt, sizeof(linkoutput_pkt), 0); + return ERR_OK; +} + +static err_t +test_netif_init(struct netif *netif) +{ + fail_unless(netif != NULL); + netif->linkoutput = test_netif_linkoutput; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + netif->hwaddr_len = ETHARP_HWADDR_LEN; + return ERR_OK; +} + +static void +test_netif_add(void) +{ + IP4_ADDR(&test_gw, 192,168,0,1); + IP4_ADDR(&test_ipaddr, 192,168,0,1); + IP4_ADDR(&test_netmask, 255,255,0,0); + + fail_unless(netif_default == NULL); + netif_add(&test_netif, &test_ipaddr, &test_netmask, &test_gw, + NULL, test_netif_init, NULL); + netif_set_default(&test_netif); + netif_set_up(&test_netif); +} + +static void +test_netif_remove(void) +{ + if (netif_default == &test_netif) { + netif_remove(&test_netif); + } +} + /* Helper functions */ static void create_ip4_input_fragment(u16_t ip_id, u16_t start, u16_t len, int last) @@ -52,6 +109,12 @@ create_ip4_input_fragment(u16_t ip_id, u16_t start, u16_t len, int last) } } +static err_t arpless_output(struct netif *netif, struct pbuf *p, + const ip4_addr_t *ipaddr) { + LWIP_UNUSED_ARG(ipaddr); + return netif->linkoutput(netif, p); +} + /* Setups/teardown functions */ static void @@ -71,10 +134,34 @@ ip4_teardown(void) /* poll until all memory is released... */ tcpip_thread_poll_one(); lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); + test_netif_remove(); + netif_set_up(netif_get_loopif()); } - /* Test functions */ +START_TEST(test_ip4_frag) +{ + struct pbuf *data = pbuf_alloc(PBUF_IP, 8000, PBUF_RAM); + ip_addr_t peer_ip = IPADDR4_INIT_BYTES(192,168,0,5); + err_t err; + LWIP_UNUSED_ARG(_i); + + linkoutput_ctr = 0; + linkoutput_byte_ctr = 0; + + /* Verify that 8000 byte payload is split into six packets */ + fail_unless(data != NULL); + test_netif_add(); + test_netif.output = arpless_output; + err = ip4_output_if_src(data, &test_ipaddr, ip_2_ip4(&peer_ip), + 16, 0, IP_PROTO_UDP, &test_netif); + fail_unless(err == ERR_OK); + fail_unless(linkoutput_ctr == 6); + fail_unless(linkoutput_byte_ctr == (8000 + (6 * IP_HLEN))); + pbuf_free(data); + test_netif_remove(); +} +END_TEST START_TEST(test_ip4_reass) { @@ -148,13 +235,109 @@ START_TEST(test_ip4_reass) } END_TEST +/* packets to 127.0.0.1 shall not be sent out to netif_default */ +START_TEST(test_127_0_0_1) +{ + ip4_addr_t localhost; + struct pbuf* p; + LWIP_UNUSED_ARG(_i); + + linkoutput_ctr = 0; + + test_netif_add(); + netif_set_down(netif_get_loopif()); + + IP4_ADDR(&localhost, 127, 0, 0, 1); + p = pbuf_alloc(PBUF_IP, 10, PBUF_POOL); + + if(ip4_output(p, netif_ip4_addr(netif_default), &localhost, 0, 0, IP_PROTO_UDP) != ERR_OK) { + pbuf_free(p); + } + fail_unless(linkoutput_ctr == 0); +} +END_TEST + +START_TEST(test_ip4addr_aton) +{ + ip4_addr_t ip_addr; + + LWIP_UNUSED_ARG(_i); + + fail_unless(ip4addr_aton("192.168.0.1", &ip_addr) == 1); + fail_unless(ip4addr_aton("192.168.0.0001", &ip_addr) == 1); + fail_unless(ip4addr_aton("192.168.0.zzz", &ip_addr) == 0); + fail_unless(ip4addr_aton("192.168.1", &ip_addr) == 1); + fail_unless(ip4addr_aton("192.168.0xd3", &ip_addr) == 1); + fail_unless(ip4addr_aton("192.168.0xz5", &ip_addr) == 0); + fail_unless(ip4addr_aton("192.168.095", &ip_addr) == 0); +} +END_TEST + +/* Test for bug #59364 */ +START_TEST(test_ip4_icmp_replylen_short) +{ + /* IP packet to 192.168.0.1 using proto 0x22 and 1 byte payload */ + const u8_t unknown_proto[] = { + 0x45, 0x00, 0x00, 0x15, 0xd4, 0x31, 0x00, 0x00, 0xff, 0x22, + 0x66, 0x41, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01, + 0xaa }; + struct pbuf *p; + const int icmp_len = IP_HLEN + sizeof(struct icmp_hdr); + LWIP_UNUSED_ARG(_i); + + linkoutput_ctr = 0; + + test_netif_add(); + test_netif.output = arpless_output; + p = pbuf_alloc(PBUF_IP, sizeof(unknown_proto), PBUF_RAM); + pbuf_take(p, unknown_proto, sizeof(unknown_proto)); + fail_unless(ip4_input(p, &test_netif) == ERR_OK); + + fail_unless(linkoutput_ctr == 1); + /* Verify outgoing ICMP packet has no extra data */ + fail_unless(linkoutput_pkt_len == icmp_len + sizeof(unknown_proto)); + fail_if(memcmp(&linkoutput_pkt[icmp_len], unknown_proto, sizeof(unknown_proto))); +} +END_TEST + +START_TEST(test_ip4_icmp_replylen_first_8) +{ + /* IP packet to 192.168.0.1 using proto 0x22 and 11 bytes payload */ + const u8_t unknown_proto[] = { + 0x45, 0x00, 0x00, 0x1f, 0xd4, 0x31, 0x00, 0x00, 0xff, 0x22, + 0x66, 0x37, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, + 0xaa }; + struct pbuf *p; + const int icmp_len = IP_HLEN + sizeof(struct icmp_hdr); + const int unreach_len = IP_HLEN + 8; + LWIP_UNUSED_ARG(_i); + + linkoutput_ctr = 0; + + test_netif_add(); + test_netif.output = arpless_output; + p = pbuf_alloc(PBUF_IP, sizeof(unknown_proto), PBUF_RAM); + pbuf_take(p, unknown_proto, sizeof(unknown_proto)); + fail_unless(ip4_input(p, &test_netif) == ERR_OK); + + fail_unless(linkoutput_ctr == 1); + fail_unless(linkoutput_pkt_len == icmp_len + unreach_len); + fail_if(memcmp(&linkoutput_pkt[icmp_len], unknown_proto, unreach_len)); +} +END_TEST /** Create the suite including all tests for this module */ Suite * ip4_suite(void) { testfunc tests[] = { + TESTFUNC(test_ip4_frag), TESTFUNC(test_ip4_reass), + TESTFUNC(test_127_0_0_1), + TESTFUNC(test_ip4addr_aton), + TESTFUNC(test_ip4_icmp_replylen_short), + TESTFUNC(test_ip4_icmp_replylen_first_8), }; return create_suite("IPv4", tests, sizeof(tests)/sizeof(testfunc), ip4_setup, ip4_teardown); } diff --git a/test/unit/ip6/test_ip6.c b/test/unit/ip6/test_ip6.c index 7303741..a030ee5 100644 --- a/test/unit/ip6/test_ip6.c +++ b/test/unit/ip6/test_ip6.c @@ -2,6 +2,7 @@ #include "lwip/ethip6.h" #include "lwip/ip6.h" +#include "lwip/icmp6.h" #include "lwip/inet_chksum.h" #include "lwip/nd6.h" #include "lwip/stats.h" @@ -15,6 +16,7 @@ static struct netif test_netif6; static int linkoutput_ctr; +static int linkoutput_byte_ctr; static err_t default_netif_linkoutput(struct netif *netif, struct pbuf *p) @@ -22,6 +24,7 @@ default_netif_linkoutput(struct netif *netif, struct pbuf *p) fail_unless(netif == &test_netif6); fail_unless(p != NULL); linkoutput_ctr++; + linkoutput_byte_ctr += p->tot_len; return ERR_OK; } @@ -63,6 +66,50 @@ ip6_test_handle_timers(int count) } } +/* Helper functions */ +static void +create_ip6_input_fragment(u32_t ip_id, u16_t start, u16_t len, int last, u8_t next_hdr) +{ + struct pbuf* p; + struct netif* input_netif = netif_list; /* just use any netif */ + fail_unless((start & 7) == 0); + fail_unless(((len & 7) == 0) || last); + fail_unless(input_netif != NULL); + + p = pbuf_alloc(PBUF_RAW, len + sizeof(struct ip6_frag_hdr) + + sizeof(struct ip6_hdr), PBUF_RAM); + fail_unless(p != NULL); + if (p != NULL) { + err_t err; + struct ip6_frag_hdr* fraghdr; + + struct ip6_hdr* ip6hdr = (struct ip6_hdr*)p->payload; + IP6H_VTCFL_SET(ip6hdr, 6, 0, 0); + IP6H_PLEN_SET(ip6hdr, len + sizeof(struct ip6_frag_hdr)); + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); + IP6H_HOPLIM_SET(ip6hdr, 64); + ip6_addr_copy_to_packed(ip6hdr->src, *netif_ip6_addr(input_netif, 0)); + ip6hdr->src.addr[3]++; + ip6_addr_copy_to_packed(ip6hdr->dest, *netif_ip6_addr(input_netif, 0)); + + fraghdr = (struct ip6_frag_hdr*)(ip6hdr + 1); + fraghdr->_nexth = next_hdr; + fraghdr->reserved = 0; + if (last) { + fraghdr->_fragment_offset = htons(start & ~7); + } else { + fraghdr->_fragment_offset = htons((start & ~7) | 1); + } + fraghdr->_identification = htonl(ip_id); + + err = ip6_input(p, input_netif); + if (err != ERR_OK) { + pbuf_free(p); + } + fail_unless(err == ERR_OK); + } +} + /* Setups/teardown functions */ static void @@ -132,6 +179,8 @@ START_TEST(test_ip6_ll_addr) { LWIP_UNUSED_ARG(_i); + linkoutput_ctr = 0; + /* test without link-local address */ test_ip6_ll_addr_iter(0, 0); @@ -287,6 +336,73 @@ START_TEST(test_ip6_lladdr) } END_TEST +static struct pbuf *cloned_pbuf = NULL; +static err_t clone_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) { + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(addr); + cloned_pbuf = pbuf_clone(PBUF_RAW, PBUF_RAM, p); + return ERR_OK; +} + +/* Reproduces bug #58553 */ +START_TEST(test_ip6_dest_unreachable_chained_pbuf) +{ + + ip_addr_t my_addr = IPADDR6_INIT_HOST(0x20010db8, 0x0, 0x0, 0x1); + ip_addr_t peer_addr = IPADDR6_INIT_HOST(0x20010db8, 0x0, 0x0, 0x4); + /* Create chained pbuf with UDP data that will get destination unreachable */ + u8_t udp_hdr[] = { + 0x60, 0x00, 0x27, 0x03, 0x00, 0x2d, 0x11, 0x40, + 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0xff, 0x03, 0xff, 0x00, 0x2d, 0x00, 0x00, + }; + struct pbuf *header = pbuf_alloc(PBUF_RAW, sizeof(udp_hdr), PBUF_ROM); + u8_t udp_payload[] = "abcdefghijklmnopqrstuvwxyz0123456789"; + struct pbuf *data = pbuf_alloc(PBUF_RAW, sizeof(udp_payload), PBUF_ROM); + u8_t *icmpptr; + struct ip6_hdr *outhdr; + struct icmp6_hdr *icmp6hdr; + LWIP_UNUSED_ARG(_i); + + fail_unless(header); + header->payload = udp_hdr; + fail_unless(data); + data->payload = udp_payload; + pbuf_cat(header, data); + data = NULL; + + /* Configure and enable local address */ + netif_set_up(&test_netif6); + netif_ip6_addr_set(&test_netif6, 0, ip_2_ip6(&my_addr)); + netif_ip6_addr_set_state(&test_netif6, 0, IP6_ADDR_VALID); + test_netif6.output_ip6 = clone_output; + + /* Process packet and send ICMPv6 reply for unreachable UDP port */ + ip6_input(header, &test_netif6); + header = NULL; + + /* Verify ICMP reply packet contents */ + fail_unless(cloned_pbuf); + fail_unless(cloned_pbuf->len == IP6_HLEN + ICMP6_HLEN + sizeof(udp_hdr) + sizeof(udp_payload)); + outhdr = (struct ip6_hdr*) cloned_pbuf->payload; + fail_unless(ip6_addr_packed_eq(ip_2_ip6(&my_addr), &outhdr->src, IP6_NO_ZONE)); + fail_unless(ip6_addr_packed_eq(ip_2_ip6(&peer_addr), &outhdr->dest, IP6_NO_ZONE)); + icmpptr = &((u8_t*)cloned_pbuf->payload)[IP6_HLEN]; + icmp6hdr = (struct icmp6_hdr*) icmpptr; + fail_unless(icmp6hdr->type == ICMP6_TYPE_DUR); + fail_unless(icmp6hdr->code == ICMP6_DUR_PORT); + fail_unless(icmp6hdr->data == lwip_htonl(0)); + icmpptr += ICMP6_HLEN; + fail_unless(memcmp(icmpptr, udp_hdr, sizeof(udp_hdr)) == 0, "mismatch in copied ip6/udp header"); + icmpptr += sizeof(udp_hdr); + fail_unless(memcmp(icmpptr, udp_payload, sizeof(udp_payload)) == 0, "mismatch in copied udp payload"); + pbuf_free(cloned_pbuf); +} +END_TEST + /* Reproduces bug #57374 */ START_TEST(test_ip6_frag_pbuf_len_assert) { @@ -295,6 +411,7 @@ START_TEST(test_ip6_frag_pbuf_len_assert) struct pbuf *payload, *hdr; err_t err; int i; + LWIP_UNUSED_ARG(_i); /* Configure and enable local address */ test_netif6.mtu = 1500; @@ -324,6 +441,85 @@ START_TEST(test_ip6_frag_pbuf_len_assert) } END_TEST +static err_t direct_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) { + LWIP_UNUSED_ARG(addr); + return netif->linkoutput(netif, p); +} + +START_TEST(test_ip6_frag) +{ + ip_addr_t my_addr = IPADDR6_INIT_HOST(0x20010db8, 0x0, 0x0, 0x1); + ip_addr_t peer_addr = IPADDR6_INIT_HOST(0x20010db8, 0x0, 0x0, 0x4); + struct pbuf *data; + err_t err; + LWIP_UNUSED_ARG(_i); + + /* Configure and enable local address */ + test_netif6.mtu = 1500; + netif_set_up(&test_netif6); + netif_ip6_addr_set(&test_netif6, 0, ip_2_ip6(&my_addr)); + netif_ip6_addr_set_state(&test_netif6, 0, IP6_ADDR_VALID); + test_netif6.output_ip6 = direct_output; + /* Reset counters after multicast traffic */ + linkoutput_ctr = 0; + linkoutput_byte_ctr = 0; + + /* Verify that 8000 byte payload is split into six packets */ + data = pbuf_alloc(PBUF_IP, 8000, PBUF_RAM); + fail_unless(data != NULL); + err = ip6_output_if_src(data, ip_2_ip6(&my_addr), ip_2_ip6(&peer_addr), + 15, 0, IP_PROTO_UDP, &test_netif6); + fail_unless(err == ERR_OK); + fail_unless(linkoutput_ctr == 6); + fail_unless(linkoutput_byte_ctr == (8000 + (6 * (IP6_HLEN + IP6_FRAG_HLEN)))); + pbuf_free(data); +} +END_TEST + +static void test_ip6_reass_helper(u32_t ip_id, const u16_t *segments, size_t num_segs, u16_t seglen) +{ + ip_addr_t my_addr = IPADDR6_INIT_HOST(0x20010db8, 0x0, 0x0, 0x1); + size_t i; + + memset(&lwip_stats.mib2, 0, sizeof(lwip_stats.mib2)); + memset(&lwip_stats.ip6_frag, 0, sizeof(lwip_stats.ip6_frag)); + + netif_set_up(&test_netif6); + netif_ip6_addr_set(&test_netif6, 0, ip_2_ip6(&my_addr)); + netif_ip6_addr_set_state(&test_netif6, 0, IP6_ADDR_VALID); + + for (i = 0; i < num_segs; i++) { + u16_t seg = segments[i]; + int last = seg + 1U == num_segs; + create_ip6_input_fragment(ip_id, seg * seglen, seglen, last, IP6_NEXTH_UDP); + fail_unless(lwip_stats.ip6_frag.recv == i + 1); + fail_unless(lwip_stats.ip6_frag.err == 0); + fail_unless(lwip_stats.ip6_frag.memerr == 0); + fail_unless(lwip_stats.ip6_frag.drop == 0); + if (i + 1 == num_segs) { + fail_unless(lwip_stats.mib2.ip6reasmoks == 1); + } + else { + fail_unless(lwip_stats.mib2.ip6reasmoks == 0); + } + } +} + +START_TEST(test_ip6_reass) +{ +#define NUM_SEGS 9 + const u16_t t1[NUM_SEGS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + const u16_t t2[NUM_SEGS] = { 8, 0, 1, 2, 3, 4, 7, 6, 5 }; + const u16_t t3[NUM_SEGS] = { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; + const u16_t t4[NUM_SEGS] = { 8, 2, 4, 6, 7, 5, 3, 1, 0 }; + LWIP_UNUSED_ARG(_i); + + test_ip6_reass_helper(128, t1, NUM_SEGS, 200); + test_ip6_reass_helper(129, t2, NUM_SEGS, 208); + test_ip6_reass_helper(130, t3, NUM_SEGS, 8); + test_ip6_reass_helper(130, t4, NUM_SEGS, 1448); +} + /** Create the suite including all tests for this module */ Suite * ip6_suite(void) @@ -334,7 +530,10 @@ ip6_suite(void) TESTFUNC(test_ip6_ntoa_ipv4mapped), TESTFUNC(test_ip6_ntoa), TESTFUNC(test_ip6_lladdr), - TESTFUNC(test_ip6_frag_pbuf_len_assert) + TESTFUNC(test_ip6_dest_unreachable_chained_pbuf), + TESTFUNC(test_ip6_frag_pbuf_len_assert), + TESTFUNC(test_ip6_frag), + TESTFUNC(test_ip6_reass) }; return create_suite("IPv6", tests, sizeof(tests)/sizeof(testfunc), ip6_setup, ip6_teardown); } diff --git a/test/unit/lwip_unittests.c b/test/unit/lwip_unittests.c index 497a44b..d088a06 100644 --- a/test/unit/lwip_unittests.c +++ b/test/unit/lwip_unittests.c @@ -5,7 +5,9 @@ #include "udp/test_udp.h" #include "tcp/test_tcp.h" #include "tcp/test_tcp_oos.h" +#include "tcp/test_tcp_state.h" #include "core/test_def.h" +#include "core/test_dns.h" #include "core/test_mem.h" #include "core/test_netif.h" #include "core/test_pbuf.h" @@ -15,12 +17,20 @@ #include "mdns/test_mdns.h" #include "mqtt/test_mqtt.h" #include "api/test_sockets.h" +#include "ppp/test_pppos.h" #include "lwip/init.h" #if !NO_SYS #include "lwip/tcpip.h" #endif +/* This function is used for LWIP_RAND by some ports... */ +unsigned int +lwip_port_rand(void) +{ + return (unsigned int)rand(); +} + Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown) { size_t i; @@ -43,11 +53,20 @@ void lwip_check_ensure_no_alloc(unsigned int skip) unsigned int mask; if (!(skip & SKIP_HEAP)) { - fail_unless(lwip_stats.mem.used == 0); + fail_unless(lwip_stats.mem.used == 0, + "mem heap still has %d bytes allocated", lwip_stats.mem.used); } for (i = 0, mask = 1; i < MEMP_MAX; i++, mask <<= 1) { if (!(skip & mask)) { - fail_unless(lwip_stats.memp[i]->used == 0); +#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY + fail_unless(lwip_stats.memp[i]->used == 0, + "memp pool '%s' still has %d entries allocated", + lwip_stats.memp[i]->name, lwip_stats.memp[i]->used); +#else + fail_unless(lwip_stats.memp[i]->used == 0, + "memp pool %d still has %d entries allocated", + i, lwip_stats.memp[i]->used); +#endif } } } @@ -67,7 +86,9 @@ int main(void) udp_suite, tcp_suite, tcp_oos_suite, + tcp_state_suite, def_suite, + dns_suite, mem_suite, netif_suite, pbuf_suite, @@ -77,6 +98,9 @@ int main(void) mdns_suite, mqtt_suite, sockets_suite +#if PPP_SUPPORT && PPPOS_SUPPORT + , pppos_suite +#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ }; size_t num = sizeof(suites)/sizeof(void*); LWIP_ASSERT("No suites defined", num > 0); diff --git a/test/unit/lwipopts.h b/test/unit/lwipopts.h index e4523fc..03579ee 100644 --- a/test/unit/lwipopts.h +++ b/test/unit/lwipopts.h @@ -51,11 +51,15 @@ #define LWIP_HAVE_LOOPIF 1 #define TCPIP_THREAD_TEST -/* Enable DHCP to test it, disable UDP checksum to easier inject packets */ +/* Enable DHCP to test it */ #define LWIP_DHCP 1 +/* Enable DNS, with random source port to avoid alloc in dns_init */ +#define LWIP_DNS 1 +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_RAND_SRC_PORT) + /* Minimal changes to opt.h required for tcp unit tests: */ -#define MEM_SIZE 16000 +#define MEM_SIZE 17000 #define TCP_SND_QUEUELEN 40 #define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN #define TCP_SND_BUF (12 * TCP_MSS) @@ -69,6 +73,10 @@ #define LWIP_MDNS_RESPONDER 1 #define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER) +/* Enable PPP and PPPOS support for PPPOS test suites */ +#define PPP_SUPPORT 1 +#define PPPOS_SUPPORT 1 + /* Minimal changes to opt.h required for etharp unit tests: */ #define ETHARP_SUPPORT_STATIC_ENTRIES 1 @@ -83,4 +91,27 @@ /* Check lwip_stats.mem.illegal instead of asserting */ #define LWIP_MEM_ILLEGAL_FREE(msg) /* to nothing */ +/* autodetect if we are running the tests on 32-bit or 64-bit */ +#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN64) +#define PTR64 +#else +#define PTR32 +#endif +#elif defined(__GNUC__) +#if defined(__x86_64__) || defined(__ppc64__) +#define PTR64 +#else +#define PTR32 +#endif +#elif UINTPTR_MAX > UINT_MAX +#define PTR64 +#else +#define PTR32 +#endif + +#ifdef PTR64 +#define IPV6_FRAG_COPYHEADER 1 +#endif + #endif /* LWIP_HDR_LWIPOPTS_H */ diff --git a/test/unit/mdns/test_mdns.c b/test/unit/mdns/test_mdns.c index 6385163..01434b5 100644 --- a/test/unit/mdns/test_mdns.c +++ b/test/unit/mdns/test_mdns.c @@ -34,6 +34,7 @@ #include "lwip/pbuf.h" #include "lwip/apps/mdns.h" +#include "lwip/apps/mdns_domain.h" #include "lwip/apps/mdns_priv.h" START_TEST(readname_basic) @@ -829,7 +830,7 @@ START_TEST(compress_jump_to_jump) offset = 0x20; length = mdns_compress_domain(p, &offset, &domain); - /* Dont compress if jump would be to a jump */ + /* Don't compress if jump would be to a jump */ fail_unless(length == domain.length); offset = 0x10; diff --git a/test/unit/mqtt/test_mqtt.c b/test/unit/mqtt/test_mqtt.c index 7cff13e..9722aa6 100644 --- a/test/unit/mqtt/test_mqtt.c +++ b/test/unit/mqtt/test_mqtt.c @@ -77,7 +77,7 @@ START_TEST(basic_connect) "dumm", NULL, NULL, 10, - NULL, NULL, 0, 0 + NULL, NULL, 0, 0, 0 }; struct pbuf *p; unsigned char rxbuf[] = {0x20, 0x02, 0x00, 0x00}; diff --git a/test/unit/ppp/test_pppos.c b/test/unit/ppp/test_pppos.c new file mode 100644 index 0000000..2b9aee8 --- /dev/null +++ b/test/unit/ppp/test_pppos.c @@ -0,0 +1,67 @@ +#include "test_pppos.h" + +#include "lwip/netif.h" +#include "netif/ppp/pppos.h" +#include "netif/ppp/ppp.h" + +#if PPP_SUPPORT && PPPOS_SUPPORT +static struct netif pppos_netif; +static ppp_pcb *ppp; + +static u32_t ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(data); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(ctx); + + return 0; +} + +static void ppp_link_status_cb(ppp_pcb *pcb, int err_code, void *ctx) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(err_code); + LWIP_UNUSED_ARG(ctx); +} + +static void pppos_setup(void) +{ + ppp = pppos_create(&pppos_netif, ppp_output_cb, ppp_link_status_cb, NULL); + fail_if(ppp == NULL); + ppp_connect(ppp, 0); +} + +static void pppos_teardown(void) +{ +} + +START_TEST(test_pppos_empty_packet_with_valid_fcs) +{ + u8_t two_breaks[] = { 0x7e, 0, 0, 0x7e }; + u8_t other_packet[] = { 0x7e, 0x7d, 0x20, 0x00, 0x7e }; + /* Set internal states of the underlying pcb */ + pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; + + LWIP_UNUSED_ARG(_i); + + pppos->open = 1; /* Pretend the connection is open already */ + pppos->in_accm[0] = 0xf0; /* Make sure 0x0's are not escaped chars */ + + pppos_input(ppp, two_breaks, sizeof(two_breaks)); + pppos_input(ppp, other_packet, sizeof(other_packet)); + +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +pppos_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_pppos_empty_packet_with_valid_fcs) + }; + return create_suite("PPPOS", tests, sizeof(tests)/sizeof(testfunc), pppos_setup, pppos_teardown); +} + +#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ diff --git a/test/unit/ppp/test_pppos.h b/test/unit/ppp/test_pppos.h new file mode 100644 index 0000000..56b3b0c --- /dev/null +++ b/test/unit/ppp/test_pppos.h @@ -0,0 +1,13 @@ +#ifndef LWIP_HDR_TEST_PPPOS_H +#define LWIP_HDR_TEST_PPPOS_H + +#include "../lwip_check.h" +#include "netif/ppp/ppp.h" + +#if PPP_SUPPORT && PPPOS_SUPPORT + +Suite* pppos_suite(void); + +#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ + +#endif /* LWIP_HDR_TEST_PPPOS_H */ diff --git a/test/unit/tcp/tcp_helper.c b/test/unit/tcp/tcp_helper.c index 8689b71..61d6e56 100644 --- a/test/unit/tcp/tcp_helper.c +++ b/test/unit/tcp/tcp_helper.c @@ -3,6 +3,7 @@ #include "lwip/priv/tcp_priv.h" #include "lwip/stats.h" #include "lwip/pbuf.h" +#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/ip_addr.h" @@ -24,7 +25,11 @@ tcp_remove(struct tcp_pcb* pcb_list) while(pcb != NULL) { pcb2 = pcb; pcb = pcb->next; - tcp_abort(pcb2); + if (pcb2->state == LISTEN) { + tcp_close(pcb2); + } else { + tcp_abort(pcb2); + } } } @@ -259,6 +264,7 @@ void test_tcp_input(struct pbuf *p, struct netif *inp) ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src); ip_current_netif() = inp; ip_data.current_ip4_header = iphdr; + ip_data.current_input_netif = inp; /* since adding IPv6, p->payload must point to tcp header, not ip header */ pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index c7f85f6..2efcbbf 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -2,6 +2,7 @@ #include "lwip/priv/tcp_priv.h" #include "lwip/stats.h" +#include "lwip/inet.h" #include "tcp_helper.h" #include "lwip/inet_chksum.h" @@ -516,7 +517,7 @@ START_TEST(test_tcp_fast_retx_recover) /* queue data4, don't send it (unsent-oversize is != 0) */ err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); - /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */ + /* 3rd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); @@ -664,6 +665,7 @@ START_TEST(test_tcp_fast_rexmit_wraparound) check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); @@ -752,6 +754,7 @@ START_TEST(test_tcp_rto_rexmit_wraparound) check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); @@ -1100,6 +1103,7 @@ START_TEST(test_tcp_rto_tracking) check_seqnos(pcb->unsent, 5, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 5); EXPECT(txcounters.num_tx_bytes == 5 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); @@ -1215,6 +1219,7 @@ static void test_tcp_rto_timeout_impl(int link_down) err = tcp_write(pcb, &tx_data[0], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == 1 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); @@ -1606,7 +1611,7 @@ START_TEST(test_tcp_persist_split) #if TCP_OVERSIZE_DBGCHECK /* Split segment already transmitted, should be at 0 */ EXPECT(pcb->unacked->oversize_left == 0); - /* Remainder segement should match pcb value (which is 0) */ + /* Remainder segment should match pcb value (which is 0) */ EXPECT(pcb->unsent->oversize_left == pcb->unsent_oversize); #endif /* TCP_OVERSIZE_DBGCHECK */ #endif /* TCP_OVERSIZE */ diff --git a/test/unit/tcp/test_tcp_oos.c b/test/unit/tcp/test_tcp_oos.c index a190e7d..43d722b 100644 --- a/test/unit/tcp/test_tcp_oos.c +++ b/test/unit/tcp/test_tcp_oos.c @@ -515,7 +515,7 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) } } - /* pass in one more segment, cleary overrunning the rxwin */ + /* pass in one more segment, clearly overrunning the rxwin */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ @@ -602,7 +602,7 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin_edge) } } - /* pass in one more segment, cleary overrunning the rxwin */ + /* pass in one more segment, clearly overrunning the rxwin */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ diff --git a/test/unit/tcp/test_tcp_state.c b/test/unit/tcp/test_tcp_state.c new file mode 100644 index 0000000..afd21fc --- /dev/null +++ b/test/unit/tcp/test_tcp_state.c @@ -0,0 +1,665 @@ +#include "test_tcp_state.h" + +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" +#include "tcp_helper.h" +#include "lwip/inet_chksum.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */ +#endif + +#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS +#error "This tests needs TCP- and MEMP-statistics enabled" +#endif + +static struct netif test_netif = {0}; +static struct test_tcp_txcounters test_txcounters = {0}; + +#define SEQNO1 (0xFFFFFF00 - TCP_MSS) +#define ISS 6510 +static u8_t test_tcp_timer; + +/* our own version of tcp_tmr so we can reset fast/slow timer state */ +static void +test_tcp_tmr(void) +{ + tcp_fasttmr(); + if (++test_tcp_timer & 1) { + tcp_slowtmr(); + } +} + +/* Get TCP flags from packets */ +static u8_t +get_tcp_flags_from_packet(struct pbuf *p, u16_t tcp_hdr_offset) +{ + struct tcp_hdr tcphdr; + u16_t ret; + EXPECT_RETX(p != NULL, 0); + EXPECT_RETX(p->len >= tcp_hdr_offset + sizeof(struct tcp_hdr), 0); + ret = pbuf_copy_partial(p, &tcphdr, sizeof(struct tcp_hdr), tcp_hdr_offset); + EXPECT(ret == sizeof(struct tcp_hdr)); + return TCPH_FLAGS(&tcphdr); +} + +/* Create listening tcp_pcb */ +static struct tcp_pcb_listen * +create_listening_pcb(u16_t local_port, struct test_tcp_counters *counters) +{ + struct tcp_pcb *pcb; + struct tcp_pcb_listen *lpcb=NULL; + err_t err; + u16_t port = local_port?local_port:1234; + + if (counters) { + pcb = test_tcp_new_counters_pcb(counters); + } else { + pcb = tcp_new(); + } + EXPECT(pcb != NULL); + + if (pcb) { + err = tcp_bind(pcb, &test_netif.ip_addr, port); + EXPECT(err == ERR_OK); + lpcb = (struct tcp_pcb_listen *)tcp_listen(pcb); + } + + return lpcb; +} + +/* Setup/teardown functions */ +static struct netif* old_netif_list; +static struct netif* old_netif_default; + +static void +tcp_state_setup(void) +{ + struct tcp_pcb dummy_pcb; /* we need this for tcp_next_iss() only */ + + /* reset iss to default (6510) */ + tcp_ticks = 0; + tcp_ticks = 0 - (tcp_next_iss(&dummy_pcb) - 6510); + tcp_next_iss(&dummy_pcb); + tcp_ticks = 0; + + test_tcp_timer = 0; + + old_netif_list = netif_list; + old_netif_default = netif_default; + netif_list = NULL; + netif_default = NULL; + tcp_remove_all(); + test_tcp_init_netif(&test_netif, &test_txcounters, &test_local_ip, &test_netmask); + lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); +} + +static void +tcp_state_teardown(void) +{ + netif_list = NULL; + netif_default = NULL; + tcp_remove_all(); + /* restore netif_list for next tests (e.g. loopif) */ + netif_list = old_netif_list; + netif_default = old_netif_default; + lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); +} + +/* helper functions */ + +static void +test_rst_generation_with_incoming_packet(struct pbuf *p, + struct netif *netif, struct test_tcp_txcounters *tx_counters) +{ + u16_t tcp_flags; + EXPECT_RET(p != NULL); + memset(tx_counters, 0, sizeof(struct test_tcp_txcounters)); + /* pass the segment to tcp_input */ + tx_counters->copy_tx_packets = 1; + test_tcp_input(p, netif); + tx_counters->copy_tx_packets = 0; + /* check if packets are as expected */ + EXPECT(tx_counters->tx_packets != NULL); + if (tx_counters->tx_packets) { + tcp_flags = get_tcp_flags_from_packet(tx_counters->tx_packets, 20); + EXPECT(tcp_flags & TCP_RST); + pbuf_free(tx_counters->tx_packets); + tx_counters->tx_packets = NULL; + } +} + +/* Test functions */ + +/* Call tcp_new() and test memp stats (max number) */ +START_TEST(test_tcp_new_max_num) +{ + struct tcp_pcb* pcb[MEMP_NUM_TCP_PCB + 1]; + int i; + LWIP_UNUSED_ARG(_i); + + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + + for(i = 0;i < MEMP_NUM_TCP_PCB; i++) { + pcb[i] = tcp_new(); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == (i + 1)); + } + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == MEMP_NUM_TCP_PCB); + /* Trying to remove the oldest pcb in TIME_WAIT,LAST_ACK,CLOSING state when pcb full */ + pcb[MEMP_NUM_TCP_PCB] = tcp_new(); + fail_unless(pcb[MEMP_NUM_TCP_PCB] == NULL); + tcp_set_state(pcb[0], TIME_WAIT, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + pcb[MEMP_NUM_TCP_PCB] = tcp_new(); + fail_unless(pcb[MEMP_NUM_TCP_PCB] != NULL); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == MEMP_NUM_TCP_PCB); + + for (i = 1; i <= MEMP_NUM_TCP_PCB; i++) + { + tcp_abort(pcb[i]); + } + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + + +/* pcbs in TIME_WAIT state will be deleted when creating new pcb reach the max number */ +START_TEST(test_tcp_new_max_num_remove_TIME_WAIT) +{ + struct tcp_pcb* pcb; + struct tcp_pcb* pcb_list[MEMP_NUM_TCP_PCB + 1]; + int i; + LWIP_UNUSED_ARG(_i); + + /* create a pcb in TIME_WAIT state */ + pcb = tcp_new(); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, TIME_WAIT, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + EXPECT_RET(pcb->state == TIME_WAIT); + + /* Create max number pcbs */ + for(i = 0;i < MEMP_NUM_TCP_PCB-1; i++) { + pcb_list[i] = tcp_new(); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == (i + 2)); + } + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == MEMP_NUM_TCP_PCB); + + /* Create one more pcb, and expect that the pcb in the TIME_WAIT state is deleted */ + pcb_list[MEMP_NUM_TCP_PCB-1] = tcp_new(); + EXPECT_RET(pcb_list[MEMP_NUM_TCP_PCB-1] != NULL); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == MEMP_NUM_TCP_PCB); + + for (i = 0; i <= MEMP_NUM_TCP_PCB-1; i++) + { + tcp_abort(pcb_list[i]); + } + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + +} +END_TEST + + +/* Call tcp_connect to check active open */ +START_TEST(test_tcp_connect_active_open) +{ + struct test_tcp_counters counters; + struct tcp_pcb *pcb; + struct pbuf *p; + err_t err; + u16_t test_port = 1234; + u32_t seqno = 0; + LWIP_UNUSED_ARG(_i); + + /* create and initialize the pcb */ + tcp_ticks = SEQNO1 - ISS; + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + + /* Get seqno from SYN packet */ + test_txcounters.copy_tx_packets = 1; + err = tcp_connect(pcb, &test_remote_ip, test_port, NULL); + test_txcounters.copy_tx_packets = 0; + EXPECT(err == ERR_OK); + EXPECT(pcb->state == SYN_SENT); + EXPECT(test_txcounters.num_tx_calls == 1); + EXPECT_RET(test_txcounters.tx_packets != NULL); + if (test_txcounters.tx_packets != NULL) { + struct tcp_hdr tcphdr; + u16_t ret; + ret = pbuf_copy_partial(test_txcounters.tx_packets, &tcphdr, 20, 20); + EXPECT(ret == 20); + EXPECT(TCPH_FLAGS(&tcphdr) & TCP_SYN); + pbuf_free(test_txcounters.tx_packets); + test_txcounters.tx_packets = NULL; + seqno = lwip_htonl(tcphdr.seqno); + EXPECT(seqno == pcb->lastack); + } + + /* check correct syn packet */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, test_port, + pcb->local_port, NULL, 0, 12345, seqno + 1, TCP_SYN|TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT_RET(pcb->state == ESTABLISHED); + EXPECT_RET(test_txcounters.num_tx_calls == 2); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +START_TEST(test_tcp_active_close) +{ + struct tcp_pcb *pcb, *pcbl; + struct test_tcp_counters counters; + struct pbuf *p; + err_t err; + u32_t i; + LWIP_UNUSED_ARG(_i); + + /* create TCP in LISTEN state */ + memset(&counters, 0, sizeof(counters)); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + err = tcp_bind(pcb, &test_netif.ip_addr, 1234); + EXPECT_RET(err == ERR_OK); + pcbl = tcp_listen(pcb); + EXPECT_RET(pcbl != NULL); + EXPECT_RET(pcbl->state == LISTEN); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 1); + + memset(&test_txcounters, 0, sizeof(test_txcounters)); + err = tcp_close(pcbl); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0); + EXPECT(test_txcounters.num_tx_calls == 0); + + /* close TCP in SYN_SENT state */ + memset(&counters, 0, sizeof(counters)); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + err = tcp_connect(pcb, &test_netif.gw, 1234, NULL); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(pcb->state == SYN_SENT); + EXPECT(test_txcounters.num_tx_calls == 1); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + + memset(&test_txcounters, 0, sizeof(test_txcounters)); + err = tcp_close(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + EXPECT(test_txcounters.num_tx_calls == 0); + + /* close TCP in ESTABLISHED state */ + memset(&counters, 0, sizeof(counters)); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + + memset(&test_txcounters, 0, sizeof(test_txcounters)); + err = tcp_close(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(pcb->state == FIN_WAIT_1); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + /* test_tcp_tmr(); */ + EXPECT(test_txcounters.num_tx_calls == 1); + /* create a segment ACK and pass it to tcp_input */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 1, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT_RET(pcb->state == FIN_WAIT_2); + /* create a segment FIN and pass it to tcp_input */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_FIN); + EXPECT_RET(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT_RET(pcb->state == TIME_WAIT); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + for (i = 0; i < 2 * TCP_MSL / TCP_TMR_INTERVAL + 1; i++) { + test_tcp_tmr(); + } + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +START_TEST(test_tcp_imultaneous_close) +{ + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + char data = 0x0f; + err_t err; + u32_t i; + LWIP_UNUSED_ARG(_i); + + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = 1; + counters.expected_data = &data; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + err = tcp_close(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(pcb->state == FIN_WAIT_1); + /* create a FIN segment */ + p = tcp_create_rx_segment(pcb, &data, 0, 0, 0, TCP_FIN); + EXPECT(p != NULL); + if (p != NULL) { + test_tcp_input(p, &test_netif); + } + EXPECT_RET(pcb->state == CLOSING); + /* create an ACK segment */ + p = tcp_create_rx_segment(pcb, &data, 0, 0, 1, TCP_ACK); + EXPECT(p != NULL); + if (p != NULL) { + test_tcp_input(p, &test_netif); + } + EXPECT_RET(pcb->state == TIME_WAIT); + for (i = 0; i < 2 * TCP_MSL / TCP_TMR_INTERVAL + 1; i++) { + test_tcp_tmr(); + } + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + + +/* RST was generated when receive any incoming segment in CLOSED state */ +START_TEST(test_tcp_gen_rst_in_CLOSED) +{ + struct pbuf *p; + ip_addr_t src_addr = test_remote_ip; + ip_addr_t dst_addr = test_local_ip; + LWIP_UNUSED_ARG(_i); + + /* Do not create any pcb */ + + /* create a segment */ + p = tcp_create_segment(&src_addr, &dst_addr, TEST_REMOTE_PORT, + TEST_LOCAL_PORT, NULL, 0, 12345, 54321, TCP_ACK); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + EXPECT(test_txcounters.num_tx_calls == 1); + +} +END_TEST + +/* RST was generated when receive ACK in LISTEN state */ +START_TEST(test_tcp_gen_rst_in_LISTEN) +{ + struct tcp_pcb_listen *lpcb; + struct pbuf *p; + ip_addr_t src_addr = test_remote_ip; + LWIP_UNUSED_ARG(_i); + + /* create a pcb in LISTEN state */ + lpcb = create_listening_pcb(TEST_LOCAL_PORT, NULL); + EXPECT_RET(lpcb != NULL); + + /* create a segment */ + p = tcp_create_segment(&src_addr,&lpcb->local_ip, TEST_REMOTE_PORT, + lpcb->local_port, NULL, 0, 12345, 54321, TCP_ACK); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + EXPECT(test_txcounters.num_tx_calls == 1); + + /* the PCB still in LISTEN state */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 1); + if (MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) != 0) { + /* can not use tcp_abort() */ + tcp_close((struct tcp_pcb *)lpcb); + } + +} +END_TEST + + +/* RST was generated when receive an SYN in TIME_WAIT state */ +START_TEST(test_tcp_gen_rst_in_TIME_WAIT) +{ + struct tcp_pcb *pcb; + struct pbuf *p; + LWIP_UNUSED_ARG(_i); + + /* create a pcb in LISTEN state */ + pcb = tcp_new(); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, TIME_WAIT, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + + /* create a segment */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_SYN); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + EXPECT(test_txcounters.num_tx_calls == 1); + + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + EXPECT(pcb->state == TIME_WAIT); +} +END_TEST + +/* receive TCP_RST with different seqno */ +START_TEST(test_tcp_process_rst_seqno) +{ + struct test_tcp_counters counters; + struct tcp_pcb *pcb; + struct pbuf *p; + err_t err; + LWIP_UNUSED_ARG(_i); + + /* create and initialize a pcb in SYN_SENT state */ + memset(&counters, 0, sizeof(counters)); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + err = tcp_connect(pcb, &test_remote_ip, TEST_REMOTE_PORT, NULL); + EXPECT_RET(err == ERR_OK); + + /* a RST segment with incorrect seqno will not be accepted */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, TEST_REMOTE_PORT, + pcb->local_port, NULL, 0, 12345, pcb->snd_nxt-10, TCP_RST); + EXPECT(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT(counters.err_calls == 0); + + /* a RST segment with correct seqno will be accepted */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, TEST_REMOTE_PORT, + pcb->local_port, NULL, 0, 12345, pcb->snd_nxt, TCP_RST); + EXPECT(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT(counters.err_calls == 1); + counters.err_calls = 0; + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + + /* create another pcb in ESTABLISHED state */ + memset(&counters, 0, sizeof(counters)); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); + + /* a RST segment with incorrect seqno will not be accepted */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, + pcb->local_port, NULL, 0, pcb->rcv_nxt-10, 54321, TCP_RST); + EXPECT(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT(counters.err_calls == 0); + + /* a RST segment with correct seqno will be accepted */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, TEST_REMOTE_PORT, + pcb->local_port, NULL, 0, pcb->rcv_nxt, 54321, TCP_RST); + EXPECT(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT(counters.err_calls == 1); + counters.err_calls = 0; + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + +} +END_TEST + +/* RST was generated when receive an SYN+ACK with incorrect ACK number in SYN_SENT state */ +START_TEST(test_tcp_gen_rst_in_SYN_SENT_ackseq) +{ + struct tcp_pcb *pcb; + struct pbuf *p; + u16_t test_port = 1234; + err_t err; + LWIP_UNUSED_ARG(_i); + + /* create and initialize a pcb in listen state */ + pcb = tcp_new(); + EXPECT_RET(pcb != NULL); + err = tcp_connect(pcb, &test_remote_ip, test_port, NULL); + EXPECT_RET(err == ERR_OK); + + /* create a SYN+ACK segment with incorrect seqno */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, + pcb->local_port, NULL, 0, 12345, pcb->lastack-10, TCP_SYN|TCP_ACK); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + + /* LWIP: send RST then re-send SYN immediately */ + EXPECT(test_txcounters.num_tx_calls == 2); + +} +END_TEST + +/* RST was generated when receive an ACK without SYN in SYN_SENT state */ +START_TEST(test_tcp_gen_rst_in_SYN_SENT_non_syn_ack) +{ + struct tcp_pcb *pcb; + struct pbuf *p; + u16_t test_port = 1234; + err_t err; + LWIP_UNUSED_ARG(_i); + + /* create and initialize a pcb in listen state */ + pcb = tcp_new(); + EXPECT_RET(pcb != NULL); + err = tcp_connect(pcb, &test_remote_ip, test_port, NULL); + EXPECT_RET(err == ERR_OK); + + /* create a SYN+ACK segment with incorrect seqno */ + p = tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, + pcb->local_port, NULL, 0, 12345, pcb->lastack, TCP_ACK); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + + /* LWIP: send RST then re-send SYN immediately */ + EXPECT(test_txcounters.num_tx_calls == 2); + +} +END_TEST + +/* RST was generated when receive an ACK with incorrect seqno in SYN_RCVD state */ +START_TEST(test_tcp_gen_rst_in_SYN_RCVD) +{ + struct tcp_pcb_listen *lpcb; + struct pbuf *p; + u32_t ack_seqno = 0; + ip_addr_t src_addr = test_remote_ip; + LWIP_UNUSED_ARG(_i); + + /* create and initialize a pcb in listen state */ + lpcb = create_listening_pcb(TEST_LOCAL_PORT, NULL); + EXPECT_RET(lpcb != NULL); + + /* LISTEN -> SYN_RCVD */ + p = tcp_create_segment(&src_addr, &lpcb->local_ip, TEST_REMOTE_PORT, + lpcb->local_port, NULL, 0, 1000, 54321, TCP_SYN); + EXPECT(p != NULL); + memset(&test_txcounters, 0, sizeof(struct test_tcp_txcounters)); + test_tcp_input(p, &test_netif); + EXPECT(test_txcounters.num_tx_calls == 1); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + if (MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1) { + ack_seqno = tcp_active_pcbs[0].lastack; + } + + /* create a ACK segment with incorrect seqno */ + p = tcp_create_segment(&src_addr, &lpcb->local_ip, TEST_REMOTE_PORT, + lpcb->local_port, NULL, 0, 1001, ack_seqno+1111, TCP_ACK); + EXPECT(p != NULL); + test_rst_generation_with_incoming_packet(p, &test_netif, &test_txcounters); + EXPECT(test_txcounters.num_tx_calls == 1); + + /* the active pcb still exists */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 1); + if (MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) != 0) { + /* can not use tcp_abort() */ + tcp_close((struct tcp_pcb *)lpcb); + } +} +END_TEST + +/* a listen pcb returns to LISTEN from SYN_RCVD when RST received */ +START_TEST(test_tcp_receive_rst_SYN_RCVD_to_LISTEN) +{ + struct tcp_pcb_listen *lpcb; + struct pbuf *p; + u16_t tcp_flags; + ip_addr_t src_addr = test_remote_ip; + LWIP_UNUSED_ARG(_i); + + /* create and initialize a pcb in listen state */ + lpcb = create_listening_pcb(TEST_LOCAL_PORT, NULL); + EXPECT_RET(lpcb != NULL); + + /* create a SYN segment */ + p = tcp_create_segment(&src_addr, &lpcb->local_ip, TEST_REMOTE_PORT, + lpcb->local_port, NULL, 0, 1000, 54321, TCP_SYN); + EXPECT(p != NULL); + /* pass the segment to tcp_input */ + memset(&test_txcounters, 0, sizeof(struct test_tcp_txcounters)); + test_txcounters.copy_tx_packets = 1; + test_tcp_input(p, &test_netif); + test_txcounters.copy_tx_packets = 0; + /* check if packets are as expected */ + EXPECT(test_txcounters.num_tx_calls == 1); + tcp_flags = get_tcp_flags_from_packet(test_txcounters.tx_packets, 20); + pbuf_free(test_txcounters.tx_packets); + test_txcounters.tx_packets = NULL; + EXPECT((tcp_flags & TCP_SYN) && (tcp_flags & TCP_ACK)); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + + /* create a RST segment */ + p = tcp_create_segment(&src_addr, &lpcb->local_ip, TEST_REMOTE_PORT, + lpcb->local_port, NULL, 0, 1001, 54321, TCP_RST); + EXPECT(p != NULL); + test_tcp_input(p, &test_netif); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 1); + + if (MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) != 0) { + /* can not use tcp_abort() */ + tcp_close((struct tcp_pcb *)lpcb); + } +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +tcp_state_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_tcp_new_max_num), + TESTFUNC(test_tcp_new_max_num_remove_TIME_WAIT), + TESTFUNC(test_tcp_connect_active_open), + TESTFUNC(test_tcp_active_close), + TESTFUNC(test_tcp_imultaneous_close), + TESTFUNC(test_tcp_gen_rst_in_CLOSED), + TESTFUNC(test_tcp_gen_rst_in_LISTEN), + TESTFUNC(test_tcp_gen_rst_in_TIME_WAIT), + TESTFUNC(test_tcp_process_rst_seqno), + TESTFUNC(test_tcp_gen_rst_in_SYN_SENT_ackseq), + TESTFUNC(test_tcp_gen_rst_in_SYN_SENT_non_syn_ack), + TESTFUNC(test_tcp_gen_rst_in_SYN_RCVD), + TESTFUNC(test_tcp_receive_rst_SYN_RCVD_to_LISTEN), + }; + return create_suite("TCP_STATE", tests, sizeof(tests) / sizeof(testfunc), tcp_state_setup, tcp_state_teardown); +} diff --git a/test/unit/tcp/test_tcp_state.h b/test/unit/tcp/test_tcp_state.h new file mode 100644 index 0000000..00d5c8a --- /dev/null +++ b/test/unit/tcp/test_tcp_state.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_TCP_STATE_H +#define LWIP_HDR_TEST_TCP_STATE_H + +#include "../lwip_check.h" + +Suite *tcp_state_suite(void); + +#endif -- Gitee From 3513d7289c7445c6439aa4c906e0239857c4da14 Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 02:53:28 +0800 Subject: [PATCH 02/14] OH adapt Signed-off-by: HuangHaitao --- src/api/sockets.c | 8 ++++++-- src/include/lwip/if_api.h | 3 ++- src/include/lwip/inet.h | 4 ++-- src/include/lwip/prot/ip4.h | 2 ++ src/include/lwip/sockets.h | 6 ++++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index b97bdd7..ece445e 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -568,6 +568,7 @@ alloc_socket(struct netconn *newconn, int accepted) * (unless it has been created by accept()). */ sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); sockets[i].errevent = 0; + init_waitqueue_head(&sockets[i].wq); #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ return i + LWIP_SOCKET_OFFSET; } @@ -1081,6 +1082,7 @@ lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, #endif /* LWIP_IPV4 && LWIP_IPV6 */ IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); + DF_NADDR(*fromaddr); if (*fromlen < IPADDR_SOCKADDR_GET_LEN(&saddr)) { truncated = 1; } else if (*fromlen > IPADDR_SOCKADDR_GET_LEN(&saddr)) { @@ -1109,11 +1111,11 @@ lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fro /* get remote addr/port from tcp_pcb */ u16_t port; ip_addr_t tmpaddr; - netconn_getaddr(sock->conn, &tmpaddr, &port, 0); + err_t err = netconn_getaddr(sock->conn, &tmpaddr, &port, 0); LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); - if (from && fromlen) { + if (!err && from && fromlen) { return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); } } @@ -2604,6 +2606,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) } else { SYS_ARCH_UNPROTECT(lev); } + poll_check_waiters(s, check_waiters); done_socket(sock); } @@ -3903,6 +3906,7 @@ lwip_ioctl(int s, long cmd, void *argp) return 0; default: + IOCTL_CMD_CASE_HANDLER(); break; } /* switch (cmd) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); diff --git a/src/include/lwip/if_api.h b/src/include/lwip/if_api.h index b7269e2..54eb6ee 100644 --- a/src/include/lwip/if_api.h +++ b/src/include/lwip/if_api.h @@ -48,9 +48,10 @@ #ifdef __cplusplus extern "C" { #endif - +#ifndef LWIP_SOCKET_STDINCLUDE #ifndef IF_NAMESIZE #define IF_NAMESIZE NETIF_NAMESIZE +#endif /* LWIP_SOCKET_STDINCLUDE */ #endif char * lwip_if_indextoname(unsigned int ifindex, char *ifname); diff --git a/src/include/lwip/inet.h b/src/include/lwip/inet.h index 0970885..544643c 100644 --- a/src/include/lwip/inet.h +++ b/src/include/lwip/inet.h @@ -53,7 +53,7 @@ #ifdef __cplusplus extern "C" { #endif - +#ifndef LWIP_SOCKET_STDINCLUDE /* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED to prevent this code from redefining it. */ #if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) @@ -177,7 +177,7 @@ extern const struct in6_addr in6addr_any; #define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) #endif /* LWIP_IPV6 */ - +#endif /* LWIP_SOCKET_STDINCLUDE */ #ifdef __cplusplus } diff --git a/src/include/lwip/prot/ip4.h b/src/include/lwip/prot/ip4.h index 9347461..eb18cf5 100644 --- a/src/include/lwip/prot/ip4.h +++ b/src/include/lwip/prot/ip4.h @@ -81,10 +81,12 @@ struct ip_hdr { PACK_STRUCT_FIELD(u16_t _id); /* fragment offset field */ PACK_STRUCT_FIELD(u16_t _offset); +#ifndef LWIP_SOCKET_STDINCLUDE #define IP_RF 0x8000U /* reserved fragment flag */ #define IP_DF 0x4000U /* don't fragment flag */ #define IP_MF 0x2000U /* more fragments flag */ #define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ +#endif /* LWIP_SOCKET_STDINCLUDE */ /* time to live */ PACK_STRUCT_FLD_8(u8_t _ttl); /* protocol*/ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index b6f3d52..dcd6269 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -61,7 +61,7 @@ extern "C" { /* sockaddr and pals include length fields */ #define LWIP_SOCKET_HAVE_SA_LEN 1 - +#ifndef LWIP_SOCKET_STDINCLUDE /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED to prevent this code from redefining it. */ #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) @@ -130,9 +130,11 @@ struct iovec { size_t iov_len; }; #endif +#endif /*LWIP_SOCKET_STDINCLUDE */ typedef int msg_iovlen_t; +#ifndef LWIP_SOCKET_STDINCLUDE struct msghdr { void *msg_name; socklen_t msg_namelen; @@ -533,7 +535,7 @@ struct timeval { long tv_usec; /* and microseconds */ }; #endif /* LWIP_TIMEVAL_PRIVATE */ - +#endif /* LWIP_SOCKET_STDINCLUDE */ #ifdef __cplusplus } #endif -- Gitee From 4144cbccde187197e89d6d05b313ef0ffb17a4ed Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:00:31 +0800 Subject: [PATCH 03/14] move dhcps back to kernel Signed-off-by: HuangHaitao --- src/core/ipv4/dhcp.c | 16 ++++++++-------- src/core/netif.c | 4 ++-- src/include/lwip/dhcp.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 12e0068..85c23f8 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -157,7 +157,7 @@ #define DHCP_MIN_REPLY_LEN 44 #define REBOOT_TRIES 2 - +#if 0 /* The following codes are moved to dhcp.h for fixing it's todo, kept here just for notice */ #if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS #if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS #define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS @@ -205,7 +205,7 @@ static u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; only valid while in dhcp_recv. @todo: move this into struct dhcp? */ static u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; - +#endif /* 0 */ static u8_t dhcp_discover_request_options[] = { DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, @@ -224,12 +224,12 @@ static u32_t xid; static u8_t xid_initialised; #endif /* DHCP_GLOBAL_XID */ -#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) -#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) -#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) -#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) -#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) -#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) +#define dhcp_option_given(dhcp, idx) ((dhcp)->rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) ((dhcp)->rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) ((dhcp)->rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (memset((dhcp)->rx_options_given, 0, sizeof((dhcp)->rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) ((dhcp)->rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) ((dhcp)->rx_options_val[idx] = (val)) static struct udp_pcb *dhcp_pcb; static u8_t dhcp_pcb_refcount; diff --git a/src/core/netif.c b/src/core/netif.c index 98e0553..d326a58 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -1743,7 +1743,7 @@ netif_get_by_index(u8_t idx) return NULL; } - +#ifndef netif_find /** * @ingroup netif * Find a network interface by searching for its name @@ -1780,7 +1780,7 @@ netif_find(const char *name) LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); return NULL; } - +#endif /* netif_find */ #if LWIP_NETIF_EXT_STATUS_CALLBACK /** * @ingroup netif diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index b413fa6..e22f8c9 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -74,6 +74,41 @@ typedef u16_t dhcp_timeout_t; #define DHCP_FLAG_SUBNET_MASK_GIVEN 0x01 #define DHCP_FLAG_EXTERNAL_MEM 0x02 +#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS +#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS +#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS +#endif +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 +#endif + +/** Option handling: options are parsed in dhcp_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +enum dhcp_option_idx { + DHCP_OPTION_IDX_OVERLOAD = 0, + DHCP_OPTION_IDX_MSG_TYPE, + DHCP_OPTION_IDX_SERVER_ID, + DHCP_OPTION_IDX_LEASE_TIME, + DHCP_OPTION_IDX_T1, + DHCP_OPTION_IDX_T2, + DHCP_OPTION_IDX_SUBNET_MASK, + DHCP_OPTION_IDX_ROUTER, +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + DHCP_OPTION_IDX_DNS_SERVER, + DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP_GET_NTP_SRV + DHCP_OPTION_IDX_NTP_SERVER, + DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, +#endif /* LWIP_DHCP_GET_NTP_SRV */ + DHCP_OPTION_IDX_MAX +}; + /* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ typedef enum { DHCP_AUTOIP_COOP_STATE_OFF = 0, @@ -116,6 +151,10 @@ struct dhcp /** acd struct */ struct acd acd; #endif /* LWIP_DHCP_DOES_ACD_CHECK */ + /** Holds the decoded option values, only valid while in dhcp_recv. */ + u32_t rx_options_val[DHCP_OPTION_IDX_MAX]; + /** Holds a flag which option was received and is contained in dhcp_rx_options_val, only valid while in dhcp_recv. */ + u8_t rx_options_given[DHCP_OPTION_IDX_MAX]; }; -- Gitee From f507d1e9cae29736b2d806d5d54f36bafe26ad3f Mon Sep 17 00:00:00 2001 From: Caoruihong Date: Mon, 2 Nov 2020 18:17:31 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E5=B1=8F=E8=94=BDlwip=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=B8=AD=E6=9C=89bug=E7=9A=84IPv6=E5=9C=B0=E5=9D=80=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=87=BD=E6=95=B0ip6addr=5Faton?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: HuangHaitao --- src/core/ipv6/ip6_addr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 6e0ac86..078aebf 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -58,7 +58,7 @@ const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); #define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10)) - +#if 0 // this ip6addr_aton is buggy, fixed in `fixme.c' /** * Check whether "cp" is a valid ascii representation * of an IPv6 address and convert to a binary address. @@ -205,7 +205,7 @@ fix_byte_order_and_return: return 1; } - +#endif /** * Convert numeric IPv6 address into ASCII representation. * returns ptr to static buffer; not reentrant! -- Gitee From 779bc58b48e33207a7c94d154f3e5615b6001bbb Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:05:00 +0800 Subject: [PATCH 05/14] OH adapt Signed-off-by: HuangHaitao --- src/core/dns.c | 4 ++++ src/core/udp.c | 4 ++++ src/include/lwip/errno.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/core/dns.c b/src/core/dns.c index 6540f14..0c3fd29 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -319,6 +319,10 @@ dns_init(void) ip_addr_t dnsserver; DNS_SERVER_ADDRESS(&dnsserver); dns_setserver(0, &dnsserver); +#ifdef DNS_SERVER_ADDRESS_SECONDARY + DNS_SERVER_ADDRESS_SECONDARY(&dnsserver); + dns_setserver(1, &dnsserver); +#endif /* DNS_SERVER_ADDRESS_SECONDARY */ #endif /* DNS_SERVER_ADDRESS */ LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", diff --git a/src/core/udp.c b/src/core/udp.c index c787ae0..362def8 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -388,7 +388,11 @@ udp_input(struct pbuf *p, struct netif *inp) /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; +#if USE_PBUF_RAM_UDP_INPUT + q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); +#else q = pbuf_clone(PBUF_RAW, PBUF_POOL, p); +#endif if (q != NULL) { mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } diff --git a/src/include/lwip/errno.h b/src/include/lwip/errno.h index 48d6b53..4099657 100644 --- a/src/include/lwip/errno.h +++ b/src/include/lwip/errno.h @@ -130,7 +130,9 @@ extern "C" { #define ELIBSCN 81 /* .lib section in a.out corrupted */ #define ELIBMAX 82 /* Attempting to link in too many shared libraries */ #define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#ifndef EILSEQ #define EILSEQ 84 /* Illegal byte sequence */ +#endif #define ERESTART 85 /* Interrupted system call should be restarted */ #define ESTRPIPE 86 /* Streams pipe error */ #define EUSERS 87 /* Too many users */ -- Gitee From d5159e09914d53f7b1c45838a079b3f8e9ba5348 Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:08:38 +0800 Subject: [PATCH 06/14] provide lwip gni file for gn file close: #I3Y2WZ Signed-off-by: liujiandong Signed-off-by: HuangHaitao --- lwip.gni | 1 + 1 file changed, 1 insertion(+) diff --git a/lwip.gni b/lwip.gni index e276542..14f5a9d 100644 --- a/lwip.gni +++ b/lwip.gni @@ -57,6 +57,7 @@ COREFILES = [ ] CORE4FILES = [ + "$LWIPDIR/core/ipv4/acd.c", "$LWIPDIR/core/ipv4/autoip.c", "$LWIPDIR/core/ipv4/dhcp.c", "$LWIPDIR/core/ipv4/etharp.c", -- Gitee From 69b26c520aaff5c774b158ed50922f3f4d641148 Mon Sep 17 00:00:00 2001 From: YOUR_NAME Date: Mon, 28 Jun 2021 21:49:05 +0800 Subject: [PATCH 07/14] =?UTF-8?q?fix:=20use=20sockaddr=5Fin=E3=80=81sockad?= =?UTF-8?q?dr=5Fin6=20length=20instead=20of=20sockaddr=5Fstorage=20length?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use sockaddr_inã€sockaddr_in6 length instead of sockaddr_storage length close: #I3Y8BM Signed-off-by: liujiandong Signed-off-by: HuangHaitao --- src/api/netdb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/netdb.c b/src/api/netdb.c index 73028c8..80bec23 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -389,6 +389,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, sa6->sin6_port = lwip_htons((u16_t)port_nr); sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); ai->ai_family = AF_INET6; + ai->ai_addrlen = sizeof(struct sockaddr_in6); #endif /* LWIP_IPV6 */ } else { #if LWIP_IPV4 @@ -401,6 +402,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, #endif /* LWIP_SOCKET_HAVE_SA_LEN */ sa4->sin_port = lwip_htons((u16_t)port_nr); ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); #endif /* LWIP_IPV4 */ } @@ -416,7 +418,6 @@ lwip_getaddrinfo(const char *nodename, const char *servname, MEMCPY(ai->ai_canonname, nodename, namelen); ai->ai_canonname[namelen] = 0; } - ai->ai_addrlen = sizeof(struct sockaddr_storage); ai->ai_addr = (struct sockaddr *)sa; *res = ai; -- Gitee From d87ca6dbea55ea724d14c534eefb6ff9d4ac0451 Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:21:57 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E8=93=9D=E7=89=99=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: HuangHaitao --- src/api/sockets.c | 65 +++++ src/core/distributed_net/distributed_net.c | 152 +++++++++++ .../distributed_net/distributed_net_core.c | 251 ++++++++++++++++++ .../distributed_net/distributed_net_utils.c | 100 +++++++ src/core/distributed_net/udp_transmit.c | 142 ++++++++++ src/core/dns.c | 81 ++++++ src/core/tcp.c | 2 +- .../lwip/distributed_net/distributed_net.h | 78 ++++++ .../distributed_net/distributed_net_core.h | 78 ++++++ .../distributed_net/distributed_net_utils.h | 43 +++ .../lwip/distributed_net/udp_transmit.h | 58 ++++ src/include/lwip/sockets.h | 19 ++ 12 files changed, 1068 insertions(+), 1 deletion(-) create mode 100644 src/core/distributed_net/distributed_net.c create mode 100644 src/core/distributed_net/distributed_net_core.c create mode 100644 src/core/distributed_net/distributed_net_utils.c create mode 100644 src/core/distributed_net/udp_transmit.c create mode 100644 src/include/lwip/distributed_net/distributed_net.h create mode 100644 src/include/lwip/distributed_net/distributed_net_core.h create mode 100644 src/include/lwip/distributed_net/distributed_net_utils.h create mode 100644 src/include/lwip/distributed_net/udp_transmit.h diff --git a/src/api/sockets.c b/src/api/sockets.c index ece445e..ddb6824 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -54,6 +54,10 @@ #include "lwip/netif.h" #include "lwip/priv/tcpip_priv.h" #include "lwip/mld6.h" +#if LWIP_ENABLE_DISTRIBUTED_NET +#include "lwip/distributed_net/distributed_net.h" +#include "lwip/distributed_net/distributed_net_core.h" +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ #if LWIP_CHECKSUM_ON_COPY #include "lwip/inet_chksum.h" #endif @@ -812,6 +816,17 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) int lwip_close(int s) { +#if LWIP_ENABLE_DISTRIBUTED_NET + if (!is_distributed_net_enabled()) { + return lwip_close_internal(s); + } + return distributed_net_close(s); +} + +int +lwip_close_internal(int s) +{ +#endif struct lwip_sock *sock; int is_tcp = 0; err_t err; @@ -853,6 +868,17 @@ lwip_close(int s) int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) { +#if LWIP_ENABLE_DISTRIBUTED_NET + if (!is_distributed_net_enabled()) { + return lwip_connect_internal(s, name, namelen); + } + return distributed_net_connect(s, name, namelen); +} + +int +lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) +{ +#endif struct lwip_sock *sock; err_t err; @@ -1241,6 +1267,18 @@ ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (!is_distributed_net_enabled()) { + return lwip_recvfrom_internal(s, mem, len, flags, from, fromlen); + } + return distributed_net_recvfrom(s, mem, len, flags, from, fromlen); +} + +ssize_t +lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ +#endif struct lwip_sock *sock; ssize_t ret; @@ -1439,7 +1477,11 @@ lwip_send(int s, const void *data, size_t size, int flags) if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) done_socket(sock); +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + return lwip_sendto_internal(s, data, size, flags, NULL, 0); +#else return lwip_sendto(s, data, size, flags, NULL, 0); +#endif #else /* (LWIP_UDP || LWIP_RAW) */ set_errno(err_to_errno(ERR_ARG)); done_socket(sock); @@ -1463,6 +1505,17 @@ lwip_send(int s, const void *data, size_t size, int flags) ssize_t lwip_sendmsg(int s, const struct msghdr *msg, int flags) { +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL && LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG + if (!is_distributed_net_enabled()) { + return lwip_sendmsg_internal(s, msg, flags); + } + return distributed_net_sendmsg(s, msg, flags); +} + +ssize_t +lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) +{ +#endif struct lwip_sock *sock; #if LWIP_TCP u8_t write_flags; @@ -1627,6 +1680,18 @@ ssize_t lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen) { +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (!is_distributed_net_enabled()) { + return lwip_sendto_internal(s, data, size, flags, to, tolen); + } + return distributed_net_sendto(s, data, size, flags, to, tolen); +} + +ssize_t +lwip_sendto_internal(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ +#endif struct lwip_sock *sock; err_t err; u16_t short_size; diff --git a/src/core/distributed_net/distributed_net.c b/src/core/distributed_net/distributed_net.c new file mode 100644 index 0000000..fc3d0b4 --- /dev/null +++ b/src/core/distributed_net/distributed_net.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/distributed_net/distributed_net.h" +#include "lwip/priv/sockets_priv.h" + +static sys_mutex_t g_mutex = {0}; + +static u8_t g_is_distributed_net_enabled = 0; + +static u16_t g_local_tcp_server_port = 0; + +static u16_t g_local_udp_server_port = 0; + +static u8_t g_is_distributed_net_socket[NUM_SOCKETS] = {0}; + +#if LWIP_DISTRIBUTED_NET_TRY_CONNECT +static int try_connect_to_local_tcp_server(u16_t tcp_port) +{ + struct sockaddr_in addr = {0}; + (void)memset_s(&addr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in)); + INIT_SOCK_ADDR(&addr, LOCAL_SERVER_IP, tcp_port); + + int sock = lwip_socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + return -1; + } + + int ret = lwip_connect_internal(sock, (struct sockaddr *)&addr, sizeof(addr)); + (void)lwip_close_internal(sock); + return ret; +} +#endif /* LWIP_DISTRIBUTED_NET_TRY_CONNECT */ + +void set_distributed_net_socket(int sock) +{ + int index = SOCKET_TO_INDEX(sock); + if (index >= 0 && index < NUM_SOCKETS) { + sys_mutex_lock(&g_mutex); + g_is_distributed_net_socket[index] = 1; + sys_mutex_unlock(&g_mutex); + } +} + +void reset_distributed_net_socket(int sock) +{ + int index = SOCKET_TO_INDEX(sock); + if (index >= 0 && index < NUM_SOCKETS) { + sys_mutex_lock(&g_mutex); + g_is_distributed_net_socket[index] = 0; + sys_mutex_unlock(&g_mutex); + } +} + +u16_t get_local_tcp_server_port(void) +{ + sys_mutex_lock(&g_mutex); + u16_t ret = g_local_tcp_server_port; + sys_mutex_unlock(&g_mutex); + return ret; +} + +u16_t get_local_udp_server_port(void) +{ + sys_mutex_lock(&g_mutex); + u16_t ret = g_local_udp_server_port; + sys_mutex_unlock(&g_mutex); + return ret; +} + +u8_t is_distributed_net_enabled(void) +{ + sys_mutex_lock(&g_mutex); + u8_t ret = g_is_distributed_net_enabled; + sys_mutex_unlock(&g_mutex); + return ret; +} + +int enable_distributed_net(u16_t tcp_port, u16_t udp_port) +{ + LWIP_DEBUGF(SOCKETS_DEBUG, ("enable distributed_net")); + if (is_distributed_net_enabled()) { + if (get_local_tcp_server_port() == tcp_port && get_local_udp_server_port() == udp_port) { + return 0; + } + set_errno(EINVAL); + return -1; + } + +#if LWIP_DISTRIBUTED_NET_TRY_CONNECT + if (try_connect_to_local_tcp_server(tcp_port) < 0) { + return -1; + } +#endif /* LWIP_DISTRIBUTED_NET_TRY_CONNECT */ + + sys_mutex_lock(&g_mutex); + g_is_distributed_net_enabled = 1; + g_local_tcp_server_port = tcp_port; + g_local_udp_server_port = udp_port; + sys_mutex_unlock(&g_mutex); + return 0; +} + +int disable_distributed_net(void) +{ + LWIP_DEBUGF(SOCKETS_DEBUG, ("disable distributed_net")); + sys_mutex_lock(&g_mutex); + for (int i = 0; i < NUM_SOCKETS; ++i) { + if (g_is_distributed_net_socket[i]) { + (void)lwip_close_internal(INDEX_TO_SOCKET(i)); + } + } + g_local_tcp_server_port = 0; + g_local_udp_server_port = 0; + g_is_distributed_net_enabled = 0; + (void)memset_s(g_is_distributed_net_socket, sizeof(g_is_distributed_net_socket), 0, + sizeof(g_is_distributed_net_socket)); + sys_mutex_unlock(&g_mutex); + return 0; +} + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ \ No newline at end of file diff --git a/src/core/distributed_net/distributed_net_core.c b/src/core/distributed_net/distributed_net_core.c new file mode 100644 index 0000000..62f424e --- /dev/null +++ b/src/core/distributed_net/distributed_net_core.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/distributed_net/distributed_net_core.h" +#include "lwip/distributed_net/distributed_net_utils.h" +#include "lwip/distributed_net/udp_transmit.h" +#include "lwip/priv/sockets_priv.h" + +int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t addr_len) +{ + CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); + CHECK_PARA(addr != NULL, EINVAL); + CHECK_PARA(addr_len > 0, EINVAL); + + struct sockaddr_in addr_in = {0}; + (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); + (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); + if (is_no_proxy_network_segment(&addr_in)) { + return lwip_connect_internal(sock, addr, addr_len); + } + + (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); + INIT_SOCK_ADDR(&addr_in, LOCAL_SERVER_IP, get_local_tcp_server_port()); + if (lwip_connect_internal(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) { + if (get_errno() != EINPROGRESS) { + return -1; + } + } + set_distributed_net_socket(sock); + + (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); + (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); + + tcp_connect_data data = {0}; + (void)memset_s(&data, sizeof(data), 0, sizeof(data)); + (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(addr_in.sin_addr)); + data.dest_port = ntohs(addr_in.sin_port); + + if (lwip_send(sock, &data, sizeof(data), 0) < 0) { + reset_distributed_net_socket(sock); + return -1; + } + return 0; +} + +int distributed_net_close(int sock) +{ + CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); + + reset_distributed_net_socket(sock); + return lwip_close_internal(sock); +} + +#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL +typedef union { + struct sockaddr sa; +#if LWIP_IPV6 + struct sockaddr_in6 sin6; +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + struct sockaddr_in sin; +#endif /* LWIP_IPV4 */ +} aligned_sockaddr; + +ssize_t distributed_net_sendto(int sock, const void *buf, size_t buf_len, int flags, const struct sockaddr *addr, + socklen_t addr_len) +{ + CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); + CHECK_PARA(buf != NULL, EINVAL); + CHECK_PARA(buf_len > 0, EINVAL); + + int type = 0; + socklen_t type_len = sizeof(type); + if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { + return -1; + } + + if (type != SOCK_DGRAM) { + return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len); + } + + struct sockaddr_in addr_in = {0}; + (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); + if (addr != NULL && addr_len != 0) { + (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); + } + + if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) { + set_errno(EPERM); + return -1; + } + + if (is_no_proxy_network_segment(&addr_in)) { + return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len); + } + + if (!IS_DNS_PORT(addr_in)) { + set_errno(EPERM); + return -1; + } + + ssize_t ret = udp_transmit_sendto(sock, buf, buf_len, &addr_in); + return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1; +} + +#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG +ssize_t distributed_net_sendmsg(int sock, const struct msghdr *hdr, int flags) +{ + CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); + CHECK_PARA(hdr != NULL, EINVAL); + CHECK_PARA(hdr->msg_iov != NULL, EINVAL); + CHECK_PARA(hdr->msg_iovlen > 0, EINVAL); + + int type = 0; + socklen_t type_len = sizeof(type); + if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { + return -1; + } + + if (type != SOCK_DGRAM) { + return lwip_sendmsg_internal(sock, hdr, flags); + } + + const struct sockaddr *addr = (const struct sockaddr *)hdr->msg_name; + socklen_t addr_len = hdr->msg_namelen; + + struct sockaddr_in addr_in = {0}; + (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); + if (addr != NULL && addr_len != 0) { + (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len)); + } + + if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) { + set_errno(EPERM); + return -1; + } + + if (is_no_proxy_network_segment(&addr_in)) { + return lwip_sendmsg_internal(sock, hdr, flags); + } + + if (!IS_DNS_PORT(addr_in)) { + set_errno(EPERM); + return -1; + } + + ssize_t ret = udp_transmit_sendmsg(sock, hdr); + return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1; +} +#endif /* LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG */ + +ssize_t distributed_net_recvfrom(int sock, void *buf, size_t buf_len, int flags, struct sockaddr *from, + socklen_t *from_len) +{ + CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF); + CHECK_PARA(buf != NULL, EINVAL); + CHECK_PARA(buf_len > 0, EINVAL); + + int type = 0; + socklen_t type_len = sizeof(type); + if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) { + return -1; + } + + if (type != SOCK_DGRAM) { + return lwip_recvfrom_internal(sock, buf, buf_len, flags, from, from_len); + } + + size_t new_buf_len = buf_len + sizeof(udp_data); + void *new_buf = mem_malloc(new_buf_len); + if (new_buf == NULL) { + set_errno(ENOMEM); + return -1; + } + + aligned_sockaddr addr_from = {0}; + socklen_t addr_from_len = sizeof(addr_from); + ssize_t ret = + lwip_recvfrom_internal(sock, new_buf, new_buf_len, flags, (struct sockaddr *)&addr_from, &addr_from_len); + if (ret <= 0) { + mem_free(new_buf); + return ret; + } + + if (!IS_LOCAL_UDP_SERVER_ADDR((struct sockaddr_in *)(&addr_from))) { + (void)memcpy_s(buf, buf_len, new_buf, ret); + if (from != NULL && from_len != NULL) { + if (*from_len > addr_from_len) { + *from_len = addr_from_len; + } + (void)memcpy_s(from, *from_len, &addr_from, *from_len); + mem_free(new_buf); + return ret; + } + } + + if (ret <= sizeof(udp_data)) { + mem_free(new_buf); + set_errno(EINVAL); + return -1; + } + + udp_data *data = (udp_data *)new_buf; + (void)memcpy_s(buf, buf_len, data->payload, ret - sizeof(udp_data)); + if (from != NULL && from_len != NULL) { + (void)memcpy_s(from, *from_len, &addr_from, MIN(addr_from_len, *from_len)); + if (*from_len >= sizeof(struct sockaddr_in) - SIN_ZERO_LEN) { + struct sockaddr_in *temp_addr = (struct sockaddr_in *)from; + INIT_SOCK_ADDR(temp_addr, data->dest_addr, data->dest_port); + if (*from_len > sizeof(struct sockaddr_in)) { + *from_len = sizeof(struct sockaddr_in); + } + } + } + + mem_free(new_buf); + return ret - (ssize_t)sizeof(udp_data); +} +#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ diff --git a/src/core/distributed_net/distributed_net_utils.c b/src/core/distributed_net/distributed_net_utils.c new file mode 100644 index 0000000..0a94f57 --- /dev/null +++ b/src/core/distributed_net/distributed_net_utils.c @@ -0,0 +1,100 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/distributed_net/distributed_net_utils.h" + +typedef struct no_proxy_network_segment { + const char *ip; + const in_addr_t mask_len; +} no_proxy_network_segment; + +static const no_proxy_network_segment g_special_network_segment[] = { + {"127.0.0.0", 8}, + {"192.0.0.0", 29}, + {"192.0.2.0", 24}, + {"192.168.0.0", 16}, + {"192.18.0.0", 15}, + {"192.51.100.0", 24}, + {"0.0.0.0", 8}, + {"100.64.0.0", 10}, + {"169.254.0.0", 16}, + {"172.16.0.0", 12}, + {"203.0.113.0", 24}, + {"224.0.0.0", 4}, + {"240.0.0.0", 4}, + {"10.0.0.0", 8}, + {"255.255.255.255", 32}, +}; + +static in_addr_t mask_len_to_mask(u32_t mask_len) +{ + if (mask_len > 32) { + return UINT_MAX; + } + u8_t num[4] = {0}; + for (int i = 0; i < 4; ++i) { + u32_t len = (mask_len > 8 ? 8 : mask_len); + if (len > 0) { + u8_t byte = 0x80;// binary 1000|0000 + u8_t bit = 0x80; // binary 1000|0000 + for (u32_t j = 0; j < len - 1; ++j) { + byte = (bit >> 1U) | byte; + bit >>= 1U; + } + num[i] = byte; + } + if (mask_len < 8) { + break; + } + mask_len -= 8; + } + int mask = 0; + (void)memcpy_s(&mask, sizeof(int), num, sizeof(int)); + return mask; +} + +u8_t is_no_proxy_network_segment(const struct sockaddr_in *addr_in) +{ + for (int i = 0; i < sizeof(g_special_network_segment) / sizeof(g_special_network_segment[0]); ++i) { + ip4_addr_t ip4_ip = {addr_in->sin_addr.s_addr}; + ip4_addr_t ip4_net_ip = {ipaddr_addr(g_special_network_segment[i].ip)}; + ip4_addr_t ip4_mask = {mask_len_to_mask(g_special_network_segment[i].mask_len)}; + + if (ip4_addr_netcmp(&ip4_ip, &ip4_net_ip, &ip4_mask)) { + return 1; + } + } + return 0; +} + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ \ No newline at end of file diff --git a/src/core/distributed_net/udp_transmit.c b/src/core/distributed_net/udp_transmit.c new file mode 100644 index 0000000..7992513 --- /dev/null +++ b/src/core/distributed_net/udp_transmit.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + +#include "lwip/distributed_net/udp_transmit.h" + +static s32_t get_msg_data_len(const struct msghdr *hdr) +{ + if (hdr->msg_iovlen > MAX_IOV_NUM) { + return -1; + } + + s32_t data_len = 0; + for (int i = 0; i < hdr->msg_iovlen; ++i) { + if (hdr->msg_iov[i].iov_len > MAX_UDP_PAYLOAD_LEN) { + set_errno(EMSGSIZE); + return -1; + } + data_len += (s32_t)hdr->msg_iov[i].iov_len; + if (data_len > MAX_UDP_PAYLOAD_LEN) { + set_errno(EMSGSIZE); + return -1; + } + } + + return data_len; +} + +ssize_t udp_transmit_sendto(int sock, const void *buf, size_t buf_len, const struct sockaddr_in *dest_addr) +{ + if (buf_len > MAX_UDP_PAYLOAD_LEN) { + set_errno(EMSGSIZE); + return -1; + } + + udp_data data = {0}; + (void)memset_s(&data, sizeof(data), 0, sizeof(data)); + (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(dest_addr->sin_addr)); + data.dest_port = ntohs(dest_addr->sin_port); + + struct iovec iov[2] = {0}; + (void)memset_s(iov, sizeof(iov), 0, sizeof(iov)); + iov[0].iov_base = (void *)&data; + iov[0].iov_len = sizeof(data); + iov[1].iov_base = (void *)buf; + iov[1].iov_len = buf_len; + + struct sockaddr_in transmit_addr = {0}; + (void)memset_s(&transmit_addr, sizeof(transmit_addr), 0, sizeof(transmit_addr)); + INIT_SOCK_ADDR(&transmit_addr, LOCAL_SERVER_IP, get_local_udp_server_port()); + + struct msghdr send_hdr = {0}; + (void)memset_s(&send_hdr, sizeof(send_hdr), 0, sizeof(send_hdr)); + SET_MSG_ADDR(&send_hdr, &transmit_addr, sizeof(transmit_addr)); + send_hdr.msg_iov = iov; + send_hdr.msg_iovlen = 2; + +#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG + return lwip_sendmsg_internal(sock, &send_hdr, 0); +#else + return lwip_sendmsg(sock, &send_hdr, 0); +#endif +} + +ssize_t udp_transmit_sendmsg(int sock, const struct msghdr *hdr) +{ + if (get_msg_data_len(hdr) < 0) { + return -1; + } + + struct sockaddr_in temp_addr_in = {0}; + (void)memset_s(&temp_addr_in, sizeof(temp_addr_in), 0, sizeof(temp_addr_in)); + (void)memcpy_s(&temp_addr_in, sizeof(temp_addr_in), hdr->msg_name, MIN(sizeof(temp_addr_in), hdr->msg_namelen)); + + udp_data data = {0}; + (void)memset_s(&data, sizeof(data), 0, sizeof(data)); + (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(temp_addr_in.sin_addr)); + data.dest_port = ntohs(temp_addr_in.sin_port); + + u32_t size = sizeof(struct iovec) * (hdr->msg_iovlen + 1); + struct iovec *iov = mem_malloc(size); + if (iov == NULL) { + set_errno(ENOMEM); + return -1; + } + (void)memset_s(iov, size, 0, size); + iov[0].iov_base = (void *)&data; + iov[0].iov_len = sizeof(data); + for (int i = 0; i < hdr->msg_iovlen; ++i) { + iov[i + 1].iov_base = hdr->msg_iov[i].iov_base; + iov[i + 1].iov_len = hdr->msg_iov[i].iov_len; + } + + struct sockaddr_in transmit_addr = {0}; + (void)memset_s(&transmit_addr, sizeof(transmit_addr), 0, sizeof(transmit_addr)); + INIT_SOCK_ADDR(&transmit_addr, LOCAL_SERVER_IP, get_local_udp_server_port()); + + struct msghdr send_hdr = {0}; + (void)memset_s(&send_hdr, sizeof(send_hdr), 0, sizeof(send_hdr)); + SET_MSG_ADDR(&send_hdr, &transmit_addr, sizeof(transmit_addr)); + send_hdr.msg_iov = iov; + send_hdr.msg_iovlen = hdr->msg_iovlen + 1; + +#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG + ssize_t ret = lwip_sendmsg_internal(sock, &send_hdr, 0); +#else + ssize_t ret = lwip_sendmsg(sock, &send_hdr, 0); +#endif + mem_free(iov); + return ret; +} + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ diff --git a/src/core/dns.c b/src/core/dns.c index 0c3fd29..ed325ea 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -86,6 +86,11 @@ #include "lwip/opt.h" +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL +#include "lwip/distributed_net/distributed_net.h" +#include "lwip/distributed_net/udp_transmit.h" +#endif + #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" @@ -797,8 +802,18 @@ dns_send(u8_t idx) } /* if here, we have either a new query or a retry on a previous query to process */ +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (is_distributed_net_enabled()) { + p = pbuf_alloc(PBUF_TRANSPORT, + (u16_t)(sizeof(udp_data) + SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); + } else { + p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); + } +#else p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + SIZEOF_DNS_QUERY), PBUF_RAM); +#endif + if (p != NULL) { const ip_addr_t *dst; u16_t dst_port; @@ -807,12 +822,41 @@ dns_send(u8_t idx) hdr.id = lwip_htons(entry->txid); hdr.flags1 = DNS_FLAG1_RD; hdr.numquestions = PP_HTONS(1); +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (is_distributed_net_enabled()) { + udp_data udp_data_hdr = {0}; + (void)memset_s(&udp_data_hdr, sizeof(udp_data_hdr), 0, sizeof(udp_data_hdr)); + dst = &dns_servers[entry->server_idx]; + +#if LWIP_IPV6 + (void)strcpy_s(udp_data_hdr.dest_addr, sizeof(udp_data_hdr.dest_addr), ip4addr_ntoa(&dst->u_addr.ip4)); +#else + (void)strcpy_s(udp_data_hdr.dest_addr, sizeof(udp_data_hdr.dest_addr), ip4addr_ntoa(dst)); +#endif + + udp_data_hdr.dest_port = DNS_SERVER_PORT; + + pbuf_take(p, &udp_data_hdr, sizeof(udp_data_hdr)); + pbuf_take_at(p, &hdr, SIZEOF_DNS_HDR, sizeof(udp_data_hdr)); + } else { + pbuf_take(p, &hdr, SIZEOF_DNS_HDR); + } +#else pbuf_take(p, &hdr, SIZEOF_DNS_HDR); +#endif hostname = entry->name; --hostname; /* convert hostname into suitable query format. */ +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (is_distributed_net_enabled()) { + query_idx = sizeof(udp_data) + SIZEOF_DNS_HDR; + } else { + query_idx = SIZEOF_DNS_HDR; + } +#else query_idx = SIZEOF_DNS_HDR; +#endif do { ++hostname; hostname_part = hostname; @@ -870,7 +914,25 @@ dns_send(u8_t idx) dst_port = DNS_SERVER_PORT; dst = &dns_servers[entry->server_idx]; } +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (is_distributed_net_enabled()) { + ip_addr_t local_addr = {0}; + dst_port = get_local_udp_server_port(); + +#if LWIP_IPV6 + local_addr.u_addr.ip4.addr = ipaddr_addr(LOCAL_SERVER_IP); + local_addr.type = IPADDR_TYPE_V4; +#else + local_addr.addr = ipaddr_addr(LOCAL_SERVER_IP); +#endif + + err = udp_sendto(dns_pcbs[pcb_idx], p, &local_addr, dst_port); + } else { + err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); + } +#else err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); +#endif /* free pbuf */ pbuf_free(p); @@ -1241,9 +1303,28 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, { /* Check whether response comes from the same network address to which the question was sent. (RFC 5452) */ +#if LWIP_ENABLE_DISTRIBUTED_NET && !LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + if (is_distributed_net_enabled()) { +#if LWIP_IPV6 + if (addr->type != IPADDR_TYPE_V4 || addr->u_addr.ip4.addr != ipaddr_addr(LOCAL_SERVER_IP) || + port != get_local_udp_server_port()) { + goto ignore_packet; /* ignore this packet */ + } +#else + if (addr->addr != ipaddr_addr(LOCAL_SERVER_IP) || port != get_local_udp_server_port()) { + goto ignore_packet; /* ignore this packet */ + } +#endif + } else { + if (!ip_addr_eq(addr, &dns_servers[entry->server_idx])) { + goto ignore_packet; /* ignore this packet */ + } + } +#else if (!ip_addr_eq(addr, &dns_servers[entry->server_idx])) { goto ignore_packet; /* ignore this packet */ } +#endif } /* Check if the name in the "question" part match with the name in the entry and diff --git a/src/core/tcp.c b/src/core/tcp.c index ea95ffe..e1f7199 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -156,7 +156,7 @@ static const char *const tcp_state_str[] = { }; /* last local TCP port */ -static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; +static volatile u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; /* Incremented every coarse grained timer shot (typically every 500 ms). */ u32_t tcp_ticks; diff --git a/src/include/lwip/distributed_net/distributed_net.h b/src/include/lwip/distributed_net/distributed_net.h new file mode 100644 index 0000000..77aee48 --- /dev/null +++ b/src/include/lwip/distributed_net/distributed_net.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_DISTRIBUTED_NET_H +#define LWIP_HDR_DISTRIBUTED_NET_H + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/sockets.h" + +#define IP4_MAX_ADDR_LEN 16 /* strlen(255.255.255.255) + 1 */ + +#define LOCAL_SERVER_IP "127.0.0.1" + +#define SOCKET_TO_INDEX(socket) ((socket)-LWIP_SOCKET_OFFSET) + +#define INDEX_TO_SOCKET(index) ((index) + LWIP_SOCKET_OFFSET) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define INIT_SOCK_ADDR(addr, ip_string, port) \ + do { \ + (addr)->sin_family = AF_INET; \ + (addr)->sin_port = lwip_htons(port); \ + (addr)->sin_addr.s_addr = ipaddr_addr(ip_string); \ + } while (0) + +#define SET_MSG_ADDR(hdr, addr, addr_len) \ + do { \ + ((struct msghdr *)(hdr))->msg_name = (void *)(addr); \ + ((struct msghdr *)(hdr))->msg_namelen = (addr_len); \ + } while (0) + +void set_distributed_net_socket(int sock); + +void reset_distributed_net_socket(int sock); + +u16_t get_local_tcp_server_port(void); + +u16_t get_local_udp_server_port(void); + +u8_t is_distributed_net_enabled(void); + +int enable_distributed_net(u16_t tcp_port, u16_t udp_port); + +int disable_distributed_net(void); + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ + +#endif /* LWIP_HDR_DISTRIBUTED_NET_H */ diff --git a/src/include/lwip/distributed_net/distributed_net_core.h b/src/include/lwip/distributed_net/distributed_net_core.h new file mode 100644 index 0000000..cd5d789 --- /dev/null +++ b/src/include/lwip/distributed_net/distributed_net_core.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_DISTRIBUTED_NET_CORE_H +#define LWIP_HDR_DISTRIBUTED_NET_CORE_H + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/distributed_net/distributed_net.h" +#include "lwip/sockets.h" + +#define DNS_PORT 53 + +#define CHECK_PARA(exp, err) \ + do { \ + if (!(exp)) { \ + set_errno(err); \ + return -1; \ + } \ + } while (0) + +#define IS_LOCAL_UDP_SERVER_ADDR(addr) \ + ((addr)->sin_addr.s_addr == ipaddr_addr(LOCAL_SERVER_IP) && (addr)->sin_port == ntohs(get_local_udp_server_port())) + +#define IS_DNS_PORT(addr) (ntohs((addr).sin_port) == DNS_PORT) + +typedef struct tcp_connect_data { + char dest_addr[IP4_MAX_ADDR_LEN]; + u32_t dest_port; +} tcp_connect_data; + +int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t addr_len); + +int distributed_net_close(int sock); + +#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL +ssize_t distributed_net_sendto(int sock, const void *buf, size_t buf_len, int flags, const struct sockaddr *addr, + socklen_t addr_len); + +#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG +ssize_t distributed_net_sendmsg(int sock, const struct msghdr *hdr, int flags); +#endif + +ssize_t distributed_net_recvfrom(int sock, void *buf, size_t buf_len, int flags, struct sockaddr *from, + socklen_t *from_len); +#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ + +#endif /* LWIP_HDR_DISTRIBUTED_NET_CORE_H */ diff --git a/src/include/lwip/distributed_net/distributed_net_utils.h b/src/include/lwip/distributed_net/distributed_net_utils.h new file mode 100644 index 0000000..0c7e1ed --- /dev/null +++ b/src/include/lwip/distributed_net/distributed_net_utils.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_DISTRIBUTED_NET_UTILS_H +#define LWIP_HDR_DISTRIBUTED_NET_UTILS_H + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET + +#include "lwip/sockets.h" + +u8_t is_no_proxy_network_segment(const struct sockaddr_in *addr_in); + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ + +#endif /* LWIP_HDR_DISTRIBUTED_NET_UTILS_H */ diff --git a/src/include/lwip/distributed_net/udp_transmit.h b/src/include/lwip/distributed_net/udp_transmit.h new file mode 100644 index 0000000..3a2972e --- /dev/null +++ b/src/include/lwip/distributed_net/udp_transmit.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_UDP_TRANSMIT_H +#define LWIP_HDR_UDP_TRANSMIT_H + +#include "lwip/opt.h" + +#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL + +#include "lwip/distributed_net/distributed_net.h" +#include "lwip/sockets.h" + +#define MAX_UDP_PAYLOAD_LEN 1024 + +#define MAX_IOV_NUM 32 + +#define UDP_PAYLOAD_LEN(send_len) ((send_len) - (ssize_t)sizeof(udp_data)) + +typedef struct udp_data { + char dest_addr[IP4_MAX_ADDR_LEN]; + u32_t dest_port; + char payload[]; +} udp_data; + +ssize_t udp_transmit_sendto(int sock, const void *buf, size_t buf_len, const struct sockaddr_in *dest_addr); + +ssize_t udp_transmit_sendmsg(int sock, const struct msghdr *hdr); + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ + +#endif /* LWIP_HDR_UDP_TRANSMIT_H */ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index dcd6269..eccadeb 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -629,6 +629,25 @@ int lwip_fcntl(int s, int cmd, int val); const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); int lwip_inet_pton(int af, const char *src, void *dst); +#if LWIP_ENABLE_DISTRIBUTED_NET + +int lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen); + +int lwip_close_internal(int s); + +#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL +ssize_t lwip_sendto_internal(int s, const void *data, size_t size, int flags, const struct sockaddr *to, + socklen_t tolen); + +#if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG +ssize_t lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags); +#endif + +ssize_t lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); +#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ + +#endif + #if LWIP_COMPAT_SOCKETS #if LWIP_COMPAT_SOCKETS != 2 /** @ingroup socket */ -- Gitee From c817cc964da65350fe37b73ea998076354d28725 Mon Sep 17 00:00:00 2001 From: maosiping Date: Tue, 14 Dec 2021 17:59:03 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AE=8F=E5=BC=80?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: maosiping --- .../lwip/distributed_net/udp_transmit.h | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/include/lwip/distributed_net/udp_transmit.h b/src/include/lwip/distributed_net/udp_transmit.h index 3a2972e..23f76bf 100644 --- a/src/include/lwip/distributed_net/udp_transmit.h +++ b/src/include/lwip/distributed_net/udp_transmit.h @@ -32,7 +32,15 @@ #include "lwip/opt.h" -#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL +#if LWIP_ENABLE_DISTRIBUTED_NET + +typedef struct udp_data { + char dest_addr[IP4_MAX_ADDR_LEN]; + u32_t dest_port; + char payload[]; +} udp_data; + +#if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL #include "lwip/distributed_net/distributed_net.h" #include "lwip/sockets.h" @@ -43,16 +51,12 @@ #define UDP_PAYLOAD_LEN(send_len) ((send_len) - (ssize_t)sizeof(udp_data)) -typedef struct udp_data { - char dest_addr[IP4_MAX_ADDR_LEN]; - u32_t dest_port; - char payload[]; -} udp_data; - ssize_t udp_transmit_sendto(int sock, const void *buf, size_t buf_len, const struct sockaddr_in *dest_addr); ssize_t udp_transmit_sendmsg(int sock, const struct msghdr *hdr); -#endif /* LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ +#endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */ + +#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ #endif /* LWIP_HDR_UDP_TRANSMIT_H */ -- Gitee From 7b0cbcf1491cd3e600cb988a8113086562c98c1a Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:25:49 +0800 Subject: [PATCH 10/14] fix compile Signed-off-by: HuangHaitao --- src/core/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/init.c b/src/core/init.c index b906eff..951586a 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -243,10 +243,11 @@ PACK_STRUCT_END #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" #endif #endif /* LWIP_NETCONN && LWIP_TCP */ +#if 0 #if LWIP_NETCONN_FULLDUPLEX && !LWIP_NETCONN_SEM_PER_THREAD #error "For LWIP_NETCONN_FULLDUPLEX to work, LWIP_NETCONN_SEM_PER_THREAD is required" #endif - +#endif /* 0 */ /* Compile-time checks for deprecated options. */ -- Gitee From 43208edb746eabab0edd06c6488ace031ef433b4 Mon Sep 17 00:00:00 2001 From: zhushengle Date: Sat, 25 Feb 2023 11:42:23 +0800 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E5=AE=B9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close #I6HPH2 Signed-off-by: zhushengle --- src/Filelists.cmake | 2 + src/Filelists.mk | 3 +- src/api/api_msg.c | 37 ++++++++ src/api/netifapi.c | 9 +- src/api/sockets.c | 4 + src/core/init.c | 7 ++ src/core/ip.c | 14 +++ src/core/ipv4/dhcp.c | 8 ++ src/core/ipv4/etharp.c | 5 +- src/core/ipv4/icmp.c | 8 ++ src/core/ipv4/igmp.c | 13 ++- src/core/ipv4/ip4.c | 50 ++++++++++- src/core/ipv6/dhcp6.c | 4 + src/core/ipv6/icmp6.c | 4 + src/core/ipv6/ip6.c | 72 ++++++++++++++++ src/core/ipv6/mld6.c | 12 +++ src/core/ipv6/nd6.c | 8 ++ src/core/net_group.c | 90 +++++++++++++++++++ src/core/netif.c | 143 +++++++++++++++++++++++++++++++ src/core/raw.c | 33 +++++++ src/core/tcp.c | 30 +++++++ src/core/tcp_in.c | 34 ++++++++ src/core/tcp_out.c | 12 +++ src/core/udp.c | 46 ++++++++++ src/include/lwip/ip.h | 38 ++++++++ src/include/lwip/ip4.h | 8 ++ src/include/lwip/ip6.h | 4 + src/include/lwip/ip6_zone.h | 8 ++ src/include/lwip/net_group.h | 61 +++++++++++++ src/include/lwip/netif.h | 38 ++++++++ src/include/lwip/netifapi.h | 4 + src/include/lwip/priv/tcp_priv.h | 5 ++ src/include/lwip/raw.h | 4 + src/include/lwip/tcp.h | 4 + src/include/lwip/udp.h | 4 + 35 files changed, 820 insertions(+), 6 deletions(-) create mode 100644 src/core/net_group.c create mode 100644 src/include/lwip/net_group.h diff --git a/src/Filelists.cmake b/src/Filelists.cmake index 228e0f0..c4e366d 100644 --- a/src/Filelists.cmake +++ b/src/Filelists.cmake @@ -56,6 +56,8 @@ set(lwipcore_SRCS ${LWIP_DIR}/src/core/tcp_out.c ${LWIP_DIR}/src/core/timeouts.c ${LWIP_DIR}/src/core/udp.c + ${LWIP_DIR}/src/core/net_group.c + ${LWIP_DIR}/src/core/lowpower.c ) set(lwipcore4_SRCS ${LWIP_DIR}/src/core/ipv4/acd.c diff --git a/src/Filelists.mk b/src/Filelists.mk index 7e076f3..3680999 100644 --- a/src/Filelists.mk +++ b/src/Filelists.mk @@ -49,7 +49,8 @@ COREFILES=$(LWIPDIR)/core/init.c \ $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c \ $(LWIPDIR)/core/timeouts.c \ - $(LWIPDIR)/core/udp.c + $(LWIPDIR)/core/udp.c \ + $(LWIPDIR)/core/net_group.c CORE4FILES=$(LWIPDIR)/core/ipv4/acd.c \ $(LWIPDIR)/core/ipv4/autoip.c \ diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 8092be9..8d54a5e 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -609,7 +609,11 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) * @param msg the api_msg describing the connection type */ static void +#ifdef LOSCFG_NET_CONTAINER +pcb_new(struct api_msg *msg, struct net_group *group) +#else pcb_new(struct api_msg *msg) +#endif { enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; @@ -628,6 +632,9 @@ pcb_new(struct api_msg *msg) case NETCONN_RAW: msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); if (msg->conn->pcb.raw != NULL) { +#ifdef LOSCFG_NET_CONTAINER + set_raw_pcb_net_group(msg->conn->pcb.raw, group); +#endif #if LWIP_IPV6 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { @@ -643,6 +650,9 @@ pcb_new(struct api_msg *msg) case NETCONN_UDP: msg->conn->pcb.udp = udp_new_ip_type(iptype); if (msg->conn->pcb.udp != NULL) { +#ifdef LOSCFG_NET_CONTAINER + set_udp_pcb_net_group(msg->conn->pcb.udp, group); +#endif #if LWIP_UDPLITE if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); @@ -659,6 +669,9 @@ pcb_new(struct api_msg *msg) case NETCONN_TCP: msg->conn->pcb.tcp = tcp_new_ip_type(iptype); if (msg->conn->pcb.tcp != NULL) { +#ifdef LOSCFG_NET_CONTAINER + set_tcp_pcb_net_group(msg->conn->pcb.tcp, group); +#endif setup_tcp(msg->conn); } break; @@ -686,7 +699,11 @@ lwip_netconn_do_newconn(void *m) msg->err = ERR_OK; if (msg->conn->pcb.tcp == NULL) { +#ifdef LOSCFG_NET_CONTAINER + pcb_new(msg, get_curr_process_net_group()); +#else pcb_new(msg); +#endif } /* Else? This "new" connection already has a PCB allocated. */ /* Is this an error condition? Should it be deleted? */ @@ -1249,6 +1266,7 @@ lwip_netconn_do_bind(void *m) msg->err = err; TCPIP_APIMSG_ACK(msg); } + /** * Bind a pcb contained in a netconn to an interface * Called from netconn_bind_if. @@ -1262,8 +1280,17 @@ lwip_netconn_do_bind_if(void *m) struct netif *netif; struct api_msg *msg = (struct api_msg *)m; err_t err; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); + if (group != NULL) { + netif = netif_get_by_index(msg->msg.bc.if_idx, group); + } else { + netif = NULL; + } +#else netif = netif_get_by_index(msg->msg.bc.if_idx); +#endif if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { err = ERR_OK; @@ -2065,8 +2092,18 @@ lwip_netconn_do_join_leave_group_netif(void *m) { struct api_msg *msg = (struct api_msg *)m; struct netif *netif; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); + if (group != NULL) { + netif = netif_get_by_index(msg->msg.jl.if_idx, group); + } else { + netif = NULL; + } +#else netif = netif_get_by_index(msg->msg.jl.if_idx); +#endif + if (netif == NULL) { msg->err = ERR_IF; goto done; diff --git a/src/api/netifapi.c b/src/api/netifapi.c index 25957cd..4ccb50c 100644 --- a/src/api/netifapi.c +++ b/src/api/netifapi.c @@ -63,8 +63,11 @@ netifapi_do_netif_add(struct tcpip_api_call_data *m) /* cast through void* to silence alignment warnings. * We know it works because the structs have been instantiated as struct netifapi_msg */ struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; - +#ifdef LOSCFG_NET_CONTAINER + if (!netif_add( msg->netif, get_curr_process_net_group(), +#else if (!netif_add( msg->netif, +#endif #if LWIP_IPV4 API_EXPR_REF(msg->msg.add.ipaddr), API_EXPR_REF(msg->msg.add.netmask), @@ -122,7 +125,11 @@ netifapi_do_index_to_name(struct tcpip_api_call_data *m) * We know it works because the structs have been instantiated as struct netifapi_msg */ struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; +#ifdef LOSCFG_NET_CONTAINER + if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name, get_curr_process_net_group())) { +#else if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) { +#endif /* return failure via empty name */ msg->msg.ifs.name[0] = '\0'; } diff --git a/src/api/sockets.c b/src/api/sockets.c index ddb6824..b42c6a4 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -3790,7 +3790,11 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index((u8_t)imr->ipv6mr_interface, get_net_group_from_ippcb(sock->conn->pcb.ip)); +#else netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); +#endif if (netif == NULL) { err = EADDRNOTAVAIL; break; diff --git a/src/core/init.c b/src/core/init.c index 951586a..85aadf2 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -57,6 +57,9 @@ #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/api.h" +#ifdef LOSCFG_NET_CONTAINER +#include "lwip/net_group.h" +#endif #include "netif/ppp/ppp_opts.h" #include "netif/ppp/ppp_impl.h" @@ -359,7 +362,11 @@ lwip_init(void) mem_init(); memp_init(); pbuf_init(); +#ifdef LOSCFG_NET_CONTAINER + netif_init(get_root_net_group()); +#else netif_init(); +#endif #if LWIP_IPV4 ip_init(); #if LWIP_ARP diff --git a/src/core/ip.c b/src/core/ip.c index 18514cf..4d66f99 100644 --- a/src/core/ip.c +++ b/src/core/ip.c @@ -164,4 +164,18 @@ ip_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_IPV4 && LWIP_IPV6 */ +#ifdef LOSCFG_NET_CONTAINER +void set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group) +{ + get_default_net_group_ops()->set_ippcb_net_group(pcb, group); +} + +struct net_group *get_net_group_from_ippcb(struct ip_pcb *pcb) +{ + if (pcb != NULL) { + return get_default_net_group_ops()->get_net_group_from_ippcb(pcb); + } + return NULL; +} +#endif #endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 85c23f8..2e1892e 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -512,7 +512,11 @@ dhcp_coarse_tmr(void) struct netif *netif; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); /* iterate through all network interfaces */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif /* only act on DHCP configured interfaces */ struct dhcp *dhcp = netif_dhcp_data(netif); if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { @@ -549,7 +553,11 @@ dhcp_fine_tmr(void) { struct netif *netif; /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif struct dhcp *dhcp = netif_dhcp_data(netif); /* only act on DHCP configured interfaces */ if (dhcp != NULL) { diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c index 3092dc9..2163e5d 100644 --- a/src/core/ipv4/etharp.c +++ b/src/core/ipv4/etharp.c @@ -509,8 +509,11 @@ etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); - +#ifdef LOSCFG_NET_CONTAINER + netif = ip4_route(ipaddr, get_root_net_group()); +#else netif = ip4_route(ipaddr); +#endif if (netif == NULL) { return ERR_RTE; } diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index f35ff4b..f06c2b5 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -386,10 +386,18 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { ip4_addr_t iphdr_dst; ip4_addr_copy(iphdr_dst, iphdr->dest); +#ifdef LOSCFG_NET_CONTAINER + netif = ip4_route_src(&iphdr_dst, &iphdr_src, get_root_net_group()); +#else netif = ip4_route_src(&iphdr_dst, &iphdr_src); +#endif } +#else +#ifdef LOSCFG_NET_CONTAINER + netif = ip4_route(&iphdr_src, get_root_net_group()); #else netif = ip4_route(&iphdr_src); +#endif #endif if (netif != NULL) { /* calculate checksum */ diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index a74df16..35b020b 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -458,7 +458,11 @@ igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif /* Should we join this interface ? */ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) { err = igmp_joingroup_netif(netif, groupaddr); @@ -555,7 +559,11 @@ igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif /* Should we leave this interface ? */ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) { err_t res = igmp_leavegroup_netif(netif, groupaddr); @@ -641,8 +649,11 @@ void igmp_tmr(void) { struct netif *netif; - +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif struct igmp_group *group = netif_igmp_data(netif); while (group != NULL) { diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index e044bff..1419b3a 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -126,7 +126,11 @@ ip4_set_default_multicast_netif(struct netif *default_multicast_netif) * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides the parameters. */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest, struct net_group *group) +#else ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) +#endif { if (src != NULL) { /* when src==NULL, the hook is called from ip4_route(dest) */ @@ -135,7 +139,11 @@ ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) return netif; } } +#ifdef LOSCFG_NET_CONTAINER + return ip4_route(dest, group); +#else return ip4_route(dest); +#endif } #endif /* LWIP_HOOK_IP4_ROUTE_SRC */ @@ -149,7 +157,11 @@ ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) * @return the netif on which to send to reach dest */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +ip4_route(const ip4_addr_t *dest, struct net_group *group) +#else ip4_route(const ip4_addr_t *dest) +#endif { #if !LWIP_SINGLE_NETIF struct netif *netif; @@ -167,7 +179,11 @@ ip4_route(const ip4_addr_t *dest) LWIP_UNUSED_ARG(dest); /* iterate through netifs */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif /* is the netif up, does it have a link and a valid address? */ if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { /* network mask matches? */ @@ -187,11 +203,20 @@ ip4_route(const ip4_addr_t *dest) /* loopif is disabled, loopback traffic is passed through any netif */ if (ip4_addr_isloopback(dest)) { /* don't check for link on loopback traffic */ +#ifdef LOSCFG_NET_CONTAINER + if (group->netif_default != NULL && netif_is_up(group->netif_default)) { + return group->netif_default; +#else if ((netif_default != NULL) && netif_is_up(netif_default)) { return netif_default; +#endif } /* default netif is not up, just use any netif for loopback traffic */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (netif_is_up(netif)) { return netif; } @@ -212,9 +237,14 @@ ip4_route(const ip4_addr_t *dest) } #endif #endif /* !LWIP_SINGLE_NETIF */ - +#ifdef LOSCFG_NET_CONTAINER + if ((group->netif_default == NULL) || !netif_is_up(group->netif_default) || + !netif_is_link_up(group->netif_default) || + ip4_addr_isany_val(*netif_ip4_addr(group->netif_default)) || ip4_addr_isloopback(dest)) { +#else if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) { +#endif /* No matching netif found and default netif is not usable. If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", @@ -223,8 +253,11 @@ ip4_route(const ip4_addr_t *dest) MIB2_STATS_INC(mib2.ipoutnoroutes); return NULL; } - +#ifdef LOSCFG_NET_CONTAINER + return group->netif_default; +#else return netif_default; +#endif } #if IP_FORWARD @@ -475,6 +508,10 @@ ip4_input(struct pbuf *p, struct netif *inp) IP_STATS_INC(ip.recv); MIB2_STATS_INC(mib2.ipinreceives); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_netif(inp); +#endif + /* identify the IP header */ iphdr = (struct ip_hdr *)p->payload; if (IPH_V(iphdr) != 4) { @@ -586,7 +623,11 @@ ip4_input(struct pbuf *p, struct netif *inp) #endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ { #if !LWIP_SINGLE_NETIF +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (netif == inp) { /* we checked that before already */ continue; @@ -1065,8 +1106,13 @@ ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif; LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_curr_process_net_group(); + if ((netif = ip4_route_src(src, dest, group)) == NULL) { +#else if ((netif = ip4_route_src(src, dest)) == NULL) { +#endif LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); diff --git a/src/core/ipv6/dhcp6.c b/src/core/ipv6/dhcp6.c index e6a7e64..e16c36b 100644 --- a/src/core/ipv6/dhcp6.c +++ b/src/core/ipv6/dhcp6.c @@ -800,7 +800,11 @@ dhcp6_tmr(void) { struct netif *netif; /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); /* only act on DHCPv6 configured interfaces */ if (dhcp6 != NULL) { diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index ed0bd7b..da17ced 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -360,7 +360,11 @@ icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, /* Swap source and destination for the reply. */ reply_dest = src_addr; reply_src = dest_addr; +#ifdef LOSCFG_NET_CONTAINER + netif = ip6_route(reply_src, reply_dest, get_root_net_group()); +#else netif = ip6_route(reply_src, reply_dest); +#endif if (netif == NULL) { ICMP6_STATS_INC(icmp6.rterr); return; diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 2c25f8a..cb3cade 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -83,7 +83,11 @@ * @return the netif on which to send to reach dest */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, struct net_group *group) +#else ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) +#endif { #if LWIP_SINGLE_NETIF LWIP_UNUSED_ARG(src); @@ -95,12 +99,22 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) LWIP_ASSERT_CORE_LOCKED(); /* If single netif configuration, fast return. */ +#ifdef LOSCFG_NET_CONTAINER + if ((group->netif_list != NULL) && (group->netif_list->next == NULL)) { + if (!netif_is_up(group->netif_list) || !netif_is_link_up(group->netif_list) || + (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, group->netif_list))) { +#else if ((netif_list != NULL) && (netif_list->next == NULL)) { if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list) || (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, netif_list))) { +#endif return NULL; } +#ifdef LOSCFG_NET_CONTAINER + return group->netif_list; +#else return netif_list; +#endif } #if LWIP_IPV6_SCOPES @@ -113,7 +127,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) IP6_ADDR_ZONECHECK(dest); /* Find a netif based on the zone. For custom mappings, one zone may map * to multiple netifs, so find one that can actually send a packet. */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (ip6_addr_test_zone(dest, netif) && netif_is_up(netif) && netif_is_link_up(netif)) { return netif; @@ -150,7 +168,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #if LWIP_IPV6_SCOPES if (ip6_addr_has_zone(src)) { /* Find a netif matching the source zone (relatively cheap). */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (netif_is_up(netif) && netif_is_link_up(netif) && ip6_addr_test_zone(src, netif)) { return netif; @@ -160,7 +182,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #endif /* LWIP_IPV6_SCOPES */ { /* Find a netif matching the source address (relatively expensive). */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } @@ -193,7 +219,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) * such, the destination address may still match a local address, and so we * still need to check for exact matches here. By (lwIP) policy, statically * configured addresses do always have an implied local /64 subnet. */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } @@ -216,7 +246,11 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) /* Try with the netif that matches the source address. Given the earlier rule * for scoped source addresses, this applies to unscoped addresses only. */ if (!ip6_addr_isany(src)) { +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } @@ -233,11 +267,20 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) /* loopif is disabled, loopback traffic is passed through any netif */ if (ip6_addr_isloopback(dest)) { /* don't check for link on loopback traffic */ +#ifdef LOSCFG_NET_CONTAINER + if (group->netif_default != NULL && netif_is_up(group->netif_default)) { + return group->netif_default; +#else if (netif_default != NULL && netif_is_up(netif_default)) { return netif_default; +#endif } /* default netif is not up, just use any netif for loopback traffic */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (netif_is_up(netif)) { return netif; } @@ -248,10 +291,19 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) #endif /* !LWIP_SINGLE_NETIF */ /* no matching netif found, use default netif, if up */ +#ifdef LOSCFG_NET_CONTAINER + if ((group->netif_default == NULL) || !netif_is_up(group->netif_default) || + !netif_is_link_up(group->netif_default)) { +#else if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { +#endif return NULL; } +#ifdef LOSCFG_NET_CONTAINER + return group->netif_default; +#else return netif_default; +#endif } /** @@ -524,6 +576,10 @@ ip6_input(struct pbuf *p, struct netif *inp) IP6_STATS_INC(ip6.recv); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_netif(inp); +#endif + /* identify the IP header */ ip6hdr = (struct ip6_hdr *)p->payload; if (IP6H_V(ip6hdr) != 6) { @@ -652,7 +708,11 @@ ip6_input(struct pbuf *p, struct netif *inp) } #endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ #if !LWIP_SINGLE_NETIF +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, group) { +#else NETIF_FOREACH(netif) { +#endif if (netif == inp) { /* we checked that before already */ continue; @@ -1298,14 +1358,26 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_curr_process_net_group(); +#endif + if (dest != LWIP_IP_HDRINCL) { +#ifdef LOSCFG_NET_CONTAINER + netif = ip6_route(src, dest, group); +#else netif = ip6_route(src, dest); +#endif } else { /* IP header included in p, read addresses. */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy_from_packed(src_addr, ip6hdr->src); ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); +#ifdef LOSCFG_NET_CONTAINER + netif = ip6_route(&src_addr, &dest_addr, group); +#else netif = ip6_route(&src_addr, &dest_addr); +#endif dest = &dest_addr; } diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index ac4fb01..4d1a0a2 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -320,7 +320,11 @@ mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) LWIP_ASSERT_CORE_LOCKED(); /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif /* Should we join this interface ? */ if (ip6_addr_isany(srcaddr) || netif_get_ip6_addr_match(netif, srcaddr) >= 0) { @@ -409,7 +413,11 @@ mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) LWIP_ASSERT_CORE_LOCKED(); /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif /* Should we leave this interface ? */ if (ip6_addr_isany(srcaddr) || netif_get_ip6_addr_match(netif, srcaddr) >= 0) { @@ -497,7 +505,11 @@ mld6_tmr(void) { struct netif *netif; +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif struct mld_group *group = netif_mld6_data(netif); while (group != NULL) { diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index f7b5f56..a6ba67e 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1076,7 +1076,11 @@ nd6_tmr(void) } /* Process our own addresses, updating address lifetimes and/or DAD state. */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { u8_t addr_state; #if LWIP_IPV6_ADDRESS_LIFETIMES @@ -1157,7 +1161,11 @@ nd6_tmr(void) /* Send router solicitation messages, if necessary. */ if (!nd6_tmr_rs_reduction) { nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) { +#else NETIF_FOREACH(netif) { +#endif if ((netif->rs_count > 0) && netif_is_up(netif) && netif_is_link_up(netif) && !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && diff --git a/src/core/net_group.c b/src/core/net_group.c new file mode 100644 index 0000000..c366c45 --- /dev/null +++ b/src/core/net_group.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef LOSCFG_NET_CONTAINER +#include "lwip/net_group.h" +#include "lwip/netif.h" + +static struct netif root_loop_netif = {0}; +static struct net_group root_net_group = { + .loop_netif = &root_loop_netif, +}; + +struct net_group *get_root_net_group(void) +{ + return &root_net_group; +} + +struct net_group *get_curr_process_net_group(void) +{ + return get_default_net_group_ops()->get_curr_process_net_group(); +} + +static void do_set_netif_net_group(struct netif *netif, struct net_group *group) +{ + (void)netif; + (void)group; +} + +static struct net_group *do_get_net_group_from_netif(struct netif *netif) +{ + (void)netif; + return get_root_net_group(); +} + +static void do_set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group) +{ + (void)pcb; + (void)group; +} + +static struct net_group *do_get_net_group_from_ippcb(struct ip_pcb *pcb) +{ + (void)pcb; + return get_root_net_group(); +} + +static struct net_group_ops root_net_group_ops = { + .get_curr_process_net_group = get_root_net_group, + .set_netif_net_group = do_set_netif_net_group, + .get_net_group_from_netif = do_get_net_group_from_netif, + .set_ippcb_net_group = do_set_ippcb_net_group, + .get_net_group_from_ippcb = do_get_net_group_from_ippcb, +}; + +struct net_group_ops *default_net_group_ops = &root_net_group_ops; + +void set_default_net_group_ops(struct net_group_ops *ops) { + default_net_group_ops = ops; +} + +struct net_group_ops *get_default_net_group_ops(void) { + return default_net_group_ops; +} +#endif diff --git a/src/core/netif.c b/src/core/netif.c index d326a58..c00b03d 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -109,13 +109,17 @@ static netif_ext_callback_t *ext_callback; #endif +#ifndef LOSCFG_NET_CONTAINER #if !LWIP_SINGLE_NETIF struct netif *netif_list; #endif /* !LWIP_SINGLE_NETIF */ struct netif *netif_default; +#endif #define netif_index_to_num(index) ((index) - 1) +#ifndef LOSCFG_NET_CONTAINER static u8_t netif_num; +#endif #if LWIP_NUM_NETIF_CLIENT_DATA > 0 static u8_t netif_client_id; @@ -141,7 +145,16 @@ static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const i #endif +#ifdef LOSCFG_NET_CONTAINER +struct net_group *get_net_group_from_netif(struct netif *netif) { + if (netif != NULL) { + return get_default_net_group_ops()->get_net_group_from_netif(netif); + } + return NULL; +} +#else static struct netif loop_netif; +#endif #if LWIP_TESTMODE struct netif* netif_get_loopif(void) @@ -185,7 +198,11 @@ netif_loopif_init(struct netif *netif) #endif /* LWIP_HAVE_LOOPIF */ void +#ifdef LOSCFG_NET_CONTAINER +netif_init(struct net_group *group) +#else netif_init(void) +#endif { #if LWIP_HAVE_LOOPIF #if LWIP_IPV4 @@ -198,19 +215,41 @@ netif_init(void) #define LOOPIF_ADDRINIT #endif /* LWIP_IPV4 */ +#ifdef LOSCFG_NET_CONTAINER +struct netif *loop_netif = group->loop_netif; +#endif + #if NO_SYS +#ifdef LOSCFG_NET_CONTAINER + netif_add(loop_netif, group, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); +#else netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); +#endif #else /* NO_SYS */ +#ifdef LOSCFG_NET_CONTAINER + netif_add(loop_netif, group, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); +#else netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); +#endif #endif /* NO_SYS */ #if LWIP_IPV6 +#ifdef LOSCFG_NET_CONTAINER + IP_ADDR6_HOST(loop_netif->ip6_addr, 0, 0, 0, 0x00000001UL); + loop_netif->ip6_addr_state[0] = IP6_ADDR_VALID; +#else IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; +#endif #endif /* LWIP_IPV6 */ +#ifdef LOSCFG_NET_CONTAINER + netif_set_link_up(loop_netif); + netif_set_up(loop_netif); +#else netif_set_link_up(&loop_netif); netif_set_up(&loop_netif); +#endif #endif /* LWIP_HAVE_LOOPIF */ } @@ -247,9 +286,17 @@ netif_input(struct pbuf *p, struct netif *inp) * Same as @ref netif_add but without IPv4 addresses */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +netif_add_noaddr(struct netif *netif, struct net_group *group, void *state, netif_init_fn init, netif_input_fn input) +#else netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input) +#endif { +#ifdef LOSCFG_NET_CONTAINER + return netif_add(netif, group, +#else return netif_add(netif, +#endif #if LWIP_IPV4 NULL, NULL, NULL, #endif /* LWIP_IPV4*/ @@ -284,7 +331,11 @@ netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_inp * @return netif, or NULL if failed. */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +netif_add(struct netif *netif, struct net_group *group, +#else netif_add(struct netif *netif, +#endif #if LWIP_IPV4 const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, #endif /* LWIP_IPV4 */ @@ -296,8 +347,16 @@ netif_add(struct netif *netif, LWIP_ASSERT_CORE_LOCKED(); +#ifdef LOSCFG_NET_CONTAINER + get_default_net_group_ops()->set_netif_net_group(netif, group); +#endif + #if LWIP_SINGLE_NETIF +#ifdef LOSCFG_NET_CONTAINER + if (group->loop_netif != NULL) { +#else if (netif_default != NULL) { +#endif LWIP_ASSERT("single netif already set", 0); return NULL; } @@ -362,7 +421,11 @@ netif_add(struct netif *netif, /* remember netif specific state information data */ netif->state = state; +#ifdef LOSCFG_NET_CONTAINER + netif->num = group->netif_num; +#else netif->num = netif_num; +#endif netif->input = input; #if LWIP_ACD @@ -408,7 +471,11 @@ netif_add(struct netif *netif, netif->num = 0; } num_netifs = 0; +#ifdef LOSCFG_NET_CONTAINER + for (netif2 = group->netif_list; netif2 != NULL; netif2 = netif2->next) { +#else for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) { +#endif LWIP_ASSERT("netif already added", netif2 != netif); num_netifs++; LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255); @@ -420,14 +487,27 @@ netif_add(struct netif *netif, } while (netif2 != NULL); } if (netif->num == 254) { +#ifdef LOSCFG_NET_CONTAINER + group->netif_num = 0; +#else netif_num = 0; +#endif } else { +#ifdef LOSCFG_NET_CONTAINER + group->netif_num = (u8_t)(netif->num + 1); +#else netif_num = (u8_t)(netif->num + 1); +#endif } /* add this netif to the list */ +#ifdef LOSCFG_NET_CONTAINER + netif->next = group->netif_list; + group->netif_list = netif; +#else netif->next = netif_list; netif_list = netif; +#endif #endif /* "LWIP_SINGLE_NETIF */ mib2_netif_added(netif); @@ -772,7 +852,13 @@ netif_remove(struct netif *netif) if (netif == NULL) { return; } +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_netif(netif); + if (group == NULL) { + return; + } +#endif netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL); #if LWIP_IPV4 @@ -807,18 +893,35 @@ netif_remove(struct netif *netif) mib2_remove_ip4(netif); /* this netif is default? */ +#ifdef LOSCFG_NET_CONTAINER + if (group->netif_default == netif) { +#else if (netif_default == netif) { +#endif /* reset default netif */ +#ifdef LOSCFG_NET_CONTAINER + netif_set_default(NULL, group); +#else netif_set_default(NULL); +#endif } #if !LWIP_SINGLE_NETIF /* is it the first netif? */ +#ifdef LOSCFG_NET_CONTAINER + if (group->netif_list == netif) { + group->netif_list = netif->next; +#else if (netif_list == netif) { netif_list = netif->next; +#endif } else { /* look for netif further down the list */ struct netif *tmp_netif; +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(tmp_netif, group) { +#else NETIF_FOREACH(tmp_netif) { +#endif if (tmp_netif->next == netif) { tmp_netif->next = netif->next; break; @@ -846,7 +949,11 @@ netif_remove(struct netif *netif) * @param netif the default network interface */ void +#ifdef LOSCFG_NET_CONTAINER +netif_set_default(struct netif *netif, struct net_group *group) +#else netif_set_default(struct netif *netif) +#endif { LWIP_ASSERT_CORE_LOCKED(); @@ -857,11 +964,22 @@ netif_set_default(struct netif *netif) /* install default route */ mib2_add_route_ip4(1, netif); } +#ifdef LOSCFG_NET_CONTAINER + group->netif_default = netif; +#else netif_default = netif; +#endif LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); } +#ifdef LOSCFG_NET_CONTAINER +void +netif_set_default2(struct netif *netif) +{ + netif_set_default(netif, get_curr_process_net_group()); +} +#endif /** * @ingroup netif * Bring an interface up, available for processing @@ -1130,7 +1248,11 @@ netif_loop_output(struct netif *netif, struct pbuf *p) * if not they are adjusted for 'netif'. */ #if MIB2_STATS #if LWIP_HAVE_LOOPIF +#ifdef LOSCFG_NET_CONTAINER + struct netif *stats_if = get_net_group_from_netif(netif)->loop_netif; +#else struct netif *stats_if = &loop_netif; +#endif #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ @@ -1255,7 +1377,11 @@ netif_poll(struct netif *netif) * if not they are adjusted for 'netif'. */ #if MIB2_STATS #if LWIP_HAVE_LOOPIF +#ifdef LOSCFG_NET_CONTAINER + struct netif *stats_if = get_net_group_from_netif(netif)->loop_netif; +#else struct netif *stats_if = &loop_netif; +#endif #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ @@ -1707,9 +1833,17 @@ netif_name_to_index(const char *name) * @param name char buffer of at least NETIF_NAMESIZE bytes */ char * +#ifdef LOSCFG_NET_CONTAINER +netif_index_to_name(u8_t idx, char *name, struct net_group *group) +#else netif_index_to_name(u8_t idx, char *name) +#endif { +#ifdef LOSCFG_NET_CONTAINER + struct netif *netif = netif_get_by_index(idx, group); +#else struct netif *netif = netif_get_by_index(idx); +#endif if (netif != NULL) { name[0] = netif->name[0]; @@ -1727,14 +1861,23 @@ netif_index_to_name(u8_t idx, char *name) * @param idx index of netif to find */ struct netif * +#ifdef LOSCFG_NET_CONTAINER +netif_get_by_index(u8_t idx, struct net_group *group) +#else netif_get_by_index(u8_t idx) +#endif { struct netif *netif; LWIP_ASSERT_CORE_LOCKED(); +#ifdef LOSCFG_NET_CONTAINER + if (idx != NETIF_NO_INDEX && group != NULL) { + NETIF_FOREACH(netif, group) { +#else if (idx != NETIF_NO_INDEX) { NETIF_FOREACH(netif) { +#endif if (idx == netif_get_index(netif)) { return netif; /* found! */ } diff --git a/src/core/raw.c b/src/core/raw.c index d85aaec..133c98b 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -135,6 +135,9 @@ raw_input_state_t raw_input(struct pbuf *p, struct netif *inp) { struct raw_pcb *pcb, *prev; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *inp_net_group = get_net_group_from_netif(inp); +#endif s16_t proto; raw_input_state_t ret = RAW_INPUT_NONE; u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); @@ -164,7 +167,12 @@ raw_input(struct pbuf *p, struct netif *inp) /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while (pcb != NULL) { +#ifdef LOSCFG_NET_CONTAINER + if (inp_net_group == get_net_group_from_raw_pcb(pcb) && + (pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && +#else if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && +#endif (((pcb->flags & RAW_FLAGS_CONNECTED) == 0) || ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()))) { /* receive callback function available? */ @@ -362,8 +370,15 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_raw_pcb(pcb); +#endif if (pcb->netif_idx != NETIF_NO_INDEX) { +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index(pcb->netif_idx, group); +#else netif = netif_get_by_index(pcb->netif_idx); +#endif } else { #if LWIP_MULTICAST_TX_OPTIONS netif = NULL; @@ -371,13 +386,21 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) /* For multicast-destined packets, use the user-provided interface index to * determine the outgoing interface, if an interface index is set and a * matching netif can be found. Otherwise, fall back to regular routing. */ +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index(pcb->mcast_ifindex, group); +#else netif = netif_get_by_index(pcb->mcast_ifindex); +#endif } if (netif == NULL) #endif /* LWIP_MULTICAST_TX_OPTIONS */ { +#ifdef LOSCFG_NET_CONTAINER + netif = ip_route(&pcb->local_ip, ipaddr, group); +#else netif = ip_route(&pcb->local_ip, ipaddr); +#endif } } @@ -581,6 +604,16 @@ raw_remove(struct raw_pcb *pcb) memp_free(MEMP_RAW_PCB, pcb); } +#ifdef LOSCFG_NET_CONTAINER +void set_raw_pcb_net_group(struct raw_pcb *pcb, struct net_group *group) +{ + set_ippcb_net_group((struct ip_pcb *)pcb, group); +} + +struct net_group *get_net_group_from_raw_pcb(struct raw_pcb *pcb) { + return get_net_group_from_ippcb((struct ip_pcb *)pcb); +} +#endif /** * @ingroup raw_raw * Create a RAW PCB. diff --git a/src/core/tcp.c b/src/core/tcp.c index e1f7199..f883c31 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -194,6 +194,17 @@ static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); #endif +#ifdef LOSCFG_NET_CONTAINER +void set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group) +{ + set_ippcb_net_group((struct ip_pcb *)pcb, group); +} + +struct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb) +{ + return get_net_group_from_ippcb((struct ip_pcb *)pcb); +} +#endif /** * Initialize this module. */ @@ -715,7 +726,11 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) /* Check if the address already is in use (on all lists) */ for (i = 0; i < max_pcb_list; i++) { for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { +#ifdef LOSCFG_NET_CONTAINER + if (cpcb->local_port == port && (get_net_group_from_tcp_pcb(pcb) == get_net_group_from_tcp_pcb(cpcb))) { +#else if (cpcb->local_port == port) { +#endif #if SO_REUSE /* Omit checking for the same port if both pcbs have REUSEADDR set. For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in @@ -885,6 +900,9 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) res = ERR_MEM; goto done; } +#ifdef LOSCFG_NET_CONTAINER + set_tcp_pcb_net_group((struct tcp_pcb *)lpcb, get_net_group_from_tcp_pcb(pcb)); +#endif lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; @@ -1083,15 +1101,27 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_tcp_pcb(pcb); + LWIP_ERROR("tcp_connect: invalid net group", group != NULL, return ERR_RTE); +#endif LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); ip_addr_set(&pcb->remote_ip, ipaddr); pcb->remote_port = port; if (pcb->netif_idx != NETIF_NO_INDEX) { +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index(pcb->netif_idx, group); +#else netif = netif_get_by_index(pcb->netif_idx); +#endif } else { /* check if we have a route to the remote host */ +#ifdef LOSCFG_NET_CONTAINER + netif = ip_route(&pcb->local_ip, &pcb->remote_ip, group); +#else netif = ip_route(&pcb->local_ip, &pcb->remote_ip); +#endif } if (netif == NULL) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 1b17e40..01c6488 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -119,6 +119,9 @@ tcp_input(struct pbuf *p, struct netif *inp) { struct tcp_pcb *pcb, *prev; struct tcp_pcb_listen *lpcb; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_netif(inp); +#endif #if SO_REUSE struct tcp_pcb *lpcb_prev = NULL; struct tcp_pcb_listen *lpcb_any = NULL; @@ -259,7 +262,12 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } +#ifdef LOSCFG_NET_CONTAINER + if (group == get_net_group_from_tcp_pcb(pcb) && + pcb->remote_port == tcphdr->src && +#else if (pcb->remote_port == tcphdr->src && +#endif pcb->local_port == tcphdr->dest && ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()) && ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { @@ -292,7 +300,12 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } +#ifdef LOSCFG_NET_CONTAINER + if (group == get_net_group_from_tcp_pcb(pcb) && + pcb->remote_port == tcphdr->src && +#else if (pcb->remote_port == tcphdr->src && +#endif pcb->local_port == tcphdr->dest && ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()) && ip_addr_eq(&pcb->local_ip, ip_current_dest_addr())) { @@ -323,7 +336,11 @@ tcp_input(struct pbuf *p, struct netif *inp) continue; } +#ifdef LOSCFG_NET_CONTAINER + if (group == get_net_group_from_tcp_pcb((struct tcp_pcb *)lpcb) && lpcb->local_port == tcphdr->dest) { +#else if (lpcb->local_port == tcphdr->dest) { +#endif if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { /* found an ANY TYPE (IPv4/IPv6) match */ #if SO_REUSE @@ -640,6 +657,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_tcp_pcb((struct tcp_pcb *)pcb); +#endif /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { @@ -668,6 +688,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_UNUSED_ARG(err); /* err not useful here */ return; } +#ifdef LOSCFG_NET_CONTAINER + set_tcp_pcb_net_group(npcb, group); +#endif #if TCP_LISTEN_BACKLOG pcb->accepts_pending++; tcp_set_flags(npcb, TF_BACKLOGPEND); @@ -706,7 +729,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->snd_wnd_max = npcb->snd_wnd; #if TCP_CALCULATE_EFF_SEND_MSS +#ifdef LOSCFG_NET_CONTAINER + npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip, group); +#else npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); +#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ MIB2_STATS_INC(mib2.tcppassiveopens); @@ -795,6 +822,9 @@ tcp_process(struct tcp_pcb *pcb) err_t err; err = ERR_OK; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_tcp_pcb(pcb); +#endif LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL); @@ -877,7 +907,11 @@ tcp_process(struct tcp_pcb *pcb) pcb->state = ESTABLISHED; #if TCP_CALCULATE_EFF_SEND_MSS +#ifdef LOSCFG_NET_CONTAINER + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, group); +#else pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); +#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index cfcc55d..ebbc6b3 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -135,11 +135,23 @@ static struct netif * tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) { LWIP_UNUSED_ARG(src); /* in case IPv4-only and source-based routing is disabled */ +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_tcp_pcb(pcb); + LWIP_ERROR("tcp_route: invalid net group", group != NULL, return NULL); +#endif if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { +#ifdef LOSCFG_NET_CONTAINER + return netif_get_by_index(pcb->netif_idx, group); +#else return netif_get_by_index(pcb->netif_idx); +#endif } else { +#ifdef LOSCFG_NET_CONTAINER + return ip_route(src, dst, group); +#else return ip_route(src, dst); +#endif } } diff --git a/src/core/udp.c b/src/core/udp.c index 362def8..daaee48 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -80,6 +80,17 @@ static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; /* exported in udp.h (was static) */ struct udp_pcb *udp_pcbs; +#ifdef LOSCFG_NET_CONTAINER +void set_udp_pcb_net_group(struct udp_pcb *pcb, struct net_group *group) +{ + set_ippcb_net_group((struct ip_pcb *)pcb, group); +} + +struct net_group *get_net_group_from_udp_pcb(struct udp_pcb *pcb) +{ + return get_net_group_from_ippcb((struct ip_pcb *)pcb); +} +#endif /** * Initialize this module. */ @@ -196,6 +207,9 @@ udp_input(struct pbuf *p, struct netif *inp) struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; +#ifdef LOSCFG_NET_CONTAINER + struct net_group *inp_net_group = get_net_group_from_netif(inp); +#endif u16_t src, dest; u8_t broadcast; u8_t for_us = 0; @@ -259,7 +273,11 @@ udp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ +#ifdef LOSCFG_NET_CONTAINER + if (inp_net_group == get_net_group_from_udp_pcb(pcb) && (pcb->local_port == dest) && +#else if ((pcb->local_port == dest) && +#endif (udp_input_local_match(pcb, inp, broadcast) != 0)) { if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) { if (uncon_pcb == NULL) { @@ -381,7 +399,11 @@ udp_input(struct pbuf *p, struct netif *inp) if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { +#ifdef LOSCFG_NET_CONTAINER + if (mpcb != pcb && inp_net_group == get_net_group_from_udp_pcb(mpcb)) { +#else if (mpcb != pcb) { +#endif /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && (udp_input_local_match(mpcb, inp, broadcast) != 0)) { @@ -547,8 +569,16 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); +#ifdef LOSCFG_NET_CONTAINER + struct net_group *group = get_net_group_from_udp_pcb(pcb); + LWIP_ERROR("udp_sendto: invalid net group", group != NULL, return ERR_VAL); +#endif if (pcb->netif_idx != NETIF_NO_INDEX) { +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index(pcb->netif_idx, group); +#else netif = netif_get_by_index(pcb->netif_idx); +#endif } else { #if LWIP_MULTICAST_TX_OPTIONS netif = NULL; @@ -560,7 +590,11 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, * list, but by doing so we skip a route lookup. If the interface index has * gone stale, we fall through and do the regular route lookup after all. */ if (pcb->mcast_ifindex != NETIF_NO_INDEX) { +#ifdef LOSCFG_NET_CONTAINER + netif = netif_get_by_index(pcb->mcast_ifindex, group); +#else netif = netif_get_by_index(pcb->mcast_ifindex); +#endif } #if LWIP_IPV4 else @@ -575,7 +609,11 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, fails, we try regular routing as though no override was set. */ if (!ip4_addr_isany_val(pcb->mcast_ip4) && !ip4_addr_eq(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { +#ifdef LOSCFG_NET_CONTAINER + netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4, group); +#else netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4); +#endif } } #endif /* LWIP_IPV4 */ @@ -585,7 +623,11 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, #endif /* LWIP_MULTICAST_TX_OPTIONS */ { /* find the outgoing network interface for this packet */ +#ifdef LOSCFG_NET_CONTAINER + netif = ip_route(&pcb->local_ip, dst_ip, group); +#else netif = ip_route(&pcb->local_ip, dst_ip); +#endif } } @@ -990,7 +1032,11 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) } } else { for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { +#ifdef LOSCFG_NET_CONTAINER + if (pcb != ipcb && (get_net_group_from_udp_pcb(pcb) == get_net_group_from_udp_pcb(ipcb))) { +#else if (pcb != ipcb) { +#endif /* By default, we don't allow to bind to a port that any other udp PCB is already bound to, unless *all* PCBs with that port have the REUSEADDR flag set. */ diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 668d831..3599d38 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -47,6 +47,9 @@ #include "lwip/ip4.h" #include "lwip/ip6.h" #include "lwip/prot/ip.h" +#ifdef LOSCFG_NET_CONTAINER +#include "lwip/net_group.h" +#endif #ifdef __cplusplus extern "C" { @@ -69,10 +72,33 @@ extern "C" { #define IP_PCB_NETIFHINT #endif /* LWIP_NETIF_USE_HINTS */ +#ifdef LOSCFG_NET_CONTAINER +#ifndef IP_PCB_NETGROUP +#define IP_PCB_NETGROUP +#endif +#endif + /** This is the common part of all PCB types. It needs to be at the beginning of a PCB type definition. It is located here so that changes to this common part are made in one location instead of having to change all PCB structs. */ +#ifdef LOSCFG_NET_CONTAINER +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Bound netif index */ \ + u8_t netif_idx; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_NETIFHINT \ + IP_PCB_NETGROUP +#else #define IP_PCB \ /* ip addresses in network byte order */ \ ip_addr_t local_ip; \ @@ -87,6 +113,7 @@ extern "C" { u8_t ttl \ /* link layer address resolution hint */ \ IP_PCB_NETIFHINT +#endif struct ip_pcb { /* Common members of all PCB types */ @@ -270,10 +297,17 @@ extern struct ip_globals ip_data; * @ingroup ip * Get netif for address combination. See \ref ip6_route and \ref ip4_route */ +#ifdef LOSCFG_NET_CONTAINER +#define ip_route(src, dest, group) \ + (IP_IS_V6(dest) ? \ + ip6_route(ip_2_ip6(src), ip_2_ip6(dest), group) : \ + ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest), group)) +#else #define ip_route(src, dest) \ (IP_IS_V6(dest) ? \ ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest))) +#endif /** * @ingroup ip * Get netif for IP. @@ -332,6 +366,10 @@ err_t ip_input(struct pbuf *p, struct netif *inp); (ipaddr) = ip_netif_get_local_ip(netif, dest); \ }while(0) +#ifdef LOSCFG_NET_CONTAINER +void set_ippcb_net_group(struct ip_pcb *pcb, struct net_group *group); +struct net_group *get_net_group_from_ippcb(struct ip_pcb *pcb); +#endif #ifdef __cplusplus } #endif diff --git a/src/include/lwip/ip4.h b/src/include/lwip/ip4.h index 4d7228d..4483e77 100644 --- a/src/include/lwip/ip4.h +++ b/src/include/lwip/ip4.h @@ -62,11 +62,19 @@ extern "C" { #define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) #define ip_init() /* Compatibility define, no init needed. */ +#ifdef LOSCFG_NET_CONTAINER +struct netif *ip4_route(const ip4_addr_t *dest, struct net_group *group); +#else struct netif *ip4_route(const ip4_addr_t *dest); +#endif #if LWIP_IPV4_SRC_ROUTING struct netif *ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest); #else /* LWIP_IPV4_SRC_ROUTING */ +#ifdef LOSCFG_NET_CONTAINER +#define ip4_route_src(src, dest, group) ip4_route(dest, group) +#else #define ip4_route_src(src, dest) ip4_route(dest) +#endif #endif /* LWIP_IPV4_SRC_ROUTING */ err_t ip4_input(struct pbuf *p, struct netif *inp); err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, diff --git a/src/include/lwip/ip6.h b/src/include/lwip/ip6.h index f894e06..3a31bdf 100644 --- a/src/include/lwip/ip6.h +++ b/src/include/lwip/ip6.h @@ -57,7 +57,11 @@ extern "C" { #endif +#ifdef LOSCFG_NET_CONTAINER +struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, struct net_group *group); +#else struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); +#endif const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); err_t ip6_input(struct pbuf *p, struct netif *inp); err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, diff --git a/src/include/lwip/ip6_zone.h b/src/include/lwip/ip6_zone.h index 834c32f..cad93ac 100644 --- a/src/include/lwip/ip6_zone.h +++ b/src/include/lwip/ip6_zone.h @@ -248,12 +248,20 @@ enum lwip_ipv6_scope_type * @param dest the IPv6 address for which to select and set a zone. * @param src source IPv6 address (const); may be equal to dest. */ +#ifdef LOSCFG_NET_CONTAINER +#define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ + selected_netif = ip6_route((src), (dest), get_root_net_group()); \ + if (selected_netif != NULL) { \ + ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ + } } while (0) +#else #define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ selected_netif = ip6_route((src), (dest)); \ if (selected_netif != NULL) { \ ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ } } while (0) +#endif /** * @} */ diff --git a/src/include/lwip/net_group.h b/src/include/lwip/net_group.h new file mode 100644 index 0000000..bfec088 --- /dev/null +++ b/src/include/lwip/net_group.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef LOSCFG_NET_CONTAINER +#ifndef _NET_GROUP_H +#define _NET_GROUP_H +#include "lwip/arch.h" + +struct netif; +struct ip_pcb; + +struct net_group { + u8_t netif_num; + /** The default network interface. */ + struct netif *netif_default; + /** The list of network interfaces. */ + struct netif *netif_list; + struct netif *loop_netif; +}; + +struct net_group_ops { + struct net_group *(*get_curr_process_net_group)(void); + void (*set_netif_net_group)(struct netif *, struct net_group *); + struct net_group *(*get_net_group_from_netif)(struct netif *); + void (*set_ippcb_net_group)(struct ip_pcb *, struct net_group *); + struct net_group *(*get_net_group_from_ippcb)(struct ip_pcb *); +}; + +struct net_group *get_root_net_group(void); +struct net_group *get_curr_process_net_group(void); +struct net_group_ops *get_default_net_group_ops(void); +void set_default_net_group_ops(struct net_group_ops *ops); +#endif +#endif /* _NET_GROUP_H */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 0cde2c2..7a82649 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -48,6 +48,9 @@ #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/stats.h" +#ifdef LOSCFG_NET_CONTAINER +#include "lwip/net_group.h" +#endif #ifdef __cplusplus extern "C" { @@ -417,21 +420,46 @@ struct netif { #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ #if LWIP_SINGLE_NETIF +#ifdef LOSCFG_NET_CONTAINER +#define NETIF_FOREACH(netif, group) if (((netif) = group->netif_default) != NULL) +#else #define NETIF_FOREACH(netif) if (((netif) = netif_default) != NULL) +#endif #else /* LWIP_SINGLE_NETIF */ +#ifdef LOSCFG_NET_CONTAINER +#define NETIF_FOREACH(netif, group) for ((netif) = group->netif_list; (netif) != NULL; (netif) = (netif)->next) +#else /** The list of network interfaces. */ extern struct netif *netif_list; #define NETIF_FOREACH(netif) for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) +#endif + #endif /* LWIP_SINGLE_NETIF */ +#ifndef LOSCFG_NET_CONTAINER /** The default network interface. */ extern struct netif *netif_default; +#endif +#ifdef LOSCFG_NET_CONTAINER +struct net_group *get_net_group_from_netif(struct netif *netif); +void netif_init(struct net_group *group); +#else void netif_init(void); +#endif +#ifdef LOSCFG_NET_CONTAINER +struct netif *netif_add_noaddr(struct netif *netif, struct net_group *group, + void *state, netif_init_fn init, netif_input_fn input); +#else struct netif *netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); +#endif #if LWIP_IPV4 +#ifdef LOSCFG_NET_CONTAINER +struct netif *netif_add(struct netif *netif, struct net_group *group, +#else struct netif *netif_add(struct netif *netif, +#endif const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, @@ -447,7 +475,12 @@ void netif_remove(struct netif * netif); structure. */ struct netif *netif_find(const char *name); +#ifdef LOSCFG_NET_CONTAINER +void netif_set_default(struct netif *netif, struct net_group *group); +void netif_set_default2(struct netif *netif); +#else void netif_set_default(struct netif *netif); +#endif #if LWIP_IPV4 void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); @@ -571,8 +604,13 @@ err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t #endif /* LWIP_NETIF_USE_HINTS */ u8_t netif_name_to_index(const char *name); +#ifdef LOSCFG_NET_CONTAINER +char * netif_index_to_name(u8_t idx, char *name, struct net_group *group); +struct netif* netif_get_by_index(u8_t idx, struct net_group *group); +#else char * netif_index_to_name(u8_t idx, char *name); struct netif* netif_get_by_index(u8_t idx); +#endif /* Interface indexes always start at 1 per RFC 3493, section 4, num starts at 0 (internal index is 0..254)*/ #define netif_get_index(netif) ((u8_t)((netif)->num + 1)) diff --git a/src/include/lwip/netifapi.h b/src/include/lwip/netifapi.h index e063179..3190043 100644 --- a/src/include/lwip/netifapi.h +++ b/src/include/lwip/netifapi.h @@ -96,7 +96,11 @@ err_t netifapi_netif_index_to_name(u8_t index, char *name); /** @ingroup netifapi_netif * @see netif_set_default() */ +#ifdef LOSCFG_NET_CONTAINER +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default2, NULL) +#else #define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#endif /** @ingroup netifapi_netif * @see netif_set_link_up() */ diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index a8e87e5..ec2ad2b 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.h @@ -478,8 +478,13 @@ void tcp_trigger_input_pcb_close(void); #if TCP_CALCULATE_EFF_SEND_MSS u16_t tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest); +#ifdef LOSCFG_NET_CONTAINER +#define tcp_eff_send_mss(sendmss, src, dest, group) \ + tcp_eff_send_mss_netif(sendmss, ip_route(src, dest, group), dest) +#else #define tcp_eff_send_mss(sendmss, src, dest) \ tcp_eff_send_mss_netif(sendmss, ip_route(src, dest), dest) +#endif #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if LWIP_CALLBACK_API diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index f916ff6..689cfb3 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -101,6 +101,10 @@ struct raw_pcb { /* The following functions is the application layer interface to the RAW code. */ +#ifdef LOSCFG_NET_CONTAINER +void set_raw_pcb_net_group(struct raw_pcb *pcb, struct net_group *group); +struct net_group *get_net_group_from_raw_pcb(struct raw_pcb *pcb); +#endif struct raw_pcb * raw_new (u8_t proto); struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); void raw_remove (struct raw_pcb *pcb); diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 3991fd6..b527027 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -408,6 +408,10 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, #endif /* LWIP_EVENT_API */ /* Application program's interface: */ +#ifdef LOSCFG_NET_CONTAINER +void set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group); +struct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb); +#endif struct tcp_pcb * tcp_new (void); struct tcp_pcb * tcp_new_ip_type (u8_t type); diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index f1deae3..b512055 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -116,6 +116,10 @@ extern struct udp_pcb *udp_pcbs; /* The following functions is the application layer interface to the UDP code. */ +#ifdef LOSCFG_NET_CONTAINER +void set_udp_pcb_net_group(struct udp_pcb *pcb, struct net_group *group); +struct net_group *get_net_group_from_udp_pcb(struct udp_pcb *pcb); +#endif struct udp_pcb * udp_new (void); struct udp_pcb * udp_new_ip_type(u8_t type); void udp_remove (struct udp_pcb *pcb); -- Gitee From a19a5d20518e1fd963b3ea550b915be8db4ce2cb Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 03:43:24 +0800 Subject: [PATCH 12/14] =?UTF-8?q?OpenHarmony=20lwip=E4=BD=8E=E5=8A=9F?= =?UTF-8?q?=E8=80=97=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: HuangHaitao --- src/Filelists.mk | 3 +- src/api/api_msg.c | 29 ++ src/api/netifapi.c | 41 +++ src/api/sockets.c | 7 + src/api/tcpip.c | 79 ++++- src/core/dns.c | 25 ++ src/core/ipv4/autoip.c | 23 ++ src/core/ipv4/dhcp.c | 59 ++++ src/core/ipv4/etharp.c | 29 ++ src/core/ipv4/igmp.c | 26 ++ src/core/ipv4/ip4_frag.c | 20 ++ src/core/ipv6/dhcp6.c | 25 ++ src/core/ipv6/ip6_frag.c | 20 ++ src/core/ipv6/mld6.c | 29 ++ src/core/ipv6/nd6.c | 100 ++++++ src/core/lowpower.c | 489 +++++++++++++++++++++++++++++ src/core/tcp.c | 147 +++++++++ src/core/timeouts.c | 3 + src/include/lwip/autoip.h | 4 + src/include/lwip/dhcp.h | 5 + src/include/lwip/dhcp6.h | 4 + src/include/lwip/dns.h | 4 + src/include/lwip/etharp.h | 4 + src/include/lwip/igmp.h | 4 + src/include/lwip/ip4_frag.h | 5 + src/include/lwip/ip6_frag.h | 4 + src/include/lwip/lowpower.h | 169 ++++++++++ src/include/lwip/mld6.h | 4 + src/include/lwip/nd6.h | 4 + src/include/lwip/netifapi.h | 5 + src/include/lwip/opt.h | 34 ++ src/include/lwip/priv/api_msg.h | 10 + src/include/lwip/priv/memp_std.h | 5 + src/include/lwip/priv/tcpip_priv.h | 9 + src/include/lwip/tcp.h | 5 + src/include/lwip/tcpip.h | 4 + src/include/lwip/timeouts.h | 6 +- src/include/netif/lowpan6.h | 3 + src/netif/lowpan6.c | 25 ++ 39 files changed, 1467 insertions(+), 4 deletions(-) create mode 100644 src/core/lowpower.c create mode 100644 src/include/lwip/lowpower.h diff --git a/src/Filelists.mk b/src/Filelists.mk index 3680999..8383bc7 100644 --- a/src/Filelists.mk +++ b/src/Filelists.mk @@ -50,7 +50,8 @@ COREFILES=$(LWIPDIR)/core/init.c \ $(LWIPDIR)/core/tcp_out.c \ $(LWIPDIR)/core/timeouts.c \ $(LWIPDIR)/core/udp.c \ - $(LWIPDIR)/core/net_group.c + $(LWIPDIR)/core/net_group.c \ + $(LWIPDIR)/core/lowpower.c CORE4FILES=$(LWIPDIR)/core/ipv4/acd.c \ $(LWIPDIR)/core/ipv4/autoip.c \ diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 8d54a5e..acbd2b1 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -390,6 +390,35 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) return ERR_OK; } +#if LWIP_LOWPOWER +/* check wether need to poll tcp */ +u8_t +poll_tcp_needed(void *arg, struct tcp_pcb *pcb) +{ + struct netconn *conn = (struct netconn *)arg; + u8_t ret = 0; + + LWIP_UNUSED_ARG(pcb); + if (conn == NULL) { + return 0; + } + if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { + ret = 1; + } + + /* Did a nonblocking write fail before? Then check available write-space. */ + if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + ret = 1; + } + } + return ret; +} +#endif /* LWIP_LOWPOWER */ + /** * Sent callback function for TCP netconns. * Signals the conn->sem and calls API_EVENT. diff --git a/src/api/netifapi.c b/src/api/netifapi.c index 4ccb50c..8aef568 100644 --- a/src/api/netifapi.c +++ b/src/api/netifapi.c @@ -384,4 +384,45 @@ netifapi_netif_index_to_name(u8_t idx, char *name) return err; } +#if LWIP_LOWPOWER +static err_t +netifapi_do_set_lowpower_mod(struct tcpip_api_call_data *m) +{ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + enum lowpower_mod mod = msg->msg.lp.mod; + set_lowpower_mod(mod); + return ERR_OK; +} + +err_t +netifapi_enable_lowpower(void) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + + NETIFAPI_VAR_ALLOC(msg); + + NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_LOWPOWER_MOD; + + err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} + +err_t +netifapi_disable_lowpower(void) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + + NETIFAPI_VAR_ALLOC(msg); + + NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_NORMAL_MOD; + + err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} +#endif /* LWIP_LOWPOWER */ + #endif /* LWIP_NETIF_API */ diff --git a/src/api/sockets.c b/src/api/sockets.c index b42c6a4..0be4521 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -72,6 +72,10 @@ #include LWIP_HOOK_FILENAME #endif +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +#endif + /* If the netconn API is not required publicly, then we include the necessary files here to get the implementation */ #if !LWIP_NETCONN @@ -3385,6 +3389,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt LOCK_TCPIP_CORE(); err = lwip_setsockopt_impl(s, level, optname, optval, optlen); UNLOCK_TCPIP_CORE(); +#if LWIP_LOWPOWER + tcpip_send_msg_na(LOW_NON_BLOCK); +#endif #else /* LWIP_TCPIP_CORE_LOCKING */ diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 0891f9e..24e90fe 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -49,6 +49,9 @@ #include "lwip/pbuf.h" #include "lwip/etharp.h" #include "netif/ethernet.h" +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +#endif #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) @@ -81,7 +84,7 @@ tcpip_mbox_fetch(sys_mbox_t* mbox, void** msg) } #else /* !LWIP_TIMERS */ - +#if !LWIP_LOWPOWER /** * Wait (forever) for a message to arrive in an mbox. * While waiting, timeouts are processed. @@ -120,6 +123,7 @@ again: goto again; } } +#endif /* !LWIP_LOWPOWER */ #endif /* !LWIP_TIMERS */ /** @@ -215,7 +219,17 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg) LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); msg->msg.cb.function(msg->msg.cb.ctx); break; - +#if LWIP_LOWPOWER + /* just wake up thread do nothing */ + case TCPIP_MSG_NA: + if (msg->msg.lowpower.type == LOW_BLOCK) { + LOWPOWER_SIGNAL(msg->msg.lowpower.wait_up); + } else { + memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); + } + sys_timeout_set_wake_time(LOW_TMR_DELAY); + break; +#endif default: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); LWIP_ASSERT("tcpip_thread: invalid message", 0); @@ -223,6 +237,58 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg) } } +#if LWIP_LOWPOWER +/* send a na msg to wake up tcpip_thread */ +void +tcpip_send_msg_na(enum lowpower_msg_type type) +{ + struct tcpip_msg *msg = NULL; + err_t val; + + /* is not used lowpower mode */ + if ((type != LOW_FORCE_NON_BLOCK) && (get_lowpowper_mod() == LOW_TMR_NORMAL_MOD)) { + return; + } + if (sys_timeout_waiting_long() == 0) { + return; + } + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_LOWPOWER); + if (msg == NULL) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na alloc faild\n")); + return; + } + + /* just wake up thread if nonblock */ + msg->type = TCPIP_MSG_NA; + msg->msg.lowpower.type = type; + + if (type == LOW_BLOCK) { + LOWPOWER_SEM_NEW(msg->msg.lowpower.wait_up, val); + if (val != ERR_OK) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("alloc sem faild\n")); + memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); + return; + } + } + + if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { + if (type == LOW_BLOCK) { + LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); + } + memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); + LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na post faild\n")); + return; + } + + if (type == LOW_BLOCK) { + LOWPOWER_SEM_WAIT(msg->msg.lowpower.wait_up); + LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); + memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); + } +} +#endif /* LWIP_LOWPOWER */ + #ifdef TCPIP_THREAD_TEST /** Work on queued items in single-threaded test mode */ int @@ -256,6 +322,9 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) #if LWIP_TCPIP_CORE_LOCKING_INPUT err_t ret; LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); +#if LWIP_LOWPOWER + tcpip_send_msg_na(LOW_BLOCK); +#endif LOCK_TCPIP_CORE(); ret = input_fn(p, inp); UNLOCK_TCPIP_CORE(); @@ -452,6 +521,9 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) { #if LWIP_TCPIP_CORE_LOCKING LWIP_UNUSED_ARG(sem); +#if LWIP_LOWPOWER + tcpip_send_msg_na(LOW_BLOCK); +#endif LOCK_TCPIP_CORE(); fn(apimsg); UNLOCK_TCPIP_CORE(); @@ -488,6 +560,9 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) { #if LWIP_TCPIP_CORE_LOCKING err_t err; +#if LWIP_LOWPOWER + tcpip_send_msg_na(LOW_BLOCK); +#endif LOCK_TCPIP_CORE(); err = fn(call); UNLOCK_TCPIP_CORE(); diff --git a/src/core/dns.c b/src/core/dns.c index ed325ea..e228eb1 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -407,6 +407,31 @@ dns_tmr(void) dns_check_entries(); } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +dns_tmr_tick(void) +{ + u32_t tick = 0; + u32_t val; + s32_t i; + + for (i = 0; i < DNS_TABLE_SIZE; i++) { + if ((dns_table[i].state == DNS_STATE_NEW) || + (dns_table[i].state == DNS_STATE_ASKING)) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "dns_tmr_tick")); + return 1; + } + if (dns_table[i].state == DNS_STATE_DONE) { + val = dns_table[i].ttl; + SET_TMR_TICK(tick, val); + } + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dns_tmr_tick", tick)); + return tick; +} +#endif + #if DNS_LOCAL_HOSTLIST static void dns_init_local(void) diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index 461a005..7c6d35d 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -330,6 +330,29 @@ autoip_network_changed_link_down(struct netif *netif) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +autoip_tmr_tick(void) +{ + struct netif *netif = NULL; + u32_t tick = 0; + NETIF_FOREACH(netif) { + struct autoip *autoip = netif_autoip_data(netif); + if ((autoip != NULL) && (autoip->ttw > 0)) { + if ((autoip->state == AUTOIP_STATE_PROBING) || + (autoip->state == AUTOIP_STATE_ANNOUNCING)) { + SET_TMR_TICK(tick, autoip->ttw); + } + } + } + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "autoip_tmr_tick", tick)); + return tick; +} + +#endif + /** * @ingroup autoip * Stop AutoIP client diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 2e1892e..6881144 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -541,6 +541,65 @@ dhcp_coarse_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" + +u32_t +dhcp_coarse_tmr_tick(void) +{ + struct netif *netif; + u32_t tick = 0; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); + /* iterate through all network interfaces */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + struct dhcp *dhcp = netif_dhcp_data(netif); + if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { + if (dhcp->t0_timeout > 0) { + if (dhcp->t0_timeout > dhcp->lease_used) { + SET_TMR_TICK(tick, dhcp->t0_timeout - dhcp->lease_used); + } else { + SET_TMR_TICK(tick, 1); + } + } + if (dhcp->t2_rebind_time > 0) { + SET_TMR_TICK(tick, dhcp->t2_rebind_time); + } + if (dhcp->t1_renew_time > 0) { + SET_TMR_TICK(tick, dhcp->t1_renew_time); + } + } + } + return tick; +} + +u32_t +dhcp_fine_tmr_tick(void) +{ + struct netif *netif; + u32_t tick = 0; + /* loop through netif's */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + struct dhcp *dhcp = netif_dhcp_data(netif); + if (dhcp != NULL) { + if (dhcp->request_timeout > 0) { + SET_TMR_TICK(tick, dhcp->request_timeout); + } + } + } + return tick; +} +#endif /* LWIP_LOWPOWER */ + /** * DHCP transaction timeout handling (this function must be called every 500ms, * see @ref DHCP_FINE_TIMER_MSECS). diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c index 2163e5d..5133d1b 100644 --- a/src/core/ipv4/etharp.c +++ b/src/core/ipv4/etharp.c @@ -188,6 +188,35 @@ etharp_free_entry(int i) #endif /* LWIP_DEBUG */ } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +etharp_tmr_tick(void) +{ + s32_t i; + u32_t tick = 0; + u32_t time; + + for (i = 0; i < ARP_TABLE_SIZE; i++) { + u8_t state = arp_table[i].state; + if ((state != ETHARP_STATE_EMPTY) +#if ETHARP_SUPPORT_STATIC_ENTRIES + && (state != ETHARP_STATE_STATIC) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + ) { + if (arp_table[i].state != ETHARP_STATE_STABLE) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "etharp_tmr_tick")); + return 1; + } + time = (u32_t)ARP_MAXAGE - arp_table[i].ctime; + SET_TMR_TICK(tick, time); + } + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "etharp_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + /** * Clears expired entries in the ARP table. * diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 35b020b..5ad38d0 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -668,6 +668,32 @@ igmp_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +igmp_tmr_tick(void) +{ + struct netif *netif = NULL; + u32_t tick = 0; +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + struct igmp_group *group = netif_igmp_data(netif); + while (group != NULL) { + if (group->timer > 0) { + SET_TMR_TICK(tick, group->timer); + } + group = group->next; + } + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "igmp_tmr_tick", tick)); + return tick; +} +#endif + /** * Called if a timeout for one group is reached. * Sends a report for this group. diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index 5303144..56b7881 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -213,6 +213,26 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p return pbufs_freed; } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +ip_reass_tmr_tick(void) +{ + struct ip_reassdata *r = NULL; + u32_t tick = 0; + u32_t val; + + r = reassdatagrams; + while (r != NULL) { + val = r->timer + 1; + SET_TMR_TICK(tick, val); + r = r->next; + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip_reass_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + #if IP_REASS_FREE_OLDEST /** * Free the oldest datagram to make room for enqueueing new fragments. diff --git a/src/core/ipv6/dhcp6.c b/src/core/ipv6/dhcp6.c index e16c36b..d278cf1 100644 --- a/src/core/ipv6/dhcp6.c +++ b/src/core/ipv6/dhcp6.c @@ -822,4 +822,29 @@ dhcp6_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +dhcp6_tmr_tick() +{ + struct netif *netif = NULL; + u32_t tick = 0; + /* loop through netif's */ + #ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); + /* only act on DHCPv6 configured interfaces */ + if ((dhcp6 != NULL) && (dhcp6->request_timeout > 0)) { + SET_TMR_TICK(tick, dhcp6->request_timeout); + } + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dhcp6_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + #endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index ba91cfd..b4d62f2 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -137,6 +137,26 @@ ip6_reass_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +ip6_reass_tmr_tick(void) +{ + u32_t tick = 0; + u32_t val = 0; + struct ip6_reassdata *r = NULL; + + r = reassdatagrams; + while (r != NULL) { + val = r->timer + 1; + SET_TMR_TICK(tick, val); + r = r->next; + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip6_reass_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + /** * Free a datagram (struct ip6_reassdata) and all its pbufs. * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index 4d1a0a2..91ac1c8 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -529,6 +529,35 @@ mld6_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" + +u32_t +mld6_tmr_tick(void) +{ + struct netif *netif = NULL; + u32_t tick = 0; + +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + struct mld_group *group = netif_mld6_data(netif); + while (group != NULL) { + if (group->timer > 0) { + SET_TMR_TICK(tick, group->timer); + } + group = group->next; + } + } + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "mld6_tmr_tick", tick)); + return tick; +} +#endif + /** * Schedule a delayed membership report for a group * diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index a6ba67e..32aa03a 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1182,6 +1182,106 @@ nd6_tmr(void) } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +u32_t +nd6_tmr_tick(void) +{ + s8_t i; + struct netif *netif = NULL; + u32_t tick = 0; + u32_t val = 0; + + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + switch (neighbor_cache[i].state) { + case ND6_PROBE: + case ND6_INCOMPLETE: /* state PROBE and INCOMPLETE return 1 */ + return 1; + case ND6_REACHABLE: + /* Send queued packets, if any are left. Should have been sent already. */ + if (neighbor_cache[i].q != NULL) { + return 1; + } + if (neighbor_cache[i].counter.reachable_time >= ND6_TMR_INTERVAL) { + val = neighbor_cache[i].counter.reachable_time / ND6_TMR_INTERVAL; + SET_TMR_TICK(tick, val); + } + break; + case ND6_DELAY: + val = neighbor_cache[i].counter.delay_time; + SET_TMR_TICK(tick, val); + break; + default: + /* Do nothing. */ + break; + } + } + + /* Process router entries. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (default_router_list[i].neighbor_entry != NULL) { + val = default_router_list[i].invalidation_timer; + SET_TMR_TICK(tick, val); + } + } + + /* Process prefix entries. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].netif != NULL) { + val = prefix_list[i].invalidation_timer; + SET_TMR_TICK(tick, val); + } + } + + /* Process our own addresses, updating address lifetimes and/or DAD state. */ +#ifdef LOSCFG_NET_CONTAINER + NETIF_FOREACH(netif, get_root_net_group()) +#else + NETIF_FOREACH(netif) +#endif + { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + u8_t addr_state; +#if LWIP_IPV6_ADDRESS_LIFETIMES + /* Step 1: update address lifetimes (valid and preferred). */ + addr_state = netif_ip6_addr_state(netif, i); + if (!ip6_addr_isinvalid(addr_state) && + !netif_ip6_addr_isstatic(netif, i)) { + u32_t life = netif_ip6_addr_valid_life(netif, i); + if (!ip6_addr_life_isinfinite(life)) { + SET_TMR_TICK(tick, life); + } + + life = netif_ip6_addr_pref_life(netif, i); + if (!ip6_addr_life_isinfinite(life)) { + SET_TMR_TICK(tick, life); + } + } + /* The address state may now have changed, so reobtain it next. */ +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ + /* Step 2: update DAD state. */ + addr_state = netif_ip6_addr_state(netif, i); + if (ip6_addr_istentative(addr_state)) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "nd6_tmr_tick")); + return 1; + } + } + } + + /* Router solicitations are sent in 4 second intervals (see RFC 4861, ch. 6.3.7) */ + /* ND6_RTR_SOLICITATION_INTERVAL */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + if (nd6_tmr_rs_reduction > 0) { + val = nd6_tmr_rs_reduction; + SET_TMR_TICK(tick, val); + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "nd6_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + /** Send a neighbor solicitation message for a specific neighbor cache entry * * @param entry the neighbor cache entry for which to send the message diff --git a/src/core/lowpower.c b/src/core/lowpower.c new file mode 100644 index 0000000..63abefe --- /dev/null +++ b/src/core/lowpower.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if LWIP_LOWPOWER +#include "lwip/priv/tcp_priv.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/priv/tcpip_priv.h" + +#include "lwip/ip4_frag.h" +#include "lwip/etharp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" +#include "lwip/dhcp6.h" +#include "lwip/sys.h" +#include "lwip/pbuf.h" +#include "netif/lowpan6.h" +#include "lwip/api.h" + +#include "lwip/lowpower.h" + +#define TIMEOUT_MAX 120000 /* two mins */ +#define SYS_TIMEOUT_WAIT_TICKS 30 +#define SYS_TIMEOUT_WAIT_TIME_MS 3 + +static u32_t g_wake_up_time = TIMEOUT_MAX; +static enum lowpower_mod g_lowpower_switch = LOW_TMR_LOWPOWER_MOD; +static struct timer_entry *g_timer_header = NULL; +static struct timer_mng g_timer_mng = { LOW_TMR_TIMER_HANDLING, 0 }; +static u32_t g_last_check_timeout = 0; + +static const struct timer_handler lowpower_timer_handler[] = { +#if LWIP_TCP + /* + * The TCP timer is a special case: it does not have to run always and + * is triggered to start from TCP using tcp_timer_needed() + */ + {TCP_FAST_INTERVAL, tcp_fasttmr, tcp_fast_tmr_tick TCP_FASTTMR_NAME}, + {TCP_SLOW_INTERVAL, tcp_slowtmr, tcp_slow_tmr_tick TCP_SLOWTMR_NAME}, +#endif /* LWIP_TCP */ + +#if LWIP_IPV4 +#if IP_REASSEMBLY + {IP_TMR_INTERVAL, ip_reass_tmr, ip_reass_tmr_tick IP_REASSTRM_NAME}, +#endif /* IP_REASSEMBLY */ + +#if LWIP_ARP + {ARP_TMR_INTERVAL, etharp_tmr, etharp_tmr_tick ETHARPTMR_NAME}, +#endif /* LWIP_ARP */ + +#if LWIP_DHCP + {DHCP_FINE_TIMER_MSECS, dhcp_fine_tmr, dhcp_fine_tmr_tick DHCP_FINETMR_NAME}, + {DHCP_COARSE_TIMER_MSECS, dhcp_coarse_tmr, dhcp_coarse_tmr_tick DHCP_COARSETMR_NAME}, +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP + {AUTOIP_TMR_INTERVAL, autoip_tmr, autoip_tmr_tick AUTOIPTMR_NAME}, +#endif /* LWIP_AUTOIP */ + +#if LWIP_IGMP + {IGMP_TMR_INTERVAL, igmp_tmr, igmp_tmr_tick IGMPTMR_NAME}, +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4 */ + +#if LWIP_DNS + {DNS_TMR_INTERVAL, dns_tmr, dns_tmr_tick DNSTMR_NAME}, +#endif /* LWIP_DNS */ + +#if LWIP_IPV6 + {ND6_TMR_INTERVAL, nd6_tmr, nd6_tmr_tick ND6TMR_NAME}, +#if LWIP_IPV6_REASS + {IP6_REASS_TMR_INTERVAL, ip6_reass_tmr, ip6_reass_tmr_tick IP6_TREASSTMR_NAME}, +#endif /* LWIP_IPV6_REASS */ + +#if LWIP_IPV6_MLD + {MLD6_TMR_INTERVAL, mld6_tmr, mld6_tmr_tick MLD6TMR_NAME}, +#endif /* LWIP_IPV6_MLD */ + +#if LWIP_IPV6_DHCP6 + {DHCP6_TIMER_MSECS, dhcp6_tmr, dhcp6_tmr_tick DHCP6TMR_NAME}, +#endif /* LWIP_IPV6_DHCP6 */ + +#if LWIP_6LOWPAN + {LOWPAN6_TMR_INTERVAL, lowpan6_tmr, lowpan6_tmr_tick LOWPAN6TMR_NAME}, +#endif /* LWIP_6LOWPAN */ +#endif /* LWIP_IPV6 */ +}; + +void +set_timer_state(enum timer_state state, u32_t waiting_time) +{ + g_timer_mng.waiting_time = waiting_time; + g_timer_mng.state = state; +} + +/* should not call by tcpip_thread */ +u8_t +sys_timeout_waiting_long(void) +{ + u8_t i = 0; + u8_t j = 0; + + while (g_timer_mng.state == LOW_TMR_GETING_TICKS) { + i++; + if (i == SYS_TIMEOUT_WAIT_TICKS) { + i = 0; + j++; + if (j == SYS_TIMEOUT_WAIT_TIME_MS) { + break; + } + sys_msleep(1); + } + } + + if (g_timer_mng.state == LOW_TMR_TIMER_WAITING) { + return ((g_timer_mng.waiting_time > TIMEOUT_TICK) ? 1 : 0); + } + + return 0; +} + +err_t +sys_timeout_reg( + u32_t msec, + sys_timeout_handler handler, + void *arg, +#if LOWPOWER_TIMER_DEBUG + char *name, +#endif + get_next_timeout next_tick) +{ + struct timer_entry *timeout = NULL; + struct timer_entry *temp = NULL; + + if (handler == NULL) { + return -1; + } + + timeout = (struct timer_entry *)memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("sys_timeout_reg: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty")); + return -1; + } + + timeout->handler = handler; + timeout->clock_max = msec / TIMEOUT_TICK; /* time interval */ + timeout->next_tick = next_tick; + timeout->timeout = sys_now(); + timeout->args = arg; + timeout->enable = 0; + +#if LOWPOWER_TIMER_DEBUG + timeout->name = name; +#endif + + /* add list tail */ + timeout->next = NULL; + if (g_timer_header == NULL) { + g_timer_header = timeout; + } else { + temp = g_timer_header; + while (temp->next != NULL) { + temp = temp->next; + } + temp->next = timeout; + } + + return 0; +} + +/* deal timeout and return next timer prev */ +static void +timeout_handler(struct timer_entry *t, u32_t now) +{ +#if LOWPOWER_TIMER_DEBUG + if (t->name != NULL) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s timeout: now:%u\n", t->name, now)); + } +#endif + + t->handler(t->args); + LWIP_UNUSED_ARG(now); + t->timeout += t->clock_max * TIMEOUT_TICK; +} + +static u32_t +get_timer_tick(struct timer_entry *t) +{ + u32_t tick; + + /* disable lowpower, need to timeout once a tick */ + if (g_lowpower_switch == LOW_TMR_NORMAL_MOD) { + return t->clock_max; + } + + if (t->next_tick != NULL) { + tick = t->next_tick(); + } else { + tick = 1; + LWIP_DEBUGF(LOWPOWER_DEBUG, ("next->tick is NULL\n")); + } + tick *= t->clock_max; + return tick; +} + +static void +handle_timer_and_free(struct timer_entry **pt, struct timer_entry **pn, struct timer_entry *p) +{ + struct timer_entry *t = *pt; + struct timer_entry *n = *pn; + /* insert after previous node or as the header */ + if (p == NULL) { + g_timer_header = n; + } else { + p->next = n; + } + + t->next = NULL; + sys_timeout_handler handler = t->handler; + void *args = t->args; + memp_free(MEMP_SYS_TIMEOUT, t); + *pt = NULL; + handler(args); + + /* the last entry */ + if ((n == NULL) && (p != NULL)) { + *pn = p->next; + } +} + +static u32_t +get_sleep_time(u32_t now) +{ + struct timer_entry *t = NULL; + struct timer_entry *n = NULL; + struct timer_entry *p = NULL; + u32_t msec = TIMEOUT_MAX; + u32_t tick; + u32_t temp; + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n*******get_sleep_time*****************\n")); + + for (t = g_timer_header, p = NULL; t != NULL; t = n) { + n = t->next; +again: + tick = get_timer_tick(t); + if (tick == 0) { + t->enable = 0; + p = t; + continue; + } + + if (t->enable == 0) { + t->timeout = now; + } + t->enable = 1; + temp = tick * TIMEOUT_TICK; + + if (temp <= now - t->timeout) { + if (t->next_tick == NULL) { + handle_timer_and_free(&t, &n, p); + /* t is free p=p */ + continue; + } + timeout_handler(t, now); + goto again; + } + + temp = temp - (now - t->timeout); + msec = msec > temp ? temp : msec; + p = t; + } + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("msec = %u now = %u\n", msec, now)); + return msec; +} + +static void +check_timeout(u32_t now) +{ + struct timer_entry *t = NULL; + struct timer_entry *n = NULL; + struct timer_entry *p = NULL; + u32_t msec; + u32_t ticks; + u32_t i; + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n**********timeout**************\n")); + LWIP_DEBUGF(LOWPOWER_DEBUG, ("now = %u\n", now)); + + for (t = g_timer_header, p = NULL; t != NULL; t = n) { + n = t->next; + if (t->enable == 0) { + p = t; + continue; + } + + msec = now - t->timeout; + ticks = msec / TIMEOUT_TICK; + ticks = ticks / t->clock_max; + + for (i = 0; i < ticks; i++) { + /* remove timer_entry form list */ + if (t->next_tick == NULL) { + handle_timer_and_free(&t, &n, p); + break; + } + timeout_handler(t, now); + PBUF_CHECK_FREE_OOSEQ(); + } + if (t != NULL) { + p = t; + } + } +} + +void +tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +{ + u32_t sleeptime; + u32_t ret; + u32_t now; + +again: + if (g_timer_header == NULL) { + UNLOCK_TCPIP_CORE(); + (void)sys_arch_mbox_fetch(mbox, msg, 0); + LOCK_TCPIP_CORE(); + return; + } + + set_timer_state(LOW_TMR_GETING_TICKS, 0); + sleeptime = get_sleep_time(sys_now()); + sleeptime = sleeptime > sys_timeout_get_wake_time() ? sys_timeout_get_wake_time() : sleeptime; + set_timer_state(LOW_TMR_TIMER_WAITING, sleeptime); + + sys_timeout_set_wake_time(TIMEOUT_MAX); + UNLOCK_TCPIP_CORE(); + ret = sys_arch_mbox_fetch(mbox, msg, sleeptime); + LOCK_TCPIP_CORE(); + set_timer_state(LOW_TMR_TIMER_HANDLING, 0); + now = sys_now(); + if ((now - g_last_check_timeout) >= TIMEOUT_CHECK) { + check_timeout(sys_now()); + g_last_check_timeout = sys_now(); + } + + if (ret == SYS_ARCH_TIMEOUT) { + goto again; + } +} + +void +lowpower_cycle_tmr(void *args) +{ + struct timer_handler *handler = (struct timer_handler *)args; + + handler->handler(); +} + +err_t +set_timer_interval(u8_t i, u32_t interval) +{ + if (i >= LWIP_ARRAYSIZE(lowpower_timer_handler)) { + return -1; + } + return sys_timeout_reg(interval, lowpower_cycle_tmr, + (void *)(&lowpower_timer_handler[i]), +#if LOWPOWER_TIMER_DEBUG + lowpower_timer_handler[i].name, +#endif + lowpower_timer_handler[i].next_tick); +} + +/* registed when init */ +void +tcp_timer_needed(void) +{} + +void +sys_timeouts_init(void) +{ + u8_t i; + + for (i = 0; i < LWIP_ARRAYSIZE(lowpower_timer_handler); i++) { + if (set_timer_interval(i, lowpower_timer_handler[i].interval) != 0) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("ERROR:regist timer faild! i = %u\n", i)); + } + } +} + +void +sys_untimeout(sys_timeout_handler handler, void *arg) +{ + struct timer_entry *t = NULL; + struct timer_entry *p = NULL; + struct timer_entry *n = NULL; + + for (t = g_timer_header, p = NULL; t != NULL; t = n) { + n = t->next; + if ((t->handler == handler) && (t->args == arg)) { + if (p == NULL) { + g_timer_header = t->next; + } else { + p->next = t->next; + } + t->next = NULL; + memp_free(MEMP_SYS_TIMEOUT, t); + t = NULL; + } + if (t != NULL) { + p = t; + } + } +} +void +sys_restart_timeouts(void) +{} + +err_t +sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +{ + return sys_timeout_reg(msecs, handler, arg, +#if LOWPOWER_TIMER_DEBUG + NULL, +#endif + NULL); +} + +void +sys_timeout_set_wake_time(u32_t val) +{ + g_wake_up_time = val; +} + +u32_t +sys_timeout_get_wake_time(void) +{ + return g_wake_up_time; +} + +void +set_lowpower_mod(enum lowpower_mod sw) +{ + g_lowpower_switch = sw; +} + +enum lowpower_mod +get_lowpowper_mod(void) +{ + return g_lowpower_switch; +} +#endif /* LWIP_LOWPOWER */ diff --git a/src/core/tcp.c b/src/core/tcp.c index f883c31..5f6ea5b 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -111,6 +111,9 @@ #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/nd6.h" +#if LWIP_LOWPOWER +#include "lwip/priv/api_msg.h" +#endif #include @@ -254,6 +257,150 @@ tcp_tmr(void) } } +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" + +static u32_t +tcp_set_timer_tick_by_persist(struct tcp_pcb *pcb, u32_t tick) +{ + u32_t val; + + if (pcb->persist_backoff > 0) { + u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; + SET_TMR_TICK(tick, backoff_cnt); + return tick; + } + + /* timer not running */ + if (pcb->rtime >= 0) { + val = pcb->rto - pcb->rtime; + if (val == 0) { + val = 1; + } + SET_TMR_TICK(tick, val); + } + return tick; +} + +static u32_t +tcp_set_timer_tick_by_keepalive(struct tcp_pcb *pcb, u32_t tick) +{ + u32_t val; + + if (ip_get_option(pcb, SOF_KEEPALIVE) && + ((pcb->state == ESTABLISHED) || + (pcb->state == CLOSE_WAIT))) { + u32_t idle = (pcb->keep_idle) / TCP_SLOW_INTERVAL; + if (pcb->keep_cnt_sent == 0) { + val = idle - (tcp_ticks - pcb->tmr); + } else { + val = (tcp_ticks - pcb->tmr) - idle; + idle = (TCP_KEEP_INTVL(pcb) / TCP_SLOW_INTERVAL); + val = idle - (val % idle); + } + /* need add 1 to trig timer */ + val++; + SET_TMR_TICK(tick, val); + } + + return tick; +} + +static u32_t tcp_set_timer_tick_by_tcp_state(struct tcp_pcb *pcb, u32_t tick) +{ + u32_t val; + + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if (pcb->state == FIN_WAIT_2) { + /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ + if (pcb->flags & TF_RXCLOSED) { + val = TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL; + SET_TMR_TICK(tick, val); + } + } + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if (pcb->state == SYN_RCVD) { + val = TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL; + SET_TMR_TICK(tick, val); + } + + /* Check if this PCB has stayed too long in LAST-ACK */ + if (pcb->state == LAST_ACK) { + /* + * In a TCP connection the end that performs the active close + * is required to stay in TIME_WAIT state for 2MSL of time + */ + val = (2 * TCP_MSL) / TCP_SLOW_INTERVAL; + SET_TMR_TICK(tick, val); + } + + return tick; +} + +u32_t +tcp_slow_tmr_tick(void) +{ + struct tcp_pcb *pcb = NULL; + u32_t tick = 0; + + pcb = tcp_active_pcbs; + while (pcb != NULL) { + if (((pcb->state == SYN_SENT) && (pcb->nrtx >= TCP_SYNMAXRTX)) || + ((pcb->state == FIN_WAIT_1) || (pcb->state == CLOSING)) || + (pcb->nrtx >= TCP_MAXRTX)) { + return 1; + } + + tick = tcp_set_timer_tick_by_persist(pcb, tick); + tick = tcp_set_timer_tick_by_keepalive(pcb, tick); + + /* + * If this PCB has queued out of sequence data, but has been + * inactive for too long, will drop the data (it will eventually + * be retransmitted). + */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + SET_TMR_TICK(tick, 1); + } +#endif /* TCP_QUEUE_OOSEQ */ + + tick = tcp_set_timer_tick_by_tcp_state(pcb, tick); + + u8_t ret = poll_tcp_needed(pcb->callback_arg, pcb); + if ((pcb->poll != NULL) && (ret != 0)) { + SET_TMR_TICK(tick, 1); + } + pcb = pcb->next; + } + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "tcp_slow_tmr_tick", tick)); + return tick; +} + +u32_t +tcp_fast_tmr_tick(void) +{ + struct tcp_pcb *pcb = NULL; + + pcb = tcp_active_pcbs; + while (pcb != NULL) { + /* send delayed ACKs or send pending FIN */ + if ((pcb->flags & TF_ACK_DELAY) || + (pcb->flags & TF_CLOSEPEND) || + (pcb->refused_data != NULL) + ) { + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "tcp_fast_tmr_tick")); + return 1; + } + pcb = pcb->next; + } + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 0\n", "tcp_fast_tmr_tick")); + return 0; +} +#endif /* LWIP_LOWPOWER */ + #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG /** Called when a listen pcb is closed. Iterates one pcb list and removes the * closed listener pcb from pcb->listener if matching. diff --git a/src/core/timeouts.c b/src/core/timeouts.c index 91657eb..98ae192 100644 --- a/src/core/timeouts.c +++ b/src/core/timeouts.c @@ -61,6 +61,8 @@ #include "lwip/sys.h" #include "lwip/pbuf.h" +#if !LWIP_LOWPOWER + #if LWIP_DEBUG_TIMERNAMES #define HANDLER(x) x, #x #else /* LWIP_DEBUG_TIMERNAMES */ @@ -449,3 +451,4 @@ tcp_timer_needed(void) { } #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ +#endif /* !LWIP_LOWPOWER */ diff --git a/src/include/lwip/autoip.h b/src/include/lwip/autoip.h index b3f9feb..6be2605 100644 --- a/src/include/lwip/autoip.h +++ b/src/include/lwip/autoip.h @@ -81,6 +81,10 @@ u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); #define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) +#if LWIP_LOWPOWER +u32_t autoip_tmr_tick(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index e22f8c9..ac88c7f 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -176,6 +176,11 @@ void dhcp_coarse_tmr(void); /* to be called every half second */ void dhcp_fine_tmr(void); +#if LWIP_LOWPOWER +u32_t dhcp_coarse_tmr_tick(void); +u32_t dhcp_fine_tmr_tick(void); +#endif + #if LWIP_DHCP_GET_NTP_SRV /** This function must exist, in other to add offered NTP servers to * the NTP (or SNTP) engine. diff --git a/src/include/lwip/dhcp6.h b/src/include/lwip/dhcp6.h index 5cc4a01..4f994a8 100644 --- a/src/include/lwip/dhcp6.h +++ b/src/include/lwip/dhcp6.h @@ -95,6 +95,10 @@ extern void dhcp6_set_ntp_servers(u8_t num_ntp_servers, const ip_addr_t* ntp_ser #define netif_dhcp6_data(netif) ((struct dhcp6*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6)) +#if LWIP_LOWPOWER +u32_t dhcp6_tmr_tick(); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 0913415..2bb7d71 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -86,6 +86,10 @@ struct local_hostlist_entry { #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #endif /* DNS_LOCAL_HOSTLIST */ +#if LWIP_LOWPOWER +u32_t dns_tmr_tick(void); +#endif + #if LWIP_IPV4 extern const ip_addr_t dns_mquery_v4group; #endif /* LWIP_IPV4 */ diff --git a/src/include/lwip/etharp.h b/src/include/lwip/etharp.h index 48a1d22..62378d3 100644 --- a/src/include/lwip/etharp.h +++ b/src/include/lwip/etharp.h @@ -98,6 +98,10 @@ err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +#if LWIP_LOWPOWER +u32_t etharp_tmr_tick(void); +#endif /* LWIP_LOWPOWER */ + void etharp_input(struct pbuf *p, struct netif *netif); #ifdef __cplusplus diff --git a/src/include/lwip/igmp.h b/src/include/lwip/igmp.h index 0a16db0..8a377e0 100644 --- a/src/include/lwip/igmp.h +++ b/src/include/lwip/igmp.h @@ -99,6 +99,10 @@ err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); void igmp_tmr(void); +#if LWIP_LOWPOWER +u32_t igmp_tmr_tick(void); +#endif + /** @ingroup igmp * Get list head of IGMP groups for netif. * Note: The allsystems group IP is contained in the list as first entry. diff --git a/src/include/lwip/ip4_frag.h b/src/include/lwip/ip4_frag.h index ed5bf14..13744f2 100644 --- a/src/include/lwip/ip4_frag.h +++ b/src/include/lwip/ip4_frag.h @@ -89,6 +89,11 @@ struct pbuf_custom_ref { #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); + +#if LWIP_LOWPOWER +u32_t ip_reass_tmr_tick(void); +#endif /* LWIP_LOWPOWER */ + #endif /* IP_FRAG */ #ifdef __cplusplus diff --git a/src/include/lwip/ip6_frag.h b/src/include/lwip/ip6_frag.h index 87e0e86..b278ddd 100644 --- a/src/include/lwip/ip6_frag.h +++ b/src/include/lwip/ip6_frag.h @@ -115,6 +115,10 @@ struct ip6_reassdata { void ip6_reass_tmr(void); struct pbuf *ip6_reass(struct pbuf *p); +#if LWIP_LOWPOWER +u32_t ip6_reass_tmr_tick(void); +#endif + #endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ #if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ diff --git a/src/include/lwip/lowpower.h b/src/include/lwip/lowpower.h new file mode 100644 index 0000000..eab2c46 --- /dev/null +++ b/src/include/lwip/lowpower.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef LWIP_HDR_LOWPOWER_H +#define LWIP_HDR_LOWPOWER_H + +#include "lwip/opt.h" + +#if LWIP_LOWPOWER +#include "lwip/err.h" +#if !NO_SYS +#include "lwip/sys.h" +#endif + +#define LOWPOWER_TIMER_DEBUG 0 +#define TIMEOUT_TICK 100 /* 100ms */ +#define TIMEOUT_CHECK 30 + +#if LOWPOWER_TIMER_DEBUG +#define TCP_FASTTMR_NAME , "tcp_fasttmr" +#define TCP_SLOWTMR_NAME , "tcp_slowtmr" +#define IP_REASSTRM_NAME , "ip_reass_tmr" +#define ETHARPTMR_NAME , "etharp_tmr" +#define DHCP_COARSETMR_NAME , "dhcp_coarse_tmr" +#define DHCP_FINETMR_NAME , "dhcp_fine_tmr" +#define AUTOIPTMR_NAME , "autoip_tmr" +#define IGMPTMR_NAME , "igmp_tmr" +#define DNSTMR_NAME , "dns_tmr" +#define NAT64TMR_NAME , "nat64_tmr" +#define ND6TMR_NAME , "nd6_tmr" +#define IP6_TREASSTMR_NAME , "ip6_reass_tmr" +#define MLD6TMR_NAME , "mld6_tmr" +#define DHCP6TMR_NAME , "dhcp6_tmr" +#define LOWPAN6TMR_NAME , "lowpan6_tmr" +#else +#define TCP_FASTTMR_NAME +#define TCP_SLOWTMR_NAME +#define IP_REASSTRM_NAME +#define ETHARPTMR_NAME +#define DHCP_COARSETMR_NAME +#define DHCP_FINETMR_NAME +#define AUTOIPTMR_NAME +#define IGMPTMR_NAME +#define DNSTMR_NAME +#define NAT64TMR_NAME +#define ND6TMR_NAME +#define IP6_TREASSTMR_NAME +#define MLD6TMR_NAME +#define DHCP6TMR_NAME +#define LOWPAN6TMR_NAME +#endif + +#define SET_TMR_TICK(tick, val) do { \ + if ((val) > 0) { \ + if ((tick) == 0) { \ + (tick) = (val); \ + } else { \ + (tick) = (tick) > (val) ? (val) : (tick); \ + } \ + } \ +} while (0) + +typedef void (*lwip_timer_handler)(void); +typedef void (*sys_timeout_handler)(void *args); + +/* get time count to trigger */ +typedef u32_t (*get_next_timeout)(void); + +struct timer_handler { + u32_t interval; + lwip_timer_handler handler; + get_next_timeout next_tick; +#if LOWPOWER_TIMER_DEBUG + char *name; +#endif +}; + +struct timer_entry { + u32_t clock_max; /* tmr interval */ + u32_t timeout; + sys_timeout_handler handler; + void *args; + get_next_timeout next_tick; + struct timer_entry *next; +#if LOWPOWER_TIMER_DEBUG + char *name; +#endif + u8_t enable; +}; + +enum timer_state { + LOW_TMR_GETING_TICKS = 0, + LOW_TMR_TIMER_WAITING, + LOW_TMR_TIMER_HANDLING, +}; + +struct timer_mng { + enum timer_state state; + u32_t waiting_time; +}; + +enum lowpower_msg_type { + LOW_NON_BLOCK = 0, + LOW_BLOCK = 1, + LOW_FORCE_NON_BLOCK = 2, +}; + +enum lowpower_mod { + LOW_TMR_LOWPOWER_MOD = 0, + LOW_TMR_NORMAL_MOD = 1, +}; + +#define lowpower_sem_t sys_sem_t +#define LOWPOWER_SEM_WAIT(lock) sys_sem_wait(&(lock)) +#define LOWPOWER_SIGNAL(lock) sys_sem_signal(&(lock)) +#define LOWPOWER_SEM_NEW(lock, val) \ + do { \ + (val) = sys_sem_new(&(lock), 0); \ + } while (0) +#define LOWPOWER_SEM_FREE(lock) sys_sem_free(&(lock)) + +/* all timer use the same timeout step */ +#define STEP_TIMEOUT_TO_TICK(step, type) (((step) * lwip_cyclic_timers[(type)].interval_ms) / TIMEOUT_TICK) +#define STEP_TICK_TO_TIMEOUT(tick, type) (((tick) * TIMEOUT_TICK) / lwip_cyclic_timers[(type)].interval_ms) + +#define LOW_TMR_DELAY 20 +void sys_timeout_set_wake_time(u32_t val); +u32_t sys_timeout_get_wake_time(void); + +void sys_untimeout(sys_timeout_handler handler, void *arg); +void sys_restart_timeouts(void); +void tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +void sys_timeouts_init(void); +err_t sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +u8_t sys_timeout_waiting_long(void); + +void set_lowpower_mod(enum lowpower_mod sw); +enum lowpower_mod get_lowpowper_mod(void); + +#endif /* LOWEPOWER */ + +#endif /* LWIP_HDR_LOWPOWER_H */ diff --git a/src/include/lwip/mld6.h b/src/include/lwip/mld6.h index 2764fdd..041e9fb 100644 --- a/src/include/lwip/mld6.h +++ b/src/include/lwip/mld6.h @@ -82,6 +82,10 @@ err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); +#if LWIP_LOWPOWER +u32_t mld6_tmr_tick(void); +#endif + /** @ingroup mld6 * Get list head of MLD6 groups for netif. * Note: The allnodes group IP is NOT in the list, since it must always diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index c30e624..e262ff6 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -81,6 +81,10 @@ void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_stat #endif /* LWIP_IPV6_MLD */ void nd6_restart_netif(struct netif *netif); +#ifdef LWIP_LOWPOWER +u32_t nd6_tmr_tick(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/netifapi.h b/src/include/lwip/netifapi.h index 3190043..df05065 100644 --- a/src/include/lwip/netifapi.h +++ b/src/include/lwip/netifapi.h @@ -156,6 +156,11 @@ err_t netifapi_netif_index_to_name(u8_t index, char *name); */ #define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) +#if LWIP_LOWPOWER +err_t netifapi_enable_lowpower(void); +err_t netifapi_disable_lowpower(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 2573285..971196e 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -3622,4 +3622,38 @@ * @} */ +/** + * enable LWIP_LOWPOWER macro to use lowpower function + */ +#undef LWIP_LOWPOWER +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM +#if defined (CONFIG_LWIP_LOWPOWER) +#define LWIP_LOWPOWER 1 +#else +#define LWIP_LOWPOWER 0 +#endif +#else +#define LWIP_LOWPOWER 0 +#endif + +#if LWIP_LOWPOWER + +/** + * LOWPOWER_DEBUG: Enable debugging in lowpower.c. + */ +#if !defined LOWPOWER_DEBUG || defined __DOXYGEN__ +#define LOWPOWER_DEBUG LWIP_DBG_OFF +#endif + +#ifndef MEMP_NUM_TCPIP_MSG_LOWPOWER +#define MEMP_NUM_TCPIP_MSG_LOWPOWER 10 +#endif + +#define LWIP_SNTP_TIMER 2 + +#define LOWPOWER_TCP_TIMER 1 + +#define MEMP_NUM_SYS_TIMEOUT_LOW (MEMP_NUM_SYS_TIMEOUT + LWIP_SNTP_TIMER + LOWPOWER_TCP_TIMER) +#endif /* LWIP_LOWPOWER */ + #endif /* LWIP_HDR_OPT_H */ diff --git a/src/include/lwip/priv/api_msg.h b/src/include/lwip/priv/api_msg.h index 9e8ffc9..77e4fdb 100644 --- a/src/include/lwip/priv/api_msg.h +++ b/src/include/lwip/priv/api_msg.h @@ -187,6 +187,11 @@ struct dns_api_msg { }; #endif /* LWIP_DNS */ +#if LWIP_LOWPOWER +/* check wether need to poll tcp */ +u8_t poll_tcp_needed(void *arg, struct tcp_pcb *pcb); +#endif + #if LWIP_NETCONN_FULLDUPLEX int lwip_netconn_is_deallocated_msg(void *msg); #endif @@ -260,6 +265,11 @@ struct netifapi_msg { #endif /* LWIP_MPU_COMPATIBLE */ u8_t index; } ifs; +#if LWIP_LOWPOWER + struct { + enum lowpower_mod mod; + } lp; +#endif } msg; }; diff --git a/src/include/lwip/priv/memp_std.h b/src/include/lwip/priv/memp_std.h index 669ad4d..3c2f9e6 100644 --- a/src/include/lwip/priv/memp_std.h +++ b/src/include/lwip/priv/memp_std.h @@ -99,7 +99,12 @@ LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group) #endif /* LWIP_IGMP */ #if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM +#if LWIP_LOWPOWER +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT_LOW, sizeof(struct timer_entry), "SYS_TIMEOUT") +LWIP_MEMPOOL(TCPIP_MSG_LOWPOWER, MEMP_NUM_TCPIP_MSG_LOWPOWER, sizeof(struct tcpip_msg), "TCPIP_MSG_NA") +#else LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") +#endif /* LWIP_LOWPOWER */ #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ #if LWIP_DNS && LWIP_SOCKET diff --git a/src/include/lwip/priv/tcpip_priv.h b/src/include/lwip/priv/tcpip_priv.h index bfa88ff..eacc2f4 100644 --- a/src/include/lwip/priv/tcpip_priv.h +++ b/src/include/lwip/priv/tcpip_priv.h @@ -124,6 +124,9 @@ enum tcpip_msg_type { #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ TCPIP_MSG_CALLBACK, TCPIP_MSG_CALLBACK_STATIC, +#if LWIP_LOWPOWER + TCPIP_MSG_NA, +#endif /* LWIP_LOWPOWER */ TCPIP_MSG_CALLBACK_STATIC_WAIT }; @@ -164,6 +167,12 @@ struct tcpip_msg { void *arg; } tmo; #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ +#if LWIP_LOWPOWER + struct { + enum lowpower_msg_type type; + lowpower_sem_t wait_up; + } lowpower; +#endif } msg; }; diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index b527027..f312fe7 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -424,6 +424,11 @@ void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); #endif /* LWIP_CALLBACK_API */ void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); +#if LWIP_LOWPOWER +u32_t tcp_fast_tmr_tick(void); +u32_t tcp_slow_tmr_tick(void); +#endif + #define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0) #define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0) #define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) diff --git a/src/include/lwip/tcpip.h b/src/include/lwip/tcpip.h index 30ce4fe..bc4d2b6 100644 --- a/src/include/lwip/tcpip.h +++ b/src/include/lwip/tcpip.h @@ -105,6 +105,10 @@ err_t tcpip_untimeout(sys_timeout_handler h, void *arg); int tcpip_thread_poll_one(void); #endif +#if LWIP_LOWPOWER +void tcpip_send_msg_na(enum lowpower_msg_type type); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/timeouts.h b/src/include/lwip/timeouts.h index b601f9e..10a34f3 100644 --- a/src/include/lwip/timeouts.h +++ b/src/include/lwip/timeouts.h @@ -43,11 +43,15 @@ #if !NO_SYS #include "lwip/sys.h" #endif +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +#endif #ifdef __cplusplus extern "C" { #endif +#if !LWIP_LOWPOWER #ifndef LWIP_DEBUG_TIMERNAMES #ifdef LWIP_DEBUG #define LWIP_DEBUG_TIMERNAMES SYS_DEBUG @@ -120,7 +124,7 @@ void lwip_cyclic_timer(void *arg); #endif #endif /* LWIP_TIMERS */ - +#endif /* !LWIP_LOWPOWER */ #ifdef __cplusplus } #endif diff --git a/src/include/netif/lowpan6.h b/src/include/netif/lowpan6.h index ecff24b..06a2c95 100644 --- a/src/include/netif/lowpan6.h +++ b/src/include/netif/lowpan6.h @@ -60,6 +60,9 @@ extern "C" { #define LOWPAN6_TMR_INTERVAL 1000 void lowpan6_tmr(void); +#if LWIP_LOWPOWER +u32_t lowpan6_tmr_tick(void); +#endif err_t lowpan6_set_context(u8_t idx, const ip6_addr_t * context); err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); diff --git a/src/netif/lowpan6.c b/src/netif/lowpan6.c index 8eb751c..d7ecd0a 100644 --- a/src/netif/lowpan6.c +++ b/src/netif/lowpan6.c @@ -63,6 +63,9 @@ #include "lwip/snmp.h" #include "netif/ieee802154.h" +#if LWIP_LOWPOWER +#include "lwip/lowpower.h" +#endif #include #if LWIP_6LOWPAN_802154_HW_CRC @@ -118,6 +121,28 @@ static const struct lowpan6_link_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; static struct lowpan6_link_addr short_mac_addr = {2, {0, 0}}; #endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ +#if LWIP_LOWPOWER +u32_t +lowpan6_tmr_tick() +{ + struct lowpan6_reass_helper *lrh = NULL; + struct lowpan6_reass_helper *lrh_temp = NULL; + u32_t tick = 0; + + lrh = lowpan6_data.reass_list; + while (lrh != NULL) { + lrh_temp = lrh->next_packet; + if (lrh->timer > 0) { + SET_TMR_TICK(tick, lrh->timer); + } + lrh = lrh_temp; + } + + LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "lowpan6_tmr_tick", tick)); + return tick; +} +#endif /* LWIP_LOWPOWER */ + /* IEEE 802.15.4 specific functions: */ /** Write the IEEE 802.15.4 header that encapsulates the 6LoWPAN frame. -- Gitee From 8e5d7119b64709727304a3432ddbed2e92be41cf Mon Sep 17 00:00:00 2001 From: maosiping Date: Thu, 3 Aug 2023 14:50:15 +0800 Subject: [PATCH 13/14] fix sockets offset error Signed-off-by: maosiping --- src/core/distributed_net/distributed_net.c | 7 ++++++- src/core/distributed_net/distributed_net_core.c | 13 +++++++++++-- src/core/distributed_net/distributed_net_utils.c | 7 ++++++- src/core/distributed_net/udp_transmit.c | 7 ++++++- src/core/dns.c | 4 +++- src/include/lwip/distributed_net/distributed_net.h | 7 ++++++- .../lwip/distributed_net/distributed_net_core.h | 7 ++++++- .../lwip/distributed_net/distributed_net_utils.h | 7 ++++++- src/include/lwip/distributed_net/udp_transmit.h | 7 ++++++- 9 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/core/distributed_net/distributed_net.c b/src/core/distributed_net/distributed_net.c index fc3d0b4..f66240c 100644 --- a/src/core/distributed_net/distributed_net.c +++ b/src/core/distributed_net/distributed_net.c @@ -27,7 +27,12 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET diff --git a/src/core/distributed_net/distributed_net_core.c b/src/core/distributed_net/distributed_net_core.c index 62f424e..b0ede51 100644 --- a/src/core/distributed_net/distributed_net_core.c +++ b/src/core/distributed_net/distributed_net_core.c @@ -27,7 +27,13 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" +#include #if LWIP_ENABLE_DISTRIBUTED_NET @@ -51,8 +57,11 @@ int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t add (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in)); INIT_SOCK_ADDR(&addr_in, LOCAL_SERVER_IP, get_local_tcp_server_port()); +#if (defined(EMUI_WEB_CLIENT)) + DISTRIBUTED_NET_START_TCP_SERVER(); +#endif if (lwip_connect_internal(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) { - if (get_errno() != EINPROGRESS) { + if (errno != EINPROGRESS) { return -1; } } diff --git a/src/core/distributed_net/distributed_net_utils.c b/src/core/distributed_net/distributed_net_utils.c index 0a94f57..7ca803b 100644 --- a/src/core/distributed_net/distributed_net_utils.c +++ b/src/core/distributed_net/distributed_net_utils.c @@ -27,7 +27,12 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET diff --git a/src/core/distributed_net/udp_transmit.c b/src/core/distributed_net/udp_transmit.c index 7992513..f41d1cb 100644 --- a/src/core/distributed_net/udp_transmit.c +++ b/src/core/distributed_net/udp_transmit.c @@ -27,7 +27,12 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL diff --git a/src/core/dns.c b/src/core/dns.c index e228eb1..e66a738 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -950,7 +950,9 @@ dns_send(u8_t idx) #else local_addr.addr = ipaddr_addr(LOCAL_SERVER_IP); #endif - +#if (defined(EMUI_WEB_CLIENT)) + DISTRIBUTED_NET_START_UDP_SERVER(); +#endif err = udp_sendto(dns_pcbs[pcb_idx], p, &local_addr, dst_port); } else { err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); diff --git a/src/include/lwip/distributed_net/distributed_net.h b/src/include/lwip/distributed_net/distributed_net.h index 77aee48..6680b5b 100644 --- a/src/include/lwip/distributed_net/distributed_net.h +++ b/src/include/lwip/distributed_net/distributed_net.h @@ -30,7 +30,12 @@ #ifndef LWIP_HDR_DISTRIBUTED_NET_H #define LWIP_HDR_DISTRIBUTED_NET_H -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET diff --git a/src/include/lwip/distributed_net/distributed_net_core.h b/src/include/lwip/distributed_net/distributed_net_core.h index cd5d789..0adf24f 100644 --- a/src/include/lwip/distributed_net/distributed_net_core.h +++ b/src/include/lwip/distributed_net/distributed_net_core.h @@ -30,7 +30,12 @@ #ifndef LWIP_HDR_DISTRIBUTED_NET_CORE_H #define LWIP_HDR_DISTRIBUTED_NET_CORE_H -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET diff --git a/src/include/lwip/distributed_net/distributed_net_utils.h b/src/include/lwip/distributed_net/distributed_net_utils.h index 0c7e1ed..27172b5 100644 --- a/src/include/lwip/distributed_net/distributed_net_utils.h +++ b/src/include/lwip/distributed_net/distributed_net_utils.h @@ -30,7 +30,12 @@ #ifndef LWIP_HDR_DISTRIBUTED_NET_UTILS_H #define LWIP_HDR_DISTRIBUTED_NET_UTILS_H -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET diff --git a/src/include/lwip/distributed_net/udp_transmit.h b/src/include/lwip/distributed_net/udp_transmit.h index 23f76bf..27e13ab 100644 --- a/src/include/lwip/distributed_net/udp_transmit.h +++ b/src/include/lwip/distributed_net/udp_transmit.h @@ -30,7 +30,12 @@ #ifndef LWIP_HDR_UDP_TRANSMIT_H #define LWIP_HDR_UDP_TRANSMIT_H -#include "lwip/opt.h" +#include "lwip/sockets.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/if_api.h" #if LWIP_ENABLE_DISTRIBUTED_NET -- Gitee From ed2da6c294e619ba97405fa599ef933dfed79db6 Mon Sep 17 00:00:00 2001 From: HuangHaitao Date: Thu, 3 Jul 2025 04:09:27 +0800 Subject: [PATCH 14/14] fix compilation error Signed-off-by: HuangHaitao --- BUILD.gn | 2 ++ src/api/sockets.c | 5 +++++ src/core/ipv4/dhcp.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index f2dd58b..1539fb3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -44,8 +44,10 @@ ohos_shared_library("liblwip") { "src/core/ipv6/ip6_frag.c", "src/core/ipv6/mld6.c", "src/core/ipv6/nd6.c", + "src/core/lowpower.c", "src/core/mem.c", "src/core/memp.c", + "src/core/net_group.c", "src/core/netif.c", "src/core/pbuf.c", "src/core/raw.c", diff --git a/src/api/sockets.c b/src/api/sockets.c index 0be4521..cac009c 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -330,6 +330,11 @@ static volatile int select_cb_ctr; static struct lwip_select_cb *select_cb_list; #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ +#define sock_set_errno(sk, e) do { \ + const int sockerr = (e); \ + set_errno(sockerr); \ +} while (0) + /* Forward declaration of some functions */ #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 6881144..5f2f3e3 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -167,12 +167,14 @@ #else #define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 #endif +#endif /* 0 */ #ifndef LWIP_DHCP_INPUT_ERROR #define LWIP_DHCP_INPUT_ERROR(message, expression, handler) do { if (!(expression)) { \ handler;} } while(0) #endif +#if 0 /** Option handling: options are parsed in dhcp_parse_reply * and saved in an array where other functions can load them from. * This might be moved into the struct dhcp (not necessarily since -- Gitee