summaryrefslogtreecommitdiff
path: root/tmk_core/tool/mbed/mbed-sdk/libraries/net
diff options
context:
space:
mode:
authorJun Wako <wakojun@gmail.com>2015-04-24 16:26:14 +0900
committerJun Wako <wakojun@gmail.com>2015-04-24 16:26:14 +0900
commita3d96d3aa96318d339a67de1085e0ae495d57c84 (patch)
treedb85c16d03b52399d6c109eda7ea0341a0de0b1d /tmk_core/tool/mbed/mbed-sdk/libraries/net
parent1d5bac21dc6f1425b8ef4bbe7935330c37c3a93e (diff)
parent1fe4406f374291ab2e86e95a97341fd9c475fcb8 (diff)
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
Diffstat (limited to 'tmk_core/tool/mbed/mbed-sdk/libraries/net')
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h78
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp902
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h153
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h59
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h95
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h27
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp127
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h79
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h47
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h61
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp81
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h60
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp52
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h44
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp466
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h69
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp175
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h96
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h26
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp350
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h90
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp423
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h97
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h67
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp196
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h80
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.cpp253
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.h72
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.cpp236
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.h74
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.cpp114
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.h63
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.cpp131
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.h63
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.cpp559
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.h183
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.cpp398
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.h118
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.cpp605
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.h155
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.cpp156
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.h90
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/eth_arch.h41
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/fsl_enet_driver.c469
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c93
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac.c885
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h58
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h29
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17_emac.c1046
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h661
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h111
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy.h151
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c438
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h30
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h26
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c192
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/lwipopts_conf.h26
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/stm32f4_emac.c560
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.cpp24
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.h29
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.cpp163
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.h56
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c460
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c1515
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h99
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h133
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h229
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c375
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c105
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c163
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c294
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h67
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c92
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c270
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c249
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c565
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h133
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h62
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h176
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c364
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c480
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c323
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c280
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h45
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h194
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c483
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h54
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h499
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c2324
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h304
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c414
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c478
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h1
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c556
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.cpp73
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.h63
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.cpp91
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.h104
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.cpp133
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.h81
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.cpp78
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.h52
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.cpp94
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.h75
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/cc.h119
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/checksum.c126
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/memcpy.c59
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/perf.h38
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.c463
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.h120
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/COPYING33
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_lib.c740
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_msg.c1535
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/err.c75
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netbuf.c245
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netdb.c352
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netifapi.c160
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/sockets.c2347
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/tcpip.c460
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/def.c108
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dhcp.c1749
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dns.c970
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/init.c306
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/autoip.c536
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/icmp.c335
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/igmp.c805
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet.c42
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet_chksum.c450
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip.c857
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_addr.c312
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_frag.c863
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/mem.c657
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/memp.c475
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/netif.c758
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/pbuf.c1158
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/raw.c354
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_dec.c657
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_enc.c611
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib2.c4146
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib_structs.c1174
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_in.c1437
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_out.c681
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/stats.c176
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp.c1635
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_in.c1567
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_out.c1471
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/timers.c482
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/udp.c966
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/autoip.h119
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/icmp.h111
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/igmp.h106
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet.h107
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet_chksum.h90
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip.h213
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_addr.h244
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_frag.h88
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api.h284
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api_msg.h174
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/arch.h238
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/debug.h98
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/def.h127
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dhcp.h242
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dns.h124
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/err.h85
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/init.h72
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/mem.h123
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp.h116
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp_std.h122
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netbuf.h101
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netdb.h124
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netif.h315
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netifapi.h108
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/opt.h2043
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/pbuf.h154
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/raw.h98
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sio.h141
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp.h367
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_asn1.h101
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_msg.h315
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_structs.h268
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sockets.h376
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/stats.h292
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sys.h331
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp.h377
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp_impl.h471
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcpip.h159
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/timers.h98
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/udp.h171
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/etharp.h221
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/ppp_oe.h190
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/slipif.h51
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/lwipopts.h148
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/etharp.c1318
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ethernetif.c318
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.c1334
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.h111
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.c908
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.h150
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.c396
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.h64
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.c890
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.h157
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.c1415
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.h106
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.c2066
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.h151
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.c80
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.h63
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.c320
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.h55
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.c628
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.h118
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.c2030
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.h483
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp_oe.c1132
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pppdebug.h73
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.c249
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.h81
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.c652
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.h156
-rw-r--r--tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/slipif.c367
221 files changed, 83372 insertions, 0 deletions
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h
new file mode 100644
index 0000000000..fd47622c86
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h
@@ -0,0 +1,78 @@
+/* CellularModem.h */
+/* Copyright (C) 2013 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CELLULARMODEM_H_
+#define CELLULARMODEM_H_
+
+#include "core/fwk.h"
+#include "at/ATCommandsInterface.h"
+
+class CellularModem
+{
+public:
+ //Internet-related functions
+
+ /** Open a 3G internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL) = 0;
+
+ /** Close the internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int disconnect() = 0;
+
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int sendSM(const char* number, const char* message) = 0;
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int getSM(char* number, char* message, size_t maxLength) = 0;
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getSMCount(size_t* pCount) = 0;
+
+ /** Get the ATCommandsInterface instance
+ @return Pointer to the ATCommandsInterface instance
+ */
+ virtual ATCommandsInterface* getATCommandsInterface() = 0;
+
+ /** Switch power on or off
+ In order to use this function, a pin name must have been entered in the constructor
+ @param enable true to switch the dongle on, false to switch it off
+ @return 0 on success, error code on failure
+ */
+ virtual int power(bool enable) = 0;
+};
+
+
+#endif /* CELLULARMODEM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp
new file mode 100644
index 0000000000..9f711630ce
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp
@@ -0,0 +1,902 @@
+/* ATCommandsInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 2 //ERR+WARN
+#ifndef __MODULE__
+#define __MODULE__ "ATCommandsInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <cstdio>
+#include <cstring> //For memset, strstr...
+
+using std::memmove;
+
+#include "ATCommandsInterface.h"
+
+ATCommandsInterface::ATCommandsInterface(IOStream* pStream) :
+ m_pStream(pStream), m_open(false), m_transactionState(IDLE), m_env2AT(), m_AT2Env(), m_processingMtx(),
+ m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192),
+ m_eventsMgmtMtx(), m_eventsProcessingMtx()
+{
+ memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*));
+
+ m_processingMtx.lock();
+}
+
+//Open connection to AT Interface in order to execute command & register/unregister events
+int ATCommandsInterface::open()
+{
+ if( m_open )
+ {
+ WARN("AT interface is already open");
+ return OK;
+ }
+ DBG("Opening AT interface");
+ //Start processing
+ m_processingThread.signal_set(AT_SIG_PROCESSING_START);
+
+ m_processingMtx.unlock();
+
+ m_open = true;
+
+ DBG("AT interface opened");
+
+ return OK;
+}
+
+//Initialize AT link & start events processing
+int ATCommandsInterface::init(bool reset /* = true*/)
+{
+
+ //Lock transaction mutex
+ m_transactionMtx.lock();
+
+ if (reset)
+ {
+ DBG("Sending ATZ E1 V1");
+ //Should we flush m_pStream at this point ???
+ int err;
+ int tries = 5;
+ do
+ {
+ err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
+ if(err && tries)
+ {
+ WARN("No response, trying again");
+ Thread::wait(1000); //Give dongle time to recover
+ }
+ } while(err && tries--);
+ if( err )
+ {
+ ERR("Sending ATZ E1 V1 returned with err code %d", err);
+ m_transactionMtx.unlock();
+ return err;
+ }
+ }
+
+ //Enable events handling and execute events enabling commands
+ enableEvents();
+
+ DBG("AT interface initialized");
+
+ //Unlock transaction mutex
+ m_transactionMtx.unlock();
+
+ return OK;
+}
+
+//Close connection
+int ATCommandsInterface::close()
+{
+ if( !m_open )
+ {
+ WARN("AT interface is already closed");
+ return OK;
+ }
+
+ DBG("Closing AT interface");
+
+ //Lock transaction mutex
+ m_transactionMtx.lock();
+
+ //Disable events handling and advertize this to the events handlers
+ disableEvents();
+
+ //Stop processing
+ m_processingThread.signal_set(AT_SIG_PROCESSING_STOP);
+ //m_stopSphre.release();
+
+ int* msg = m_env2AT.alloc(osWaitForever);
+ *msg = AT_STOP;
+ m_env2AT.put(msg); //Used to unstall the process if needed
+
+ //Unlock process routine (abort read)
+ m_pStream->abortRead(); //This is thread-safe
+ m_processingMtx.lock();
+ m_open = false;
+
+ //Unlock transaction mutex
+ m_transactionMtx.unlock();
+
+ DBG("AT interface closed");
+ return OK;
+}
+
+bool ATCommandsInterface::isOpen()
+{
+ return m_open;
+}
+
+int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+ return execute(command, this, pResult, timeout);
+}
+
+int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+ if(!m_open)
+ {
+ WARN("Interface is not open!");
+ return NET_INVALID;
+ }
+
+ //Lock transaction mutex
+ m_transactionMtx.lock();
+
+ disableEvents(); //Disable unsollicited result codes
+ int ret = executeInternal(command, pProcessor, pResult, timeout);
+ enableEvents(); //Re-enable unsollicited result codes whatever the result of the command is
+
+ //Unlock transaction mutex
+ m_transactionMtx.unlock();
+
+ return ret;
+}
+
+int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr)
+{
+ m_eventsMgmtMtx.lock();
+ m_eventsProcessingMtx.lock();
+ for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+ {
+ if( m_eventsHandlers[i] == NULL )
+ {
+ m_eventsHandlers[i] = pHdlr;
+ m_eventsProcessingMtx.unlock();
+ m_eventsMgmtMtx.unlock();
+ return OK;
+ }
+ }
+ m_eventsProcessingMtx.unlock();
+ m_eventsMgmtMtx.unlock();
+ return NET_OOM; //No room left
+}
+
+int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr)
+{
+ m_eventsMgmtMtx.lock();
+ m_eventsProcessingMtx.lock();
+ for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list
+ {
+ if( m_eventsHandlers[i] == pHdlr )
+ {
+ m_eventsHandlers[i] = NULL;
+ m_eventsProcessingMtx.unlock();
+ m_eventsMgmtMtx.unlock();
+ return OK;
+ }
+ }
+ m_eventsProcessingMtx.unlock();
+ m_eventsMgmtMtx.unlock();
+ return NET_NOTFOUND; //Not found
+}
+
+//Private methods
+
+int ATCommandsInterface::executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+ DBG("Executing command %s", command);
+
+ //Discard previous result if it arrived too late
+ osEvent evt = m_AT2Env.get(0);
+
+ if(evt.status == osEventMail)
+ {
+ m_AT2Env.free((int*)evt.value.p);
+ WARN("Previous result discarded");
+ }
+
+ //Send params to the process routine
+ m_transactionCommand = command;
+ if(pProcessor != NULL)
+ {
+ m_pTransactionProcessor = pProcessor;
+ }
+ else
+ {
+ m_pTransactionProcessor = this; //Use default behaviour
+ }
+
+ DBG("Sending command ready signal to AT thread & aborting current blocking read operation");
+
+ //Produce command ready signal
+ int* msg = m_env2AT.alloc(osWaitForever);
+ *msg = AT_CMD_READY;
+ m_env2AT.put(msg);
+
+ DBG("Trying to enter abortRead()");
+ //Unlock process routine (abort read)
+ m_pStream->abortRead(); //This is thread-safe
+
+ //Wait for a result (get result message)
+ evt = m_AT2Env.get(timeout);
+
+ if(evt.status != osEventMail)
+ {
+ //Cancel request
+ msg = m_env2AT.alloc(osWaitForever);
+ *msg = AT_TIMEOUT;
+ m_env2AT.put(msg);
+
+ DBG("Trying to enter abortRead()");
+ //Unlock process routine (abort read)
+ m_pStream->abortRead(); //This is thread-safe
+
+ //Wait for acknowledge
+ int msgResult;
+ do
+ {
+ evt = m_AT2Env.get(osWaitForever);
+ msgResult = *((int*) evt.value.p);
+ m_AT2Env.free((int*)evt.value.p);
+ } while(msgResult != AT_TIMEOUT);
+
+ WARN("Command returned no message");
+ WARN("Command \"%s\" returned no message", command);
+ return NET_TIMEOUT;
+ }
+ DBG("Command returned with message %d", *msg);
+
+ m_AT2Env.free((int*)evt.value.p);
+
+ if(pResult != NULL)
+ {
+ *pResult = m_transactionResult;
+ }
+
+ int ret = ATResultToReturnCode(m_transactionResult);
+ if(ret != OK)
+ {
+ WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code);
+ WARN("Command \"%s\" returned AT result %d with code %d", command, m_transactionResult.result, m_transactionResult.code);
+ }
+
+ DBG("Command returned successfully");
+
+ return ret;
+}
+
+int ATCommandsInterface::tryReadLine()
+{
+ static bool lineDetected = false;
+
+ //Block on serial read or incoming command
+ DBG("Trying to read a new line from stream");
+ int ret = m_pStream->waitAvailable(); //This can be aborted
+ size_t readLen = 0;
+ if(ret == OK)
+ {
+ ret = m_pStream->read((uint8_t*)m_inputBuf + m_inputPos, &readLen, AT_INPUT_BUF_SIZE - 1 - m_inputPos, 0); //Do NOT wait at this point
+ }
+ if(ret == OK)
+ {
+ m_inputPos+=readLen;
+ m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions
+ DBG("In buffer: [%s]", m_inputBuf);
+ }
+
+ if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted
+ {
+ DBG("Read was interrupted");
+ return NET_INTERRUPTED; //0 chars were read
+ }
+ else if(readLen == 0)
+ {
+ DBG("Nothing read");
+ return OK; //0 chars were read
+ }
+
+ DBG("Trying to process incoming line");
+ bool lineProcessed = false;
+
+ do
+ {
+ lineProcessed = false; //Reset flag
+
+ DBG("New iteration");
+
+ //Look for a new line
+ if(!lineDetected)
+ {
+ DBG("No line detected yet");
+ //Try to look for a starting CRLF
+ char* crPtr = strchr(m_inputBuf, CR);
+ /*
+ Different cases at this point:
+ - CRLF%c sequence: this is the start of a line
+ - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
+ - LF: this is the trailing LF char of the previous line, discard
+ - CR / CRLF incomplete sequence: more data is needed to determine which action to take
+ - %c ... CR sequence: this should be the echo of the previous sequence
+ - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
+
+ In every case, move mem at the beginning
+ */
+ if(crPtr != NULL)
+ {
+ DBG("CR char found");
+
+#if 0
+ //Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
+ memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos
+#endif
+
+ //If the line starts with CR, this should be a result code
+ if( crPtr == m_inputBuf )
+ {
+ //To determine the sequence we need at least 3 chars
+ if(m_inputPos >= 3)
+ {
+ //Look for a LF char next to the CR char
+ if(m_inputBuf[1] == LF)
+ {
+ //At this point we can check whether this is the end of a preceding line or the beginning of a new one
+ if(m_inputBuf[2] != CR)
+ {
+ DBG("Beginning of new line found");
+ //Beginning of a line
+ lineDetected = true; //Move to next state-machine step
+ }
+ else
+ {
+ //End of an unprocessed line
+ WARN("End of unprocessed line");
+ }
+ //In both cases discard CRLF
+ DBG("Discarding CRLF");
+ memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well
+ m_inputPos = m_inputPos - 2; //Adjust m_inputPos
+ }
+ else
+ {
+ //This is completely unexpected, discard the CR char to try to recover good state
+ WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]);
+ memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
+ m_inputPos = m_inputPos - 1; //Adjust m_inputPos
+ }
+ }
+ }
+ //if the line does NOT begin with CR, this can be an echo of the previous command, process it
+ else
+ {
+ int crPos = crPtr - m_inputBuf;
+ int lfOff = 0; //Offset for LF if present
+ DBG("New line found (possible echo of command)");
+ //This is the end of line
+ //Replace m_inputBuf[crPos] with null-terminating char
+ m_inputBuf[crPos] = '\0';
+ //Check if there is a LF char afterwards
+ if(m_inputPos - crPos >= 1)
+ {
+ if(m_inputBuf[crPos+1] == LF)
+ {
+ lfOff++; //We will discard LF char as well
+ }
+ }
+ //Process line
+ int ret = processReadLine();
+ if(ret)
+ {
+ m_inputPos = 0;
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ lineDetected = false;
+ return ret;
+ }
+
+ //If sendData has been called, all incoming data has been discarded
+ if(m_inputPos > 0)
+ {
+ memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos
+ }
+ DBG("One line was successfully processed");
+ lineProcessed = true; //Line was processed with success
+ lineDetected = false; //Search now for a new line
+ }
+ }
+ else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it
+ {
+ DBG("Discarding single LF char");
+ memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
+ m_inputPos = m_inputPos - 1; //Adjust m_inputPos
+ }
+ }
+
+ //Look for the end of line
+ if(lineDetected)
+ {
+ DBG("Looking for end of line");
+ //Try to look for a terminating CRLF
+ char* crPtr = strchr(m_inputBuf, CR);
+ /*
+ Different cases at this point:
+ - CRLF sequence: this is the end of the line
+ - CR%c sequence : unexpected
+ - CR incomplete sequence: more data is needed to determine which action to take
+ */
+
+ //Try to look for a '>' (greater than character) that marks an entry prompt
+ char* greaterThanPtr = strchr(m_inputBuf, GD);
+ /*
+ This character must be detected as there is no CRLF sequence at the end of an entry prompt
+ */
+
+ if(crPtr != NULL)
+ {
+ DBG("CR char found");
+ int crPos = crPtr - m_inputBuf;
+ //To determine the sequence we need at least 2 chars
+ if(m_inputPos - crPos >= 2)
+ {
+ //Look for a LF char next to the CR char
+ if(m_inputBuf[crPos + 1] == LF)
+ {
+ DBG("End of new line found");
+ //This is the end of line
+ //Replace m_inputBuf[crPos] with null-terminating char
+ m_inputBuf[crPos] = '\0';
+ //Process line
+ int ret = processReadLine();
+ if(ret)
+ {
+ m_inputPos = 0;
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ lineDetected = false;
+ return ret;
+ }
+
+ //If sendData has been called, all incoming data has been discarded
+ if(m_inputPos > 0)
+ {
+ //Shift remaining data to beginning of buffer
+ memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos
+ }
+
+ DBG("One line was successfully processed");
+ lineProcessed = true; //Line was processed with success
+ }
+ else
+ {
+ //This is completely unexpected, discard all chars till the CR char to try to recover good state
+ WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]);
+ memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos
+ }
+ lineDetected = false; //In both case search now for a new line
+ }
+ }
+ else if(greaterThanPtr != NULL)
+ {
+ DBG("> char found");
+ int gdPos = greaterThanPtr - m_inputBuf;
+ //To determine the sequence we need at least 2 chars
+ if(m_inputPos - gdPos >= 2)
+ {
+ //Look for a space char next to the GD char
+ if(m_inputBuf[gdPos + 1] == ' ')
+ {
+ //This is an entry prompt
+ //Replace m_inputBuf[gdPos] with null-terminating char
+ m_inputBuf[gdPos] = '\0';
+
+ //Shift remaining data to beginning of buffer
+ memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
+
+ //Process prompt
+ ret = processEntryPrompt();
+ if(ret)
+ {
+ m_inputPos = 0;
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ lineDetected = false;
+ return ret;
+ }
+
+ DBG("One line was successfully processed");
+ lineProcessed = true; //Line was processed with success
+ }
+ else
+ {
+ //This is completely unexpected, discard all chars till the GD char to try to recover good state
+ WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]);
+ memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
+ m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
+ }
+ lineDetected = false; //In both case search now for a new line
+ }
+ }
+ }
+ } while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again
+
+ //If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short)
+ if(m_inputPos == AT_INPUT_BUF_SIZE - 1)
+ {
+ //Discard everything
+ m_inputPos = 0;
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ WARN("Incoming buffer is too short to process incoming line");
+ //Look for a new line
+ lineDetected = false;
+ }
+
+ DBG("Processed every full incoming lines");
+
+ return OK;
+}
+
+int ATCommandsInterface::trySendCommand()
+{
+ osEvent evt = m_env2AT.get(0);
+ DBG("status = %d, msg = %d", evt.status, evt.value.p);
+ if(evt.status == osEventMail)
+ {
+ int* msg = (int*) evt.value.p;
+ if( *msg == AT_CMD_READY ) //Command pending
+ {
+ if(m_transactionState != IDLE)
+ {
+ WARN("Previous command not processed!");
+ }
+ DBG("Sending pending command");
+ m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever);
+ char cr = CR;
+ m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator
+ m_transactionState = COMMAND_SENT;
+ }
+ else //Timeout
+ {
+ //Acknowledge
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_TIMEOUT;
+ m_AT2Env.put(msg); //Command has timed out
+ m_transactionState = IDLE; //State-machine reset
+ }
+ m_env2AT.free(msg);
+ }
+ return OK;
+}
+
+int ATCommandsInterface::processReadLine()
+{
+ DBG("Processing read line [%s]", m_inputBuf);
+ //The line is stored in m_inputBuf
+ if(m_transactionState == COMMAND_SENT)
+ {
+ //If the command has been sent, checks echo to see if it has been received properly
+ if( strcmp(m_transactionCommand, m_inputBuf) == 0 )
+ {
+ DBG("Command echo received");
+ //If so, it means that the following lines will only be solicited results
+ m_transactionState = READING_RESULT;
+ return OK;
+ }
+ }
+ if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT)
+ {
+ bool found = false;
+ char* pSemicol = strchr(m_inputBuf, ':');
+ char* pData = NULL;
+ if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
+ {
+ *pSemicol = '\0';
+ pData = pSemicol + 1;
+ if(pData[0]==' ')
+ {
+ pData++; //Suppress whitespace
+ }
+ }
+ //Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command
+ m_eventsProcessingMtx.lock();
+ //Go through the list
+ for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+ {
+ if( m_eventsHandlers[i] != NULL )
+ {
+ if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) )
+ {
+ m_eventsHandlers[i]->onEvent(m_inputBuf, pData);
+ found = true; //Do not break here as there might be multiple handlers for one event type
+ }
+ }
+ }
+ m_eventsProcessingMtx.unlock();
+ if(found)
+ {
+ return OK;
+ }
+ }
+ if(m_transactionState == READING_RESULT)
+ {
+ //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s)
+ if(strcmp("OK", m_inputBuf) == 0)
+ {
+ DBG("OK result received");
+ m_transactionResult.code = 0;
+ m_transactionResult.result = ATResult::AT_OK;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else if(strcmp("ERROR", m_inputBuf) == 0)
+ {
+ DBG("ERROR result received");
+ m_transactionResult.code = 0;
+ m_transactionResult.result = ATResult::AT_ERROR;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
+ {
+ DBG("CONNECT result received");
+ m_transactionResult.code = 0;
+ m_transactionResult.result = ATResult::AT_CONNECT;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized
+ {
+ DBG("COMMAND NOT SUPPORT result received");
+ m_transactionResult.code = 0;
+ m_transactionResult.result = ATResult::AT_ERROR;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error
+ {
+ std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
+ DBG("+CME ERROR: %d result received", m_transactionResult.code);
+ m_transactionResult.result = ATResult::AT_CME_ERROR;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error
+ {
+ std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
+ DBG("+CMS ERROR: %d result received", m_transactionResult.code);
+ m_transactionResult.result = ATResult::AT_CMS_ERROR;
+ m_transactionState = IDLE;
+ int* msg = m_AT2Env.alloc(osWaitForever);
+ *msg = AT_RESULT_READY;
+ m_AT2Env.put(msg); //Command has been processed
+ return OK;
+ }
+ else
+ {
+ DBG("Unprocessed result received: '%s'", m_inputBuf);
+ //Must call transaction processor to complete line processing
+ int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called
+ return ret;
+ }
+ }
+
+ return OK;
+}
+
+int ATCommandsInterface::processEntryPrompt()
+{
+ DBG("Calling prompt handler");
+ int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called
+
+ if( ret != NET_MOREINFO ) //A new prompt is expected
+ {
+ DBG("Sending break character");
+ //Send CTRL+Z (break sequence) to exit prompt
+ char seq[2] = {BRK, 0x00};
+ sendData(seq);
+ }
+ return OK;
+}
+
+//This will be called on initialization & after the execution of a command
+void ATCommandsInterface::enableEvents()
+{
+ //Advertize this to events handlers
+ m_eventsMgmtMtx.lock();
+ for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+ {
+ if( m_eventsHandlers[i] != NULL )
+ {
+ m_eventsHandlers[i]->onDispatchStart();
+ //Enable this kind of events
+ const char* cmd = m_eventsHandlers[i]->getEventsEnableCommand();
+ if(cmd != NULL)
+ {
+ int ret = executeInternal(cmd, this, NULL); //Execute enable command
+ if(ret)
+ {
+ WARN("Events enabling command \"%s\" failed", cmd);
+ }
+ }
+ }
+ }
+ m_eventsMgmtMtx.unlock();
+}
+
+//This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results
+void ATCommandsInterface::disableEvents()
+{
+ //Advertize this to events handlers
+ m_eventsMgmtMtx.lock();
+ for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+ {
+ if( m_eventsHandlers[i] != NULL )
+ {
+ m_eventsHandlers[i]->onDispatchStart();
+ //Disable this kind of events
+ const char* cmd = m_eventsHandlers[i]->getEventsDisableCommand();
+ if(cmd != NULL)
+ {
+ int ret = executeInternal(cmd, this, NULL); //Execute disable command
+ if(ret)
+ {
+ WARN("Events disabling command \"%s\" failed", cmd);
+ }
+ }
+ }
+ }
+ m_eventsMgmtMtx.unlock();
+}
+
+//Commands that can be called during onNewATResponseLine callback, additionally to close()
+//Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
+int ATCommandsInterface::sendData(const char* data)
+{
+ //m_inputBuf is cleared at this point (and MUST therefore be empty)
+ int dataLen = strlen(data);
+ DBG("Sending raw string of length %d", dataLen);
+ int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever);
+ if(ret)
+ {
+ WARN("Could not write to stream (returned %d)", ret);
+ return ret;
+ }
+
+ int dataPos = 0;
+ do
+ {
+ //Read echo
+ size_t readLen;
+ int ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, MIN(dataLen - dataPos, AT_INPUT_BUF_SIZE - 1), osWaitForever); //Make sure we do not read more than needed otherwise it could break the parser
+ if(ret)
+ {
+ WARN("Could not read from stream (returned %d)", ret);
+ m_inputPos = 0; //Reset input buffer state
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ return ret;
+ }
+
+ if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
+ {
+ //Echo does not match output
+ m_inputBuf[readLen] = '\0';
+ WARN("Echo does not match output, got '%s' instead", m_inputBuf);
+ m_inputPos = 0; //Reset input buffer state
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+ return NET_DIFF;
+ }
+
+ dataPos += readLen;
+ //If all characters have not been read yet
+
+ } while(dataPos < dataLen);
+
+ DBG("String sent successfully");
+
+ m_inputPos = 0; //Reset input buffer state
+ m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
+
+ return OK;
+}
+
+/*static*/ void ATCommandsInterface::staticCallback(void const* p)
+{
+ ((ATCommandsInterface*)p)->process();
+}
+
+int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper
+{
+ if(result.result == ATResult::AT_OK)
+ {
+ return OK;
+ }
+ else
+ {
+ return NET_MOREINFO;
+ }
+}
+
+/*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling
+{
+ return OK;
+}
+
+/*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
+{
+ return OK;
+}
+
+void ATCommandsInterface::process() //Processing thread
+{
+ DBG("AT Thread started");
+ while(true)
+ {
+ DBG("AT Processing on hold");
+ m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started
+
+ m_processingMtx.lock();
+ DBG("AT Processing started");
+ //First of all discard buffer
+ int ret;
+ size_t readLen;
+ do //Drop everything
+ {
+ ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point
+ } while(ret == OK);
+ m_inputPos = 0; //Clear input buffer
+ do
+ {
+ DBG("Trying to send a pending command");
+ trySendCommand(); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command
+ DBG("Trying to read a new line");
+ tryReadLine();
+ } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted
+ m_processingMtx.unlock();
+ DBG("AT Processing stopped");
+ }
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h
new file mode 100644
index 0000000000..8334df8957
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h
@@ -0,0 +1,153 @@
+/* ATCommandsInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ATCOMMANDSINTERFACE_H_
+#define ATCOMMANDSINTERFACE_H_
+
+#include "core/fwk.h"
+#include "rtos.h"
+
+#define MAX_AT_EVENTS_HANDLERS 4
+
+class ATCommandsInterface;
+
+/** Interface implemented by components handling AT events
+ *
+ */
+class IATEventsHandler
+{
+protected:
+ virtual bool isATCodeHandled(const char* atCode) = 0; //Is this AT code handled
+ virtual void onDispatchStart() = 0;
+ virtual void onDispatchStop() = 0;
+ virtual char* getEventsEnableCommand() = 0;
+ virtual char* getEventsDisableCommand() = 0;
+ virtual void onEvent(const char* atCode, const char* evt) = 0;
+ friend class ATCommandsInterface;
+};
+
+/** Interface implemented by components executing complex AT commands
+ *
+ */
+class IATCommandsProcessor
+{
+protected:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) = 0;
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst) = 0;
+ friend class ATCommandsInterface;
+};
+
+#define AT_INPUT_BUF_SIZE 192//64
+
+//Signals to be sent to the processing thread
+#define AT_SIG_PROCESSING_START 1
+#define AT_SIG_PROCESSING_STOP 2
+//Messages to be sent to the processing thread
+#define AT_CMD_READY 1
+#define AT_TIMEOUT 2
+#define AT_STOP 3
+//Messages to be sent from the processing thread
+#define AT_RESULT_READY 1
+
+/** AT Commands interface class
+ *
+ */
+class ATCommandsInterface : protected IATCommandsProcessor
+{
+public:
+ ATCommandsInterface(IOStream* pStream);
+
+ //Open connection to AT Interface in order to execute command & register/unregister events
+ int open();
+
+ //Initialize AT link
+ int init(bool reset = true);
+
+ //Close connection
+ int close();
+
+ bool isOpen();
+
+ class ATResult
+ {
+ public:
+ enum { AT_OK, AT_ERROR, AT_CONNECT, AT_CMS_ERROR, AT_CME_ERROR } result;
+ int code;
+ };
+
+ int executeSimple(const char* command, ATResult* pResult, uint32_t timeout=1000);
+ int execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
+
+ int registerEventsHandler(IATEventsHandler* pHdlr);
+ int deregisterEventsHandler(IATEventsHandler* pHdlr);
+
+ //Commands that can be called during onNewATResponseLine callback, additionally to close()
+ //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
+ int sendData(const char* data);
+
+ static void staticCallback(void const* p);
+private:
+ int executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
+
+ int tryReadLine();
+ int trySendCommand();
+ int processReadLine();
+ int processEntryPrompt();
+
+ void enableEvents();
+ void disableEvents();
+
+ int ATResultToReturnCode(ATResult result); //Helper
+
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); //Default implementation for simple commands handling
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst); //Default implementation (just sends Ctrl+Z to exit the prompt)
+
+ void process(); //Processing thread
+
+ IOStream* m_pStream;
+
+ bool m_open; //< TRUE when the AT interface is open, and FALSE when it is not.
+
+ const char* m_transactionCommand;
+ const char* m_transactionData;
+
+ IATCommandsProcessor* m_pTransactionProcessor;
+ ATResult m_transactionResult;
+
+ enum { IDLE, COMMAND_SENT, READING_RESULT, ABORTED } m_transactionState;
+
+ char m_inputBuf[AT_INPUT_BUF_SIZE]; // Stores characters received from the modem.
+ int m_inputPos; // Current position of fill pointer in the input buffer.
+
+ Mutex m_transactionMtx;
+
+ // These are RTOS queues, concurrent access protected. In this case both only contain an integer.
+ Mail<int,1> m_env2AT; // used by calling function to inform processing thread of events
+ Mail<int,1> m_AT2Env; // used by processing thread to inform calling function of events
+
+ IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS]; // all registered events handlers
+
+ Mutex m_processingMtx;
+ Thread m_processingThread;
+
+ Mutex m_eventsMgmtMtx; //Lock events use within the calling thread
+ Mutex m_eventsProcessingMtx; //Lock events use within the processing thread
+};
+
+#endif /* ATCOMMANDSINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h
new file mode 100644
index 0000000000..6d411b8e4b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h
@@ -0,0 +1,59 @@
+/* IOStream.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef IOSTREAM_H_
+#define IOSTREAM_H_
+
+#include "rtos.h"
+
+class IStream
+{
+public:
+ //IStream();
+ //virtual ~IStream();
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever) = 0;
+ virtual size_t available() = 0;
+ virtual int waitAvailable(uint32_t timeout=osWaitForever) = 0; //Wait for data to be available
+ virtual int abortRead() = 0; //Abort current reading (or waiting) operation
+};
+
+class OStream
+{
+public:
+ //OStream();
+ //virtual ~OStream();
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever) = 0;
+ virtual size_t space() = 0;
+ virtual int waitSpace(uint32_t timeout=osWaitForever) = 0; //Wait for space to be available
+ virtual int abortWrite() = 0; //Abort current writing (or waiting) operation
+};
+
+class IOStream : public IStream, public OStream
+{
+public:
+ //IOStream();
+ //virtual ~IOStream();
+};
+
+
+#endif /* IOSTREAM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h
new file mode 100644
index 0000000000..b011693eb4
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h
@@ -0,0 +1,95 @@
+/* MtxCircBuf.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MTXCIRCBUFFER_H
+#define MTXCIRCBUFFER_H
+
+#include "rtos.h"
+
+//Mutex protected circualr buffer
+template<typename T, int size>
+class MtxCircBuffer
+{
+public:
+ MtxCircBuffer() //:
+ //mtx()
+ {
+ write = 0;
+ read = 0;
+ }
+
+ bool isFull()
+ {
+ mtx.lock();
+ bool r = (((write + 1) % size) == read);
+ mtx.unlock();
+ return r;
+ }
+
+ bool isEmpty()
+ {
+ mtx.lock();
+ bool r = (read == write);
+ mtx.unlock();
+ return r;
+ }
+
+ void queue(T k)
+ {
+ mtx.lock();
+ buf[write++] = k;
+ write %= size;
+ if (isFull())
+ {
+ read++;
+ read %= size;
+ }
+ mtx.unlock();
+ }
+
+ uint16_t available()
+ {
+ mtx.lock();
+ uint16_t a = (write >= read) ? (write - read) : (size - read + write);
+ mtx.unlock();
+ return a;
+ }
+
+ bool dequeue(T * c)
+ {
+ mtx.lock();
+ bool empty = (read == write);
+ if (!empty)
+ {
+ *c = buf[read++];
+ read %= size;
+ }
+ mtx.unlock();
+ return (!empty);
+ }
+
+private:
+ volatile uint16_t write;
+ volatile uint16_t read;
+ volatile T buf[size];
+ Mutex mtx;
+};
+
+#endif
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h
new file mode 100644
index 0000000000..508424dc66
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h
@@ -0,0 +1,27 @@
+/* config.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+
+//Configuration
+#define AT_THREAD_PRIORITY 0
+
+
+#endif /* CONFIG_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp
new file mode 100644
index 0000000000..4314e2342f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp
@@ -0,0 +1,127 @@
+/* dbg.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbg.h"
+
+#include "mbed.h"
+#include "rtos.h"
+
+#include <cstdio>
+#include <cstdarg>
+
+using namespace std;
+
+static Serial debug_pc(USBTX, USBRX);
+
+static char debug_newline[3];
+
+static void debug_lock(bool set)
+{
+ static Mutex* mtx = new Mutex(); //Singleton runtime initialisation to avoid static initialisation chaos problems
+ static bool init = false;
+ if(set)
+ {
+ mtx->lock();
+ if(!init)
+ {
+ strncpy( debug_newline, "\n", 2 );
+ printf("[START]\n");
+ fflush(stdout);
+ init = true;
+ }
+ }
+ else
+ {
+ mtx->unlock();
+ }
+}
+
+void debug_init()
+{
+ debug_lock(true); //Force init
+ debug_lock(false);
+}
+
+void debug_set_newline(const char* newline)
+{
+ debug_lock(true);
+ strncpy( debug_newline, newline, 2 );
+ debug_newline[2] = '\0';
+ debug_lock(false);
+}
+
+void debug_set_speed(int speed)
+{
+ debug_pc.baud(speed);
+}
+
+void debug(int level, const char* module, int line, const char* fmt, ...)
+{
+ debug_lock(true);
+ switch(level)
+ {
+ default:
+ case 1:
+ printf("[ERROR]");
+ break;
+ case 2:
+ printf("[WARN]");
+ break;
+ case 3:
+ printf("[INFO]");
+ break;
+ case 4:
+ printf("[DBG]");
+ break;
+ }
+
+ printf(" Module %s - Line %d: ", module, line);
+
+ va_list argp;
+
+ va_start(argp, fmt);
+ vprintf(fmt, argp);
+ va_end(argp);
+
+ printf(debug_newline);
+
+ fflush(stdout);
+
+ debug_lock(false);
+
+}
+
+void debug_error(const char* module, int line, int ret)
+{
+ debug_lock(true);
+ printf("[RC] Module %s - Line %d : Error %d\n", module, line, ret);
+ fflush(stdout);
+ debug_lock(false);
+}
+
+void debug_exact(const char* fmt, ...)
+{
+ debug_lock(true);
+ va_list argp;
+
+ va_start(argp, fmt);
+ vprintf(fmt, argp);
+ va_end(argp);
+ debug_lock(false);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h
new file mode 100644
index 0000000000..2ff24e1b31
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h
@@ -0,0 +1,79 @@
+/* dbg.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBG_H_
+#define DBG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void debug_init(void);
+void debug(int level, const char* module, int line, const char* fmt, ...);
+void debug_set_newline(const char* newline);
+void debug_set_speed(int speed);
+void debug_error(const char* module, int line, int ret);
+void debug_exact(const char* fmt, ...);
+
+#define DBG_INIT() do{ debug_init(); }while(0)
+
+#define DBG_SET_NEWLINE( x ) do{ debug_set_newline(x); }while(0)
+
+#define DBG_SET_SPEED( x ) do{ debug_set_speed(x); }while(0)
+
+#if __DEBUG__ > 0
+#ifndef __MODULE__
+#error "__MODULE__ must be defined"
+#endif
+#endif
+
+#if __DEBUG__ >= 1
+#define ERR(...) do{ debug(1, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
+#else
+#define ERR(...) do{ }while(0)
+#endif
+
+#if __DEBUG__ >= 2
+#define WARN(...) do{ debug(2, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
+#else
+#define WARN(...) do{ }while(0)
+#endif
+
+#if __DEBUG__ >= 3
+#define INFO(...) do{ debug(3, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
+#define CHECK(ret) do{ if(ret){ debug_error(__MODULE__, __LINE__, ret); } }while(0)
+#else
+#define INFO(...) do{ }while(0)
+#define CHECK(ret) do{ }while(0)
+#endif
+
+#if __DEBUG__ >= 4
+#define DBG(...) do{ debug(4, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
+#define DBGX(...) do{ debug_exact(__VA_ARGS__); }while(0)
+#else
+#define DBG(...) do{ }while(0)
+#define DBGX(...) do{ }while(0)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DBG_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h
new file mode 100644
index 0000000000..73ca00c1c4
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h
@@ -0,0 +1,47 @@
+/* errors.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ERRORS_H_
+#define ERRORS_H_
+
+/** \page Network-related errors */
+
+#define OK 0 //No error
+
+#define NET_FULL 1 //>All available resources are already used
+#define NET_EMPTY 2 //>No resource
+#define NET_NOTFOUND 3 //>Element cannot be found
+#define NET_INVALID 4 //>Invalid
+#define NET_CONTEXT 5 //>Called in a wrong context (eg during an interrupt)
+#define NET_TIMEOUT 6 //>Timeout
+#define NET_UNKNOWN 7 //>Unknown error
+#define NET_OVERFLOW 8 //>Overflow
+#define NET_PROCESSING 9 //>Command is processing
+#define NET_INTERRUPTED 10 //>Current operation has been interrupted
+#define NET_MOREINFO 11 //>More info on this error can be retrieved elsewhere (eg in a parameter passed as ptr)
+#define NET_ABORT 12 //>Current operation must be aborted
+#define NET_DIFF 13 //>Items that should match are different
+#define NET_AUTH 14 //>Authentication failed
+#define NET_PROTOCOL 15 //>Protocol error
+#define NET_OOM 16 //>Out of memory
+#define NET_CONN 17 //>Connection error
+#define NET_CLOSED 18 //>Connection was closed by remote end
+#define NET_TOOSMALL 19 //>Buffer is too small
+
+#endif /* ERRORS_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h
new file mode 100644
index 0000000000..4efc281c0e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h
@@ -0,0 +1,61 @@
+/* fwk.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef FWK_H_
+#define FWK_H_
+
+#include "config.h"
+
+#include "string.h"
+//using namespace std;
+
+#include "stdint.h"
+typedef unsigned int size_t;
+
+#ifndef __cplusplus
+//boolean type compatibility
+typedef byte bool;
+#define true 1
+#define false 0
+#endif
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+#define CR '\x0D'
+#define LF '\x0A'
+#define GD '\x3E'
+#define BRK '\x1A'
+
+//Custom utility classes
+#include "IOStream.h"
+//#include "String.h"
+
+//Error codes
+#include "errors.h"
+
+//Debug
+#include "dbg.h"
+
+//Utility macros
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#define MAX(x,y) (((x)>(y))?(x):(y))
+
+#endif /* FWK_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp
new file mode 100644
index 0000000000..3732303e24
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp
@@ -0,0 +1,81 @@
+/* IPInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "core/fwk.h"
+
+#include "IPInterface.h"
+
+#include <cstring> //For strcpy
+
+
+IPInterface::IPInterface() : m_connected(false)
+{
+
+}
+
+/*virtual*/ IPInterface::~IPInterface()
+{
+
+}
+
+void IPInterface::registerAsDefaultInterface() //First come, first served
+{
+ s_pDefaultInterface = this;
+}
+
+void IPInterface::unregisterAsDefaultInterface() //Must be called before inst is destroyed to avoid invalid ptr fault
+{
+ s_pDefaultInterface = NULL;
+}
+
+/*static*/ IPInterface* IPInterface::getDefaultInterface() //For use by TCP, UDP sockets library
+{
+ return s_pDefaultInterface;
+}
+
+/*static*/ IPInterface* IPInterface::s_pDefaultInterface = NULL;
+
+
+char* IPInterface::getIPAddress() //Get IP Address as a string ('a.b.c.d')
+{
+ if(isConnected())
+ {
+ return m_ipAddr;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool IPInterface::isConnected() //Is the interface connected?
+{
+ return m_connected;
+}
+
+void IPInterface::setIPAddress(char* ipAddr)
+{
+ std::strcpy(m_ipAddr, ipAddr); //Let's trust the derived class not to buffer overflow us
+}
+
+void IPInterface::setConnected(bool connected)
+{
+ m_connected = connected;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h
new file mode 100644
index 0000000000..6655aec9ca
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h
@@ -0,0 +1,60 @@
+/* IPInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef IPINTERFACE_H_
+#define IPINTERFACE_H_
+
+#include "core/fwk.h"
+
+/** Generic IP-based network interface
+ *
+ */
+class IPInterface
+{
+public:
+ IPInterface();
+ virtual ~IPInterface();
+
+ //int init(); //Initialize interface; no connection should be performed at this stage
+ virtual int connect() = 0; //Do connect the interface
+ virtual int disconnect() = 0;
+ //It is encouraged that the derived class implement a "setup(...)" function to configure the interface before the connection
+
+ char* getIPAddress(); //Get IP Address as a string ('a.b.c.d')
+ bool isConnected(); //Is the interface connected?
+
+ static IPInterface* getDefaultInterface(); //For use by TCP, UDP sockets library
+
+ //WARN: Implementation will have to be more careful in case of multiple interfaces (or implement a routing protocol based on local IP addresses differentiation)
+ void registerAsDefaultInterface(); //First come, first served
+ void unregisterAsDefaultInterface(); //Must be called before inst is destroyed to avoid invalid ptr fault
+
+protected:
+ //Must be called by subclasses
+ void setIPAddress(char* ipAddr);
+ void setConnected(bool connected);
+
+private:
+ char m_ipAddr[16];
+ bool m_connected;
+
+ static IPInterface* s_pDefaultInterface;
+};
+
+#endif /* IPINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp
new file mode 100644
index 0000000000..b20f2a6617
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp
@@ -0,0 +1,52 @@
+/* LwIPInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "core/fwk.h"
+
+#include "LwIPInterface.h"
+
+extern "C" {
+#include "lwip/init.h"
+#include "lwip/tcpip.h"
+}
+
+LwIPInterface::LwIPInterface() : IPInterface(), m_rdySphre(1)
+{
+ m_rdySphre.wait();
+}
+
+LwIPInterface::~LwIPInterface()
+{
+
+}
+
+int LwIPInterface::init() //Init LwIP-specific stuff, create the right bindings, etc
+{
+ //lwip_init(); //All LwIP initialisation functions called on a per-module basis (according to lwipopts.h)
+ tcpip_init(LwIPInterface::tcpipRdyCb, this); //Start TCP/IP processing thread
+ m_rdySphre.wait(); //Wait for callback to produce resource
+ return OK;
+}
+
+/*static*/ void LwIPInterface::tcpipRdyCb(void* ctx) //Result of TCP/IP thread launch
+{
+ LwIPInterface* pIf = (LwIPInterface*) ctx;
+ pIf->m_rdySphre.release();
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h
new file mode 100644
index 0000000000..7e5471e204
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h
@@ -0,0 +1,44 @@
+/* LwIPInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPINTERFACE_H_
+#define LWIPINTERFACE_H_
+
+#include "core/fwk.h"
+#include "IPInterface.h"
+
+#include "rtos.h"
+
+/** LwIP-based network interface
+ *
+ */
+class LwIPInterface : public IPInterface
+{
+public:
+ LwIPInterface();
+ virtual ~LwIPInterface();
+
+ int init(); //Init LwIP-specific stuff, create the right bindings, etc
+
+private:
+ static void tcpipRdyCb(void* ctx); //Result of TCP/IP thread launch
+ Semaphore m_rdySphre;
+};
+
+#endif /* LWIPINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp
new file mode 100644
index 0000000000..98614050ef
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp
@@ -0,0 +1,466 @@
+/* PPPIPInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "PPPIPInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+#include "rtos.h"
+
+#include <cstdio>
+using std::sscanf;
+using std::sprintf;
+
+#include "PPPIPInterface.h"
+
+#define MSISDN "*99#"
+
+#define CONNECT_CMD_PREFIX "ATD "
+#define CONNECT_CMD_SUFFIX "\x0D"
+#define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
+#define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
+#define EXPECTED_RESP_MIN_LEN 20
+#define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
+#define ESCAPE_SEQ "+++"
+#define HANGUP_CMD "ATH" "\x0D"
+#define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
+extern "C" {
+#include "lwip/ip_addr.h"
+#include "lwip/inet.h"
+#include "lwip/err.h"
+#include "lwip/dns.h"
+
+#include "netif/ppp/ppp.h"
+}
+
+PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
+{
+ m_linkStatusSphre.wait();
+}
+
+
+
+/*virtual*/ PPPIPInterface::~PPPIPInterface()
+{
+}
+
+/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
+{
+ DBG("Initializing LwIP");
+ LwIPInterface::init(); //Init LwIP, NOT including PPP
+ DBG("Initializing PPP");
+ pppInit();
+ DBG("Done");
+ return OK;
+}
+
+int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
+{
+ DBG("Configuring PPP authentication method");
+ pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
+ m_msisdn = msisdn;
+ DBG("Done");
+ return OK;
+}
+
+/*virtual*/ int PPPIPInterface::connect()
+{
+ int ret;
+ char cmd[32];
+ int cmdLen;
+ char buf[32];
+ size_t len;
+ DBG("Trying to connect with PPP");
+
+ cleanupLink();
+
+ cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
+ DBG("Sending %s", cmd);
+ ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
+ if( ret != OK )
+ {
+ return NET_UNKNOWN;
+ }
+
+ len = 0;
+ size_t readLen;
+ ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
+ if( ret != OK )
+ {
+ return NET_UNKNOWN;
+ }
+ len += readLen;
+ while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) )
+ {
+ ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000);
+ if( ret != OK )
+ {
+ return NET_UNKNOWN;
+ }
+ len += readLen;
+ }
+
+ buf[len]=0;
+
+ DBG("Got %s[len %d]", buf, len);
+
+ int datarate = 0;
+ strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
+ if( (sscanf(buf, cmd, &datarate ) != 1))
+ {
+ strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
+ if (strcmp(cmd, buf) != 0)
+ {
+ //Discard buffer
+ do //Clear buf
+ {
+ ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
+ } while( (ret == OK) && (len > 0) );
+ return NET_CONN;
+ }
+ }
+
+ DBG("Transport link open");
+ if(datarate != 0)
+ {
+ DBG("Datarate: %d bps", datarate);
+ }
+ m_linkStatusSphre.wait(0);
+ if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
+ {
+ return NET_INVALID;
+ }
+
+ ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
+ if(ret < 0)
+ {
+ switch(ret)
+ {
+ case PPPERR_OPEN:
+ default:
+ return NET_FULL; //All available resources are already used
+ }
+ }
+ m_pppd = ret; //PPP descriptor
+ m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
+ if(m_pppErrCode != PPPERR_NONE)
+ {
+ m_pppd = -1;
+ }
+ switch(m_pppErrCode)
+ {
+ case PPPERR_NONE: //Connected OK
+ return OK;
+ case PPPERR_CONNECT: //Connection lost
+ return NET_INTERRUPTED;
+ case PPPERR_AUTHFAIL: //Authentication failed
+ return NET_AUTH;
+ case PPPERR_PROTOCOL: //Protocol error
+ return NET_PROTOCOL;
+ default:
+ return NET_UNKNOWN;
+ }
+}
+
+/*virtual*/ int PPPIPInterface::disconnect()
+{
+ int ret = m_linkStatusSphre.wait(0);
+ if(ret > 0) //Already disconnected?
+ {
+ m_pppd = -1; //Discard PPP descriptor
+ switch(m_pppErrCode)
+ {
+ case PPPERR_CONNECT: //Connection terminated
+ case PPPERR_AUTHFAIL: //Authentication failed
+ case PPPERR_PROTOCOL: //Protocol error
+ case PPPERR_USER:
+ return OK;
+ default:
+ return NET_UNKNOWN;
+ }
+ }
+ else
+ {
+ if(m_pppd == -1)
+ {
+ return NET_INVALID;
+ }
+ pppClose(m_pppd);
+ do
+ {
+ m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
+ DBG("Received PPP err code %d", m_pppErrCode);
+ } while(m_pppErrCode != PPPERR_USER);
+ m_pppd = -1; //Discard PPP descriptor
+ }
+
+ DBG("Sending %s", ESCAPE_SEQ);
+
+ ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
+ if( ret != OK )
+ {
+ return NET_UNKNOWN;
+ }
+
+ cleanupLink();
+
+ return OK;
+}
+
+
+int PPPIPInterface::cleanupLink()
+{
+ int ret;
+ char buf[32];
+ size_t len;
+
+ do //Clear buf
+ {
+ ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
+ if(ret == OK)
+ {
+ buf[len] = '\0';
+ DBG("Got %s", buf);
+ }
+ } while( (ret == OK) && (len > 0) );
+
+ DBG("Sending %s", HANGUP_CMD);
+
+ ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
+ if( ret != OK )
+ {
+ return NET_UNKNOWN;
+ }
+
+ size_t readLen;
+
+ //Hangup
+ DBG("Expect %s", HANGUP_CMD);
+
+ len = 0;
+ while( len < strlen(HANGUP_CMD) )
+ {
+ ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
+ if( ret != OK )
+ {
+ break;
+ }
+ len += readLen;
+ /////
+ buf[len]=0;
+ DBG("Got %s", buf);
+ }
+
+ buf[len]=0;
+
+ DBG("Got %s[len %d]", buf, len);
+
+ //OK response
+ DBG("Expect %s", OK_RESP);
+
+ len = 0;
+ while( len < strlen(OK_RESP) )
+ {
+ ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
+ if( ret != OK )
+ {
+ break;
+ }
+ len += readLen;
+ /////
+ buf[len]=0;
+ DBG("Got %s", buf);
+ }
+
+ buf[len]=0;
+
+ DBG("Got %s[len %d]", buf, len);
+
+ //NO CARRIER event
+ DBG("Expect %s", NO_CARRIER_RESP);
+
+ len = 0;
+ while( len < strlen(NO_CARRIER_RESP) )
+ {
+ ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
+ if( ret != OK )
+ {
+ break;
+ }
+ len += readLen;
+ /////
+ buf[len]=0;
+ DBG("Got %s", buf);
+ }
+
+ buf[len]=0;
+
+ DBG("Got %s[len %d]", buf, len);
+
+ do //Clear buf
+ {
+ ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
+ if(ret == OK)
+ {
+ buf[len] = '\0';
+ DBG("Got %s", buf);
+ }
+ } while( (ret == OK) && (len > 0) );
+
+
+ return OK;
+}
+
+/*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
+{
+ PPPIPInterface* pIf = (PPPIPInterface*)ctx;
+ struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
+
+ switch(errCode)
+ {
+ case PPPERR_NONE:
+ WARN("Connected via PPP.");
+ DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
+ DBG("Netmask: %s", inet_ntoa(addrs->netmask));
+ DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
+ DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
+ DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
+ //Setup DNS
+ if (addrs->dns1.addr != 0)
+ {
+ dns_setserver(0, (struct ip_addr*)&(addrs->dns1));
+ }
+ if (addrs->dns2.addr != 0)
+ {
+ dns_setserver(1, (struct ip_addr*)&(addrs->dns1));
+ }
+
+ pIf->setConnected(true);
+ pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
+ break;
+ case PPPERR_CONNECT: //Connection lost
+ WARN("Connection lost/terminated");
+ pIf->setConnected(false);
+ break;
+ case PPPERR_AUTHFAIL: //Authentication failed
+ WARN("Authentication failed");
+ pIf->setConnected(false);
+ break;
+ case PPPERR_PROTOCOL: //Protocol error
+ WARN("Protocol error");
+ pIf->setConnected(false);
+ break;
+ case PPPERR_USER:
+ WARN("Disconnected by user");
+ pIf->setConnected(false);
+ break;
+ default:
+ WARN("Unknown error (%d)", errCode);
+ pIf->setConnected(false);
+ break;
+ }
+
+ pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
+ pIf->m_pppErrCode = errCode;
+ pIf->m_linkStatusSphre.release();
+}
+
+//LwIP PPP implementation
+extern "C"
+{
+
+/**
+ * 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, u8_t *data, u32_t len)
+{
+ DBG("sio_write");
+ PPPIPInterface* pIf = (PPPIPInterface*)fd;
+ int ret;
+ if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+ {
+ return 0;
+ }
+ ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
+ if(ret != OK)
+ {
+ return 0;
+ }
+ return len;
+}
+
+/**
+ * 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)
+{
+ DBG("sio_read");
+ PPPIPInterface* pIf = (PPPIPInterface*)fd;
+ int ret;
+ size_t readLen;
+ if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+ {
+ WARN("EXIT NOT AVAIL");
+ return 0;
+ }
+ ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
+ if(ret != OK)
+ {
+ return 0;
+ }
+ DBG("ret");
+ return readLen;
+}
+
+/**
+ * Aborts a blocking sio_read() call.
+ *
+ * @param fd serial device handle
+ */
+void sio_read_abort(sio_fd_t fd)
+{
+ DBG("sio_read_abort");
+ PPPIPInterface* pIf = (PPPIPInterface*)fd;
+ if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+ {
+ return;
+ }
+ pIf->m_pStream->abortRead();
+ DBG("ret");
+}
+
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h
new file mode 100644
index 0000000000..2d24009dcd
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h
@@ -0,0 +1,69 @@
+/* PPPIPInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PPPIPINTERFACE_H_
+#define PPPIPINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "LwIPInterface.h"
+
+#include "lwip/sio.h"
+
+namespace rtos {
+class Semaphore;
+}
+using namespace rtos;
+
+#define DEFAULT_MSISDN_GSM "*99#"
+#define DEFAULT_MSISDN_CDMA "#777"
+
+/** Interface using PPP to connect to an IP-based network
+ *
+ */
+class PPPIPInterface : public LwIPInterface
+{
+public:
+ PPPIPInterface(IOStream* pStream);
+ virtual ~PPPIPInterface();
+
+ int init(); //Init PPP-specific stuff, create the right bindings, etc
+ int setup(const char* user, const char* pw, const char* msisdn); //Setup authentication
+ virtual int connect();
+ virtual int disconnect();
+
+private:
+ int cleanupLink();
+
+ static void linkStatusCb(void *ctx, int errCode, void *arg); //PPP link status
+ Semaphore m_linkStatusSphre;
+ int m_pppErrCode;
+
+ IOStream* m_pStream; //Serial stream
+ bool m_streamAvail;
+ const char* m_msisdn;
+
+ int m_pppd;
+
+ friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
+ friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
+ friend void sio_read_abort(sio_fd_t fd);
+};
+
+#endif /* PPPIPINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp
new file mode 100644
index 0000000000..612b376921
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp
@@ -0,0 +1,175 @@
+/* LinkMonitor.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "LinkMonitor.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "LinkMonitor.h"
+
+#include <cstdio>
+using std::sscanf;
+
+#define DEFAULT_TIMEOUT 10000
+
+LinkMonitor::LinkMonitor(ATCommandsInterface* pIf) : m_pIf(pIf), m_rssi(0), m_registrationState(REGISTRATION_STATE_UNKNOWN), m_bearer(BEARER_UNKNOWN)
+{
+ m_gsm = true;
+}
+
+int LinkMonitor::init(bool gsm)
+{
+ m_gsm = gsm;
+ if (m_gsm)
+ {
+ // we need to make sure that we setup the operator selection to be in 'numeric' format.
+ // i.e. it is made up of a network and country code when returned by the modem e.g. Operator = 23415. This allows easy logic parsing for
+ // setting up other network parameters in future.
+ DBG("LinkMonitor::init() being called. This should only happen once: executinging AT+COPS=0,2");
+ int ret = m_pIf->executeSimple("AT+COPS=0,2", NULL, DEFAULT_TIMEOUT); //Configure to set the operator string to Country Code and mobile network code
+ if(ret != OK)
+ {
+ WARN(" NET_PROTOCOL error from sending the AT+COPS command to the modem. ");
+ return NET_PROTOCOL;
+ }
+ }
+ return OK;
+}
+
+/*virtual*/ int LinkMonitor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+ DBG("Line is %s", line);
+ char n[32] = "";
+ char s[32] = "";
+ int v;
+ if( sscanf(line, "+CREG: %*d,%d", &v) >= 1 ) //Reg state is valid
+ {
+ DBG("+CREG %d", v);
+ switch( v )
+ {
+ case 0:
+ m_registrationState = REGISTRATION_STATE_UNKNOWN;
+ break;
+ case 1:
+ m_registrationState = REGISTRATION_STATE_HOME_NETWORK;
+ break;
+ case 2:
+ m_registrationState = REGISTRATION_STATE_REGISTERING;
+ break;
+ case 3:
+ m_registrationState = REGISTRATION_STATE_DENIED;
+ break;
+ case 4:
+ m_registrationState = REGISTRATION_STATE_NO_SIGNAL;
+ break;
+ case 5:
+ m_registrationState = REGISTRATION_STATE_ROAMING;
+ break;
+ default:
+ m_registrationState = REGISTRATION_STATE_UNKNOWN;
+ break;
+ }
+ }
+ else if( sscanf(line, "+COPS: %*d,%*d,\"%*[^\"]\",%d", &v) >= 1 )
+ {
+ DBG("+COPS %d", v);
+ switch( v )
+ {
+ case 0:
+ m_bearer = BEARER_GSM;
+ break;
+ case 2:
+ m_bearer = BEARER_UMTS;
+ break;
+ case 3:
+ m_bearer = BEARER_EDGE;
+ break;
+ case 4: //HSDPA
+ case 5: //HSUPA
+ case 6: //HSDPA + HSUPA
+ m_bearer = BEARER_HSPA;
+ break;
+ case 7:
+ m_bearer = BEARER_LTE;
+ break;
+ case 1: //GSM Compact
+ default:
+ m_bearer = BEARER_UNKNOWN;
+ break;
+ }
+ }
+ else if( sscanf(line, "+CSQ: %d,%*d", &v) >= 1 )
+ {
+ DBG("+CSQ %d", v);
+ if(v == 99) //Unknown
+ {
+ m_rssi = 0; //Unknown
+ }
+ else
+ {
+ m_rssi = -113 + 2*v;
+ }
+ }
+ else if ( (sscanf(line, "+CNUM: \"%[^\"]\",\"%[^\"]\",%d", n, s, &v) == 3) ||
+ (sscanf(line, "+CNUM: \"\",\"%[^\"]\",%d", s, &v) == 2) )
+ {
+ if (*s && ((v == 145/*number includes + */) || (v == 129/*otherwise*/))) {
+ strcpy(m_phoneNumber, s);
+ }
+ }
+ return OK;
+}
+
+/*virtual*/ int LinkMonitor::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+ return OK;
+}
+
+int LinkMonitor::getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer)
+{
+ m_rssi = 0;
+ m_registrationState = REGISTRATION_STATE_UNKNOWN;
+ m_bearer = BEARER_UNKNOWN;
+ int ret = m_pIf->execute(m_gsm ? "AT+CREG?;+COPS?;+CSQ" : "AT+CREG?;+CSQ", this, NULL, DEFAULT_TIMEOUT); //Configure to get registration info & get it; get signal quality
+ if(ret != OK)
+ {
+ return NET_PROTOCOL;
+ }
+ *pRssi = m_rssi;
+ *pRegistrationState = m_registrationState;
+ *pBearer = m_bearer;
+ return OK;
+}
+
+int LinkMonitor::getPhoneNumber(char* phoneNumber)
+{
+ *m_phoneNumber = '\0';
+ if (m_gsm) {
+ int ret = m_pIf->execute("AT+CNUM", this, NULL, DEFAULT_TIMEOUT);
+ if(ret != OK)
+ {
+ return NET_PROTOCOL;
+ }
+ }
+ strcpy(phoneNumber, m_phoneNumber);
+ return OK;
+} \ No newline at end of file
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h
new file mode 100644
index 0000000000..864909d6c5
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h
@@ -0,0 +1,96 @@
+/* LinkMonitor.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LINKMONITOR_H_
+#define LINKMONITOR_H_
+
+#include "core/fwk.h"
+
+#include "rtos.h"
+
+#include "at/ATCommandsInterface.h"
+
+/** Component to monitor link quality
+ *
+ */
+class LinkMonitor : protected IATCommandsProcessor
+{
+public:
+ /** Create LinkMonitor instance
+ @param pIf Pointer to the ATCommandsInterface instance to use
+ */
+ LinkMonitor(ATCommandsInterface* pIf);
+
+ /** Initialize monitor
+ */
+ int init(bool gsm = true);
+
+ /** Registration State
+ */
+ enum REGISTRATION_STATE
+ {
+ REGISTRATION_STATE_UNKNOWN, //!< Unknown
+ REGISTRATION_STATE_REGISTERING, //!< Registering
+ REGISTRATION_STATE_DENIED, //!< Denied
+ REGISTRATION_STATE_NO_SIGNAL, //!< No Signal
+ REGISTRATION_STATE_HOME_NETWORK, //!< Registered on home network
+ REGISTRATION_STATE_ROAMING //!< Registered on roaming network
+ };
+
+ /** Bearer type
+ */
+ enum BEARER
+ {
+ BEARER_UNKNOWN, //!< Unknown
+ BEARER_GSM, //!< GSM (2G)
+ BEARER_EDGE, //!< EDGE (2.5G)
+ BEARER_UMTS, //!< UMTS (3G)
+ BEARER_HSPA, //!< HSPA (3G+)
+ BEARER_LTE //!< LTE (4G)
+ };
+
+ /** Get link state
+ @param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
+ @param pRegistrationState pointer to store the current registration state
+ @param pBearer pointer to store the current bearer
+ @return 0 on success, error code on failure
+ */
+ int getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer);
+
+ /** Get my phone number
+ @param phoneNumber pointer to store the current phoneNumber
+ @return 0 on success, error code on failure
+ */
+ int getPhoneNumber(char* phoneNumber);
+protected:
+ //IATCommandsProcessor
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+
+private:
+ ATCommandsInterface* m_pIf;
+
+ int m_rssi;
+ bool m_gsm;
+ REGISTRATION_STATE m_registrationState;
+ BEARER m_bearer;
+ char m_phoneNumber[16];
+};
+
+#endif /* LINKMONITOR_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h
new file mode 100644
index 0000000000..5cd84be875
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h
@@ -0,0 +1,26 @@
+/* lwipopts.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_CONF_H_
+#define LWIPOPTS_CONF_H_
+
+#define LWIP_TRANSPORT_PPP 1
+
+#endif /* LWIPOPTS_CONF_H_ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp
new file mode 100644
index 0000000000..978b3e1e8b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp
@@ -0,0 +1,350 @@
+/* CDMASMSInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "CDMASMSInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "CDMASMSInterface.h"
+
+#include <cstdio>
+#include <cstring>
+
+using std::sscanf;
+
+#define DEFAULT_TIMEOUT 10000
+
+CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
+{
+}
+
+int CDMASMSInterface::init()
+{
+ m_state = SMS_IDLE;
+
+ DBG("Get number of messages in the different inboxes");
+ int ret = updateInbox();
+ if(ret)
+ {
+ return NET_PROTOCOL;
+ }
+
+ DBG("Initialization done");
+ return OK;
+}
+
+int CDMASMSInterface::send(const char* number, const char* message)
+{
+ if( strlen(number) > 16 )
+ {
+ return NET_INVALID; //Number too long
+ }
+
+ int ret;
+
+ //Prepare infos
+ m_state = SMS_SEND_CMD_SENT;
+
+ bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
+
+ DBG("Send SM");
+ //Send command
+ char cmd[32+strlen(message)];
+ std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
+ ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+
+ if(ret != OK)
+ {
+ WARN("ret %d", ret);
+ m_state = SMS_IDLE;
+ return NET_PROTOCOL;
+ }
+
+ DBG("Check status");
+ m_txState = SMS_PENDING;
+
+ int tries = 10;
+ while(tries--)
+ {
+ m_state = SMS_GET_TX_STATUS_CMD_SENT;
+ ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
+ if(ret)
+ {
+ m_state = SMS_IDLE;
+ return ret;
+ }
+ m_state = SMS_IDLE;
+ if(m_txState == SMS_PENDING) //Wait more
+ {
+ Thread::wait(1000);
+ continue;
+ }
+ else if(m_txState == SMS_FAILED)
+ {
+ ERR("The modem could not send the SM");
+ return NET_CONN; //Probably a conenction issue, the user can retry
+ }
+ else
+ {
+ break;
+ }
+ }
+ if(!tries)
+ {
+ ERR("The is still trying to send the SM");
+ return NET_TIMEOUT;
+ }
+ return OK;
+}
+
+
+int CDMASMSInterface::get(char* number, char* message, size_t maxLength)
+{
+ if( maxLength < 1 )
+ {
+ return NET_INVALID; //Buffer too short
+ }
+
+ int ret;
+
+ DBG("Get next message");
+ if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
+ {
+ DBG("Message list count is 0 and needs updating. Running updateInbox.");
+ ret = updateInbox();
+ if (ret)
+ {
+ return ret;
+ }
+ }
+
+ if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
+ {
+ DBG("Message list count is 0");
+ return NET_EMPTY; //No message to read
+ }
+
+ //Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
+ int index;
+ if(m_msgInListsCount[2])
+ {
+ index = 3;
+ }
+ else if(m_msgInListsCount[0])
+ {
+ index = 1;
+ }
+ else //if(m_msgInListsCount[1])
+ {
+ index = 2;
+ }
+
+ //Prepare infos
+ m_state = SMS_GET_CMD_SENT;
+ m_msisdn = (char*) number;
+ m_msg = (char*) message;
+ m_maxMsgLength = maxLength;
+ m_headersToRead = 3;
+
+ m_msisdn[0] = '\0';
+
+ DBG("Get SMS");
+ //Read command
+ char cmd[32];
+ std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
+ ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ WARN("AT!GSMS returned %d", ret);
+ m_state = SMS_IDLE;
+ return NET_PROTOCOL;
+ }
+
+ //If message is not read, it will be put at the end of the read list
+ int item;
+ if( index != 3 )
+ {
+ //Decrement count in relevant list
+ m_msgInListsCount[index-1]--;
+ //Increment count in read list
+ m_msgInListsCount[3-1]++;
+ item = m_msgInListsCount[3-1];
+ //Normally item should be equal to 1 as we'd have read any older messages first
+ if( item != 1 )
+ {
+ WARN("Still some older messages pending in the read inbox");
+ }
+ }
+ else
+ {
+ //The item is still the oldest one
+ item = 1;
+ }
+
+ DBG("Deleting message");
+ //Delete message from inbox
+ std::sprintf(cmd, "AT!DSMS=3"/*,%d", item*/); //FIXME why doesn't that work when specifying the index??
+ ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
+ if(ret != OK)
+ {
+ ERR("Could not delete message");
+ }
+ else
+ {
+ //Now we can decrease the number of read messages
+ m_msgInListsCount[3-1]--;
+ }
+
+ if (m_state != SMS_CMD_PROCESSED)
+ {
+ WARN("Message could not be retrieved properly");
+ m_state = SMS_IDLE;
+ return NET_EMPTY;
+ }
+
+ m_state = SMS_IDLE;
+
+ return OK;
+}
+
+
+int CDMASMSInterface::getCount(size_t* pCount)
+{
+ int ret = updateInbox();
+ if(ret)
+ {
+ return NET_PROTOCOL;
+ }
+
+ *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
+
+ return OK;
+}
+
+
+/*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+ if(m_state == SMS_SEND_CMD_SENT)
+ {
+ DBG("SMS Send: %s", line);
+ }
+ else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
+ {
+ if(!strcmp(line, "sent"))
+ {
+ m_txState = SMS_SENT;
+ m_state = SMS_CMD_PROCESSED;
+ }
+ else if(!strcmp(line, "failed"))
+ {
+ m_txState = SMS_FAILED;
+ m_state = SMS_CMD_PROCESSED;
+ }
+ else if(!strcmp(line, "none"))
+ {
+ m_txState = SMS_NONE;
+ m_state = SMS_CMD_PROCESSED;
+ }
+ else if(!strcmp(line, "pending"))
+ {
+ m_txState = SMS_PENDING;
+ m_state = SMS_CMD_PROCESSED;
+ }
+ }
+ else if(m_state == SMS_GET_CMD_SENT)
+ {
+ DBG("Header: %s", line);
+
+ if(m_msisdn[0]=='\0')
+ {
+ sscanf(line, "From: %16s", m_msisdn);
+ }
+
+ m_headersToRead--;
+
+ if(m_headersToRead==0) //End of headers
+ {
+ if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
+ {
+ m_state = SMS_GET_HDR_RECEIVED;
+ }
+ else
+ {
+ m_state = SMS_IDLE; //Error, signal it
+ }
+ }
+ }
+ else if(m_state == SMS_GET_HDR_RECEIVED)
+ {
+ DBG("Message: %s", line);
+ size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
+ std::memcpy( m_msg, line, cpyLen );
+ m_msg[cpyLen] = '\0';
+ m_state = SMS_CMD_PROCESSED;
+ }
+ else if(m_state == SMS_GET_COUNT_CMD_SENT)
+ {
+ DBG("Inbox: %s", line);
+ int index;
+ size_t count;
+ if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
+ {
+ if((index > 0) && (index <=4))
+ {
+ m_msgInListsCount[index-1] = count;
+ }
+ if(index == 4)
+ {
+ m_state = SMS_CMD_PROCESSED;
+ }
+ }
+ }
+ return OK;
+}
+
+/*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+ return OK;
+}
+
+
+int CDMASMSInterface::updateInbox()
+{
+ //Get number of unread/read messages
+
+ DBG("Updating inbox");
+ m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
+
+ //Get counts
+ m_state = SMS_GET_COUNT_CMD_SENT;
+ int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ WARN("AT!CNTSMS returned %d", ret);
+ m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
+ m_state = SMS_IDLE;
+ return NET_PROTOCOL;
+ }
+
+ return OK;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h
new file mode 100644
index 0000000000..6aa4557c36
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h
@@ -0,0 +1,90 @@
+/* SMSInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CDMASMSINTERFACE_H_
+#define CDMASMSINTERFACE_H_
+
+#include "SMSInterface.h"
+
+#define MAX_SM 8
+
+/** Component to use the Short Messages Service (SMS)
+ *
+ */
+class CDMASMSInterface : public ISMSInterface, protected IATCommandsProcessor
+{
+public:
+ /** Create SMSInterface instance
+ @param pIf Pointer to the ATCommandsInterface instance to use
+ */
+ CDMASMSInterface(ATCommandsInterface* pIf);
+
+ /** Initialize interface
+ Configure SMS commands & register for SMS-related unsolicited result codes
+ */
+ virtual int init();
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int send(const char* number, const char* message);
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int get(char* number, char* message, size_t maxLength);
+
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getCount(size_t* pCount);
+
+protected:
+ //IATCommandsProcessor
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+
+ int updateInbox(); //Update messages count in the different inboxes
+
+private:
+ ATCommandsInterface* m_pIf;
+
+ //Current message
+ char* m_msg;
+ size_t m_maxMsgLength;
+ char* m_msisdn;
+
+ //Messages list
+ size_t m_msgInListsCount[4]; //4 lists
+
+ size_t m_headersToRead;
+
+ enum { SMS_NONE, SMS_SENT, SMS_PENDING, SMS_FAILED } m_txState;
+ enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_TX_STATUS_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_CMD_PROCESSED } m_state;
+};
+
+#endif /* CDMASMSINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp
new file mode 100644
index 0000000000..2ed50ad126
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp
@@ -0,0 +1,423 @@
+/* GSMSMSInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 2
+#ifndef __MODULE__
+#define __MODULE__ "GSMSMSInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "GSMSMSInterface.h"
+
+#include <cstdio>
+#include <cstring>
+
+#define DEFAULT_TIMEOUT 10000
+
+GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
+{
+ m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
+}
+
+int GSMSMSInterface::init()
+{
+ m_msgRefListCount = 0;
+ m_needsUpdate = true;
+ m_state = SMS_IDLE;
+
+ DBG("Set format");
+ //Set Text mode format
+ int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
+ if(ret != OK)
+ {
+ return NET_PROTOCOL;
+ }
+
+ DBG("Setup new messages indication");
+ //Setup new messages indication
+ ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
+ if(ret != OK)
+ {
+ return NET_PROTOCOL;
+ }
+
+ DBG("Try to fetch inbox");
+ m_inboxMtx.lock();
+ if( m_needsUpdate )
+ {
+ ret = updateInbox(); //Fetch existing messages references
+ if(ret)
+ {
+ m_inboxMtx.unlock();
+ return NET_PROTOCOL;
+ }
+ }
+ m_inboxMtx.unlock();
+
+ DBG("Initialization done");
+ return OK;
+}
+
+int GSMSMSInterface::send(const char* number, const char* message)
+{
+ if( strlen(number) > 16 )
+ {
+ return NET_INVALID; //Number too long to match 3GPP spec
+ }
+
+ int ret;
+
+ //Prepare infos
+ m_state = SMS_SEND_CMD_SENT;
+ m_msg = (char*) message;
+
+ DBG("Send SM");
+ //Send command
+ char cmd[32];
+ std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
+ ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+
+ if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
+ {
+ WARN("ret %d, state %d", ret, m_state);
+ m_state = SMS_IDLE;
+ return NET_PROTOCOL;
+ }
+
+ DBG("SM sent");
+ m_state = SMS_IDLE;
+ return OK;
+}
+
+
+int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
+{
+ if( maxLength < 1 )
+ {
+ return NET_INVALID; //Buffer too short
+ }
+
+ int ret;
+
+ DBG("Get next message");
+ m_inboxMtx.lock();
+ if( ((m_msgRefListCount == 0) && m_needsUpdate) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
+ {
+ DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
+ ret = updateInbox();
+
+ if (ret)
+ {
+ m_inboxMtx.unlock();
+ return ret;
+ }
+ }
+
+ DBG("%d messages to read", m_msgRefListCount);
+
+ if(m_msgRefListCount == 0)
+ {
+ m_inboxMtx.unlock();
+ DBG("Message list count is 0, I think it's empty and returning.");
+ return NET_EMPTY; //No message to read
+ }
+
+ //Prepare infos
+ m_state = SMS_GET_CMD_SENT;
+ m_msisdn = (char*) number;
+ m_msg = (char*) message;
+ m_maxMsgLength = maxLength;
+
+ DBG("Get SMS");
+ //List command
+ char cmd[32];
+ std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
+ ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ WARN("AT+CMGR returned %d", ret);
+ m_state = SMS_IDLE;
+ m_inboxMtx.unlock();
+ return NET_PROTOCOL;
+ }
+
+ if (m_state != SMS_CMD_PROCESSED)
+ {
+ WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
+ }
+
+ DBG("Deleting message from index number: %d", m_msgRefList[0] );
+ //Delete message from outbox
+ std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
+ ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
+ if(ret != OK)
+ {
+ ERR("Could not delete message");
+ }
+ //Remove message from list
+ std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
+ m_msgRefListCount--;
+
+ if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
+ {
+ DBG("Last message index is unknown, will need to be updated");
+ m_msgRefList[MAX_SM - 1] = -1;
+ }
+
+ DBG("%d messages to read", m_msgRefListCount);
+
+ if (m_state != SMS_CMD_PROCESSED)
+ {
+ m_state = SMS_IDLE;
+ m_inboxMtx.unlock();
+ return NET_EMPTY;
+ }
+
+ m_state = SMS_IDLE;
+ m_inboxMtx.unlock();
+
+ return OK;
+}
+
+
+int GSMSMSInterface::getCount(size_t* pCount)
+{
+ int ret;
+
+ m_inboxMtx.lock();
+ if( m_needsUpdate )
+ {
+ ret = updateInbox();
+ if(ret)
+ {
+ m_inboxMtx.unlock();
+ return NET_PROTOCOL;
+ }
+ }
+
+ *pCount = m_msgRefListCount;
+ m_inboxMtx.unlock();
+
+ return OK;
+}
+
+
+/*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+ if(m_state == SMS_SEND_CMD_SENT)
+ {
+ if( std::sscanf(line, "+CMGS: %*d") == 0 )
+ {
+ DBG("SM sent");
+ m_state = SMS_CMD_PROCESSED;
+ }
+ }
+ else if(m_state == SMS_GET_CMD_SENT)
+ {
+ DBG("Header: %s", line);
+ if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
+ {
+ m_state = SMS_GET_HDR_RECEIVED;
+ }
+ }
+ else if(m_state == SMS_GET_HDR_RECEIVED)
+ {
+ DBG("Message: %s", line);
+ size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
+ std::memcpy( m_msg, line, cpyLen );
+ m_msg[cpyLen] = '\0';
+ m_state = SMS_CMD_PROCESSED;
+ }
+ else if(m_state == SMS_GET_COUNT_CMD_SENT)
+ {
+ DBG("Header: %s", line);
+ int msgRef;
+ if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages
+ {
+ m_state = SMS_GET_COUNT_HDR_RECEIVED;
+ //Add message to list
+ if(m_msgRefListCount < MAX_SM)
+ {
+ m_msgRefList[m_msgRefListCount] = msgRef;
+ }
+ m_msgRefListCount++; //Always count message
+ DBG("m_msgRefListCount=%d",m_msgRefListCount);
+ }
+ }
+ else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
+ {
+ DBG("Message (debug only): %s", line); //For debug only
+ m_state = SMS_GET_COUNT_CMD_SENT;
+ }
+ return OK;
+}
+
+/*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+ if(m_state == SMS_SEND_CMD_SENT)
+ {
+ char* crPtr = strchr(m_msg, CR);
+ if(crPtr != NULL)
+ {
+ int crPos = crPtr - m_msg;
+ //Replace m_inputBuf[crPos] with null-terminating char
+ m_msg[crPos] = '\x0';
+
+ //If there is a CR char, split message there
+
+ //Do print the message
+ int ret = pInst->sendData(m_msg);
+ if(ret)
+ {
+ return ret;
+ }
+
+ char cr[2] = {CR, '\0'};
+ ret = pInst->sendData(cr);
+ if(ret)
+ {
+ return ret;
+ }
+
+ m_msg += crPos;
+
+ if(m_msg[0] == LF)
+ {
+ m_msg++; //Discard LF char as well
+ }
+
+ return NET_MOREINFO;
+ }
+ else
+ {
+ //Do print the message
+ pInst->sendData(m_msg);
+ return OK;
+ }
+ }
+
+ return OK;
+}
+
+/*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
+{
+ DBG("AT code is %s", atCode);
+ if( strcmp("+CMTI", atCode) == 0 )
+ {
+ return true;
+ }
+
+ DBG("Not handled");
+ return false;
+}
+
+/*virtual*/ void GSMSMSInterface::onDispatchStart()
+{
+
+}
+
+/*virtual*/ void GSMSMSInterface::onDispatchStop()
+{
+
+}
+
+/*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
+{
+ return "AT+CNMI=2,1,0,0,0";
+}
+
+/*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
+{
+ return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
+}
+
+/*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
+{
+ if( strcmp("+CMTI", atCode) != 0 )
+ {
+ return; //Not supported
+ }
+
+ DBG("Unsollicited result code: %s - %s", atCode, evt);
+
+ //Get index
+ int msgRef;
+ if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) ||
+ ( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
+ {
+ DBG("Adding message to list (ref %d)", msgRef);
+ if(m_inboxMtx.trylock())
+ {
+ //Add message to list
+ if(m_msgRefListCount < MAX_SM)
+ {
+ m_msgRefList[m_msgRefListCount] = msgRef;
+ }
+ m_msgRefListCount++; //Always count message
+ m_inboxMtx.unlock();
+ }
+ else
+ {
+ WARN("Could not get lock");
+ m_needsUpdate = true;
+ }
+ }
+}
+
+int GSMSMSInterface::updateInbox()
+{
+ //Get memory indexes of unread messages
+
+ DBG("Updating inbox");
+ m_msgRefListCount = 0; //Reset list
+ m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
+
+ //First list the "REC READ" messages that were not processed in the previous session
+ m_state = SMS_GET_COUNT_CMD_SENT;
+ int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ WARN("AT+CMGL returned %d", ret);
+ m_state = SMS_IDLE;
+ m_msgRefListCount = 0; //List could be invalid
+ m_needsUpdate = true;
+ return NET_PROTOCOL;
+ }
+
+ //Now list the "REC UNREAD" messages that were received by the modem since
+ m_state = SMS_GET_COUNT_CMD_SENT;
+ ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ WARN("AT+CMGL returned %d", ret);
+ m_state = SMS_IDLE;
+ m_msgRefListCount = 0; //List could be invalid
+ m_needsUpdate = true;
+ return NET_PROTOCOL;
+ }
+
+ DBG("%d incoming messages in inbox", m_msgRefListCount);
+
+ m_state = SMS_IDLE;
+
+ return OK;
+}
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h
new file mode 100644
index 0000000000..446a73e518
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h
@@ -0,0 +1,97 @@
+/* SMSInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GSMSMSINTERFACE_H_
+#define GSMSMSINTERFACE_H_
+
+#include "SMSInterface.h"
+
+/** Component to use the Short Messages Service (SMS)
+ *
+ */
+class GSMSMSInterface : public ISMSInterface, protected IATCommandsProcessor, IATEventsHandler
+{
+public:
+ /** Create SMSInterface instance
+ @param pIf Pointer to the ATCommandsInterface instance to use
+ */
+ GSMSMSInterface(ATCommandsInterface* pIf);
+
+ /** Initialize interface
+ Configure SMS commands & register for SMS-related unsolicited result codes
+ */
+ virtual int init();
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int send(const char* number, const char* message);
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int get(char* number, char* message, size_t maxLength);
+
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getCount(size_t* pCount);
+
+protected:
+ //IATCommandsProcessor
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+
+ //IATEventsHandler
+ virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
+ virtual void onDispatchStart();
+ virtual void onDispatchStop();
+ virtual char* getEventsEnableCommand();
+ virtual char* getEventsDisableCommand();
+ virtual void onEvent(const char* atCode, const char* evt);
+
+ //Updates messages count/references
+ int updateInbox();
+
+private:
+ ATCommandsInterface* m_pIf;
+
+ //Current message
+ char* m_msg;
+ size_t m_maxMsgLength;
+ char* m_msisdn;
+
+ //Messages list
+ int m_msgRefList[MAX_SM];
+ size_t m_msgRefListCount;
+ bool m_needsUpdate;
+ Mutex m_inboxMtx; //To protect concurrent accesses btw the user's thread and the AT thread
+
+ enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_GET_COUNT_HDR_RECEIVED, SMS_CMD_PROCESSED } m_state;
+};
+
+#endif /* GSMSMSINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h
new file mode 100644
index 0000000000..df226709d1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h
@@ -0,0 +1,67 @@
+/* SMSInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ISMSINTERFACE_H_
+#define ISMSINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "rtos.h"
+
+#include "at/ATCommandsInterface.h"
+
+#define MAX_SM 8
+
+/** Component to use the Short Messages Service (SMS)
+ *
+ */
+class ISMSInterface
+{
+public:
+ /** Initialize interface
+ Configure SMS commands & register for SMS-related unsolicited result codes
+ */
+ virtual int init() = 0;
+
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int send(const char* number, const char* message) = 0;
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int get(char* number, char* message, size_t maxLength) = 0;
+
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getCount(size_t* pCount) = 0;
+};
+
+#endif /* ISMSINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp
new file mode 100644
index 0000000000..4815babd6a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp
@@ -0,0 +1,196 @@
+/* USSDInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "USSDInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "USSDInterface.h"
+
+#include <cstdio>
+
+#define DEFAULT_TIMEOUT 10000
+#define USSD_TIMEOUT 15000
+
+USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0)
+{
+ m_responseSphre.wait(0); //Take ownership of the semaphore
+ m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
+}
+
+int USSDInterface::init()
+{
+ DBG("Initialization done");
+ return OK;
+}
+
+int USSDInterface::send(const char* command, char* result, size_t maxLength)
+{
+ if (strlen(command) > 20) //Prevent buffer overflow
+ {
+ return NET_TOOSMALL;
+ }
+
+ m_responseMtx.lock();
+ m_result = result;
+ m_maxResultLength = maxLength;
+ m_responseMtx.unlock();
+
+ m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded
+
+ DBG("Send USSD command & register for unsolicited result codes");
+ //Send USSD command to the network
+ char cmd[32];
+ std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command);
+ int ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+ if( ret != OK )
+ {
+ return NET_PROTOCOL;
+ }
+
+ //Did we already get a response (3GPP rev < 6) ?
+
+ //Now wait for response
+ int res = m_responseSphre.wait(USSD_TIMEOUT);
+
+ //Reset data
+ m_responseMtx.lock();
+ m_result = NULL;
+ m_maxResultLength = 0;
+ m_responseMtx.unlock();
+
+ if(res <= 0)
+ {
+ DBG("No result received");
+ ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command
+ if( ret != OK )
+ {
+ return NET_PROTOCOL;
+ }
+ return NET_TIMEOUT;
+ }
+
+ DBG("Result received: %s", result);
+
+ return OK;
+}
+
+/*virtual*/ int USSDInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+ const char* pSemicol = strchr(line, ':');
+ if( ( (pSemicol - line) != strlen("+CUSD") ) || ( memcmp(line, "+CUSD", strlen("+CUSD")) != 0) )
+ {
+ WARN("Unknown code");
+ return OK;
+ }
+
+ const char* pData = NULL;
+ if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
+ {
+ pData = pSemicol + 1;
+ if(pData[0]==' ')
+ {
+ pData++; //Suppress whitespace
+ }
+ processResult(pData);
+ }
+ return OK;
+}
+
+/*virtual*/ int USSDInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+ return OK;
+}
+
+/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
+{
+ DBG("AT code is %s", atCode);
+ if( strcmp("+CUSD", atCode) == 0 )
+ {
+ return true;
+ }
+
+ DBG("Not handled");
+ return false;
+}
+
+/*virtual*/ void USSDInterface::onDispatchStart()
+{
+
+
+}
+
+/*virtual*/ void USSDInterface::onDispatchStop()
+{
+
+}
+
+/*virtual*/ char* USSDInterface::getEventsEnableCommand()
+{
+ return NULL; //No need to disable events here
+}
+
+/*virtual*/ char* USSDInterface::getEventsDisableCommand()
+{
+ return NULL; //No need to re-enable events here
+}
+
+/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt)
+{
+ if( strcmp("+CUSD", atCode) != 0 )
+ {
+ WARN("Wrong AT Code");
+ return; //Not supported
+ }
+
+ processResult(evt);
+}
+
+void USSDInterface::processResult(const char* data)
+{
+ char* pStart = (char*) strchr(data,'\"');
+ if(pStart==NULL)
+ {
+ WARN("Could not find opening quote");
+ return; //Invalid/incomplete response
+ }
+ pStart++; //Point to first char of response
+ char* pEnd = (char*) strchr(pStart,'\"');
+ if(pEnd==NULL)
+ {
+ WARN("Could not find closing quote");
+ return; //Invalid/incomplete response
+ }
+ m_responseMtx.lock();
+ if(m_maxResultLength == 0) //No pending command
+ {
+ WARN("No pending command");
+ m_responseMtx.unlock();
+ return;
+ }
+ size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 );
+ memcpy((void*)m_result, pStart, cpyLen);
+ m_result[cpyLen] = '\0';
+ DBG("Got USSD response: %s", m_result);
+ m_responseMtx.unlock();
+ m_responseSphre.release(); //Signal user thread that response is ready
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h
new file mode 100644
index 0000000000..47984d1d91
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h
@@ -0,0 +1,80 @@
+/* USSDInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef USSDINTERFACE_H_
+#define USSDINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "rtos.h"
+
+#include "at/ATCommandsInterface.h"
+
+/** Component to send/receive Unstructured Supplementary Service Data (USSD)
+ *
+ */
+class USSDInterface : protected IATCommandsProcessor, IATEventsHandler
+{
+public:
+ /** Create USSDInterface instance
+ @param pIf Pointer to the ATCommandsInterface instance to use
+ */
+ USSDInterface(ATCommandsInterface* pIf);
+
+ /** Initialize interface
+ Configure USSD commands & register for USSD-related unsolicited result codes
+ */
+ int init();
+
+ /** Send a USSD command & wait for its result
+ @param command The command to send
+ @param result Buffer in which to store the result
+ @param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ int send(const char* command, char* result, size_t maxLength);
+
+protected:
+ //IATCommandsProcessor, needed for implementations of 3GGP standard < r06
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+
+ //IATEventsHandler, needed for implementations of 3GGP standard >= r06
+ virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
+ virtual void onDispatchStart();
+ virtual void onDispatchStop();
+ virtual char* getEventsEnableCommand();
+ virtual char* getEventsDisableCommand();
+ virtual void onEvent(const char* atCode, const char* evt);
+
+private:
+ void processResult(const char* data);
+
+ ATCommandsInterface* m_pIf;
+ Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread
+ Semaphore m_responseSphre;
+
+ //Result
+ volatile char* m_result;
+ volatile size_t m_maxResultLength;
+
+};
+
+
+#endif /* USSDINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.cpp
new file mode 100644
index 0000000000..2a05c1c2c4
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.cpp
@@ -0,0 +1,253 @@
+/* IOSerialStream.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "IOSerialStream.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <cstring>
+
+#include "IOSerialStream.h"
+
+#define UART_X ((LPC_UART_TypeDef *)(UART_1))
+
+IOSerialStream::IOSerialStream(mbed::RawSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
+m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
+{
+ m_availableSphre.wait();
+ m_spaceSphre.wait();
+ //Attach interrupts
+ m_serial.attach(this, &IOSerialStream::readable, mbed::SerialBase::RxIrq);
+ m_serial.attach(this, &IOSerialStream::writeable, mbed::SerialBase::TxIrq);
+}
+
+/*virtual*/ IOSerialStream::~IOSerialStream()
+{
+ m_serial.attach(NULL, mbed::SerialBase::RxIrq);
+ m_serial.attach(NULL, mbed::SerialBase::TxIrq);
+}
+
+//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
+{
+ DBG("Trying to read at most %d chars", maxLength);
+ int ret = waitAvailable(timeout);
+ if(ret)
+ {
+ WARN("Error %d while waiting for incoming data", ret);
+ return ret;
+ }
+ int readLen = MIN( available(), maxLength );
+ *pLength = readLen;
+ setupReadableISR(false);
+ while(readLen--)
+ {
+ m_inBuf.dequeue(buf);
+ buf++;
+ }
+ setupReadableISR(true);
+ DBG("Read %d chars successfully", *pLength);
+ return OK;
+}
+
+/*virtual*/ size_t IOSerialStream::available()
+{
+ setupReadableISR(false); //m_inBuf.available() is not reentrant
+ size_t len = m_inBuf.available();
+ setupReadableISR(true);
+ return len;
+}
+
+/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
+{
+ int ret;
+ if(available()) //Is data already available?
+ {
+ m_availableSphre.wait(0); //Clear the queue as data is available
+ return OK;
+ }
+
+ DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
+ ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
+ if(ret <= 0)
+ {
+ DBG("Timeout");
+ return NET_TIMEOUT;
+ }
+ if(!available()) //Even if abort has been called, return that data is available
+ {
+ DBG("Aborted");
+ return NET_INTERRUPTED;
+ }
+ DBG("Finished waiting");
+ m_availableSphre.wait(0); //Clear the queue as data is available
+ return OK;
+}
+
+/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation
+{
+ if( !available() ) //If there is data pending, no need to abort
+ {
+ m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
+ }
+ else
+ {
+ DBG("Serial is readable"); ;
+ }
+ return OK;
+}
+
+void IOSerialStream::setupReadableISR(bool en)
+{
+ if(en)
+ {
+ UART_X->IER |= 1 << 0;
+ }
+ else
+ {
+ UART_X->IER &= ~(1 << 0);
+ }
+}
+
+void IOSerialStream::readable() //Callback from m_serial when new data is available
+{
+ do
+ {
+ m_inBuf.queue(m_serial.getc());
+ } while(m_serial.readable());
+ m_availableSphre.release(); //Force exiting the waiting state
+}
+
+//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
+{
+ DBG("Trying to write %d chars", length);
+ int ret = waitSpace(timeout);
+ if(ret)
+ {
+ WARN("Error %d while waiting for space", ret);
+ return ret;
+ }
+ DBG("Writing %d chars", length);
+ setupWriteableISR(false);
+ while(length)
+ {
+ m_outBuf.queue(*buf);
+ buf++;
+ length--;
+ if(length && !space())
+ {
+ DBG("Waiting to write remaining %d chars", length);
+ setupWriteableISR(true);
+ ret = waitSpace(timeout);
+ if(ret)
+ {
+ WARN("Error %d while waiting for space", ret);
+ return ret;
+ }
+ setupWriteableISR(false);
+ }
+ }
+ //If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
+ if( m_outBuf.available() && m_serialTxFifoEmpty )
+ {
+ m_serialTxFifoEmpty = false;
+ uint8_t c;
+ m_outBuf.dequeue(&c);
+ m_serial.putc((char)c);
+ }
+ setupWriteableISR(true);
+ DBG("Write successful");
+ return OK;
+}
+
+/*virtual*/ size_t IOSerialStream::space()
+{
+ setupWriteableISR(false); //m_outBuf.available() is not reentrant
+ size_t len = CIRCBUF_SIZE - m_outBuf.available();
+ setupWriteableISR(true);
+ return len;
+}
+
+/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
+{
+ int ret;
+ if(space()) //Is still space already left?
+ {
+ m_spaceSphre.wait(0); //Clear the queue as space is available
+ return OK;
+ }
+
+ DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
+ ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
+ if(ret <= 0)
+ {
+ DBG("Timeout");
+ return NET_TIMEOUT;
+ }
+ if(!space()) //Even if abort has been called, return that space is available
+ {
+ DBG("Aborted");
+ return NET_INTERRUPTED;
+ }
+ m_spaceSphre.wait(0); //Clear the queue as space is available
+ return OK;
+}
+
+/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
+{
+ if( !space() ) //If there is space left, no need to abort
+ {
+ m_spaceSphre.release(); //Force exiting the waiting state
+ }
+ return OK;
+}
+
+void IOSerialStream::setupWriteableISR(bool en)
+{
+ if(en)
+ {
+ UART_X->IER |= 1 << 1;
+ }
+ else
+ {
+ UART_X->IER &= ~(1 << 1);
+ }
+}
+
+void IOSerialStream::writeable() //Callback from m_serial when new space is available
+{
+ if(m_outBuf.isEmpty())
+ {
+ m_serialTxFifoEmpty = true;
+ }
+ else
+ {
+ while(m_serial.writeable() && !m_outBuf.isEmpty())
+ {
+ uint8_t c;
+ m_outBuf.dequeue(&c);
+ m_serial.putc((char)c);
+ }
+ }
+ m_spaceSphre.release(); //Force exiting the waiting state
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.h
new file mode 100644
index 0000000000..7e9ef89d05
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/io/IOSerialStream.h
@@ -0,0 +1,72 @@
+/* IOSerialStream.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef IOSERIALSTREAM_H_
+#define IOSERIALSTREAM_H_
+
+#include "core/fwk.h"
+
+#include "RawSerial.h"
+
+#include "rtos.h"
+#include "core/MtxCircBuffer.h"
+
+/** Input Serial Stream for physical serial interfaces (UART...)
+This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
+*/
+class IOSerialStream : public IOStream
+{
+public:
+ enum { CIRCBUF_SIZE = 255 };
+ IOSerialStream(mbed::RawSerial& serial);
+ /*virtual*/ ~IOSerialStream();
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
+ virtual size_t available();
+ virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
+ virtual int abortRead(); //Abort current reading (or waiting) operation
+
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
+ virtual size_t space();
+ virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
+ virtual int abortWrite(); //Abort current writing (or waiting) operation
+
+private:
+
+ mbed::RawSerial& m_serial;
+ volatile bool m_serialTxFifoEmpty;
+
+ void setupReadableISR(bool en);
+ void readable(); //Callback from m_serial when new data is available
+
+ Semaphore m_availableSphre; //Used for signalling
+
+ void setupWriteableISR(bool en);
+ void writeable(); //Callback from m_serial when new space is available
+
+ Semaphore m_spaceSphre; //Used for signalling
+
+ MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
+ MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
+
+};
+
+#endif /* IOSERIALSTREAM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.cpp
new file mode 100644
index 0000000000..81349ce884
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.cpp
@@ -0,0 +1,236 @@
+/* USBSerialStream.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "USBSerialStream.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <cstring>
+
+#include "USBSerialStream.h"
+
+
+USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
+m_availableSphre(1), m_spaceSphre(1), m_inBuf()
+{
+ m_availableSphre.wait();
+ m_spaceSphre.wait();
+ //Attach interrupts
+ m_serial.attach(this);
+}
+
+/*virtual*/ USBSerialStream::~USBSerialStream()
+{
+ m_serial.attach(NULL);
+}
+
+//0 for non-blocking (returns immediately), -1 for infinite blocking
+/*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
+{
+ DBG("Trying to read at most %d chars", maxLength);
+ int ret = waitAvailable(timeout);
+ if(ret)
+ {
+ WARN("Error %d while waiting for incoming data", ret);
+ return ret;
+ }
+ int a = available(); //Prevent macro issues
+ int readLen = MIN( a, maxLength );
+ *pLength = readLen;
+
+ setupReadableISR(false);
+ while(readLen--)
+ {
+ m_inBuf.dequeue(buf);
+ buf++;
+ }
+ setupReadableISR(true);
+ DBG("Read %d chars successfully", *pLength);
+ return OK;
+}
+
+/*virtual*/ size_t USBSerialStream::available()
+{
+ setupReadableISR(false); //m_inBuf.available() is not reentrant
+ size_t len = m_inBuf.available();
+ setupReadableISR(true);
+ return len;
+}
+
+/*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
+{
+ int ret;
+ if(available()) //Is data already available?
+ {
+ while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
+ return OK;
+ }
+
+ DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
+ ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
+ if(ret <= 0)
+ {
+ DBG("Timeout");
+ return NET_TIMEOUT;
+ }
+ if(!m_inBuf.available()) //Even if abort has been called, return that data is available
+ {
+ DBG("Aborted");
+ return NET_INTERRUPTED;
+ }
+ DBG("Finished waiting");
+ while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
+ return OK;
+}
+
+/*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
+{
+ if( /*!available()*/true ) //If there is data pending, no need to abort
+ {
+ m_availableSphre.release(); //Force exiting the waiting state
+ }
+ else
+ {
+ DBG("Serial is readable"); ;
+ }
+ return OK;
+}
+
+void USBSerialStream::setupReadableISR(bool en)
+{
+ m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
+}
+
+void USBSerialStream::readable() //Callback from m_serial when new data is available
+{
+ while(m_serial.readable())
+ {
+ m_inBuf.queue(m_serial.getc());
+ }
+ m_serial.readPacket(); //Start read of next packet
+ m_availableSphre.release(); //Force exiting the waiting state
+}
+
+//0 for non-blocking (returns immediately), -1 for infinite blocking
+/*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
+{
+ DBG("Trying to write %d chars", length);
+ do
+ {
+ int ret = waitSpace(timeout);
+ if(ret)
+ {
+ WARN("Error %d while waiting for space", ret);
+ return ret;
+ }
+ int s = space(); //Prevent macro issues
+ int writeLen = MIN( s, length );
+ DBG("Writing %d chars", writeLen);
+ setupWriteableISR(false);
+ while(writeLen)
+ {
+ m_outBuf.queue(*buf);
+ buf++;
+ length--;
+ writeLen--;
+ }
+ //If m_serial tx fifo is empty we need to start the packet write
+ if( m_outBuf.available() && m_serialTxFifoEmpty )
+ {
+ writeable();
+ }
+ setupWriteableISR(true);
+ } while(length);
+
+ DBG("Write successful");
+ return OK;
+}
+
+/*virtual*/ size_t USBSerialStream::space()
+{
+ setupWriteableISR(false); //m_outBuf.available() is not reentrant
+ size_t len = CIRCBUF_SIZE - m_outBuf.available();
+ setupWriteableISR(true);
+ return len;
+}
+
+/*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
+{
+ int ret;
+ if(space()) //Is still space already left?
+ {
+ while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
+ return OK;
+ }
+
+ DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
+ ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
+ if(ret <= 0)
+ {
+ DBG("Timeout");
+ return NET_TIMEOUT;
+ }
+ if(!space()) //Even if abort has been called, return that space is available
+ {
+ DBG("Aborted");
+ return NET_INTERRUPTED;
+ }
+ while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
+ return OK;
+}
+
+/*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
+{
+ if( !space() ) //If there is space left, no need to abort
+ {
+ m_spaceSphre.release(); //Force exiting the waiting state
+ }
+ return OK;
+}
+
+void USBSerialStream::setupWriteableISR(bool en)
+{
+ m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
+}
+
+void USBSerialStream::writeable() //Callback from m_serial when new space is available
+{
+ if(m_outBuf.isEmpty())
+ {
+ m_serialTxFifoEmpty = true;
+ }
+ else
+ {
+ m_serialTxFifoEmpty = false;
+ while(m_serial.writeable() && !m_outBuf.isEmpty())
+ {
+ uint8_t c;
+ m_outBuf.dequeue(&c);
+ m_serial.putc((char)c);
+ }
+ m_serial.writePacket(); //Start packet write
+ }
+ if(!m_outBuf.isFull())
+ {
+ m_spaceSphre.release(); //Force exiting the waiting state
+ }
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.h
new file mode 100644
index 0000000000..97cf3c6860
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularUSBModem/serial/usb/USBSerialStream.h
@@ -0,0 +1,74 @@
+/* USBSerialStream.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef USBSERIALSTREAM_H_
+#define USBSERIALSTREAM_H_
+
+
+#include "core/fwk.h"
+
+#include "USBHost3GModule/IUSBHostSerial.h"
+#include "USBHost3GModule/IUSBHostSerialListener.h"
+
+#include "rtos.h"
+#include "core/MtxCircBuffer.h"
+
+/* Input Serial Stream for USB virtual serial ports interfaces
+This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
+*/
+
+class USBSerialStream : public IOStream, IUSBHostSerialListener
+{
+public:
+ enum { CIRCBUF_SIZE = 127 };
+ USBSerialStream(IUSBHostSerial& serial);
+ /*virtual*/ ~USBSerialStream();
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
+ virtual size_t available();
+ virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
+ virtual int abortRead(); //Abort current reading (or waiting) operation
+
+
+ //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+ virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
+ virtual size_t space();
+ virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
+ virtual int abortWrite(); //Abort current writing (or waiting) operation
+
+private:
+ IUSBHostSerial& m_serial;
+ volatile bool m_serialTxFifoEmpty;
+
+ void setupReadableISR(bool en);
+ virtual void readable(); //Callback from m_serial when new data is available
+
+ Semaphore m_availableSphre; //Used for signalling
+
+ void setupWriteableISR(bool en);
+ virtual void writeable(); //Callback from m_serial when new space is available
+
+ Semaphore m_spaceSphre; //Used for signalling
+
+ MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
+ MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
+};
+
+#endif /* USBSERIALSTREAM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.cpp
new file mode 100644
index 0000000000..6464afc984
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.cpp
@@ -0,0 +1,114 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#define __DEBUG__ 4
+#ifndef __MODULE__
+#define __MODULE__ "UbloxCDMAModemInitializer.cpp"
+#endif
+
+#include "core/dbg.h"
+
+#include <stdint.h>
+
+#include "UbloxCDMAModemInitializer.h"
+
+UbloxCDMAModemInitializer::UbloxCDMAModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
+{
+}
+
+uint16_t UbloxCDMAModemInitializer::getMSDVid()
+{
+ return 0x05C6;
+}
+uint16_t UbloxCDMAModemInitializer::getMSDPid()
+{
+ return 0x0000; //No MSD mode (presumably)
+}
+
+uint16_t UbloxCDMAModemInitializer::getSerialVid()
+{
+ return 0x05C6;
+}
+uint16_t UbloxCDMAModemInitializer::getSerialPid()
+{
+ return 0x9004;
+}
+
+bool UbloxCDMAModemInitializer::switchMode(USBDeviceConnected* pDev)
+{
+ return true;
+}
+
+int UbloxCDMAModemInitializer::getSerialPortCount()
+{
+ return 2;
+}
+
+/*virtual*/ void UbloxCDMAModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
+{
+ m_currentSerialIntf = 0;
+ m_currentEndpoint = 0;
+}
+
+/*virtual*/ bool UbloxCDMAModemInitializer::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
+
+ if( intf_class == 0xFF ) {
+ if( m_currentSerialIntf == 0 || m_currentSerialIntf == 1) {
+ m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
+ return true;
+ }
+ m_currentSerialIntf++;
+ }
+
+ return false;
+}
+
+/*virtual*/ bool UbloxCDMAModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d Current %d", intf_nb, type, dir, m_currentEndpoint);
+ if(type == BULK_ENDPOINT) {
+ if( intf_nb == 1 || intf_nb == 0) {
+ m_currentEndpoint++;
+ return true;
+ } else {
+ m_currentEndpoint++;
+ }
+ }
+
+ /*
+ if(type == INTERRUPT_ENDPOINT) {
+ if( intf_nb == 1) {
+ m_currentEndpoint++;
+ return true;
+ } else {
+ m_currentEndpoint++;
+ }
+ }
+ */
+
+ return false;
+}
+
+
+/*virtual*/ int UbloxCDMAModemInitializer::getType()
+{
+ return WAN_DONGLE_TYPE_UBLOX_LISAC200;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.h
new file mode 100644
index 0000000000..4836680da2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxCDMAModemInitializer.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef UBLOXCDMAMODEMINITIALIZER_H
+#define UBLOXCDMAMODEMINITIALIZER_H
+
+#include <stdint.h>
+
+#include "WANDongleInitializer.h"
+#include "USBHost.h"
+#include "IUSBEnumerator.h"
+
+enum
+{
+ WAN_DONGLE_TYPE_UBLOX_LISAC200 = 0xC200,
+};
+
+class UbloxCDMAModemInitializer : public WANDongleInitializer
+{
+public:
+ UbloxCDMAModemInitializer(USBHost* pHost);
+
+ virtual uint16_t getMSDVid();
+ virtual uint16_t getMSDPid();
+
+ virtual uint16_t getSerialVid();
+ virtual uint16_t getSerialPid();
+
+ virtual bool switchMode(USBDeviceConnected* pDev);
+
+ virtual int getSerialPortCount();
+
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+ virtual int getType();
+
+private:
+
+ int m_currentSerialIntf;
+ int m_currentEndpoint;
+};
+
+#endif
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.cpp
new file mode 100644
index 0000000000..e28632593a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.cpp
@@ -0,0 +1,131 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "UbloxGSMModemInitializer.h"
+#include "core/dbg.h"
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "UbloxGSMModemInitializer.cpp"
+#endif
+
+//-----------------------------------------------------------------------
+// mamm, u-blox Modem
+//-----------------------------------------------------------------------
+
+UbloxGSMModemInitializer::UbloxGSMModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
+{
+
+}
+
+uint16_t UbloxGSMModemInitializer::getMSDVid() { return 0x1546; }
+uint16_t UbloxGSMModemInitializer::getMSDPid() { return 0x0000; }
+
+uint16_t UbloxGSMModemInitializer::getSerialVid() { return 0x1546; }
+uint16_t UbloxGSMModemInitializer::getSerialPid() { return 0x1102; }
+
+bool UbloxGSMModemInitializer::switchMode(USBDeviceConnected* pDev)
+{
+ for (int i = 0; i < pDev->getNbIntf(); i++)
+ {
+ if (pDev->getInterface(i)->intf_class == MSD_CLASS)
+ {
+ USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
+ if ( pEp != NULL )
+ {
+ ERR("MSD descriptor found on device %p, intf %d", (void *)pDev, i);
+ }
+ }
+ }
+ return false;
+}
+
+#define UBX_SERIALCOUNT 7
+
+int UbloxGSMModemInitializer::getSerialPortCount()
+{
+ return UBX_SERIALCOUNT;
+}
+
+/*virtual*/ void UbloxGSMModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
+{
+ if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
+ {
+ m_hasSwitched = true;
+ m_currentSerialIntf = 0;
+ m_endpointsToFetch = UBX_SERIALCOUNT*2;
+ }
+ else
+ {
+ m_hasSwitched = false;
+ m_endpointsToFetch = 1;
+ }
+}
+
+/*virtual*/ bool UbloxGSMModemInitializer::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if( m_hasSwitched )
+ {
+ DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
+ if( intf_class == 0x0A )
+ {
+ if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
+ {
+ m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
+ return true;
+ }
+ m_currentSerialIntf++;
+ }
+ }
+ else
+ {
+ if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*virtual*/ bool UbloxGSMModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if( m_hasSwitched )
+ {
+ DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
+ if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
+ {
+ m_endpointsToFetch--;
+ return true;
+ }
+ }
+ else
+ {
+ if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
+ {
+ m_endpointsToFetch--;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*virtual*/ int UbloxGSMModemInitializer::getType()
+{
+ return WAN_DONGLE_TYPE_UBLOX_LISAU200;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.h
new file mode 100644
index 0000000000..383c443eb3
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxGSMModemInitializer.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef UBLOXGSMMODEMINITIALIZER_H
+#define UBLOXGSNMODEMINITIALIZER_H
+
+#include "WANDongleInitializer.h"
+
+enum
+{
+ WAN_DONGLE_TYPE_UBLOX_LISAU200 = 0x0200
+};
+
+//-----------------------------------------------------------------------
+// mamm, u-blox Modem
+//-----------------------------------------------------------------------
+
+class UbloxGSMModemInitializer : public WANDongleInitializer
+{
+public:
+ UbloxGSMModemInitializer(USBHost* pHost);
+
+ virtual uint16_t getMSDVid();
+ virtual uint16_t getMSDPid();
+
+ virtual uint16_t getSerialVid();
+ virtual uint16_t getSerialPid();
+
+ virtual bool switchMode(USBDeviceConnected* pDev);
+
+ virtual int getSerialPortCount();
+
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+ virtual int getType();
+
+private:
+
+ bool m_hasSwitched;
+ int m_currentSerialIntf;
+ int m_endpointsToFetch;
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.cpp
new file mode 100644
index 0000000000..a9fec4cbf0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.cpp
@@ -0,0 +1,559 @@
+/* UbloxModem.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 3
+#ifndef __MODULE__
+#define __MODULE__ "UbloxModem.cpp"
+#endif
+
+#include "core/fwk.h"
+#include "sms/GSMSMSInterface.h"
+#include "sms/CDMASMSInterface.h"
+
+#include "UbloxModem.h"
+
+UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
+ m_at(atStream), // Construct ATCommandsInterface with the AT serial channel
+ m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
+ m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
+ m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
+ m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
+ m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel
+ m_ipInit(false), // PPIPInterface connection is initially down
+ m_smsInit(false), // SMSInterface starts un-initialised
+ m_ussdInit(false), // USSDInterface starts un-initialised
+ m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
+ m_atOpen(false), // ATCommandsInterface starts in a closed state
+ m_onePort(pppStream == NULL),
+ m_type(UNKNOWN)
+{
+}
+
+
+genericAtProcessor::genericAtProcessor()
+{
+ i = 0;
+ str[0] = '\0';
+}
+
+const char* genericAtProcessor::getResponse(void)
+{
+ return str;
+}
+
+int genericAtProcessor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+ int l = strlen(line);
+ if (i + l + 2 > sizeof(str))
+ return NET_OVERFLOW;
+ if (i) str[i++] = ',';
+ strcat(&str[i], line);
+ i += l;
+ return OK;
+}
+
+int genericAtProcessor::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+ return OK;
+}
+
+class CREGProcessor : public IATCommandsProcessor
+{
+public:
+ CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
+ {
+ m_gsm = gsm;
+ }
+ enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
+ REGISTERING_STATUS getStatus()
+ {
+ return status;
+ }
+ const char* getAtCommand()
+ {
+ return m_gsm ? "AT+CREG?" : "AT+CSS?";
+ }
+private:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+ {
+ int r;
+ if (m_gsm)
+ {
+ if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
+ {
+ status = (r == 1 || r == 5) ? STATUS_OK :
+ (r == 0 || r == 2) ? STATUS_REGISTERING :
+ // (r == 3) ? STATUS_FAILED :
+ STATUS_FAILED;
+ }
+ }
+ else
+ {
+ char bc[3] = "";
+ if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
+ {
+ status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
+ }
+ }
+ return OK;
+ }
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+ {
+ return OK;
+ }
+ volatile REGISTERING_STATUS status;
+ bool m_gsm;
+};
+
+int UbloxModem::connect(const char* apn, const char* user, const char* password)
+{
+ if( !m_ipInit )
+ {
+ m_ipInit = true;
+ m_ppp.init();
+ }
+ m_ppp.setup(user, password, (m_type != LISA_C200) ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
+
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if (m_onePort)
+ {
+ m_smsInit = false; //SMS status reset
+ m_ussdInit = false; //USSD status reset
+ m_linkMonitorInit = false; //Link monitor status reset
+ }
+
+ ATCommandsInterface::ATResult result;
+
+ if(apn != NULL)
+ {
+ char cmd[48];
+ int tries = 30;
+ sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
+ do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
+ {
+ ret = m_at.executeSimple(cmd, &result);
+ DBG("Result of command: Err code=%d", ret);
+ if(ret)
+ {
+ Thread::wait(500);
+ }
+ } while(ret && --tries);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+ DBG("APN set to %s", apn);
+ }
+
+ //Connect
+ DBG("Connecting");
+ if (m_onePort)
+ {
+ m_at.close(); // Closing AT parser
+ m_atOpen = false; //Will need to be reinitialized afterwards
+ }
+
+ DBG("Connecting PPP");
+
+ ret = m_ppp.connect();
+ DBG("Result of connect: Err code=%d", ret);
+ return ret;
+}
+
+
+int UbloxModem::disconnect()
+{
+ DBG("Disconnecting from PPP");
+ int ret = m_ppp.disconnect();
+ if(ret)
+ {
+ ERR("Disconnect returned %d, still trying to disconnect", ret);
+ }
+
+ //Ugly but leave dongle time to recover
+ Thread::wait(500);
+
+ if (m_onePort)
+ {
+ //ATCommandsInterface::ATResult result;
+ DBG("Starting AT thread");
+ ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+ }
+
+ DBG("Trying to hangup");
+
+ if (m_onePort)
+ {
+ //Reinit AT parser
+ ret = m_at.init(false);
+ DBG("Result of command: Err code=%d\n", ret);
+ if(ret)
+ {
+ m_at.close(); // Closing AT parser
+ DBG("AT Parser closed, could not complete disconnection");
+ return NET_TIMEOUT;
+ }
+
+ }
+ return OK;
+}
+
+int UbloxModem::sendSM(const char* number, const char* message)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ ISMSInterface* sms;
+ if (m_type == LISA_C200) sms = &m_CdmaSms;
+ else sms = &m_GsmSms;
+ if(!m_smsInit)
+ {
+ ret = sms->init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = sms->send(number, message);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxModem::getSM(char* number, char* message, size_t maxLength)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ ISMSInterface* sms;
+ if (m_type == LISA_C200) sms = &m_CdmaSms;
+ else sms = &m_GsmSms;
+ if(!m_smsInit)
+ {
+ ret = sms->init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = sms->get(number, message, maxLength);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxModem::getSMCount(size_t* pCount)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ ISMSInterface* sms;
+ if (m_type == LISA_C200) sms = &m_CdmaSms;
+ else sms = &m_GsmSms;
+ if(!m_smsInit)
+ {
+ ret = sms->init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = sms->getCount(pCount);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+ATCommandsInterface* UbloxModem::getATCommandsInterface()
+{
+ return &m_at;
+}
+
+int UbloxModem::init()
+{
+ if(m_atOpen)
+ {
+ return OK;
+ }
+
+ DBG("Starting AT thread if needed");
+ int ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+
+ DBG("Sending initialisation commands");
+ ret = m_at.init(false);
+ if(ret)
+ {
+ return ret;
+ }
+
+
+ ATCommandsInterface::ATResult result;
+ genericAtProcessor atiProcessor;
+ ret = m_at.execute("ATI", &atiProcessor, &result);
+ if (OK != ret)
+ return ret;
+ const char* info = atiProcessor.getResponse();
+ INFO("Modem Identification [%s]", info);
+ if (strstr(info, "LISA-C200")) {
+ m_type = LISA_C200;
+ m_onePort = true; // force use of only one port
+ }
+ else if (strstr(info, "LISA-U200")) {
+ m_type = LISA_U200;
+ }
+ else if (strstr(info, "SARA-G350")) {
+ m_type = SARA_G350;
+ }
+
+ // enable the network indicator
+ if (m_type == SARA_G350) {
+ m_at.executeSimple("AT+UGPIOC=16,2", &result);
+ }
+ else if (m_type == LISA_U200) {
+ m_at.executeSimple("AT+UGPIOC=20,2", &result);
+ }
+ else if (m_type == LISA_C200) {
+ // LISA-C200 02S/22S : GPIO1 do not support network status indication
+ // m_at.executeSimple("AT+UGPIOC=20,2", &result);
+ }
+ INFO("Modem Identification [%s]", info);
+
+ CREGProcessor cregProcessor(m_type != LISA_C200);
+ //Wait for network registration
+ do
+ {
+ DBG("Waiting for network registration");
+ ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
+ {
+ Thread::wait(3000);
+ }
+ } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
+ if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
+ {
+ ERR("Registration denied");
+ return NET_AUTH;
+ }
+
+ m_atOpen = true;
+
+ return OK;
+}
+
+int UbloxModem::cleanup()
+{
+ if(m_ppp.isConnected())
+ {
+ WARN("Data connection is still open"); //Try to encourage good behaviour from the user
+ m_ppp.disconnect();
+ }
+
+ m_smsInit = false;
+ m_ussdInit = false;
+ m_linkMonitorInit = false;
+ //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
+
+ if(m_atOpen)
+ {
+ m_at.close();
+ m_atOpen = false;
+ }
+
+ return OK;
+}
+
+int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_ussdInit)
+ {
+ ret = m_ussd.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_ussdInit = true;
+ }
+
+ ret = m_ussd.send(command, result, maxLength);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_linkMonitorInit)
+ {
+ ret = m_linkMonitor.init(m_type != LISA_C200);
+ if(ret)
+ {
+ return ret;
+ }
+ m_linkMonitorInit = true;
+ }
+
+ ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxModem::getPhoneNumber(char* phoneNumber)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_linkMonitorInit)
+ {
+ ret = m_linkMonitor.init(m_type != LISA_C200);
+ if(ret)
+ {
+ return ret;
+ }
+ m_linkMonitorInit = true;
+ }
+
+ ret = m_linkMonitor.getPhoneNumber(phoneNumber);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+#include "USBHost.h"
+#include "UbloxGSMModemInitializer.h"
+#include "UbloxCDMAModemInitializer.h"
+
+UbloxUSBModem::UbloxUSBModem() :
+ UbloxModem(&m_atStream, &m_pppStream),
+ m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
+ m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
+ m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
+ m_dongleConnected(false) // Dongle is initially not ready for anything
+{
+ USBHost* host = USBHost::getHostInst();
+ m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
+ m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
+}
+
+int UbloxUSBModem::init()
+{
+ if( !m_dongleConnected )
+ {
+ m_dongleConnected = true;
+ while( !m_dongle.connected() )
+ {
+ m_dongle.tryConnect();
+ Thread::wait(10);
+ }
+ if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
+ {
+ INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
+ m_type = LISA_U200;
+ }
+ else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
+ {
+ INFO("Using a u-blox LISA-C200 CDMA Modem");
+ m_type = LISA_C200;
+ m_onePort = true;
+ }
+ else
+ {
+ WARN("Using an Unknown Dongle");
+ }
+ }
+ return UbloxModem::init();
+}
+
+int UbloxUSBModem::cleanup()
+{
+ UbloxModem::cleanup();
+ m_dongle.disconnect();
+ m_dongleConnected = false;
+ return OK;
+}
+
+UbloxSerModem::UbloxSerModem() :
+ UbloxModem(&m_atStream, NULL),
+ m_Serial(P0_15/*MDMTXD*/,P0_16/*MDMRXD*/),
+ m_atStream(m_Serial)
+{
+ m_Serial.baud(115200/*MDMBAUD*/);
+ m_Serial.set_flow_control(SerialBase::RTSCTS, P0_22/*MDMRTS*/, P0_17/*MDMCTS*/);
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.h
new file mode 100644
index 0000000000..dc0e1205a4
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.h
@@ -0,0 +1,183 @@
+/* VodafoneUSBModem.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UBLOXMODEM_H_
+#define UBLOXMODEM_H_
+
+#include "core/fwk.h"
+
+#include "at/ATCommandsInterface.h"
+#include "ip/PPPIPInterface.h"
+#include "sms/GSMSMSInterface.h"
+#include "sms/CDMASMSInterface.h"
+#include "ussd/USSDInterface.h"
+#include "link/LinkMonitor.h"
+#include "CellularModem.h"
+
+class genericAtProcessor : public IATCommandsProcessor
+{
+public:
+ genericAtProcessor();
+ const char* getResponse(void);
+private:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+protected:
+ char str[256];
+ int i;
+};
+
+/** u-blox WCDMA modem (LISA-U200)
+ */
+class UbloxModem: public CellularModem
+{
+public:
+ /** Create u-blox API instance
+ @param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
+ @param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
+ */
+ UbloxModem(IOStream* atStream, IOStream* pppStream);
+
+ //Internet-related functions
+
+ /** Open a 3G internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
+
+ /** Close the internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int disconnect();
+
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int sendSM(const char* number, const char* message);
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int getSM(char* number, char* message, size_t maxLength);
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getSMCount(size_t* pCount);
+
+ /** Send a USSD command & wait for its result
+ @param command The command to send
+ @param result Buffer in which to store the result
+ @param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ int sendUSSD(const char* command, char* result, size_t maxLength);
+
+ /** Get link state
+ @param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
+ @param pRegistrationState pointer to store the current registration state
+ @param pBearer pointer to store the current bearer
+ @return 0 on success, error code on failure
+ */
+ int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
+
+ int getPhoneNumber(char* phoneNumber);
+
+ /** Get the ATCommandsInterface instance
+ @return Pointer to the ATCommandsInterface instance
+ */
+ virtual ATCommandsInterface* getATCommandsInterface();
+
+protected:
+ /** Initialise dongle.
+ * The following actions are performed:
+ * 1) Start AT interface thread
+ * 2) Wait for network registration
+ */
+ virtual int init();
+
+ /** De-initialise dongle.
+ * The following actions are performed:
+ * 1) Tear down PPP session
+ * 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
+ * 3) Close the AT commands interface
+ */
+ virtual int cleanup();
+
+private:
+ ATCommandsInterface m_at; //< Interface to AT commands processing
+
+ CDMASMSInterface m_CdmaSms; //< Interface to SMS manager (send/receive etc)
+ GSMSMSInterface m_GsmSms; //< Interface to SMS manager (send/receive etc)
+ USSDInterface m_ussd; //< Interface to USSD manager (send etc)
+ LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
+
+ PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
+
+ bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
+ bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
+ bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
+ bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
+ bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
+protected:
+ bool m_onePort;
+ enum { LISA_C200, LISA_U200, SARA_G350, UNKNOWN } m_type;
+};
+
+#include "WANDongle.h"
+#include "serial/usb/USBSerialStream.h"
+
+class UbloxUSBModem: public UbloxModem
+{
+public:
+ UbloxUSBModem();
+ virtual int init();
+ virtual int cleanup();
+ virtual int power(bool enable) { return 1; }
+
+private:
+ WANDongle m_dongle; //< Interface to USB connected WAN dongle
+
+ USBSerialStream m_atStream; //< Serial interface to AT channel on modem
+ USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
+
+ bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
+};
+
+#include "serial/io/IOSerialStream.h"
+
+class UbloxSerModem: public UbloxModem
+{
+public:
+ UbloxSerModem();
+ virtual int power(bool enable) { return 1; }
+private:
+ RawSerial m_Serial;
+ IOSerialStream m_atStream; //< Serial interface to AT channel on modem
+};
+
+#endif /* UBLOXMODEM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.cpp
new file mode 100644
index 0000000000..5e4e32a2b5
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.cpp
@@ -0,0 +1,398 @@
+/* UbloxUSBCDMAModem.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 4
+#ifndef __MODULE__
+#define __MODULE__ "UbloxUSBCDMAModem.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "UbloxUSBCDMAModem.h"
+#include "UbloxCDMAModemInitializer.h"
+#include "USBHost.h"
+
+#define USE_ONE_PORT 1
+
+UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
+m_stream(m_dongle.getSerial(serial)),
+m_at(&m_stream),
+m_sms(&m_at), m_ppp(&m_stream),
+m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
+m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
+{
+ USBHost* host = USBHost::getHostInst();
+ m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
+ if( m_powerGatingPin != NC )
+ {
+ power(false); //Dongle will have to be powered on manually
+ }
+}
+
+class CSSProcessor : public IATCommandsProcessor
+{
+public:
+ CSSProcessor() : status(STATUS_REGISTERING)
+ {
+
+ }
+ enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
+ REGISTERING_STATUS getStatus()
+ {
+ return status;
+ }
+private:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+ {
+ char b;
+ char bc[3] = "";
+ int sid = 99999;
+
+ //if( sscanf(line, "%*d, %c", &r) == 1 )
+ if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
+ {
+ if(strcmp("Z", bc) == 0)
+ status = STATUS_REGISTERING;
+ else
+ status = STATUS_OK;
+ }
+ return OK;
+ }
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+ {
+ return OK;
+ }
+ volatile REGISTERING_STATUS status;
+};
+
+int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
+{
+ if( !m_ipInit )
+ {
+ m_ipInit = true;
+ m_ppp.init();
+ }
+ m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
+
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ #if USE_ONE_PORT
+ m_smsInit = false; //SMS status reset
+ //m_ussdInit = false; //USSD status reset
+ //m_linkMonitorInit = false; //Link monitor status reset
+ #endif
+
+ ATCommandsInterface::ATResult result;
+
+ if(apn != NULL)
+ {
+ char cmd[48];
+ sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
+ ret = m_at.executeSimple(cmd, &result);
+ DBG("Result of command: Err code=%d", ret);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+ DBG("APN set to %s", apn);
+ }
+
+
+ //Connect
+ DBG("Connecting");
+ #if USE_ONE_PORT
+ m_at.close(); // Closing AT parser
+ m_atOpen = false; //Will need to be reinitialized afterwards
+ #endif
+
+ DBG("Connecting PPP");
+
+ ret = m_ppp.connect();
+ DBG("Result of connect: Err code=%d", ret);
+ return ret;
+}
+
+
+int UbloxUSBCDMAModem::disconnect()
+{
+ DBG("Disconnecting from PPP");
+ int ret = m_ppp.disconnect();
+ if(ret)
+ {
+ ERR("Disconnect returned %d, still trying to disconnect", ret);
+ }
+
+ //Ugly but leave dongle time to recover
+ Thread::wait(500);
+
+ #if USE_ONE_PORT
+ ATCommandsInterface::ATResult result;
+ DBG("Starting AT thread");
+ ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+ #endif
+
+ DBG("Trying to hangup");
+
+ #if 0 //Does not appear to work
+ int tries = 10;
+ do
+ {
+ ret = m_at.executeSimple("+++", &result, 1000);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ } while(tries-- && ret);
+ if(!ret)
+ {
+ ret = m_at.executeSimple("ATH", &result);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ }
+ #endif
+
+ #if USE_ONE_PORT
+ //Reinit AT parser
+ ret = m_at.init();
+ DBG("Result of command: Err code=%d\n", ret);
+ if(ret)
+ {
+ m_at.close(); // Closing AT parser
+ DBG("AT Parser closed, could not complete disconnection");
+ return NET_TIMEOUT;
+ }
+
+ #if 0
+ m_at.close(); // Closing AT parser
+ DBG("AT Parser closed");
+ #endif
+ #endif
+ return OK;
+}
+
+int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.send(number, message);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.get(number, message, maxLength);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.getCount(pCount);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
+{
+ return &m_at;
+}
+
+int UbloxUSBCDMAModem::power(bool enable)
+{
+ if( m_powerGatingPin == NC )
+ {
+ return NET_INVALID; //A pin name has not been provided in the constructor
+ }
+
+ if(!enable) //Will force components to re-init
+ {
+ cleanup();
+ }
+
+ DigitalOut powerGatingOut(m_powerGatingPin);
+ powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
+
+ return OK;
+}
+
+bool UbloxUSBCDMAModem::power()
+{
+ if( m_powerGatingPin == NC )
+ {
+ return true; //Assume power is always on
+ }
+
+ DigitalOut powerGatingOut(m_powerGatingPin);
+ return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
+}
+
+int UbloxUSBCDMAModem::init()
+{
+ if( !m_dongleConnected )
+ {
+ if(!power())
+ {
+ //Obviously cannot initialize the dongle if it is disconnected...
+ ERR("Power is off");
+ return NET_INVALID;
+ }
+ m_dongleConnected = true;
+ while( !m_dongle.connected() )
+ {
+ m_dongle.tryConnect();
+ Thread::wait(100);
+ }
+ }
+
+ if(m_atOpen)
+ {
+ return OK;
+ }
+
+ DBG("Starting AT thread if needed");
+ int ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+
+ DBG("Sending initialisation commands");
+ ret = m_at.init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
+ {
+ INFO("Using a UBLOX C200 Dongle");
+ }
+ else
+ {
+ WARN("Using an Unknown Dongle");
+ }
+
+ ATCommandsInterface::ATResult result;
+
+ //Wait for network registration
+ CSSProcessor cssProcessor;
+ do
+ {
+ DBG("Waiting for network registration");
+ ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
+ {
+ Thread::wait(3000);
+ }
+ } while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
+
+ m_atOpen = true;
+
+ return OK;
+}
+
+int UbloxUSBCDMAModem::cleanup()
+{
+ if(m_ppp.isConnected())
+ {
+ WARN("Data connection is still open"); //Try to encourage good behaviour from the user
+ m_ppp.disconnect();
+ }
+
+ m_smsInit = false;
+// m_linkMonitorInit = false;
+ //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
+
+ if(m_atOpen)
+ {
+ m_at.close();
+ m_atOpen = false;
+ }
+
+ m_dongle.disconnect();
+ m_dongleConnected = false;
+
+ return OK;
+}
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.h
new file mode 100644
index 0000000000..988afb29ad
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.h
@@ -0,0 +1,118 @@
+/* UbloxUSBCDMAModem.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UBLOXUSBCDMAMODEM_H_
+#define UBLOXUSBCDMAMODEM_H_
+
+#include "core/fwk.h"
+
+#include "WANDongle.h"
+#include "at/ATCommandsInterface.h"
+#include "USBSerialStream.h"
+#include "ip/PPPIPInterface.h"
+#include "sms/CDMASMSInterface.h"
+#include "CellularModem.h"
+
+/** u-blox LISA-C200 modem
+ */
+class UbloxUSBCDMAModem: public CellularModem
+{
+public:
+ /** Create Sprint USB Modem (Sierra Wireless 598U) API instance
+ @param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
+ @param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
+ */
+ UbloxUSBCDMAModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true, int serial = 0);
+
+ //Internet-related functions
+
+ /** Open a 3G internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
+
+ /** Close the internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int disconnect();
+
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int sendSM(const char* number, const char* message);
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int getSM(char* number, char* message, size_t maxLength);
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getSMCount(size_t* pCount);
+
+ /** Get the ATCommandsInterface instance
+ @return Pointer to the ATCommandsInterface instance
+ */
+ virtual ATCommandsInterface* getATCommandsInterface();
+
+ /** Switch power on or off
+ In order to use this function, a pin name must have been entered in the constructor
+ @param enable true to switch the dongle on, false to switch it off
+ @return 0 on success, error code on failure
+ */
+ virtual int power(bool enable);
+
+protected:
+ bool power();
+
+ int init();
+ int cleanup();
+
+private:
+ WANDongle m_dongle;
+
+ USBSerialStream m_stream;
+
+ ATCommandsInterface m_at;
+
+ CDMASMSInterface m_sms;
+
+ PPPIPInterface m_ppp;
+
+ bool m_dongleConnected;
+ bool m_ipInit;
+ bool m_smsInit;
+ bool m_atOpen;
+
+ PinName m_powerGatingPin;
+ bool m_powerGatingOnWhenPinHigh;
+};
+
+
+#endif /* UBLOXUSBCDMAMODEM_H_ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.cpp
new file mode 100644
index 0000000000..8209dc6a88
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.cpp
@@ -0,0 +1,605 @@
+/* UbloxUSBGSMModem.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define __DEBUG__ 3
+#ifndef __MODULE__
+#define __MODULE__ "UbloxUSBGSMModem.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "UbloxUSBGSMModem.h"
+#include "UbloxGSMModemInitializer.h"
+#include "USBHost.h"
+
+UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) :
+ m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
+ m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
+ m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
+ m_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel
+ m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
+ m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
+ m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
+ m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
+ m_dongleConnected(false), // Dongle is initially not ready for anything
+ m_ipInit(false), // PPIPInterface connection is initially down
+ m_smsInit(false), // SMSInterface starts un-initialised
+ m_ussdInit(false), // USSDInterface starts un-initialised
+ m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
+ m_atOpen(false), // ATCommandsInterface starts in a closed state
+ m_powerGatingPin(powerGatingPin), // set power gating pin
+ m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) // set state semantics for power gating pin
+{
+ USBHost* host = USBHost::getHostInst();
+ m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
+ if( m_powerGatingPin != NC )
+ {
+ power(false); //Dongle will have to be powered on manually
+ }
+}
+
+class CREGProcessor : public IATCommandsProcessor
+{
+public:
+ CREGProcessor() : status(STATUS_REGISTERING)
+ {
+
+ }
+ enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
+ REGISTERING_STATUS getStatus()
+ {
+ return status;
+ }
+private:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+ {
+ int r;
+ if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
+ {
+ switch(r)
+ {
+ case 1:
+ case 5:
+ status = STATUS_OK;
+ break;
+ case 0:
+ case 2:
+ status = STATUS_REGISTERING;
+ break;
+ case 3:
+ default:
+ status = STATUS_FAILED;
+ break;
+ }
+ }
+ return OK;
+ }
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+ {
+ return OK;
+ }
+ volatile REGISTERING_STATUS status;
+};
+
+#if 0
+class COPSProcessor : public IATCommandsProcessor
+{
+public:
+ COPSProcessor() : valid(false)
+ {
+ network[0] = '\0';
+ apn[0] = '\0';
+ bearer[0] = '\0';
+ }
+ char* getNetwork()
+ {
+ return network;
+ }
+ char* getAPN()
+ {
+ return apn;
+ }
+ char* getBearer()
+ {
+ return bearer;
+ }
+ bool isValid()
+ {
+ return valid;
+ }
+private:
+ virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+ {
+ int networkId;
+ int bearerId;
+ int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
+ if( s == 2 )
+ {
+ switch(networkId)
+ {
+ case 23415:
+ strcpy(network, "Vodafone UK");
+ strcpy(apn, "pp.vodafone.co.uk");
+ valid = true;
+ break;
+ case 20810:
+ strcpy(network, "SFR FR");
+ strcpy(apn, "websfr");
+ valid = true;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ return OK;
+ }
+ switch(bearerId)
+ {
+ case 0: strcpy(bearer, "GSM"); break;
+ case 1: strcpy(bearer, "GSM Compact"); break;
+ case 2: strcpy(bearer, "UTRAN"); break;
+ case 3: strcpy(bearer, "GSM w/EGPRS"); break;
+ case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
+ case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
+ case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
+ case 7: strcpy(bearer, "E-UTRAN"); break;
+
+ default:
+ break;
+ }
+ return OK;
+ }
+ virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+ {
+ return OK;
+ }
+ char network[24];
+ char bearer[24];
+ char apn[24];
+ volatile bool valid;
+};
+#endif
+
+int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* password)
+{
+ if( !m_ipInit )
+ {
+ m_ipInit = true;
+ m_ppp.init();
+ }
+ m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
+
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ #if USE_ONE_PORT
+ m_smsInit = false; //SMS status reset
+ m_ussdInit = false; //USSD status reset
+ m_linkMonitorInit = false; //Link monitor status reset
+ #endif
+
+ ATCommandsInterface::ATResult result;
+
+ #if 0
+ //Get network info & select corresponding APN
+ COPSProcessor copsProcessor;
+ DBG("Get network info & select APN from DB");
+ ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id
+ DBG("Result of command: Err code=%d", ret);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+
+ if(!copsProcessor.isValid())
+ {
+ WARN("Connected to an unknown network, try to connect with default parameters");
+ DBG("Connected with %s", copsProcessor.getBearer());
+ }
+ else
+ {
+ DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer());
+ char cmd[48];
+ int tries = 3;
+ sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN());
+ do //Try 3 times because for some reasons it can fail with the K3772-Z dongle
+ {
+ ret = m_at.executeSimple(cmd, &result);
+ DBG("Result of command: Err code=%d", ret);
+ } while(ret && --tries);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+ DBG("APN set to %s", copsProcessor.getAPN());
+ }
+ #else
+ if(apn != NULL)
+ {
+ char cmd[48];
+ int tries = 30;
+ sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
+ do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
+ {
+ ret = m_at.executeSimple(cmd, &result);
+ DBG("Result of command: Err code=%d", ret);
+ if(ret)
+ {
+ Thread::wait(500);
+ }
+ } while(ret && --tries);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+ DBG("APN set to %s", apn);
+ }
+ #endif
+
+
+ //Connect
+ DBG("Connecting");
+ #if 0
+ ret = m_at.executeSimple("ATDT *99#", &result);
+ DBG("Result of command: Err code=%d", ret);
+ DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+ #endif
+ #if USE_ONE_PORT
+ m_at.close(); // Closing AT parser
+ m_atOpen = false; //Will need to be reinitialized afterwards
+ #endif
+
+ #if 0
+ DBG("AT Parser closed");
+ if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT))
+ {
+ ERR("Could not connect");
+ return ret; //Could not connect
+ }
+ #endif
+ DBG("Connecting PPP");
+
+ ret = m_ppp.connect();
+ DBG("Result of connect: Err code=%d", ret);
+ return ret;
+}
+
+
+int UbloxUSBGSMModem::disconnect()
+{
+ DBG("Disconnecting from PPP");
+ int ret = m_ppp.disconnect();
+ if(ret)
+ {
+ ERR("Disconnect returned %d, still trying to disconnect", ret);
+ }
+
+ //Ugly but leave dongle time to recover
+ Thread::wait(500);
+
+ #if USE_ONE_PORT
+ ATCommandsInterface::ATResult result;
+ DBG("Starting AT thread");
+ ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+ #endif
+
+ DBG("Trying to hangup");
+
+ #if 0 //Does not appear to work
+ int tries = 10;
+ do
+ {
+ ret = m_at.executeSimple("+++", &result, 1000);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ } while(tries-- && ret);
+ if(!ret)
+ {
+ ret = m_at.executeSimple("ATH", &result);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ }
+ #endif
+
+ #if USE_ONE_PORT
+ //Reinit AT parser
+ ret = m_at.init();
+ DBG("Result of command: Err code=%d\n", ret);
+ if(ret)
+ {
+ m_at.close(); // Closing AT parser
+ DBG("AT Parser closed, could not complete disconnection");
+ return NET_TIMEOUT;
+ }
+
+ #if 0
+ m_at.close(); // Closing AT parser
+ DBG("AT Parser closed");
+ #endif
+ #endif
+ return OK;
+}
+
+int UbloxUSBGSMModem::sendSM(const char* number, const char* message)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.send(number, message);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBGSMModem::getSM(char* number, char* message, size_t maxLength)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.get(number, message, maxLength);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBGSMModem::getSMCount(size_t* pCount)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_smsInit)
+ {
+ ret = m_sms.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_smsInit = true;
+ }
+
+ ret = m_sms.getCount(pCount);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBGSMModem::sendUSSD(const char* command, char* result, size_t maxLength)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_ussdInit)
+ {
+ ret = m_ussd.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_ussdInit = true;
+ }
+
+ ret = m_ussd.send(command, result, maxLength);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+int UbloxUSBGSMModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
+{
+ int ret = init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(!m_linkMonitorInit)
+ {
+ ret = m_linkMonitor.init();
+ if(ret)
+ {
+ return ret;
+ }
+ m_linkMonitorInit = true;
+ }
+
+ ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
+ if(ret)
+ {
+ return ret;
+ }
+
+ return OK;
+}
+
+
+ATCommandsInterface* UbloxUSBGSMModem::getATCommandsInterface()
+{
+ return &m_at;
+}
+
+int UbloxUSBGSMModem::power(bool enable)
+{
+ if( m_powerGatingPin == NC )
+ {
+ return NET_INVALID; //A pin name has not been provided in the constructor
+ }
+
+ if(!enable) //Will force components to re-init
+ {
+ cleanup();
+ }
+
+ DigitalOut powerGatingOut(m_powerGatingPin);
+ powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
+
+ return OK;
+}
+
+bool UbloxUSBGSMModem::power()
+{
+ if( m_powerGatingPin == NC )
+ {
+ return true; //Assume power is always on
+ }
+
+ DigitalOut powerGatingOut(m_powerGatingPin);
+ return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
+}
+
+int UbloxUSBGSMModem::init()
+{
+ if( !m_dongleConnected )
+ {
+ if(!power())
+ {
+ //Obviously cannot initialize the dongle if it is disconnected...
+ ERR("Power is off");
+ return NET_INVALID;
+ }
+ m_dongleConnected = true;
+ while( !m_dongle.connected() )
+ {
+ m_dongle.tryConnect();
+ Thread::wait(10);
+ }
+ }
+
+ if(m_atOpen)
+ {
+ return OK;
+ }
+
+ DBG("Starting AT thread if needed");
+ int ret = m_at.open();
+ if(ret)
+ {
+ return ret;
+ }
+
+ DBG("Sending initialisation commands");
+ ret = m_at.init();
+ if(ret)
+ {
+ return ret;
+ }
+
+ if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
+ {
+ INFO("Using a u-blox LISA-U");
+ }
+ else
+ {
+ WARN("Using an Unknown Dongle");
+ }
+
+ ATCommandsInterface::ATResult result;
+
+ //Wait for network registration
+ CREGProcessor cregProcessor;
+ do
+ {
+ DBG("Waiting for network registration");
+ ret = m_at.execute("AT+CREG?", &cregProcessor, &result);
+ DBG("Result of command: Err code=%d\n", ret);
+ DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+ if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
+ {
+ Thread::wait(3000);
+ }
+ } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
+ if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
+ {
+ ERR("Registration denied");
+ return NET_AUTH;
+ }
+
+ m_atOpen = true;
+
+ return OK;
+}
+
+int UbloxUSBGSMModem::cleanup()
+{
+ if(m_ppp.isConnected())
+ {
+ WARN("Data connection is still open"); //Try to encourage good behaviour from the user
+ m_ppp.disconnect();
+ }
+
+ m_smsInit = false;
+ m_ussdInit = false;
+ m_linkMonitorInit = false;
+ //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
+
+ if(m_atOpen)
+ {
+ m_at.close();
+ m_atOpen = false;
+ }
+
+ m_dongle.disconnect();
+ m_dongleConnected = false;
+
+ return OK;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.h
new file mode 100644
index 0000000000..2cc432a2c2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBGSMModem.h
@@ -0,0 +1,155 @@
+/* VodafoneUSBModem.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UBLOXUSBGSMMODEM_H_
+#define UBLOXUSBGSMMODEM_H_
+
+#include "core/fwk.h"
+
+#include "WANDongle.h"
+#include "at/ATCommandsInterface.h"
+#include "serial/usb/USBSerialStream.h"
+#include "ip/PPPIPInterface.h"
+#include "sms/GSMSMSInterface.h"
+#include "ussd/USSDInterface.h"
+#include "link/LinkMonitor.h"
+#include "CellularModem.h"
+
+/** u-blox WCDMA modem (LISA-U200)
+ */
+class UbloxUSBGSMModem: public CellularModem
+{
+public:
+ /** Create u-blox API instance
+ @param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
+ @param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
+ */
+ UbloxUSBGSMModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true);
+
+ //Internet-related functions
+
+ /** Open a 3G internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
+
+ /** Close the internet connection
+ @return 0 on success, error code on failure
+ */
+ virtual int disconnect();
+
+
+ /** Send a SM
+ @param number The receiver's phone number
+ @param message The message to send
+ @return 0 on success, error code on failure
+ */
+ virtual int sendSM(const char* number, const char* message);
+
+
+ /** Receive a SM
+ @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
+ @param message Pointer to a buffer to store the the incoming message
+ @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ virtual int getSM(char* number, char* message, size_t maxLength);
+
+ /** Get the number of SMs in the incoming box
+ @param pCount pointer to store the number of unprocessed SMs on
+ @return 0 on success, error code on failure
+ */
+ virtual int getSMCount(size_t* pCount);
+
+ /** Send a USSD command & wait for its result
+ @param command The command to send
+ @param result Buffer in which to store the result
+ @param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
+ @return 0 on success, error code on failure
+ */
+ int sendUSSD(const char* command, char* result, size_t maxLength);
+
+ /** Get link state
+ @param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
+ @param pRegistrationState pointer to store the current registration state
+ @param pBearer pointer to store the current bearer
+ @return 0 on success, error code on failure
+ */
+ int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
+
+ /** Get the ATCommandsInterface instance
+ @return Pointer to the ATCommandsInterface instance
+ */
+ virtual ATCommandsInterface* getATCommandsInterface();
+
+ /** Switch power on or off
+ In order to use this function, a pin name must have been entered in the constructor
+ @param enable true to switch the dongle on, false to switch it off
+ @return 0 on success, error code on failure
+ */
+ virtual int power(bool enable);
+
+protected:
+ bool power(); //< Turn power to USB dongle ON.
+
+ /** Initialise dongle.
+ * The following actions are performed:
+ * 1) Power up
+ * 2) Establish USB connection to dongle
+ * 3) Start AT interface thread
+ * 4) Wait for network registration
+ */
+ int init();
+
+ /** De-initialise dongle.
+ * The following actions are performed:
+ * 1) Tear down PPP session
+ * 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
+ * 3) Close the AT commands interface
+ * 4) Tear down the USB connection to dongle
+ */
+ int cleanup();
+
+private:
+ WANDongle m_dongle; //< Interface to USB connected WAN dongle
+
+ USBSerialStream m_atStream; //< Serial interface to AT channel on modem
+ USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
+
+ ATCommandsInterface m_at; //< Interface to AT commands processing
+
+ GSMSMSInterface m_sms; //< Interface to SMS manager (send/receive etc)
+ USSDInterface m_ussd; //< Interface to USSD manager (send etc)
+ LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
+
+ PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
+
+ bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
+ bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
+ bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
+ bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
+ bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
+ bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
+
+ PinName m_powerGatingPin; //< Pin which toggles power gating
+ bool m_powerGatingOnWhenPinHigh; //< Semantics of power gating (whether high or low toggles power gating)
+};
+
+
+#endif /* UBLOXMODEM_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.cpp
new file mode 100644
index 0000000000..73ce896bb8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.cpp
@@ -0,0 +1,156 @@
+/* EthernetInterface.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "EthernetInterface.h"
+
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "netif/etharp.h"
+#include "lwip/dhcp.h"
+#include "eth_arch.h"
+#include "lwip/tcpip.h"
+
+#include "mbed.h"
+
+/* TCP/IP and Network Interface Initialisation */
+static struct netif netif;
+
+static char mac_addr[19];
+static char ip_addr[17] = "\0";
+static char gateway[17] = "\0";
+static char networkmask[17] = "\0";
+static bool use_dhcp = false;
+
+static Semaphore tcpip_inited(0);
+static Semaphore netif_linked(0);
+static Semaphore netif_up(0);
+
+static void tcpip_init_done(void *arg) {
+ tcpip_inited.release();
+}
+
+static void netif_link_callback(struct netif *netif) {
+ if (netif_is_link_up(netif)) {
+ netif_linked.release();
+ }
+}
+
+static void netif_status_callback(struct netif *netif) {
+ if (netif_is_up(netif)) {
+ strcpy(ip_addr, inet_ntoa(netif->ip_addr));
+ strcpy(gateway, inet_ntoa(netif->gw));
+ strcpy(networkmask, inet_ntoa(netif->netmask));
+ netif_up.release();
+ }
+}
+
+static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
+ tcpip_init(tcpip_init_done, NULL);
+ tcpip_inited.wait();
+
+ memset((void*) &netif, 0, sizeof(netif));
+ netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
+ netif_set_default(&netif);
+
+ netif_set_link_callback (&netif, netif_link_callback);
+ netif_set_status_callback(&netif, netif_status_callback);
+}
+
+static void set_mac_address(void) {
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+ snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
+ MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
+#else
+ char mac[6];
+ mbed_mac_address(mac);
+ snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+#endif
+}
+
+int EthernetInterface::init() {
+ use_dhcp = true;
+ set_mac_address();
+ init_netif(NULL, NULL, NULL);
+ return 0;
+}
+
+int EthernetInterface::init(const char* ip, const char* mask, const char* gateway) {
+ use_dhcp = false;
+
+ set_mac_address();
+ strcpy(ip_addr, ip);
+
+ ip_addr_t ip_n, mask_n, gateway_n;
+ inet_aton(ip, &ip_n);
+ inet_aton(mask, &mask_n);
+ inet_aton(gateway, &gateway_n);
+ init_netif(&ip_n, &mask_n, &gateway_n);
+
+ return 0;
+}
+
+int EthernetInterface::connect(unsigned int timeout_ms) {
+ eth_arch_enable_interrupts();
+
+ int inited;
+ if (use_dhcp) {
+ dhcp_start(&netif);
+
+ // Wait for an IP Address
+ // -1: error, 0: timeout
+ inited = netif_up.wait(timeout_ms);
+ } else {
+ netif_set_up(&netif);
+
+ // Wait for the link up
+ inited = netif_linked.wait(timeout_ms);
+ }
+
+ return (inited > 0) ? (0) : (-1);
+}
+
+int EthernetInterface::disconnect() {
+ if (use_dhcp) {
+ dhcp_release(&netif);
+ dhcp_stop(&netif);
+ } else {
+ netif_set_down(&netif);
+ }
+
+ eth_arch_disable_interrupts();
+
+ return 0;
+}
+
+char* EthernetInterface::getMACAddress() {
+ return mac_addr;
+}
+
+char* EthernetInterface::getIPAddress() {
+ return ip_addr;
+}
+
+char* EthernetInterface::getGateway() {
+ return gateway;
+}
+
+char* EthernetInterface::getNetworkMask() {
+ return networkmask;
+}
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.h
new file mode 100644
index 0000000000..a8ccbedaa9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/EthernetInterface.h
@@ -0,0 +1,90 @@
+/* EthernetInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ETHERNETINTERFACE_H_
+#define ETHERNETINTERFACE_H_
+
+#if !defined(TARGET_LPC1768) && !defined(TARGET_LPC4088) && !defined(TARGET_LPC4088_DM) && !defined(TARGET_K64F) && !defined(TARGET_RZ_A1H) && !defined(TARGET_STM32F4)
+#error The Ethernet Interface library is not supported on this target
+#endif
+
+#include "rtos.h"
+#include "lwip/netif.h"
+
+ /** Interface using Ethernet to connect to an IP-based network
+ *
+ */
+class EthernetInterface {
+public:
+ /** Initialize the interface with DHCP.
+ * Initialize the interface and configure it to use DHCP (no connection at this point).
+ * \return 0 on success, a negative number on failure
+ */
+ static int init(); //With DHCP
+
+ /** Initialize the interface with a static IP address.
+ * Initialize the interface and configure it with the following static configuration (no connection at this point).
+ * \param ip the IP address to use
+ * \param mask the IP address mask
+ * \param gateway the gateway to use
+ * \return 0 on success, a negative number on failure
+ */
+ static int init(const char* ip, const char* mask, const char* gateway);
+
+ /** Connect
+ * Bring the interface up, start DHCP if needed.
+ * \param timeout_ms timeout in ms (default: (15)s).
+ * \return 0 on success, a negative number on failure
+ */
+ static int connect(unsigned int timeout_ms=15000);
+
+ /** Disconnect
+ * Bring the interface down
+ * \return 0 on success, a negative number on failure
+ */
+ static int disconnect();
+
+ /** Get the MAC address of your Ethernet interface
+ * \return a pointer to a string containing the MAC address
+ */
+ static char* getMACAddress();
+
+ /** Get the IP address of your Ethernet interface
+ * \return a pointer to a string containing the IP address
+ */
+ static char* getIPAddress();
+
+ /** Get the Gateway address of your Ethernet interface
+ * \return a pointer to a string containing the Gateway address
+ */
+ static char* getGateway();
+
+ /** Get the Network mask of your Ethernet interface
+ * \return a pointer to a string containing the Network mask
+ */
+ static char* getNetworkMask();
+};
+
+#include "TCPSocketConnection.h"
+#include "TCPSocketServer.h"
+
+#include "Endpoint.h"
+#include "UDPSocket.h"
+
+#endif /* ETHERNETINTERFACE_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/eth_arch.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/eth_arch.h
new file mode 100644
index 0000000000..1ff54b1d38
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/EthernetInterface/eth_arch.h
@@ -0,0 +1,41 @@
+/* EthernetInterface.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+// Architecture specific Ethernet interface
+// Must be implemented by each target
+
+#ifndef ETHARCH_H_
+#define ETHARCH_H_
+
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void eth_arch_enable_interrupts(void);
+void eth_arch_disable_interrupts(void);
+err_t eth_arch_enetif_init(struct netif *netif);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef ETHARCHINTERFACE_H_
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/fsl_enet_driver.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/fsl_enet_driver.c
new file mode 100644
index 0000000000..cb3481cf0a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/fsl_enet_driver.c
@@ -0,0 +1,469 @@
+/*
+* Copyright (c) 2013 - 2014, Freescale Semiconductor, 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:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+* of conditions and the following disclaimer.
+*
+* o 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.
+*
+* o Neither the name of Freescale Semiconductor, Inc. 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.
+*/
+
+/* Modified by mbed for the lwIP port */
+
+#include "fsl_enet_driver.h"
+#include "fsl_enet_hal.h"
+#include "fsl_clock_manager.h"
+#include "fsl_interrupt_manager.h"
+#include <string.h>
+
+#include "sys_arch.h"
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Define ENET's IRQ list */
+
+void *enetIfHandle;
+
+/*! @brief Define MAC driver API structure and for application of stack adaptor layer*/
+const enet_mac_api_t g_enetMacApi =
+{
+ enet_mac_init,
+ NULL, // enet_mac_deinit,
+ NULL, // enet_mac_send,
+#if !ENET_RECEIVE_ALL_INTERRUPT
+ NULL, // enet_mac_receive,
+#endif
+ enet_mii_read,
+ enet_mii_write,
+ NULL, // enet_mac_add_multicast_group,
+ NULL, //enet_mac_leave_multicast_group,
+};
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+// NOTE: we need these functions to be non-blocking fpr the PHY task, hence the
+// osDelay() below
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mii_read
+ * Return Value: The execution status.
+ * Description: Read function.
+ * This interface read data over the (R)MII bus from the specified PHY register,
+ * This function is called by all PHY interfaces.
+ *END*********************************************************************/
+uint32_t enet_mii_read(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
+{
+ uint32_t counter;
+
+ /* Check the input parameters*/
+ if (!dataPtr)
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ /* Check if the mii is enabled*/
+ if (!enet_hal_is_mii_enabled(instance))
+ {
+ return kStatus_ENET_Miiuninitialized;
+ }
+
+ /* Clear the MII interrupt event*/
+ enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
+
+ /* Read command operation*/
+ enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetReadValidFrame, 0);
+
+ /* Poll for MII complete*/
+ for (counter = 0; counter < kEnetMaxTimeout; counter++)
+ {
+ if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
+ {
+ break;
+ }
+ osDelay(1);
+ }
+
+ /* Check for timeout*/
+ if (counter == kEnetMaxTimeout)
+ {
+ return kStatus_ENET_TimeOut;
+ }
+
+ /* Get data from mii register*/
+ *dataPtr = enet_hal_get_mii_data(instance);
+
+ /* Clear MII interrupt event*/
+ enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
+
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mii_write
+ * Return Value: The execution status.
+ * Description: Write function.
+ * This interface write data over the (R)MII bus to the specified PHY register.
+ * This function is called by all PHY interfaces.
+ *END*********************************************************************/
+uint32_t enet_mii_write(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
+{
+ uint32_t counter;
+
+ /* Check if the mii is enabled*/
+ if (!enet_hal_is_mii_enabled(instance))
+ {
+ return kStatus_ENET_Miiuninitialized;
+ }
+
+ /* Clear the MII interrupt event*/
+ enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
+
+ /* Read command operation*/
+ enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetWriteValidFrame, data);
+
+ /* Poll for MII complete*/
+ for (counter = 0; counter < kEnetMaxTimeout; counter++)
+ {
+ if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
+ {
+ break;
+ }
+ osDelay(1);
+ }
+
+ /* Check for timeout*/
+ if (counter == kEnetMaxTimeout)
+ {
+ return kStatus_ENET_TimeOut;
+ }
+
+ /* Clear MII intrrupt event*/
+ enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
+
+ return kStatus_ENET_Success;
+}
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_mii_init
+ * Return Value: The execution status.
+ * Description:Initialize the ENET Mac mii(mdc/mdio)interface.
+ *END*********************************************************************/
+uint32_t enet_mac_mii_init(enet_dev_if_t * enetIfPtr)
+{
+ uint32_t frequency;
+
+ /* Check the input parameters*/
+ if (enetIfPtr == NULL)
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ /* Configure mii speed*/
+ CLOCK_SYS_GetFreq(kSystemClock, &frequency);
+ enet_hal_config_mii(enetIfPtr->deviceNumber, (frequency/(2 * enetIfPtr->macCfgPtr->miiClock) + 1),
+ kEnetMdioHoldOneClkCycle, false);
+
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_rxbd_init
+ * Return Value: The execution status.
+ * Description:Initialize the ENET receive buffer descriptors.
+ * Note: If you do receive on receive interrupt handler the receive
+ * data buffer number can be the same as the receive descriptor numbers.
+ * But if you are polling receive frames please make sure the receive data
+ * buffers are more than buffer descriptors to guarantee a good performance.
+ *END*********************************************************************/
+uint32_t enet_mac_rxbd_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg)
+{
+ /* Check the input parameters*/
+ if ((!enetIfPtr) || (!rxbdCfg))
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ enetIfPtr->macContextPtr->bufferdescSize = enet_hal_get_bd_size();
+
+ /* Initialize the bd status*/
+ enetIfPtr->macContextPtr->isRxFull = false;
+
+ /* Initialize receive bd base address and current address*/
+ enetIfPtr->macContextPtr->rxBdBasePtr = rxbdCfg->rxBdPtrAlign;
+ enetIfPtr->macContextPtr->rxBdCurPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
+ enetIfPtr->macContextPtr->rxBdDirtyPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
+ enet_hal_set_rxbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->rxBdBasePtr));
+
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_txbd_init
+ * Return Value: The execution status.
+ * Description:Initialize the ENET transmit buffer descriptors.
+ * This function prepare all of the transmit buffer descriptors.
+ *END*********************************************************************/
+uint32_t enet_mac_txbd_init(enet_dev_if_t * enetIfPtr, enet_txbd_config_t *txbdCfg)
+{
+ /* Check the input parameters*/
+ if ((!enetIfPtr) || (!txbdCfg))
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ /* Initialize the bd status*/
+ enetIfPtr->macContextPtr->isTxFull = false;
+
+ /* Initialize transmit bd base address and current address*/
+ enetIfPtr->macContextPtr->txBdBasePtr = txbdCfg->txBdPtrAlign;
+ enetIfPtr->macContextPtr->txBdCurPtr = enetIfPtr->macContextPtr->txBdBasePtr;
+ enetIfPtr->macContextPtr->txBdDirtyPtr = enetIfPtr->macContextPtr->txBdBasePtr;
+ enet_hal_set_txbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->txBdBasePtr));
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_configure_fifo_accel
+ * Return Value: The execution status.
+ * Description: Configure the ENET FIFO and Accelerator.
+ *END*********************************************************************/
+uint32_t enet_mac_configure_fifo_accel(enet_dev_if_t * enetIfPtr)
+{
+ enet_config_rx_fifo_t rxFifo;
+ enet_config_tx_fifo_t txFifo;
+
+ /* Check the input parameters*/
+ if (!enetIfPtr)
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ /* Initialize values that will not be initialized later on */
+ rxFifo.rxEmpty = 0;
+ rxFifo.rxFull = 0;
+ txFifo.isStoreForwardEnabled = 0;
+ txFifo.txFifoWrite = 0;
+ txFifo.txEmpty = 0;
+
+ /* Configure tx/rx accelerator*/
+ if (enetIfPtr->macCfgPtr->isRxAccelEnabled)
+ {
+ enet_hal_config_rx_accelerator(enetIfPtr->deviceNumber,
+ (enet_config_rx_accelerator_t *)&(enetIfPtr->macCfgPtr->rxAcceler));
+ if ((enetIfPtr->macCfgPtr->rxAcceler.isIpcheckEnabled) || (enetIfPtr->macCfgPtr->rxAcceler.isProtocolCheckEnabled))
+ {
+ rxFifo.rxFull = 0;
+ }
+ }
+ if (enetIfPtr->macCfgPtr->isTxAccelEnabled)
+ {
+ enet_hal_config_tx_accelerator(enetIfPtr->deviceNumber,
+ (enet_config_tx_accelerator_t *)&(enetIfPtr->macCfgPtr->txAcceler));
+ if ((enetIfPtr->macCfgPtr->txAcceler.isIpCheckEnabled) || (enetIfPtr->macCfgPtr->txAcceler.isProtocolCheckEnabled))
+ {
+ txFifo.isStoreForwardEnabled = 1;
+ }
+ }
+ if (enetIfPtr->macCfgPtr->isStoreAndFwEnabled)
+ {
+ rxFifo.rxFull = 0;
+ txFifo.isStoreForwardEnabled = 1;
+ }
+
+
+ /* Set TFWR value if STRFWD is not being used */
+ if (txFifo.isStoreForwardEnabled == 1)
+ txFifo.txFifoWrite = 0;
+ else
+ /* TFWR value is a trade-off between transmit latency and risk of transmit FIFO underrun due to contention for the system bus
+ TFWR = 15 means transmission will begin once 960 bytes has been written to the Tx FIFO (for frames larger than 960 bytes)
+ See Section 45.4.18 - Transmit FIFO Watermark Register of the K64F Reference Manual for details */
+ txFifo.txFifoWrite = 15;
+
+ /* Configure tx/rx FIFO with default value*/
+ rxFifo.rxAlmostEmpty = 4;
+ rxFifo.rxAlmostFull = 4;
+ txFifo.txAlmostEmpty = 4;
+ txFifo.txAlmostFull = 8;
+ enet_hal_config_rx_fifo(enetIfPtr->deviceNumber, &rxFifo);
+ enet_hal_config_tx_fifo(enetIfPtr->deviceNumber, &txFifo);
+
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_configure_controller
+ * Return Value: The execution status.
+ * Description: Configure the ENET controller with the basic configuration.
+ *END*********************************************************************/
+uint32_t enet_mac_configure_controller(enet_dev_if_t * enetIfPtr)
+{
+ uint32_t macCtlCfg;
+
+ /* Check the input parameters*/
+ if (enetIfPtr == NULL)
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ macCtlCfg = enetIfPtr->macCfgPtr->macCtlConfigure;
+ /* Configure rmii/mii interface*/
+ enet_hal_config_rmii(enetIfPtr->deviceNumber, enetIfPtr->macCfgPtr->rmiiCfgMode,
+ enetIfPtr->macCfgPtr->speed, enetIfPtr->macCfgPtr->duplex, false,
+ (macCtlCfg & kEnetRxMiiLoopback));
+ /* Configure receive buffer size*/
+ if (enetIfPtr->macCfgPtr->isVlanEnabled)
+ {
+ enetIfPtr->maxFrameSize = kEnetMaxFrameVlanSize;
+ enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
+ enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameVlanSize);
+ }
+ else
+ {
+ enetIfPtr->maxFrameSize = kEnetMaxFrameSize;
+ enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
+ enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameSize);
+ }
+
+ /* Set receive controller promiscuous */
+ enet_hal_config_promiscuous(enetIfPtr->deviceNumber, macCtlCfg & kEnetRxPromiscuousEnable);
+ /* Set receive flow control*/
+ enet_hal_enable_flowcontrol(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxFlowControlEnable));
+ /* Set received PAUSE frames are forwarded/terminated*/
+ enet_hal_enable_pauseforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPauseFwdEnable));
+ /* Set receive broadcast frame reject*/
+ enet_hal_enable_broadcastreject(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxBcRejectEnable));
+ /* Set padding is removed from the received frame*/
+ enet_hal_enable_padremove(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPadRemoveEnable));
+ /* Set the crc of the received frame is stripped from the frame*/
+ enet_hal_enable_rxcrcforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxCrcFwdEnable));
+ /* Set receive payload length check*/
+ enet_hal_enable_payloadcheck(enetIfPtr->deviceNumber, (macCtlCfg & kEnetPayloadlenCheckEnable));
+ /* Set control sleep mode*/
+ enet_hal_enable_sleep(enetIfPtr->deviceNumber, (macCtlCfg & kEnetSleepModeEnable));
+ return kStatus_ENET_Success;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_mac_init
+ * Return Value: The execution status.
+ * Description:Initialize the ENET device with the basic configuration
+ * When ENET is used, this function need to be called by the NET initialize
+ * interface.
+ *END*********************************************************************/
+uint32_t enet_mac_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg,
+ enet_txbd_config_t *txbdCfg)
+{
+ uint32_t timeOut = 0;
+ uint32_t devNumber, result = 0;
+
+ /* Check the input parameters*/
+ if (enetIfPtr == NULL)
+ {
+ return kStatus_ENET_InvalidInput;
+ }
+
+ /* Get device number and check the parameter*/
+ devNumber = enetIfPtr->deviceNumber;
+
+ /* Store the global ENET structure for ISR input parameters */
+ enetIfHandle = enetIfPtr;
+
+ /* Turn on ENET module clock gate */
+ CLOCK_SYS_EnableEnetClock(0U);
+
+ /* Reset ENET mac*/
+ enet_hal_reset_ethernet(devNumber);
+ while ((!enet_hal_is_reset_completed(devNumber)) && (timeOut < kEnetMaxTimeout))
+ {
+ time_delay(1);
+ timeOut++;
+ }
+
+ /* Check out if timeout*/
+ if (timeOut == kEnetMaxTimeout)
+ {
+ return kStatus_ENET_TimeOut;
+ }
+
+ /* Disable all ENET mac interrupt and Clear all interrupt events*/
+ enet_hal_config_interrupt(devNumber, kEnetAllInterrupt, false);
+ enet_hal_clear_interrupt(devNumber, kEnetAllInterrupt);
+
+ /* Program this station's physical address*/
+ enet_hal_set_mac_address(devNumber, enetIfPtr->macCfgPtr->macAddr);
+
+ /* Clear group and individual hash register*/
+ enet_hal_set_group_hashtable(devNumber, 0, kEnetSpecialAddressInit);
+ enet_hal_set_individual_hashtable(devNumber, 0, kEnetSpecialAddressInit);
+
+ /* Configure mac controller*/
+ result = enet_mac_configure_controller(enetIfPtr);
+ if(result != kStatus_ENET_Success)
+ {
+ return result;
+ }
+ /* Clear mib zero counters*/
+ enet_hal_clear_mib(devNumber, true);
+
+ /* Initialize FIFO and accelerator*/
+ result = enet_mac_configure_fifo_accel(enetIfPtr);
+ if(result != kStatus_ENET_Success)
+ {
+ return result;
+ }
+ /* Initialize receive buffer descriptors*/
+ result = enet_mac_rxbd_init(enetIfPtr, rxbdCfg);
+ if(result != kStatus_ENET_Success)
+ {
+ return result;
+ }
+ /* Initialize transmit buffer descriptors*/
+ result = enet_mac_txbd_init(enetIfPtr, txbdCfg);
+ if(result != kStatus_ENET_Success)
+ {
+ return result;
+ }
+ /* Initialize rmii/mii interface*/
+ result = enet_mac_mii_init(enetIfPtr);
+ if (result != kStatus_ENET_Success)
+ {
+ return result;
+ }
+
+ return kStatus_ENET_Success;
+}
+
+/*******************************************************************************
+ * EOF
+ ******************************************************************************/
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c
new file mode 100644
index 0000000000..708764abb8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013 - 2014, Freescale Semiconductor, 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:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o 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.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. 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 "fsl_port_hal.h"
+#include "fsl_clock_manager.h"
+#include "fsl_device_registers.h"
+#include "fsl_sim_hal.h"
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+void k64f_init_eth_hardware(void)
+{
+ uint8_t count;
+
+ /* Disable the mpu*/
+ BW_MPU_CESR_VLD(MPU_BASE, 0);
+
+ /* Open POTR clock gate*/
+ for (count = 0; count < HW_PORT_INSTANCE_COUNT; count++)
+ {
+ CLOCK_SYS_EnablePortClock(count);
+ }
+
+ /* Configure gpio*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 12, kPortMuxAlt4); /*!< ENET RMII0_RXD1/MII0_RXD1*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 13, kPortMuxAlt4); /*!< ENET RMII0_RXD0/MII0_RXD0*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 14, kPortMuxAlt4); /*!< ENET RMII0_CRS_DV/MII0_RXDV*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 15, kPortMuxAlt4); /*!< ENET RMII0_TXEN/MII0_TXEN*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 16, kPortMuxAlt4); /*!< ENET RMII0_TXD0/MII0_TXD0*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 17, kPortMuxAlt4); /*!< ENET RMII0_TXD01/MII0_TXD1*/
+ PORT_HAL_SetMuxMode(PORTB_BASE, 0, kPortMuxAlt4); /*!< ENET RMII0_MDIO/MII0_MDIO*/
+ PORT_HAL_SetOpenDrainCmd(PORTB_BASE,0, true); /*!< ENET RMII0_MDC/MII0_MDC*/
+
+ // Added for FRDM-K64F
+ PORT_HAL_SetPullMode(PORTB_BASE, 0, kPortPullUp);
+ PORT_HAL_SetPullCmd(PORTB_BASE, 0, true);
+
+ PORT_HAL_SetMuxMode(PORTB_BASE, 1, kPortMuxAlt4);
+ /* Configure GPIO for MII interface */
+ PORT_HAL_SetMuxMode(PORTA_BASE, 9, kPortMuxAlt4); /*!< ENET MII0_RXD3*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 10, kPortMuxAlt4); /*!< ENET MII0_RXD2*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 11, kPortMuxAlt4); /*!< ENET MII0_RXCLK*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 24, kPortMuxAlt4); /*!< ENET MII0_TXD2*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 25, kPortMuxAlt4); /*!< ENET MII0_TXCLK*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 26, kPortMuxAlt4); /*!< ENET MII0_TXD3*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 27, kPortMuxAlt4); /*!< ENET MII0_CRS*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 28, kPortMuxAlt4); /*!< ENET MII0_TXER*/
+ PORT_HAL_SetMuxMode(PORTA_BASE, 29, kPortMuxAlt4); /*!< ENET MII0_COL*/
+#if FSL_FEATURE_ENET_SUPPORT_PTP
+ PORT_HAL_SetMuxMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortMuxAlt4); /* ENET ENET0_1588_TMR0*/
+ PORT_HAL_SetDriveStrengthMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortHighDriveStrength);
+#endif
+
+ /* Open ENET clock gate*/
+ CLOCK_SYS_EnableEnetClock( 0U);
+
+ /* Select the ptp timer outclk*/
+ CLOCK_HAL_SetSource(g_simBaseAddr[0], kClockTimeSrc, 2);
+}
+
+/*******************************************************************************
+ * EOF
+ ******************************************************************************/
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac.c
new file mode 100644
index 0000000000..482cd79595
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac.c
@@ -0,0 +1,885 @@
+#include "lwip/opt.h"
+#include "lwip/sys.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "lwip/tcpip.h"
+#include "netif/etharp.h"
+#include "netif/ppp_oe.h"
+
+#include "eth_arch.h"
+#include "sys_arch.h"
+
+#include "fsl_enet_driver.h"
+#include "fsl_enet_hal.h"
+#include "fsl_device_registers.h"
+#include "fsl_phy_driver.h"
+#include "fsl_interrupt_manager.h"
+#include "k64f_emac_config.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mbed_interface.h"
+
+extern IRQn_Type enet_irq_ids[HW_ENET_INSTANCE_COUNT][FSL_FEATURE_ENET_INTERRUPT_COUNT];
+extern uint8_t enetIntMap[kEnetIntNum];
+extern void *enetIfHandle;
+
+/********************************************************************************
+ * Internal data
+ ********************************************************************************/
+
+extern void k64f_init_eth_hardware(void);
+
+/* K64F EMAC driver data structure */
+struct k64f_enetdata {
+ struct netif *netif; /**< Reference back to LWIP parent netif */
+ sys_sem_t RxReadySem; /**< RX packet ready semaphore */
+ sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
+ sys_mutex_t TXLockMutex; /**< TX critical section mutex */
+ sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
+ volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
+ struct pbuf *rxb[ENET_RX_RING_LEN]; /**< RX pbuf pointer list, zero-copy mode */
+ uint8_t *rx_desc_start_addr; /**< RX descriptor start address */
+ uint8_t *tx_desc_start_addr; /**< TX descriptor start address */
+ uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
+ uint8_t rx_fill_index; /**< RX ring fill index */
+ struct pbuf *txb[ENET_TX_RING_LEN]; /**< TX pbuf pointer list, zero-copy mode */
+ void *txb_aligned[ENET_TX_RING_LEN]; /**< TX aligned buffers (if needed) */
+};
+
+static struct k64f_enetdata k64f_enetdata;
+
+static enet_dev_if_t enetDevIf[HW_ENET_INSTANCE_COUNT];
+static enet_mac_config_t g_enetMacCfg[HW_ENET_INSTANCE_COUNT] =
+{
+ {
+ ENET_ETH_MAX_FLEN , /*!< enet receive buffer size*/
+ ENET_RX_LARGE_BUFFER_NUM, /*!< enet large receive buffer number*/
+ ENET_RX_RING_LEN, /*!< enet receive bd number*/
+ ENET_TX_RING_LEN, /*!< enet transmit bd number*/
+ {0}, /*!< enet mac address*/
+ kEnetCfgRmii, /*!< enet rmii interface*/
+ kEnetCfgSpeed100M, /*!< enet rmii 100M*/
+ kEnetCfgFullDuplex, /*!< enet rmii Full- duplex*/
+ /*!< enet mac control flag recommended to use enet_mac_control_flag_t
+ we send frame with crc so receive crc forward for data length check test*/
+ kEnetRxCrcFwdEnable | kEnetRxFlowControlEnable,
+ true, /*!< enet txaccelerator enabled*/
+ true, /*!< enet rxaccelerator enabled*/
+ false, /*!< enet store and forward*/
+ {false, false, true, false, true}, /*!< enet rxaccelerator config*/
+ {false, false, true}, /*!< enet txaccelerator config*/
+ true, /*!< vlan frame support*/
+ true, /*!< phy auto discover*/
+ ENET_MII_CLOCK, /*!< enet MDC clock*/
+ },
+};
+
+static enet_phy_config_t g_enetPhyCfg[HW_ENET_INSTANCE_COUNT] =
+{
+ {0, false}
+};
+
+/** \brief Driver transmit and receive thread priorities
+ *
+ * Thread priorities for receive thread and TX cleanup thread. Alter
+ * to prioritize receive or transmit bandwidth. In a heavily loaded
+ * system or with LEIP_DEBUG enabled, the priorities might be better
+ * the same. */
+#define RX_PRIORITY (osPriorityNormal)
+#define TX_PRIORITY (osPriorityNormal)
+#define PHY_PRIORITY (osPriorityNormal)
+
+/** \brief Debug output formatter lock define
+ *
+ * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
+ * define will allow RX debug messages to not interleave with the
+ * TX messages (so they are actually readable). Not enabling this
+ * define when the system is under load will cause the output to
+ * be unreadable. There is a small tradeoff in performance for this
+ * so use it only for debug. */
+//#define LOCK_RX_THREAD
+
+/** \brief Signal used for ethernet ISR to signal packet_rx() thread.
+ */
+#define RX_SIGNAL 1
+
+// K64F-specific macros
+#define RX_PBUF_AUTO_INDEX (-1)
+
+/********************************************************************************
+ * Buffer management
+ ********************************************************************************/
+
+/** \brief Queues a pbuf into the RX descriptor list
+ *
+ * \param[in] k64f_enet Pointer to the drvier data structure
+ * \param[in] p Pointer to pbuf to queue
+ * \param[in] bidx Index to queue into
+ */
+static void k64f_rxqueue_pbuf(struct k64f_enetdata *k64f_enet, struct pbuf *p, int bidx)
+{
+ enet_bd_struct_t *start = (enet_bd_struct_t *)k64f_enet->rx_desc_start_addr;
+ int idx;
+
+ /* Get next free descriptor index */
+ if (bidx == RX_PBUF_AUTO_INDEX)
+ idx = k64f_enet->rx_fill_index;
+ else
+ idx = bidx;
+
+ /* Setup descriptor and clear statuses */
+ enet_hal_init_rxbds(start + idx, (uint8_t*)p->payload, idx == ENET_RX_RING_LEN - 1);
+
+ /* Save pbuf pointer for push to network layer later */
+ k64f_enet->rxb[idx] = p;
+
+ /* Wrap at end of descriptor list */
+ idx = (idx + 1) % ENET_RX_RING_LEN;
+
+ /* Queue descriptor(s) */
+ k64f_enet->rx_free_descs -= 1;
+
+ if (bidx == RX_PBUF_AUTO_INDEX)
+ k64f_enet->rx_fill_index = idx;
+
+ enet_hal_active_rxbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64f_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
+ k64f_enet->rx_free_descs));
+}
+
+/** \brief Attempt to allocate and requeue a new pbuf for RX
+ *
+ * \param[in] netif Pointer to the netif structure
+ * \returns number of queued packets
+ */
+s32_t k64f_rx_queue(struct netif *netif, int idx)
+{
+ struct k64f_enetdata *k64f_enet = netif->state;
+ enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ struct pbuf *p;
+ int queued = 0;
+
+ /* Attempt to requeue as many packets as possible */
+ while (k64f_enet->rx_free_descs > 0) {
+ /* Allocate a pbuf from the pool. We need to allocate at the
+ maximum size as we don't know the size of the yet to be
+ received packet. */
+ p = pbuf_alloc(PBUF_RAW, enetIfPtr->macCfgPtr->rxBufferSize + RX_BUF_ALIGNMENT, PBUF_RAM);
+ if (p == NULL) {
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
+ k64f_enet->rx_free_descs));
+ return queued;
+ }
+ /* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F
+ RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing
+ a data structure which is internal to lwIP. This might not prove to be a good idea
+ in the long run, but a better fix would probably involve modifying lwIP itself */
+ p->payload = (void*)ENET_ALIGN((uint32_t)p->payload, RX_BUF_ALIGNMENT);
+
+ /* pbufs allocated from the RAM pool should be non-chained. */
+ LWIP_ASSERT("k64f_rx_queue: pbuf is not contiguous (chained)", pbuf_clen(p) <= 1);
+
+ /* Queue packet */
+ k64f_rxqueue_pbuf(k64f_enet, p, idx);
+ queued++;
+ }
+
+ return queued;
+}
+
+/** \brief Sets up the RX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for receive packets.
+ *
+ * \param[in] netif Pointer to driver data structure
+ * \returns ERR_MEM if out of memory, ERR_OK otherwise
+ */
+static err_t k64f_rx_setup(struct netif *netif, enet_rxbd_config_t *rxbdCfg) {
+ struct k64f_enetdata *k64f_enet = netif->state;
+ enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ uint8_t *rxBdPtr;
+ uint32_t rxBufferSizeAligned;
+
+ // Allocate RX descriptors
+ rxBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->rxBdNumber + ENET_BD_ALIGNMENT);
+ if(!rxBdPtr)
+ return ERR_MEM;
+ k64f_enet->rx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)rxBdPtr, ENET_BD_ALIGNMENT);
+ k64f_enet->rx_free_descs = enetIfPtr->macCfgPtr->rxBdNumber;
+ k64f_enet->rx_fill_index = 0;
+
+ rxBufferSizeAligned = ENET_ALIGN(enetIfPtr->macCfgPtr->rxBufferSize, ENET_RX_BUFFER_ALIGNMENT);
+ enetIfPtr->macContextPtr->rxBufferSizeAligned = rxBufferSizeAligned;
+ rxbdCfg->rxBdPtrAlign = k64f_enet->rx_desc_start_addr;
+ rxbdCfg->rxBdNum = enetIfPtr->macCfgPtr->rxBdNumber;
+ rxbdCfg->rxBufferNum = enetIfPtr->macCfgPtr->rxBdNumber;
+
+ k64f_rx_queue(netif, RX_PBUF_AUTO_INDEX);
+ return ERR_OK;
+}
+
+/** \brief Sets up the TX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for transmit packets.
+ *
+ * \param[in] netif Pointer to driver data structure
+ * \returns ERR_MEM if out of memory, ERR_OK otherwise
+ */
+static err_t k64f_tx_setup(struct netif *netif, enet_txbd_config_t *txbdCfg) {
+ struct k64f_enetdata *k64f_enet = netif->state;
+ enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ uint8_t *txBdPtr;
+
+ // Allocate TX descriptors
+ txBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->txBdNumber + ENET_BD_ALIGNMENT);
+ if(!txBdPtr)
+ return ERR_MEM;
+
+ k64f_enet->tx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)txBdPtr, ENET_BD_ALIGNMENT);
+ k64f_enet->tx_consume_index = k64f_enet->tx_produce_index = 0;
+
+ txbdCfg->txBdPtrAlign = k64f_enet->tx_desc_start_addr;
+ txbdCfg->txBufferNum = enetIfPtr->macCfgPtr->txBdNumber;
+ txbdCfg->txBufferSizeAlign = ENET_ALIGN(enetIfPtr->maxFrameSize, ENET_TX_BUFFER_ALIGNMENT);
+
+ // Make the TX descriptor ring circular
+ enet_hal_init_txbds(k64f_enet->tx_desc_start_addr + enet_hal_get_bd_size() * (ENET_TX_RING_LEN - 1), 1);
+
+ return ERR_OK;
+}
+
+/** \brief Free TX buffers that are complete
+ *
+ * \param[in] k64f_enet Pointer to driver data structure
+ */
+static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet)
+{
+ uint8_t i;
+ volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)k64f_enet->tx_desc_start_addr;
+
+ /* Get exclusive access */
+ sys_mutex_lock(&k64f_enet->TXLockMutex);
+
+ // Traverse all descriptors, looking for the ones modified by the uDMA
+ i = k64f_enet->tx_consume_index;
+ while(i != k64f_enet->tx_produce_index && !(bdPtr[i].control & kEnetTxBdReady)) {
+ if (k64f_enet->txb_aligned[i]) {
+ free(k64f_enet->txb_aligned[i]);
+ k64f_enet->txb_aligned[i] = NULL;
+ } else if (k64f_enet->txb[i]) {
+ pbuf_free(k64f_enet->txb[i]);
+ k64f_enet->txb[i] = NULL;
+ }
+ osSemaphoreRelease(k64f_enet->xTXDCountSem.id);
+ bdPtr[i].controlExtend2 &= ~TX_DESC_UPDATED_MASK;
+ i = (i + 1) % ENET_TX_RING_LEN;
+ }
+ k64f_enet->tx_consume_index = i;
+
+ /* Restore access */
+ sys_mutex_unlock(&k64f_enet->TXLockMutex);
+}
+
+/** \brief Low level init of the MAC and PHY.
+ *
+ * \param[in] netif Pointer to LWIP netif structure
+ */
+static err_t low_level_init(struct netif *netif)
+{
+ enet_dev_if_t * enetIfPtr;
+ uint32_t device = BOARD_DEBUG_ENET_INSTANCE_ADDR;
+ enet_rxbd_config_t rxbdCfg;
+ enet_txbd_config_t txbdCfg;
+ enet_phy_speed_t phy_speed;
+ enet_phy_duplex_t phy_duplex;
+
+ k64f_init_eth_hardware();
+
+ /* Initialize device*/
+ enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ enetIfPtr->deviceNumber = device;
+ enetIfPtr->macCfgPtr = &g_enetMacCfg[BOARD_DEBUG_ENET_INSTANCE];
+ enetIfPtr->phyCfgPtr = &g_enetPhyCfg[BOARD_DEBUG_ENET_INSTANCE];
+ enetIfPtr->macApiPtr = &g_enetMacApi;
+ enetIfPtr->phyApiPtr = (void *)&g_enetPhyApi;
+ memcpy(enetIfPtr->macCfgPtr->macAddr, (char*)netif->hwaddr, kEnetMacAddrLen);
+
+ /* Allocate buffer for ENET mac context*/
+ enetIfPtr->macContextPtr = (enet_mac_context_t *)calloc(1, sizeof(enet_mac_context_t));
+ if (!enetIfPtr->macContextPtr) {
+ return ERR_BUF;
+ }
+
+ /* Initialize enet buffers*/
+ if(k64f_rx_setup(netif, &rxbdCfg) != ERR_OK) {
+ return ERR_BUF;
+ }
+ /* Initialize enet buffers*/
+ if(k64f_tx_setup(netif, &txbdCfg) != ERR_OK) {
+ return ERR_BUF;
+ }
+ /* Initialize enet module*/
+ if (enet_mac_init(enetIfPtr, &rxbdCfg, &txbdCfg) == kStatus_ENET_Success)
+ {
+ /* Initialize PHY*/
+ if (enetIfPtr->macCfgPtr->isPhyAutoDiscover) {
+ if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_auto_discover(enetIfPtr) != kStatus_PHY_Success)
+ return ERR_IF;
+ }
+ if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_init(enetIfPtr) != kStatus_PHY_Success)
+ return ERR_IF;
+
+ enetIfPtr->isInitialized = true;
+ }
+ else
+ {
+ // TODOETH: cleanup memory
+ return ERR_IF;
+ }
+
+ /* Get link information from PHY */
+ phy_get_link_speed(enetIfPtr, &phy_speed);
+ phy_get_link_duplex(enetIfPtr, &phy_duplex);
+ BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, phy_speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
+ BW_ENET_TCR_FDEN(enetIfPtr->deviceNumber, phy_duplex == kEnetFullDuplex ? kEnetCfgFullDuplex : kEnetCfgHalfDuplex);
+
+ /* Enable Ethernet module*/
+ enet_hal_config_ethernet(BOARD_DEBUG_ENET_INSTANCE_ADDR, true, true);
+
+ /* Active Receive buffer descriptor must be done after module enable*/
+ enet_hal_active_rxbd(enetIfPtr->deviceNumber);
+
+ return ERR_OK;
+}
+
+/********************************************************************************
+ * LWIP port
+ ********************************************************************************/
+
+/** \brief Ethernet receive interrupt handler
+ *
+ * This function handles the receive interrupt of K64F.
+ */
+void enet_mac_rx_isr(void *enetIfPtr)
+{
+ /* Clear interrupt */
+ enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetRxFrameInterrupt);
+ sys_sem_signal(&k64f_enetdata.RxReadySem);
+}
+
+void enet_mac_tx_isr(void *enetIfPtr)
+{
+ /*Clear interrupt*/
+ enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetTxFrameInterrupt);
+ sys_sem_signal(&k64f_enetdata.TxCleanSem);
+}
+
+/**
+ * This function is the ethernet packet send function. It calls
+ * etharp_output after checking link status.
+ *
+ * \param[in] netif the lwip network interface structure for this enetif
+ * \param[in] q Pointer to pbug to send
+ * \param[in] ipaddr IP address
+ * \return ERR_OK or error code
+ */
+err_t k64f_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
+{
+ /* Only send packet is link is up */
+ if (netif->flags & NETIF_FLAG_LINK_UP)
+ return etharp_output(netif, q, ipaddr);
+
+ return ERR_CONN;
+}
+
+/** \brief Allocates a pbuf and returns the data from the incoming packet.
+ *
+ * \param[in] netif the lwip network interface structure
+ * \param[in] idx index of packet to be read
+ * \return a pbuf filled with the received packet (including MAC header)
+ */
+static struct pbuf *k64f_low_level_input(struct netif *netif, int idx)
+{
+ struct k64f_enetdata *k64f_enet = netif->state;
+ enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
+ struct pbuf *p = NULL;
+ u32_t length = 0, orig_length;
+ const u16_t err_mask = kEnetRxBdTrunc | kEnetRxBdCrc | kEnetRxBdNoOctet | kEnetRxBdLengthViolation;
+
+#ifdef LOCK_RX_THREAD
+ /* Get exclusive access */
+ sys_mutex_lock(&k64f_enet->TXLockMutex);
+#endif
+
+ /* Determine if a frame has been received */
+ if ((bdPtr[idx].control & err_mask) != 0) {
+#if LINK_STATS
+ if ((bdPtr[idx].control & kEnetRxBdLengthViolation) != 0)
+ LINK_STATS_INC(link.lenerr);
+ else
+ LINK_STATS_INC(link.chkerr);
+#endif
+ LINK_STATS_INC(link.drop);
+
+ /* Re-queue the same buffer */
+ k64f_enet->rx_free_descs++;
+ p = k64f_enet->rxb[idx];
+ k64f_enet->rxb[idx] = NULL;
+ k64f_rxqueue_pbuf(k64f_enet, p, idx);
+ p = NULL;
+ } else {
+ /* A packet is waiting, get length */
+ length = enet_hal_get_bd_length(bdPtr + idx);
+
+ /* Zero-copy */
+ p = k64f_enet->rxb[idx];
+ orig_length = p->len;
+ p->len = (u16_t) length;
+
+ /* Free pbuf from descriptor */
+ k64f_enet->rxb[idx] = NULL;
+ k64f_enet->rx_free_descs++;
+
+ /* Attempt to queue new buffer */
+ if (k64f_rx_queue(netif, idx) == 0) {
+ /* Drop frame (out of memory) */
+ LINK_STATS_INC(link.drop);
+
+ /* Re-queue the same buffer */
+ p->len = orig_length;
+ k64f_rxqueue_pbuf(k64f_enet, p, idx);
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64f_low_level_input: Packet index %d dropped for OOM\n",
+ idx));
+#ifdef LOCK_RX_THREAD
+ sys_mutex_unlock(&k64f_enet->TXLockMutex);
+#endif
+
+ return NULL;
+ }
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64f_low_level_input: Packet received: %p, size %d (index=%d)\n",
+ p, length, idx));
+
+ /* Save size */
+ p->tot_len = (u16_t) length;
+ LINK_STATS_INC(link.recv);
+ }
+
+#ifdef LOCK_RX_THREAD
+ sys_mutex_unlock(&k64f_enet->TXLockMutex);
+#endif
+
+ return p;
+}
+
+/** \brief Attempt to read a packet from the EMAC interface.
+ *
+ * \param[in] netif the lwip network interface structure
+ * \param[in] idx index of packet to be read
+ */
+void k64f_enetif_input(struct netif *netif, int idx)
+{
+ struct eth_hdr *ethhdr;
+ struct pbuf *p;
+
+ /* move received packet into a new pbuf */
+ p = k64f_low_level_input(netif, idx);
+ if (p == NULL)
+ return;
+
+ /* points to packet payload, which starts with an Ethernet header */
+ ethhdr = (struct eth_hdr*)p->payload;
+
+ switch (htons(ethhdr->type)) {
+ case ETHTYPE_IP:
+ case ETHTYPE_ARP:
+#if PPPOE_SUPPORT
+ 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, ("k64f_enetif_input: IP input error\n"));
+ /* Free buffer */
+ pbuf_free(p);
+ }
+ break;
+
+ default:
+ /* Return buffer */
+ pbuf_free(p);
+ break;
+ }
+}
+
+/** \brief Packet reception task
+ *
+ * This task is called when a packet is received. It will
+ * pass the packet to the LWIP core.
+ *
+ * \param[in] pvParameters pointer to the interface data
+ */
+static void packet_rx(void* pvParameters) {
+ struct k64f_enetdata *k64f_enet = pvParameters;
+ volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
+ int idx = 0;
+
+ while (1) {
+ /* Wait for receive task to wakeup */
+ sys_arch_sem_wait(&k64f_enet->RxReadySem, 0);
+
+ if ((bdPtr[idx].control & kEnetRxBdEmpty) == 0) {
+ k64f_enetif_input(k64f_enet->netif, idx);
+ idx = (idx + 1) % ENET_RX_RING_LEN;
+ }
+ }
+}
+
+/** \brief Transmit cleanup task
+ *
+ * This task is called when a transmit interrupt occurs and
+ * reclaims the pbuf and descriptor used for the packet once
+ * the packet has been transferred.
+ *
+ * \param[in] pvParameters pointer to the interface data
+ */
+static void packet_tx(void* pvParameters) {
+ struct k64f_enetdata *k64f_enet = pvParameters;
+
+ while (1) {
+ /* Wait for transmit cleanup task to wakeup */
+ sys_arch_sem_wait(&k64f_enet->TxCleanSem, 0);
+ // TODOETH: handle TX underrun?
+ k64f_tx_reclaim(k64f_enet);
+ }
+}
+
+ /** \brief Polls if an available TX descriptor is ready. Can be used to
+ * determine if the low level transmit function will block.
+ *
+ * \param[in] netif the lwip network interface structure
+ * \return 0 if no descriptors are read, or >0
+ */
+s32_t k64f_tx_ready(struct netif *netif)
+{
+ struct k64f_enetdata *k64f_enet = netif->state;
+ s32_t fb;
+ u32_t idx, cidx;
+
+ cidx = k64f_enet->tx_consume_index;
+ idx = k64f_enet->tx_produce_index;
+
+ /* Determine number of free buffers */
+ if (idx == cidx)
+ fb = ENET_TX_RING_LEN;
+ else if (cidx > idx)
+ fb = (ENET_TX_RING_LEN - 1) -
+ ((idx + ENET_TX_RING_LEN) - cidx);
+ else
+ fb = (ENET_TX_RING_LEN - 1) - (cidx - idx);
+
+ return fb;
+}
+
+/*FUNCTION****************************************************************
+ *
+ * Function Name: enet_hal_update_txbds
+ * Description: Update ENET transmit buffer descriptors.
+ *END*********************************************************************/
+void k64f_update_txbds(struct k64f_enetdata *k64f_enet, int idx, uint8_t *buffer, uint16_t length, bool isLast)
+{
+ volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)(k64f_enet->tx_desc_start_addr + idx * enet_hal_get_bd_size());
+
+ bdPtr->length = HTONS(length); /* Set data length*/
+ bdPtr->buffer = (uint8_t *)HTONL((uint32_t)buffer); /* Set data buffer*/
+ if (isLast)
+ bdPtr->control |= kEnetTxBdLast;
+ else
+ bdPtr->control &= ~kEnetTxBdLast;
+ bdPtr->controlExtend1 |= kEnetTxBdTxInterrupt;
+ bdPtr->controlExtend2 &= ~TX_DESC_UPDATED_MASK; // descriptor not updated by DMA
+ bdPtr->control |= kEnetTxBdTransmitCrc | kEnetTxBdReady;
+}
+
+/** \brief Low level output of a packet. Never call this from an
+ * interrupt context, as it may block until TX descriptors
+ * become available.
+ *
+ * \param[in] netif the lwip network interface structure for this netif
+ * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
+ * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
+ */
+static err_t k64f_low_level_output(struct netif *netif, struct pbuf *p)
+{
+ struct k64f_enetdata *k64f_enet = netif->state;
+ struct pbuf *q;
+ u32_t idx;
+ s32_t dn;
+ uint8_t *psend = NULL, *dst;
+
+ /* Get free TX buffer index */
+ idx = k64f_enet->tx_produce_index;
+
+ /* Check the pbuf chain for payloads that are not 8-byte aligned.
+ If found, a new properly aligned buffer needs to be allocated
+ and the data copied there */
+ for (q = p; q != NULL; q = q->next)
+ if (((u32_t)q->payload & (TX_BUF_ALIGNMENT - 1)) != 0)
+ break;
+ if (q != NULL) {
+ // Allocate properly aligned buffer
+ psend = (uint8_t*)malloc(p->tot_len);
+ if (NULL == psend)
+ return ERR_MEM;
+ LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)psend & (TX_BUF_ALIGNMENT - 1)) == 0);
+ for (q = p, dst = psend; q != NULL; q = q->next) {
+ MEMCPY(dst, q->payload, q->len);
+ dst += q->len;
+ }
+ k64f_enet->txb_aligned[idx] = psend;
+ dn = 1;
+ } else {
+ k64f_enet->txb_aligned[idx] = NULL;
+ dn = (s32_t) pbuf_clen(p);
+ pbuf_ref(p);
+ }
+
+ /* Wait until enough descriptors are available for the transfer. */
+ /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
+ while (dn > k64f_tx_ready(netif))
+ osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
+
+ /* Get exclusive access */
+ sys_mutex_lock(&k64f_enet->TXLockMutex);
+
+ /* Setup transfers */
+ q = p;
+ while (dn > 0) {
+ dn--;
+ if (psend != NULL) {
+ k64f_update_txbds(k64f_enet, idx, psend, p->tot_len, 1);
+ k64f_enet->txb[idx] = NULL;
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64f_low_level_output: aligned packet(%p) sent"
+ " size = %d (index=%d)\n", psend, p->tot_len, idx));
+ } else {
+ LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)q->payload & 0x07) == 0);
+
+ /* Only save pointer to free on last descriptor */
+ if (dn == 0) {
+ /* Save size of packet and signal it's ready */
+ k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 1);
+ k64f_enet->txb[idx] = p;
+ }
+ else {
+ /* Save size of packet, descriptor is not last */
+ k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 0);
+ k64f_enet->txb[idx] = NULL;
+ }
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("k64f_low_level_output: pbuf packet(%p) sent, chain#=%d,"
+ " size = %d (index=%d)\n", q->payload, dn, q->len, idx));
+ }
+
+ q = q->next;
+
+ idx = (idx + 1) % ENET_TX_RING_LEN;
+ }
+
+ k64f_enet->tx_produce_index = idx;
+ enet_hal_active_txbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
+ LINK_STATS_INC(link.xmit);
+
+ /* Restore access */
+ sys_mutex_unlock(&k64f_enet->TXLockMutex);
+
+ return ERR_OK;
+}
+
+/*******************************************************************************
+ * PHY task: monitor link
+*******************************************************************************/
+
+#define PHY_TASK_PERIOD_MS 200
+#define STATE_UNKNOWN (-1)
+
+typedef struct {
+ int connected;
+ enet_phy_speed_t speed;
+ enet_phy_duplex_t duplex;
+} PHY_STATE;
+
+int phy_link_status() {
+ bool connection_status;
+ enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ phy_get_link_status(enetIfPtr, &connection_status);
+ return (int)connection_status;
+}
+
+static void k64f_phy_task(void *data) {
+ struct netif *netif = (struct netif*)data;
+ bool connection_status;
+ enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
+ PHY_STATE crt_state = {STATE_UNKNOWN, (enet_phy_speed_t)STATE_UNKNOWN, (enet_phy_duplex_t)STATE_UNKNOWN};
+ PHY_STATE prev_state;
+
+ prev_state = crt_state;
+ while (true) {
+ // Get current status
+ phy_get_link_status(enetIfPtr, &connection_status);
+ crt_state.connected = connection_status ? 1 : 0;
+ phy_get_link_speed(enetIfPtr, &crt_state.speed);
+ phy_get_link_duplex(enetIfPtr, &crt_state.duplex);
+
+ // Compare with previous state
+ if (crt_state.connected != prev_state.connected) {
+ if (crt_state.connected)
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
+ else
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
+ }
+
+ if (crt_state.speed != prev_state.speed)
+ BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, crt_state.speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
+
+ // TODO: duplex change requires disable/enable of Ethernet interface, to be implemented
+
+ prev_state = crt_state;
+ osDelay(PHY_TASK_PERIOD_MS);
+ }
+}
+
+/**
+ * Should be called at the beginning of the program to set up the
+ * network interface.
+ *
+ * This function should be passed as a parameter to netif_add().
+ *
+ * @param[in] netif the lwip network interface structure for this netif
+ * @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 eth_arch_enetif_init(struct netif *netif)
+{
+ err_t err;
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+
+ k64f_enetdata.netif = netif;
+
+ /* set MAC hardware address */
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+ netif->hwaddr[0] = MBED_MAC_ADDR_0;
+ netif->hwaddr[1] = MBED_MAC_ADDR_1;
+ netif->hwaddr[2] = MBED_MAC_ADDR_2;
+ netif->hwaddr[3] = MBED_MAC_ADDR_3;
+ netif->hwaddr[4] = MBED_MAC_ADDR_4;
+ netif->hwaddr[5] = MBED_MAC_ADDR_5;
+#else
+ mbed_mac_address((char *)netif->hwaddr);
+#endif
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* maximum transfer unit */
+ netif->mtu = 1500;
+
+ /* device capabilities */
+ // TODOETH: check if the flags are correct below
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+
+ /* Initialize the hardware */
+ netif->state = &k64f_enetdata;
+ err = low_level_init(netif);
+ if (err != ERR_OK)
+ return err;
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ netif->hostname = "lwipk64f";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ netif->name[0] = 'e';
+ netif->name[1] = 'n';
+
+ netif->output = k64f_etharp_output;
+ netif->linkoutput = k64f_low_level_output;
+
+ /* CMSIS-RTOS, start tasks */
+#ifdef CMSIS_OS_RTX
+ memset(k64f_enetdata.xTXDCountSem.data, 0, sizeof(k64f_enetdata.xTXDCountSem.data));
+ k64f_enetdata.xTXDCountSem.def.semaphore = k64f_enetdata.xTXDCountSem.data;
+#endif
+ k64f_enetdata.xTXDCountSem.id = osSemaphoreCreate(&k64f_enetdata.xTXDCountSem.def, ENET_TX_RING_LEN);
+
+ LWIP_ASSERT("xTXDCountSem creation error", (k64f_enetdata.xTXDCountSem.id != NULL));
+
+ err = sys_mutex_new(&k64f_enetdata.TXLockMutex);
+ LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
+
+ /* Packet receive task */
+ err = sys_sem_new(&k64f_enetdata.RxReadySem, 0);
+ LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
+ sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
+
+ /* Transmit cleanup task */
+ err = sys_sem_new(&k64f_enetdata.TxCleanSem, 0);
+ LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
+ sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
+
+ /* PHY monitoring task */
+ sys_thread_new("phy_thread", k64f_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_PRIORITY);
+
+ /* Allow the PHY task to detect the initial link state and set up the proper flags */
+ osDelay(10);
+
+ return ERR_OK;
+}
+
+void eth_arch_enable_interrupts(void) {
+ enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true);
+ INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
+ INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
+}
+
+void eth_arch_disable_interrupts(void) {
+ INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
+ INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
+}
+
+void ENET_Transmit_IRQHandler(void)
+{
+ enet_mac_tx_isr(enetIfHandle);
+}
+
+void ENET_Receive_IRQHandler(void)
+{
+ enet_mac_rx_isr(enetIfHandle);
+}
+
+#if FSL_FEATURE_ENET_SUPPORT_PTP
+void ENET_1588_Timer_IRQHandler(void)
+{
+ enet_mac_ts_isr(enetIfHandle);
+}
+#endif
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h
new file mode 100644
index 0000000000..fda77aaebc
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 - 2014, Freescale Semiconductor, 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:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o 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.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. 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 K64F_EMAC_CONFIG_H__
+#define K64F_EMAC_CONFIG_H__
+
+#define ENET_RX_RING_LEN (16)
+#define ENET_TX_RING_LEN (8)
+#define ENET_RX_LARGE_BUFFER_NUM (0)
+#define ENET_RX_BUFFER_ALIGNMENT (16)
+#define ENET_TX_BUFFER_ALIGNMENT (16)
+#define ENET_BD_ALIGNMENT (16)
+#define ENET_MII_CLOCK (2500000L)
+#define RX_BUF_ALIGNMENT (16)
+#define TX_BUF_ALIGNMENT (8)
+#define BOARD_DEBUG_ENET_INSTANCE (0)
+#define BOARD_DEBUG_ENET_INSTANCE_ADDR (ENET_BASE)
+
+#define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int phy_link_status(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // #define K64F_EMAC_CONFIG_H__
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h
new file mode 100644
index 0000000000..4b135c6f13
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_CONF_H
+#define LWIPOPTS_CONF_H
+
+#include "k64f_emac_config.h"
+
+#define LWIP_TRANSPORT_ETHERNET 1
+#define ETH_PAD_SIZE 2
+
+#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + RX_BUF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN)
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17_emac.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17_emac.c
new file mode 100644
index 0000000000..82ad9b951c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17_emac.c
@@ -0,0 +1,1046 @@
+/**********************************************************************
+* $Id$ lpc17_emac.c 2011-11-20
+*//**
+* @file lpc17_emac.c
+* @brief LPC17 ethernet driver for LWIP
+* @version 1.0
+* @date 20. Nov. 2011
+* @author NXP MCU SW Application Team
+*
+* Copyright(C) 2011, NXP Semiconductor
+* All rights reserved.
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+#include "lwip/opt.h"
+#include "lwip/sys.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "netif/etharp.h"
+#include "netif/ppp_oe.h"
+
+#include "lpc17xx_emac.h"
+#include "eth_arch.h"
+#include "lpc_emac_config.h"
+#include "lpc_phy.h"
+#include "sys_arch.h"
+
+#include "mbed_interface.h"
+#include <string.h>
+
+#ifndef LPC_EMAC_RMII
+#error LPC_EMAC_RMII is not defined!
+#endif
+
+#if LPC_NUM_BUFF_TXDESCS < 2
+#error LPC_NUM_BUFF_TXDESCS must be at least 2
+#endif
+
+#if LPC_NUM_BUFF_RXDESCS < 3
+#error LPC_NUM_BUFF_RXDESCS must be at least 3
+#endif
+
+/** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP
+ * @ingroup lwip_emac
+ *
+ * @{
+ */
+
+#if NO_SYS == 0
+/** \brief Driver transmit and receive thread priorities
+ *
+ * Thread priorities for receive thread and TX cleanup thread. Alter
+ * to prioritize receive or transmit bandwidth. In a heavily loaded
+ * system or with LEIP_DEBUG enabled, the priorities might be better
+ * the same. */
+#define RX_PRIORITY (osPriorityNormal)
+#define TX_PRIORITY (osPriorityNormal)
+
+/** \brief Debug output formatter lock define
+ *
+ * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
+ * define will allow RX debug messages to not interleave with the
+ * TX messages (so they are actually readable). Not enabling this
+ * define when the system is under load will cause the output to
+ * be unreadable. There is a small tradeoff in performance for this
+ * so use it only for debug. */
+//#define LOCK_RX_THREAD
+
+/** \brief Receive group interrupts
+ */
+#define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE)
+
+/** \brief Transmit group interrupts
+ */
+#define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE)
+
+/** \brief Signal used for ethernet ISR to signal packet_rx() thread.
+ */
+#define RX_SIGNAL 1
+
+#else
+#define RXINTGROUP 0
+#define TXINTGROUP 0
+#endif
+
+ /** \brief Structure of a TX/RX descriptor
+ */
+typedef struct
+{
+ volatile u32_t packet; /**< Pointer to buffer */
+ volatile u32_t control; /**< Control word */
+} LPC_TXRX_DESC_T;
+
+/** \brief Structure of a RX status entry
+ */
+typedef struct
+{
+ volatile u32_t statusinfo; /**< RX status word */
+ volatile u32_t statushashcrc; /**< RX hash CRC */
+} LPC_TXRX_STATUS_T;
+
+/* LPC EMAC driver data structure */
+struct lpc_enetdata {
+ /* prxs must be 8 byte aligned! */
+ LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */
+ struct netif *netif; /**< Reference back to LWIP parent netif */
+ LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */
+ LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */
+ LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */
+ struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */
+ u32_t rx_fill_desc_index; /**< RX descriptor next available index */
+ volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
+ struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */
+ u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */
+#if NO_SYS == 0
+ sys_thread_t RxThread; /**< RX receive thread data object pointer */
+ sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
+ sys_mutex_t TXLockMutex; /**< TX critical section mutex */
+ sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
+#endif
+};
+
+#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+# if defined (__ICCARM__)
+# define ETHMEM_SECTION
+# elif defined(TOOLCHAIN_GCC_CR)
+# define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"), aligned))
+# else
+# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
+# endif
+#elif defined(TARGET_LPC1768)
+# if defined(TOOLCHAIN_GCC_ARM)
+# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
+# endif
+#endif
+
+#ifndef ETHMEM_SECTION
+#define ETHMEM_SECTION ALIGNED(8)
+#endif
+
+/** \brief LPC EMAC driver work data
+ */
+ETHMEM_SECTION struct lpc_enetdata lpc_enetdata;
+
+/** \brief Queues a pbuf into the RX descriptor list
+ *
+ * \param[in] lpc_enetif Pointer to the drvier data structure
+ * \param[in] p Pointer to pbuf to queue
+ */
+static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_enetif, struct pbuf *p)
+{
+ u32_t idx;
+
+ /* Get next free descriptor index */
+ idx = lpc_enetif->rx_fill_desc_index;
+
+ /* Setup descriptor and clear statuses */
+ lpc_enetif->prxd[idx].control = EMAC_RCTRL_INT | ((u32_t) (p->len - 1));
+ lpc_enetif->prxd[idx].packet = (u32_t) p->payload;
+ lpc_enetif->prxs[idx].statusinfo = 0xFFFFFFFF;
+ lpc_enetif->prxs[idx].statushashcrc = 0xFFFFFFFF;
+
+ /* Save pbuf pointer for push to network layer later */
+ lpc_enetif->rxb[idx] = p;
+
+ /* Wrap at end of descriptor list */
+ idx++;
+ if (idx >= LPC_NUM_BUFF_RXDESCS)
+ idx = 0;
+
+ /* Queue descriptor(s) */
+ lpc_enetif->rx_free_descs -= 1;
+ lpc_enetif->rx_fill_desc_index = idx;
+ LPC_EMAC->RxConsumeIndex = idx;
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
+ lpc_enetif->rx_free_descs));
+}
+
+/** \brief Attempt to allocate and requeue a new pbuf for RX
+ *
+ * \param[in] netif Pointer to the netif structure
+ * \returns 1 if a packet was allocated and requeued, otherwise 0
+ */
+s32_t lpc_rx_queue(struct netif *netif)
+{
+ struct lpc_enetdata *lpc_enetif = netif->state;
+ struct pbuf *p;
+ s32_t queued = 0;
+
+ /* Attempt to requeue as many packets as possible */
+ while (lpc_enetif->rx_free_descs > 0) {
+ /* Allocate a pbuf from the pool. We need to allocate at the
+ maximum size as we don't know the size of the yet to be
+ received packet. */
+ p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
+ if (p == NULL) {
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
+ lpc_enetif->rx_free_descs));
+ return queued;
+ }
+
+ /* pbufs allocated from the RAM pool should be non-chained. */
+ LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
+ pbuf_clen(p) <= 1);
+
+ /* Queue packet */
+ lpc_rxqueue_pbuf(lpc_enetif, p);
+
+ /* Update queued count */
+ queued++;
+ }
+
+ return queued;
+}
+
+/** \brief Sets up the RX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for receive packets.
+ *
+ * \param[in] lpc_enetif Pointer to driver data structure
+ * \returns Always returns ERR_OK
+ */
+static err_t lpc_rx_setup(struct lpc_enetdata *lpc_enetif)
+{
+ /* Setup pointers to RX structures */
+ LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetif->prxd[0];
+ LPC_EMAC->RxStatus = (u32_t) &lpc_enetif->prxs[0];
+ LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1;
+
+ lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS;
+ lpc_enetif->rx_fill_desc_index = 0;
+
+ /* Build RX buffer and descriptors */
+ lpc_rx_queue(lpc_enetif->netif);
+
+ return ERR_OK;
+}
+
+/** \brief Allocates a pbuf and returns the data from the incoming packet.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ * \return a pbuf filled with the received packet (including MAC header)
+ * NULL on memory error
+ */
+static struct pbuf *lpc_low_level_input(struct netif *netif)
+{
+ struct lpc_enetdata *lpc_enetif = netif->state;
+ struct pbuf *p = NULL;
+ u32_t idx, length;
+ u16_t origLength;
+
+#ifdef LOCK_RX_THREAD
+#if NO_SYS == 0
+ /* Get exclusive access */
+ sys_mutex_lock(&lpc_enetif->TXLockMutex);
+#endif
+#endif
+
+ /* Monitor RX overrun status. This should never happen unless
+ (possibly) the internal bus is behing held up by something.
+ Unless your system is running at a very low clock speed or
+ there are possibilities that the internal buses may be held
+ up for a long time, this can probably safely be removed. */
+ if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) {
+ LINK_STATS_INC(link.err);
+ LINK_STATS_INC(link.drop);
+
+ /* Temporarily disable RX */
+ LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
+
+ /* Reset the RX side */
+ LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX;
+ LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN;
+
+ /* De-allocate all queued RX pbufs */
+ for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
+ if (lpc_enetif->rxb[idx] != NULL) {
+ pbuf_free(lpc_enetif->rxb[idx]);
+ lpc_enetif->rxb[idx] = NULL;
+ }
+ }
+
+ /* Start RX side again */
+ lpc_rx_setup(lpc_enetif);
+
+ /* Re-enable RX */
+ LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
+
+#ifdef LOCK_RX_THREAD
+#if NO_SYS == 0
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+#endif
+
+ return NULL;
+ }
+
+ /* Determine if a frame has been received */
+ length = 0;
+ idx = LPC_EMAC->RxConsumeIndex;
+ if (LPC_EMAC->RxProduceIndex != idx) {
+ /* Handle errors */
+ if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
+ EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) {
+#if LINK_STATS
+ if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
+ EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR))
+ LINK_STATS_INC(link.chkerr);
+ if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR)
+ LINK_STATS_INC(link.lenerr);
+#endif
+
+ /* Drop the frame */
+ LINK_STATS_INC(link.drop);
+
+ /* Re-queue the pbuf for receive */
+ lpc_enetif->rx_free_descs++;
+ p = lpc_enetif->rxb[idx];
+ lpc_enetif->rxb[idx] = NULL;
+ lpc_rxqueue_pbuf(lpc_enetif, p);
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
+ lpc_enetif->prxs[idx].statusinfo));
+
+ p = NULL;
+ } else {
+ /* A packet is waiting, get length */
+ length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1;
+
+ /* Zero-copy */
+ p = lpc_enetif->rxb[idx];
+ origLength = p->len;
+ p->len = (u16_t) length;
+
+ /* Free pbuf from descriptor */
+ lpc_enetif->rxb[idx] = NULL;
+ lpc_enetif->rx_free_descs++;
+
+ /* Attempt to queue new buffer(s) */
+ if (lpc_rx_queue(lpc_enetif->netif) == 0) {
+ /* Drop the frame due to OOM. */
+ LINK_STATS_INC(link.drop);
+
+ /* Re-queue the pbuf for receive */
+ p->len = origLength;
+ lpc_rxqueue_pbuf(lpc_enetif, p);
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_low_level_input: Packet index %d dropped for OOM\n",
+ idx));
+
+#ifdef LOCK_RX_THREAD
+#if NO_SYS == 0
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+#endif
+
+ return NULL;
+ }
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n",
+ p, length, idx));
+
+ /* Save size */
+ p->tot_len = (u16_t) length;
+ LINK_STATS_INC(link.recv);
+ }
+ }
+
+#ifdef LOCK_RX_THREAD
+#if NO_SYS == 0
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+#endif
+
+ return p;
+}
+
+/** \brief Attempt to read a packet from the EMAC interface.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ */
+void lpc_enetif_input(struct netif *netif)
+{
+ struct eth_hdr *ethhdr;
+ struct pbuf *p;
+
+ /* move received packet into a new pbuf */
+ p = lpc_low_level_input(netif);
+ if (p == NULL)
+ return;
+
+ /* points to packet payload, which starts with an Ethernet header */
+ ethhdr = p->payload;
+
+ switch (htons(ethhdr->type)) {
+ case ETHTYPE_IP:
+ case ETHTYPE_ARP:
+#if PPPOE_SUPPORT
+ 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, ("lpc_enetif_input: IP input error\n"));
+ /* Free buffer */
+ pbuf_free(p);
+ }
+ break;
+
+ default:
+ /* Return buffer */
+ pbuf_free(p);
+ break;
+ }
+}
+
+/** \brief Determine if the passed address is usable for the ethernet
+ * DMA controller.
+ *
+ * \param[in] addr Address of packet to check for DMA safe operation
+ * \return 1 if the packet address is not safe, otherwise 0
+ */
+static s32_t lpc_packet_addr_notsafe(void *addr) {
+ /* Check for legal address ranges */
+#if defined(TARGET_LPC1768)
+ if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) {
+#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+ if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20007FFF))) {
+#endif
+ return 0;
+ }
+ return 1;
+}
+
+/** \brief Sets up the TX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for transmit packets.
+ *
+ * \param[in] lpc_enetif Pointer to driver data structure
+ */
+static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif)
+{
+ s32_t idx;
+
+ /* Build TX descriptors for local buffers */
+ for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
+ lpc_enetif->ptxd[idx].control = 0;
+ lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF;
+ }
+
+ /* Setup pointers to TX structures */
+ LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0];
+ LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0];
+ LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;
+
+ lpc_enetif->lpc_last_tx_idx = 0;
+
+ return ERR_OK;
+}
+
+/** \brief Free TX buffers that are complete
+ *
+ * \param[in] lpc_enetif Pointer to driver data structure
+ * \param[in] cidx EMAC current descriptor comsumer index
+ */
+static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx)
+{
+#if NO_SYS == 0
+ /* Get exclusive access */
+ sys_mutex_lock(&lpc_enetif->TXLockMutex);
+#endif
+
+ while (cidx != lpc_enetif->lpc_last_tx_idx) {
+ if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) {
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
+ lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx],
+ lpc_enetif->lpc_last_tx_idx));
+ pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]);
+ lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL;
+ }
+
+#if NO_SYS == 0
+ osSemaphoreRelease(lpc_enetif->xTXDCountSem.id);
+#endif
+ lpc_enetif->lpc_last_tx_idx++;
+ if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS)
+ lpc_enetif->lpc_last_tx_idx = 0;
+ }
+
+#if NO_SYS == 0
+ /* Restore access */
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+}
+
+/** \brief User call for freeingTX buffers that are complete
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ */
+void lpc_tx_reclaim(struct netif *netif)
+{
+ lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state,
+ LPC_EMAC->TxConsumeIndex);
+}
+
+ /** \brief Polls if an available TX descriptor is ready. Can be used to
+ * determine if the low level transmit function will block.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ * \return 0 if no descriptors are read, or >0
+ */
+s32_t lpc_tx_ready(struct netif *netif)
+{
+ s32_t fb;
+ u32_t idx, cidx;
+
+ cidx = LPC_EMAC->TxConsumeIndex;
+ idx = LPC_EMAC->TxProduceIndex;
+
+ /* Determine number of free buffers */
+ if (idx == cidx)
+ fb = LPC_NUM_BUFF_TXDESCS;
+ else if (cidx > idx)
+ fb = (LPC_NUM_BUFF_TXDESCS - 1) -
+ ((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
+ else
+ fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);
+
+ return fb;
+}
+
+/** \brief Low level output of a packet. Never call this from an
+ * interrupt context, as it may block until TX descriptors
+ * become available.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
+ * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
+ */
+static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
+{
+ struct lpc_enetdata *lpc_enetif = netif->state;
+ struct pbuf *q;
+ u8_t *dst;
+ u32_t idx, notdmasafe = 0;
+ struct pbuf *np;
+ s32_t dn;
+
+ /* Zero-copy TX buffers may be fragmented across mutliple payload
+ chains. Determine the number of descriptors needed for the
+ transfer. The pbuf chaining can be a mess! */
+ dn = (s32_t) pbuf_clen(p);
+
+ /* Test to make sure packet addresses are DMA safe. A DMA safe
+ address is once that uses external memory or periphheral RAM.
+ IRAM and FLASH are not safe! */
+ for (q = p; q != NULL; q = q->next)
+ notdmasafe += lpc_packet_addr_notsafe(q->payload);
+
+#if LPC_TX_PBUF_BOUNCE_EN==1
+ /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
+ created that will be used instead. This requires an copy from the
+ non-safe DMA region to the new pbuf */
+ if (notdmasafe) {
+ /* Allocate a pbuf in DMA memory */
+ np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+ if (np == NULL)
+ return ERR_MEM;
+
+ /* This buffer better be contiguous! */
+ LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
+ (pbuf_clen(np) == 1));
+
+ /* Copy to DMA safe pbuf */
+ dst = (u8_t *) np->payload;
+ for(q = p; q != NULL; q = q->next) {
+ /* Copy the buffer to the descriptor's buffer */
+ MEMCPY(dst, (u8_t *) q->payload, q->len);
+ dst += q->len;
+ }
+ np->len = p->tot_len;
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
+ q, np));
+
+ /* use the new buffer for descrptor queueing. The original pbuf will
+ be de-allocated outsuide this driver. */
+ p = np;
+ dn = 1;
+ }
+#else
+ if (notdmasafe)
+ LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
+ (notdmasafe == 0));
+#endif
+
+ /* Wait until enough descriptors are available for the transfer. */
+ /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
+ while (dn > lpc_tx_ready(netif))
+#if NO_SYS == 0
+ osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever);
+#else
+ osDelay(1);
+#endif
+
+ /* Get free TX buffer index */
+ idx = LPC_EMAC->TxProduceIndex;
+
+#if NO_SYS == 0
+ /* Get exclusive access */
+ sys_mutex_lock(&lpc_enetif->TXLockMutex);
+#endif
+
+ /* Prevent LWIP from de-allocating this pbuf. The driver will
+ free it once it's been transmitted. */
+ if (!notdmasafe)
+ pbuf_ref(p);
+
+ /* Setup transfers */
+ q = p;
+ while (dn > 0) {
+ dn--;
+
+ /* Only save pointer to free on last descriptor */
+ if (dn == 0) {
+ /* Save size of packet and signal it's ready */
+ lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
+ EMAC_TCTRL_LAST;
+ lpc_enetif->txb[idx] = p;
+ }
+ else {
+ /* Save size of packet, descriptor is not last */
+ lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
+ lpc_enetif->txb[idx] = NULL;
+ }
+
+ LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+ ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
+ " size = %d (index=%d)\n", q->payload, dn, q->len, idx));
+
+ lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;
+
+ q = q->next;
+
+ idx++;
+ if (idx >= LPC_NUM_BUFF_TXDESCS)
+ idx = 0;
+ }
+
+ LPC_EMAC->TxProduceIndex = idx;
+
+ LINK_STATS_INC(link.xmit);
+
+#if NO_SYS == 0
+ /* Restore access */
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+
+ return ERR_OK;
+}
+
+/** \brief LPC EMAC interrupt handler.
+ *
+ * This function handles the transmit, receive, and error interrupt of
+ * the LPC177x_8x. This is meant to be used when NO_SYS=0.
+ */
+void ENET_IRQHandler(void)
+{
+#if NO_SYS == 1
+ /* Interrupts are not used without an RTOS */
+ NVIC_DisableIRQ(ENET_IRQn);
+#else
+ uint32_t ints;
+
+ /* Interrupts are of 2 groups - transmit or receive. Based on the
+ interrupt, kick off the receive or transmit (cleanup) task */
+
+ /* Get pending interrupts */
+ ints = LPC_EMAC->IntStatus;
+
+ if (ints & RXINTGROUP) {
+ /* RX group interrupt(s): Give signal to wakeup RX receive task.*/
+ osSignalSet(lpc_enetdata.RxThread->id, RX_SIGNAL);
+ }
+
+ if (ints & TXINTGROUP) {
+ /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */
+ sys_sem_signal(&lpc_enetdata.TxCleanSem);
+ }
+
+ /* Clear pending interrupts */
+ LPC_EMAC->IntClear = ints;
+#endif
+}
+
+#if NO_SYS == 0
+/** \brief Packet reception task
+ *
+ * This task is called when a packet is received. It will
+ * pass the packet to the LWIP core.
+ *
+ * \param[in] pvParameters Not used yet
+ */
+static void packet_rx(void* pvParameters) {
+ struct lpc_enetdata *lpc_enetif = pvParameters;
+
+ while (1) {
+ /* Wait for receive task to wakeup */
+ osSignalWait(RX_SIGNAL, osWaitForever);
+
+ /* Process packets until all empty */
+ while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
+ lpc_enetif_input(lpc_enetif->netif);
+ }
+}
+
+/** \brief Transmit cleanup task
+ *
+ * This task is called when a transmit interrupt occurs and
+ * reclaims the pbuf and descriptor used for the packet once
+ * the packet has been transferred.
+ *
+ * \param[in] pvParameters Not used yet
+ */
+static void packet_tx(void* pvParameters) {
+ struct lpc_enetdata *lpc_enetif = pvParameters;
+ s32_t idx;
+
+ while (1) {
+ /* Wait for transmit cleanup task to wakeup */
+ sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0);
+
+ /* Error handling for TX underruns. This should never happen unless
+ something is holding the bus or the clocks are going too slow. It
+ can probably be safely removed. */
+ if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
+ LINK_STATS_INC(link.err);
+ LINK_STATS_INC(link.drop);
+
+#if NO_SYS == 0
+ /* Get exclusive access */
+ sys_mutex_lock(&lpc_enetif->TXLockMutex);
+#endif
+ /* Reset the TX side */
+ LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
+ LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;
+
+ /* De-allocate all queued TX pbufs */
+ for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
+ if (lpc_enetif->txb[idx] != NULL) {
+ pbuf_free(lpc_enetif->txb[idx]);
+ lpc_enetif->txb[idx] = NULL;
+ }
+ }
+
+#if NO_SYS == 0
+ /* Restore access */
+ sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+ /* Start TX side again */
+ lpc_tx_setup(lpc_enetif);
+ } else {
+ /* Free TX buffers that are done sending */
+ lpc_tx_reclaim(lpc_enetdata.netif);
+ }
+ }
+}
+#endif
+
+/** \brief Low level init of the MAC and PHY.
+ *
+ * \param[in] netif Pointer to LWIP netif structure
+ */
+static err_t low_level_init(struct netif *netif)
+{
+ struct lpc_enetdata *lpc_enetif = netif->state;
+ err_t err = ERR_OK;
+
+ /* Enable MII clocking */
+ LPC_SC->PCONP |= CLKPWR_PCONP_PCENET;
+
+#if defined(TARGET_LPC1768)
+ LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */
+ LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
+#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+ LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */
+ LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */
+ LPC_IOCON->P1_1 &= ~0x07;
+ LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */
+ LPC_IOCON->P1_4 &= ~0x07;
+ LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */
+ LPC_IOCON->P1_8 &= ~0x07;
+ LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */
+ LPC_IOCON->P1_9 &= ~0x07;
+ LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */
+ LPC_IOCON->P1_10 &= ~0x07;
+ LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */
+ LPC_IOCON->P1_14 &= ~0x07;
+ LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */
+ LPC_IOCON->P1_15 &= ~0x07;
+ LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */
+ LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */
+ LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */
+ LPC_IOCON->P1_17 &= ~0x07;
+ LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */
+#endif
+
+ /* Reset all MAC logic */
+ LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
+ EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES |
+ EMAC_MAC1_SOFT_RES;
+ LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES |
+ EMAC_CR_PASS_RUNT_FRM;
+ osDelay(10);
+
+ /* Initial MAC initialization */
+ LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
+ LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN |
+ EMAC_MAC2_VLAN_PAD_EN;
+ LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
+
+ /* Set RMII management clock rate to lowest speed */
+ LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII;
+ LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII;
+
+ /* Maximum number of retries, 0x37 collision window, gap */
+ LPC_EMAC->CLRT = EMAC_CLRT_DEF;
+ LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF;
+
+#if LPC_EMAC_RMII
+ /* RMII setup */
+ LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII;
+#else
+ /* MII setup */
+ LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM;
+#endif
+
+ /* Initialize the PHY and reset */
+ err = lpc_phy_init(netif, LPC_EMAC_RMII);
+ if (err != ERR_OK)
+ return err;
+
+ /* Save station address */
+ LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] |
+ (((u32_t) netif->hwaddr[1]) << 8);
+ LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] |
+ (((u32_t) netif->hwaddr[3]) << 8);
+ LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] |
+ (((u32_t) netif->hwaddr[5]) << 8);
+
+ /* Setup transmit and receive descriptors */
+ if (lpc_tx_setup(lpc_enetif) != ERR_OK)
+ return ERR_BUF;
+ if (lpc_rx_setup(lpc_enetif) != ERR_OK)
+ return ERR_BUF;
+
+ /* Enable packet reception */
+#if IP_SOF_BROADCAST_RECV
+ LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN;
+#else
+ LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN;
+#endif
+
+ /* Clear and enable rx/tx interrupts */
+ LPC_EMAC->IntClear = 0xFFFF;
+ LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP;
+
+ /* Enable RX and TX */
+ LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN;
+ LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
+
+ return err;
+}
+
+/* This function provides a method for the PHY to setup the EMAC
+ for the PHY negotiated duplex mode */
+void lpc_emac_set_duplex(int full_duplex)
+{
+ if (full_duplex) {
+ LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
+ LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
+ LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
+ } else {
+ LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP;
+ LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP;
+ LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
+ }
+}
+
+/* This function provides a method for the PHY to setup the EMAC
+ for the PHY negotiated bit rate */
+void lpc_emac_set_speed(int mbs_100)
+{
+ if (mbs_100)
+ LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
+ else
+ LPC_EMAC->SUPP = 0;
+}
+
+/**
+ * This function is the ethernet packet send function. It calls
+ * etharp_output after checking link status.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ * \param[in] q Pointer to pbug to send
+ * \param[in] ipaddr IP address
+ * \return ERR_OK or error code
+ */
+err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
+ ip_addr_t *ipaddr)
+{
+ /* Only send packet is link is up */
+ if (netif->flags & NETIF_FLAG_LINK_UP)
+ return etharp_output(netif, q, ipaddr);
+
+ return ERR_CONN;
+}
+
+#if NO_SYS == 0
+/* periodic PHY status update */
+void phy_update(void const *nif) {
+ lpc_phy_sts_sm((struct netif*)nif);
+}
+osTimerDef(phy_update, phy_update);
+#endif
+
+/**
+ * Should be called at the beginning of the program to set up the
+ * network interface.
+ *
+ * This function should be passed as a parameter to netif_add().
+ *
+ * @param[in] netif the lwip network interface structure for this lpc_enetif
+ * @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 eth_arch_enetif_init(struct netif *netif)
+{
+ err_t err;
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+
+ lpc_enetdata.netif = netif;
+
+ /* set MAC hardware address */
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+ netif->hwaddr[0] = MBED_MAC_ADDR_0;
+ netif->hwaddr[1] = MBED_MAC_ADDR_1;
+ netif->hwaddr[2] = MBED_MAC_ADDR_2;
+ netif->hwaddr[3] = MBED_MAC_ADDR_3;
+ netif->hwaddr[4] = MBED_MAC_ADDR_4;
+ netif->hwaddr[5] = MBED_MAC_ADDR_5;
+#else
+ mbed_mac_address((char *)netif->hwaddr);
+#endif
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* maximum transfer unit */
+ netif->mtu = 1500;
+
+ /* device capabilities */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+
+ /* Initialize the hardware */
+ netif->state = &lpc_enetdata;
+ err = low_level_init(netif);
+ if (err != ERR_OK)
+ return err;
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ netif->hostname = "lwiplpc";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ netif->name[0] = 'e';
+ netif->name[1] = 'n';
+
+ netif->output = lpc_etharp_output;
+ netif->linkoutput = lpc_low_level_output;
+
+ /* CMSIS-RTOS, start tasks */
+#if NO_SYS == 0
+#ifdef CMSIS_OS_RTX
+ memset(lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data));
+ lpc_enetdata.xTXDCountSem.def.semaphore = lpc_enetdata.xTXDCountSem.data;
+#endif
+ lpc_enetdata.xTXDCountSem.id = osSemaphoreCreate(&lpc_enetdata.xTXDCountSem.def, LPC_NUM_BUFF_TXDESCS);
+ LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL));
+
+ err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
+ LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
+
+ /* Packet receive task */
+ lpc_enetdata.RxThread = sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
+ LWIP_ASSERT("RxThread creation error", (lpc_enetdata.RxThread));
+
+ /* Transmit cleanup task */
+ err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0);
+ LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
+ sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
+
+ /* periodic PHY status update */
+ osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif);
+ osTimerStart(phy_timer, 250);
+#endif
+
+ return ERR_OK;
+}
+
+void eth_arch_enable_interrupts(void) {
+ NVIC_SetPriority(ENET_IRQn, ((0x01 << 3) | 0x01));
+ NVIC_EnableIRQ(ENET_IRQn);
+}
+
+void eth_arch_disable_interrupts(void) {
+ NVIC_DisableIRQ(ENET_IRQn);
+}
+
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h
new file mode 100644
index 0000000000..9979a2560c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h
@@ -0,0 +1,661 @@
+/**********************************************************************
+* $Id$ lpc17xx_emac.h 2010-05-21
+*//**
+* @file lpc17xx_emac.h
+* @brief Contains all macro definitions and function prototypes
+* support for Ethernet MAC firmware library on LPC17xx
+* @version 2.0
+* @date 21. May. 2010
+* @author NXP MCU SW Application Team
+*
+* Copyright(C) 2010, NXP Semiconductor
+* All rights reserved.
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+/* Peripheral group ----------------------------------------------------------- */
+/** @defgroup EMAC EMAC (Ethernet Media Access Controller)
+ * @ingroup LPC1700CMSIS_FwLib_Drivers
+ * @{
+ */
+
+#ifndef LPC17XX_EMAC_H_
+#define LPC17XX_EMAC_H_
+
+/* Includes ------------------------------------------------------------------- */
+#include "cmsis.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MCB_LPC_1768
+//#define IAR_LPC_1768
+
+/* Public Macros -------------------------------------------------------------- */
+/** @defgroup EMAC_Public_Macros EMAC Public Macros
+ * @{
+ */
+
+
+/* EMAC PHY status type definitions */
+#define EMAC_PHY_STAT_LINK (0) /**< Link Status */
+#define EMAC_PHY_STAT_SPEED (1) /**< Speed Status */
+#define EMAC_PHY_STAT_DUP (2) /**< Duplex Status */
+
+/* EMAC PHY device Speed definitions */
+#define EMAC_MODE_AUTO (0) /**< Auto-negotiation mode */
+#define EMAC_MODE_10M_FULL (1) /**< 10Mbps FullDuplex mode */
+#define EMAC_MODE_10M_HALF (2) /**< 10Mbps HalfDuplex mode */
+#define EMAC_MODE_100M_FULL (3) /**< 100Mbps FullDuplex mode */
+#define EMAC_MODE_100M_HALF (4) /**< 100Mbps HalfDuplex mode */
+
+/**
+ * @}
+ */
+/* Private Macros ------------------------------------------------------------- */
+/** @defgroup EMAC_Private_Macros EMAC Private Macros
+ * @{
+ */
+
+
+/* EMAC Memory Buffer configuration for 16K Ethernet RAM */
+#define EMAC_NUM_RX_FRAG 4 /**< Num.of RX Fragments 4*1536= 6.0kB */
+#define EMAC_NUM_TX_FRAG 3 /**< Num.of TX Fragments 3*1536= 4.6kB */
+#define EMAC_ETH_MAX_FLEN 1536 /**< Max. Ethernet Frame Size */
+#define EMAC_TX_FRAME_TOUT 0x00100000 /**< Frame Transmit timeout count */
+
+/* --------------------- BIT DEFINITIONS -------------------------------------- */
+/*********************************************************************//**
+ * Macro defines for MAC Configuration Register 1
+ **********************************************************************/
+#define EMAC_MAC1_REC_EN 0x00000001 /**< Receive Enable */
+#define EMAC_MAC1_PASS_ALL 0x00000002 /**< Pass All Receive Frames */
+#define EMAC_MAC1_RX_FLOWC 0x00000004 /**< RX Flow Control */
+#define EMAC_MAC1_TX_FLOWC 0x00000008 /**< TX Flow Control */
+#define EMAC_MAC1_LOOPB 0x00000010 /**< Loop Back Mode */
+#define EMAC_MAC1_RES_TX 0x00000100 /**< Reset TX Logic */
+#define EMAC_MAC1_RES_MCS_TX 0x00000200 /**< Reset MAC TX Control Sublayer */
+#define EMAC_MAC1_RES_RX 0x00000400 /**< Reset RX Logic */
+#define EMAC_MAC1_RES_MCS_RX 0x00000800 /**< Reset MAC RX Control Sublayer */
+#define EMAC_MAC1_SIM_RES 0x00004000 /**< Simulation Reset */
+#define EMAC_MAC1_SOFT_RES 0x00008000 /**< Soft Reset MAC */
+
+/*********************************************************************//**
+ * Macro defines for MAC Configuration Register 2
+ **********************************************************************/
+#define EMAC_MAC2_FULL_DUP 0x00000001 /**< Full-Duplex Mode */
+#define EMAC_MAC2_FRM_LEN_CHK 0x00000002 /**< Frame Length Checking */
+#define EMAC_MAC2_HUGE_FRM_EN 0x00000004 /**< Huge Frame Enable */
+#define EMAC_MAC2_DLY_CRC 0x00000008 /**< Delayed CRC Mode */
+#define EMAC_MAC2_CRC_EN 0x00000010 /**< Append CRC to every Frame */
+#define EMAC_MAC2_PAD_EN 0x00000020 /**< Pad all Short Frames */
+#define EMAC_MAC2_VLAN_PAD_EN 0x00000040 /**< VLAN Pad Enable */
+#define EMAC_MAC2_ADET_PAD_EN 0x00000080 /**< Auto Detect Pad Enable */
+#define EMAC_MAC2_PPREAM_ENF 0x00000100 /**< Pure Preamble Enforcement */
+#define EMAC_MAC2_LPREAM_ENF 0x00000200 /**< Long Preamble Enforcement */
+#define EMAC_MAC2_NO_BACKOFF 0x00001000 /**< No Backoff Algorithm */
+#define EMAC_MAC2_BACK_PRESSURE 0x00002000 /**< Backoff Presurre / No Backoff */
+#define EMAC_MAC2_EXCESS_DEF 0x00004000 /**< Excess Defer */
+
+/*********************************************************************//**
+ * Macro defines for Back-to-Back Inter-Packet-Gap Register
+ **********************************************************************/
+/** Programmable field representing the nibble time offset of the minimum possible period
+ * between the end of any transmitted packet to the beginning of the next */
+#define EMAC_IPGT_BBIPG(n) (n&0x7F)
+/** Recommended value for Full Duplex of Programmable field representing the nibble time
+ * offset of the minimum possible period between the end of any transmitted packet to the
+ * beginning of the next */
+#define EMAC_IPGT_FULL_DUP (EMAC_IPGT_BBIPG(0x15))
+/** Recommended value for Half Duplex of Programmable field representing the nibble time
+ * offset of the minimum possible period between the end of any transmitted packet to the
+ * beginning of the next */
+#define EMAC_IPGT_HALF_DUP (EMAC_IPGT_BBIPG(0x12))
+
+/*********************************************************************//**
+ * Macro defines for Non Back-to-Back Inter-Packet-Gap Register
+ **********************************************************************/
+/** Programmable field representing the Non-Back-to-Back Inter-Packet-Gap */
+#define EMAC_IPGR_NBBIPG_P2(n) (n&0x7F)
+/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 1 */
+#define EMAC_IPGR_P2_DEF (EMAC_IPGR_NBBIPG_P2(0x12))
+/** Programmable field representing the optional carrierSense window referenced in
+ * IEEE 802.3/4.2.3.2.1 'Carrier Deference' */
+#define EMAC_IPGR_NBBIPG_P1(n) ((n&0x7F)<<8)
+/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 2 */
+#define EMAC_IPGR_P1_DEF EMAC_IPGR_NBBIPG_P1(0x0C)
+
+/*********************************************************************//**
+ * Macro defines for Collision Window/Retry Register
+ **********************************************************************/
+/** Programmable field specifying the number of retransmission attempts following a collision before
+ * aborting the packet due to excessive collisions */
+#define EMAC_CLRT_MAX_RETX(n) (n&0x0F)
+/** Programmable field representing the slot time or collision window during which collisions occur
+ * in properly configured networks */
+#define EMAC_CLRT_COLL(n) ((n&0x3F)<<8)
+/** Default value for Collision Window / Retry register */
+#define EMAC_CLRT_DEF ((EMAC_CLRT_MAX_RETX(0x0F))|(EMAC_CLRT_COLL(0x37)))
+
+/*********************************************************************//**
+ * Macro defines for Maximum Frame Register
+ **********************************************************************/
+/** Represents a maximum receive frame of 1536 octets */
+#define EMAC_MAXF_MAXFRMLEN(n) (n&0xFFFF)
+
+/*********************************************************************//**
+ * Macro defines for PHY Support Register
+ **********************************************************************/
+#define EMAC_SUPP_SPEED 0x00000100 /**< Reduced MII Logic Current Speed */
+#define EMAC_SUPP_RES_RMII 0x00000800 /**< Reset Reduced MII Logic */
+
+/*********************************************************************//**
+ * Macro defines for Test Register
+ **********************************************************************/
+#define EMAC_TEST_SHCUT_PQUANTA 0x00000001 /**< Shortcut Pause Quanta */
+#define EMAC_TEST_TST_PAUSE 0x00000002 /**< Test Pause */
+#define EMAC_TEST_TST_BACKP 0x00000004 /**< Test Back Pressure */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Configuration Register
+ **********************************************************************/
+#define EMAC_MCFG_SCAN_INC 0x00000001 /**< Scan Increment PHY Address */
+#define EMAC_MCFG_SUPP_PREAM 0x00000002 /**< Suppress Preamble */
+#define EMAC_MCFG_CLK_SEL(n) ((n&0x0F)<<2) /**< Clock Select Field */
+#define EMAC_MCFG_RES_MII 0x00008000 /**< Reset MII Management Hardware */
+#define EMAC_MCFG_MII_MAXCLK 2500000UL /**< MII Clock max */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Command Register
+ **********************************************************************/
+#define EMAC_MCMD_READ 0x00000001 /**< MII Read */
+#define EMAC_MCMD_SCAN 0x00000002 /**< MII Scan continuously */
+
+#define EMAC_MII_WR_TOUT 0x00050000 /**< MII Write timeout count */
+#define EMAC_MII_RD_TOUT 0x00050000 /**< MII Read timeout count */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Address Register
+ **********************************************************************/
+#define EMAC_MADR_REG_ADR(n) (n&0x1F) /**< MII Register Address field */
+#define EMAC_MADR_PHY_ADR(n) ((n&0x1F)<<8) /**< PHY Address Field */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Write Data Register
+ **********************************************************************/
+#define EMAC_MWTD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Write Data register */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Read Data Register
+ **********************************************************************/
+#define EMAC_MRDD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Read Data register */
+
+/*********************************************************************//**
+ * Macro defines for MII Management Indicators Register
+ **********************************************************************/
+#define EMAC_MIND_BUSY 0x00000001 /**< MII is Busy */
+#define EMAC_MIND_SCAN 0x00000002 /**< MII Scanning in Progress */
+#define EMAC_MIND_NOT_VAL 0x00000004 /**< MII Read Data not valid */
+#define EMAC_MIND_MII_LINK_FAIL 0x00000008 /**< MII Link Failed */
+
+/* Station Address 0 Register */
+/* Station Address 1 Register */
+/* Station Address 2 Register */
+
+
+/* Control register definitions --------------------------------------------------------------------------- */
+/*********************************************************************//**
+ * Macro defines for Command Register
+ **********************************************************************/
+#define EMAC_CR_RX_EN 0x00000001 /**< Enable Receive */
+#define EMAC_CR_TX_EN 0x00000002 /**< Enable Transmit */
+#define EMAC_CR_REG_RES 0x00000008 /**< Reset Host Registers */
+#define EMAC_CR_TX_RES 0x00000010 /**< Reset Transmit Datapath */
+#define EMAC_CR_RX_RES 0x00000020 /**< Reset Receive Datapath */
+#define EMAC_CR_PASS_RUNT_FRM 0x00000040 /**< Pass Runt Frames */
+#define EMAC_CR_PASS_RX_FILT 0x00000080 /**< Pass RX Filter */
+#define EMAC_CR_TX_FLOW_CTRL 0x00000100 /**< TX Flow Control */
+#define EMAC_CR_RMII 0x00000200 /**< Reduced MII Interface */
+#define EMAC_CR_FULL_DUP 0x00000400 /**< Full Duplex */
+
+/*********************************************************************//**
+ * Macro defines for Status Register
+ **********************************************************************/
+#define EMAC_SR_RX_EN 0x00000001 /**< Enable Receive */
+#define EMAC_SR_TX_EN 0x00000002 /**< Enable Transmit */
+
+/*********************************************************************//**
+ * Macro defines for Transmit Status Vector 0 Register
+ **********************************************************************/
+#define EMAC_TSV0_CRC_ERR 0x00000001 /**< CRC error */
+#define EMAC_TSV0_LEN_CHKERR 0x00000002 /**< Length Check Error */
+#define EMAC_TSV0_LEN_OUTRNG 0x00000004 /**< Length Out of Range */
+#define EMAC_TSV0_DONE 0x00000008 /**< Tramsmission Completed */
+#define EMAC_TSV0_MCAST 0x00000010 /**< Multicast Destination */
+#define EMAC_TSV0_BCAST 0x00000020 /**< Broadcast Destination */
+#define EMAC_TSV0_PKT_DEFER 0x00000040 /**< Packet Deferred */
+#define EMAC_TSV0_EXC_DEFER 0x00000080 /**< Excessive Packet Deferral */
+#define EMAC_TSV0_EXC_COLL 0x00000100 /**< Excessive Collision */
+#define EMAC_TSV0_LATE_COLL 0x00000200 /**< Late Collision Occured */
+#define EMAC_TSV0_GIANT 0x00000400 /**< Giant Frame */
+#define EMAC_TSV0_UNDERRUN 0x00000800 /**< Buffer Underrun */
+#define EMAC_TSV0_BYTES 0x0FFFF000 /**< Total Bytes Transferred */
+#define EMAC_TSV0_CTRL_FRAME 0x10000000 /**< Control Frame */
+#define EMAC_TSV0_PAUSE 0x20000000 /**< Pause Frame */
+#define EMAC_TSV0_BACK_PRESS 0x40000000 /**< Backpressure Method Applied */
+#define EMAC_TSV0_VLAN 0x80000000 /**< VLAN Frame */
+
+/*********************************************************************//**
+ * Macro defines for Transmit Status Vector 1 Register
+ **********************************************************************/
+#define EMAC_TSV1_BYTE_CNT 0x0000FFFF /**< Transmit Byte Count */
+#define EMAC_TSV1_COLL_CNT 0x000F0000 /**< Transmit Collision Count */
+
+/*********************************************************************//**
+ * Macro defines for Receive Status Vector Register
+ **********************************************************************/
+#define EMAC_RSV_BYTE_CNT 0x0000FFFF /**< Receive Byte Count */
+#define EMAC_RSV_PKT_IGNORED 0x00010000 /**< Packet Previously Ignored */
+#define EMAC_RSV_RXDV_SEEN 0x00020000 /**< RXDV Event Previously Seen */
+#define EMAC_RSV_CARR_SEEN 0x00040000 /**< Carrier Event Previously Seen */
+#define EMAC_RSV_REC_CODEV 0x00080000 /**< Receive Code Violation */
+#define EMAC_RSV_CRC_ERR 0x00100000 /**< CRC Error */
+#define EMAC_RSV_LEN_CHKERR 0x00200000 /**< Length Check Error */
+#define EMAC_RSV_LEN_OUTRNG 0x00400000 /**< Length Out of Range */
+#define EMAC_RSV_REC_OK 0x00800000 /**< Frame Received OK */
+#define EMAC_RSV_MCAST 0x01000000 /**< Multicast Frame */
+#define EMAC_RSV_BCAST 0x02000000 /**< Broadcast Frame */
+#define EMAC_RSV_DRIB_NIBB 0x04000000 /**< Dribble Nibble */
+#define EMAC_RSV_CTRL_FRAME 0x08000000 /**< Control Frame */
+#define EMAC_RSV_PAUSE 0x10000000 /**< Pause Frame */
+#define EMAC_RSV_UNSUPP_OPC 0x20000000 /**< Unsupported Opcode */
+#define EMAC_RSV_VLAN 0x40000000 /**< VLAN Frame */
+
+/*********************************************************************//**
+ * Macro defines for Flow Control Counter Register
+ **********************************************************************/
+#define EMAC_FCC_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter */
+#define EMAC_FCC_PAUSE_TIM(n) ((n&0xFFFF)<<16) /**< Pause Timer */
+
+/*********************************************************************//**
+ * Macro defines for Flow Control Status Register
+ **********************************************************************/
+#define EMAC_FCS_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter Current */
+
+
+/* Receive filter register definitions -------------------------------------------------------- */
+/*********************************************************************//**
+ * Macro defines for Receive Filter Control Register
+ **********************************************************************/
+#define EMAC_RFC_UCAST_EN 0x00000001 /**< Accept Unicast Frames Enable */
+#define EMAC_RFC_BCAST_EN 0x00000002 /**< Accept Broadcast Frames Enable */
+#define EMAC_RFC_MCAST_EN 0x00000004 /**< Accept Multicast Frames Enable */
+#define EMAC_RFC_UCAST_HASH_EN 0x00000008 /**< Accept Unicast Hash Filter Frames */
+#define EMAC_RFC_MCAST_HASH_EN 0x00000010 /**< Accept Multicast Hash Filter Fram.*/
+#define EMAC_RFC_PERFECT_EN 0x00000020 /**< Accept Perfect Match Enable */
+#define EMAC_RFC_MAGP_WOL_EN 0x00001000 /**< Magic Packet Filter WoL Enable */
+#define EMAC_RFC_PFILT_WOL_EN 0x00002000 /**< Perfect Filter WoL Enable */
+
+/*********************************************************************//**
+ * Macro defines for Receive Filter WoL Status/Clear Registers
+ **********************************************************************/
+#define EMAC_WOL_UCAST 0x00000001 /**< Unicast Frame caused WoL */
+#define EMAC_WOL_BCAST 0x00000002 /**< Broadcast Frame caused WoL */
+#define EMAC_WOL_MCAST 0x00000004 /**< Multicast Frame caused WoL */
+#define EMAC_WOL_UCAST_HASH 0x00000008 /**< Unicast Hash Filter Frame WoL */
+#define EMAC_WOL_MCAST_HASH 0x00000010 /**< Multicast Hash Filter Frame WoL */
+#define EMAC_WOL_PERFECT 0x00000020 /**< Perfect Filter WoL */
+#define EMAC_WOL_RX_FILTER 0x00000080 /**< RX Filter caused WoL */
+#define EMAC_WOL_MAG_PACKET 0x00000100 /**< Magic Packet Filter caused WoL */
+#define EMAC_WOL_BITMASK 0x01BF /**< Receive Filter WoL Status/Clear bitmasl value */
+
+
+/* Module control register definitions ---------------------------------------------------- */
+/*********************************************************************//**
+ * Macro defines for Interrupt Status/Enable/Clear/Set Registers
+ **********************************************************************/
+#define EMAC_INT_RX_OVERRUN 0x00000001 /**< Overrun Error in RX Queue */
+#define EMAC_INT_RX_ERR 0x00000002 /**< Receive Error */
+#define EMAC_INT_RX_FIN 0x00000004 /**< RX Finished Process Descriptors */
+#define EMAC_INT_RX_DONE 0x00000008 /**< Receive Done */
+#define EMAC_INT_TX_UNDERRUN 0x00000010 /**< Transmit Underrun */
+#define EMAC_INT_TX_ERR 0x00000020 /**< Transmit Error */
+#define EMAC_INT_TX_FIN 0x00000040 /**< TX Finished Process Descriptors */
+#define EMAC_INT_TX_DONE 0x00000080 /**< Transmit Done */
+#define EMAC_INT_SOFT_INT 0x00001000 /**< Software Triggered Interrupt */
+#define EMAC_INT_WAKEUP 0x00002000 /**< Wakeup Event Interrupt */
+
+/*********************************************************************//**
+ * Macro defines for Power Down Register
+ **********************************************************************/
+#define EMAC_PD_POWER_DOWN 0x80000000 /**< Power Down MAC */
+
+/* Descriptor and status formats ---------------------------------------------------- */
+/*********************************************************************//**
+ * Macro defines for RX Descriptor Control Word
+ **********************************************************************/
+#define EMAC_RCTRL_SIZE(n) (n&0x7FF) /**< Buffer size field */
+#define EMAC_RCTRL_INT 0x80000000 /**< Generate RxDone Interrupt */
+
+/*********************************************************************//**
+ * Macro defines for RX Status Hash CRC Word
+ **********************************************************************/
+#define EMAC_RHASH_SA 0x000001FF /**< Hash CRC for Source Address */
+#define EMAC_RHASH_DA 0x001FF000 /**< Hash CRC for Destination Address */
+
+/*********************************************************************//**
+ * Macro defines for RX Status Information Word
+ **********************************************************************/
+#define EMAC_RINFO_SIZE 0x000007FF /**< Data size in bytes */
+#define EMAC_RINFO_CTRL_FRAME 0x00040000 /**< Control Frame */
+#define EMAC_RINFO_VLAN 0x00080000 /**< VLAN Frame */
+#define EMAC_RINFO_FAIL_FILT 0x00100000 /**< RX Filter Failed */
+#define EMAC_RINFO_MCAST 0x00200000 /**< Multicast Frame */
+#define EMAC_RINFO_BCAST 0x00400000 /**< Broadcast Frame */
+#define EMAC_RINFO_CRC_ERR 0x00800000 /**< CRC Error in Frame */
+#define EMAC_RINFO_SYM_ERR 0x01000000 /**< Symbol Error from PHY */
+#define EMAC_RINFO_LEN_ERR 0x02000000 /**< Length Error */
+#define EMAC_RINFO_RANGE_ERR 0x04000000 /**< Range Error (exceeded max. size) */
+#define EMAC_RINFO_ALIGN_ERR 0x08000000 /**< Alignment Error */
+#define EMAC_RINFO_OVERRUN 0x10000000 /**< Receive overrun */
+#define EMAC_RINFO_NO_DESCR 0x20000000 /**< No new Descriptor available */
+#define EMAC_RINFO_LAST_FLAG 0x40000000 /**< Last Fragment in Frame */
+#define EMAC_RINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
+#define EMAC_RINFO_ERR_MASK (EMAC_RINFO_FAIL_FILT | EMAC_RINFO_CRC_ERR | EMAC_RINFO_SYM_ERR | \
+EMAC_RINFO_LEN_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_OVERRUN)
+
+/*********************************************************************//**
+ * Macro defines for TX Descriptor Control Word
+ **********************************************************************/
+#define EMAC_TCTRL_SIZE 0x000007FF /**< Size of data buffer in bytes */
+#define EMAC_TCTRL_OVERRIDE 0x04000000 /**< Override Default MAC Registers */
+#define EMAC_TCTRL_HUGE 0x08000000 /**< Enable Huge Frame */
+#define EMAC_TCTRL_PAD 0x10000000 /**< Pad short Frames to 64 bytes */
+#define EMAC_TCTRL_CRC 0x20000000 /**< Append a hardware CRC to Frame */
+#define EMAC_TCTRL_LAST 0x40000000 /**< Last Descriptor for TX Frame */
+#define EMAC_TCTRL_INT 0x80000000 /**< Generate TxDone Interrupt */
+
+/*********************************************************************//**
+ * Macro defines for TX Status Information Word
+ **********************************************************************/
+#define EMAC_TINFO_COL_CNT 0x01E00000 /**< Collision Count */
+#define EMAC_TINFO_DEFER 0x02000000 /**< Packet Deferred (not an error) */
+#define EMAC_TINFO_EXCESS_DEF 0x04000000 /**< Excessive Deferral */
+#define EMAC_TINFO_EXCESS_COL 0x08000000 /**< Excessive Collision */
+#define EMAC_TINFO_LATE_COL 0x10000000 /**< Late Collision Occured */
+#define EMAC_TINFO_UNDERRUN 0x20000000 /**< Transmit Underrun */
+#define EMAC_TINFO_NO_DESCR 0x40000000 /**< No new Descriptor available */
+#define EMAC_TINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
+
+#ifdef MCB_LPC_1768
+/* DP83848C PHY definition ------------------------------------------------------------ */
+
+/** PHY device reset time out definition */
+#define EMAC_PHY_RESP_TOUT 0x100000UL
+
+/* ENET Device Revision ID */
+#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
+
+/*********************************************************************//**
+ * Macro defines for DP83848C PHY Registers
+ **********************************************************************/
+#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
+#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
+#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
+#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
+#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
+#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
+#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
+#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
+#define EMAC_PHY_REG_LPNPA 0x08
+
+/*********************************************************************//**
+ * Macro defines for PHY Extended Registers
+ **********************************************************************/
+#define EMAC_PHY_REG_STS 0x10 /**< Status Register */
+#define EMAC_PHY_REG_MICR 0x11 /**< MII Interrupt Control Register */
+#define EMAC_PHY_REG_MISR 0x12 /**< MII Interrupt Status Register */
+#define EMAC_PHY_REG_FCSCR 0x14 /**< False Carrier Sense Counter */
+#define EMAC_PHY_REG_RECR 0x15 /**< Receive Error Counter */
+#define EMAC_PHY_REG_PCSR 0x16 /**< PCS Sublayer Config. and Status */
+#define EMAC_PHY_REG_RBR 0x17 /**< RMII and Bypass Register */
+#define EMAC_PHY_REG_LEDCR 0x18 /**< LED Direct Control Register */
+#define EMAC_PHY_REG_PHYCR 0x19 /**< PHY Control Register */
+#define EMAC_PHY_REG_10BTSCR 0x1A /**< 10Base-T Status/Control Register */
+#define EMAC_PHY_REG_CDCTRL1 0x1B /**< CD Test Control and BIST Extens. */
+#define EMAC_PHY_REG_EDCR 0x1D /**< Energy Detect Control Register */
+
+/*********************************************************************//**
+ * Macro defines for PHY Basic Mode Control Register
+ **********************************************************************/
+#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
+#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
+#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
+#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
+#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
+#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
+#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
+#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
+
+/*********************************************************************//**
+ * Macro defines for PHY Basic Mode Status Status Register
+ **********************************************************************/
+#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
+#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
+#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
+#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
+#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
+#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
+#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
+#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
+#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
+#define EMAC_PHY_BMSR_LINK_ESTABLISHED (1<<2) /**< Link status */
+
+/*********************************************************************//**
+ * Macro defines for PHY Status Register
+ **********************************************************************/
+#define EMAC_PHY_SR_REMOTE_FAULT (1<<6) /**< Remote Fault */
+#define EMAC_PHY_SR_JABBER (1<<5) /**< Jabber detect */
+#define EMAC_PHY_SR_AUTO_DONE (1<<4) /**< Auto Negotiation complete */
+#define EMAC_PHY_SR_LOOPBACK (1<<3) /**< Loop back status */
+#define EMAC_PHY_SR_DUP (1<<2) /**< Duplex status */
+#define EMAC_PHY_SR_SPEED (1<<1) /**< Speed status */
+#define EMAC_PHY_SR_LINK (1<<0) /**< Link Status */
+
+#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
+#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
+#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
+#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
+#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
+
+#define EMAC_DEF_ADR 0x0100 /**< Default PHY device address */
+#define EMAC_DP83848C_ID 0x20005C90 /**< PHY Identifier */
+
+#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
+#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
+#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
+
+#elif defined(IAR_LPC_1768)
+/* KSZ8721BL PHY definition ------------------------------------------------------------ */
+/** PHY device reset time out definition */
+#define EMAC_PHY_RESP_TOUT 0x100000UL
+
+/* ENET Device Revision ID */
+#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
+
+/*********************************************************************//**
+ * Macro defines for KSZ8721BL PHY Registers
+ **********************************************************************/
+#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
+#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
+#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
+#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
+#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
+#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
+#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
+#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
+#define EMAC_PHY_REG_LPNPA 0x08 /**< Link Partner Next Page Ability */
+#define EMAC_PHY_REG_REC 0x15 /**< RXError Counter Register */
+#define EMAC_PHY_REG_ISC 0x1b /**< Interrupt Control/Status Register */
+#define EMAC_PHY_REG_100BASE 0x1f /**< 100BASE-TX PHY Control Register */
+
+/*********************************************************************//**
+ * Macro defines for PHY Basic Mode Control Register
+ **********************************************************************/
+#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
+#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
+#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
+#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
+#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
+#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
+#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
+#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
+#define EMAC_PHY_BMCR_COLLISION (1<<7) /**< Collision test */
+#define EMAC_PHY_BMCR_TXDIS (1<<0) /**< Disable transmit */
+
+/*********************************************************************//**
+ * Macro defines for PHY Basic Mode Status Register
+ **********************************************************************/
+#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
+#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
+#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
+#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
+#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
+#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
+#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
+#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
+#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
+#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
+#define EMAC_PHY_BMSR_JABBER_DETECT (1<<1) /**< Jabber detect */
+#define EMAC_PHY_BMSR_EXTEND (1<<0) /**< Extended support */
+
+/*********************************************************************//**
+ * Macro defines for PHY Identifier
+ **********************************************************************/
+/* PHY Identifier 1 bitmap definitions */
+#define EMAC_PHY_IDR1(n) (n & 0xFFFF) /**< PHY ID1 Number */
+
+/* PHY Identifier 2 bitmap definitions */
+#define EMAC_PHY_IDR2(n) (n & 0xFFFF) /**< PHY ID2 Number */
+
+/*********************************************************************//**
+ * Macro defines for Auto-Negotiation Advertisement
+ **********************************************************************/
+#define EMAC_PHY_AN_NEXTPAGE (1<<15) /**< Next page capable */
+#define EMAC_PHY_AN_REMOTE_FAULT (1<<13) /**< Remote Fault support */
+#define EMAC_PHY_AN_PAUSE (1<<10) /**< Pause support */
+#define EMAC_PHY_AN_100BASE_T4 (1<<9) /**< T4 capable */
+#define EMAC_PHY_AN_100BASE_TX_FD (1<<8) /**< TX with Full-duplex capable */
+#define EMAC_PHY_AN_100BASE_TX (1<<7) /**< TX capable */
+#define EMAC_PHY_AN_10BASE_T_FD (1<<6) /**< 10Mbps with full-duplex capable */
+#define EMAC_PHY_AN_10BASE_T (1<<5) /**< 10Mbps capable */
+#define EMAC_PHY_AN_FIELD(n) (n & 0x1F) /**< Selector Field */
+
+#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
+#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
+#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
+#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
+#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
+
+#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
+#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
+
+#define EMAC_DEF_ADR (0x01<<8) /**< Default PHY device address */
+#define EMAC_KSZ8721BL_ID ((0x22 << 16) | 0x1619 ) /**< PHY Identifier */
+#endif
+
+/**
+ * @}
+ */
+
+
+/* Public Types --------------------------------------------------------------- */
+/** @defgroup EMAC_Public_Types EMAC Public Types
+ * @{
+ */
+
+/* Descriptor and status formats ---------------------------------------------- */
+
+/**
+ * @brief RX Descriptor structure type definition
+ */
+typedef struct {
+ uint32_t Packet; /**< Receive Packet Descriptor */
+ uint32_t Ctrl; /**< Receive Control Descriptor */
+} RX_Desc;
+
+/**
+ * @brief RX Status structure type definition
+ */
+typedef struct {
+ uint32_t Info; /**< Receive Information Status */
+ uint32_t HashCRC; /**< Receive Hash CRC Status */
+} RX_Stat;
+
+/**
+ * @brief TX Descriptor structure type definition
+ */
+typedef struct {
+ uint32_t Packet; /**< Transmit Packet Descriptor */
+ uint32_t Ctrl; /**< Transmit Control Descriptor */
+} TX_Desc;
+
+/**
+ * @brief TX Status structure type definition
+ */
+typedef struct {
+ uint32_t Info; /**< Transmit Information Status */
+} TX_Stat;
+
+
+/**
+ * @brief TX Data Buffer structure definition
+ */
+typedef struct {
+ uint32_t ulDataLen; /**< Data length */
+ uint32_t *pbDataBuf; /**< A word-align data pointer to data buffer */
+} EMAC_PACKETBUF_Type;
+
+/**
+ * @brief EMAC configuration structure definition
+ */
+typedef struct {
+ uint32_t Mode; /**< Supported EMAC PHY device speed, should be one of the following:
+ - EMAC_MODE_AUTO
+ - EMAC_MODE_10M_FULL
+ - EMAC_MODE_10M_HALF
+ - EMAC_MODE_100M_FULL
+ - EMAC_MODE_100M_HALF
+ */
+ uint8_t *pbEMAC_Addr; /**< Pointer to EMAC Station address that contains 6-bytes
+ of MAC address, it must be sorted in order (bEMAC_Addr[0]..[5])
+ */
+} EMAC_CFG_Type;
+
+/** Ethernet block power/clock control bit*/
+#define CLKPWR_PCONP_PCENET ((uint32_t)(1<<30))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LPC17XX_EMAC_H_ */
+
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h
new file mode 100644
index 0000000000..831b3d76d0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h
@@ -0,0 +1,111 @@
+/**********************************************************************
+* $Id$ lpc_emac_config.h 2011-11-20
+*//**
+* @file lpc_emac_config.h
+* @brief PHY and EMAC configuration file
+* @version 1.0
+* @date 20 Nov. 2011
+* @author NXP MCU SW Application Team
+*
+* Copyright(C) 2011, NXP Semiconductor
+* All rights reserved.
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+#ifndef __LPC_EMAC_CONFIG_H
+#define __LPC_EMAC_CONFIG_H
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** @defgroup lwip_phy_config LWIP PHY configuration
+ * @ingroup lwip_phy
+ *
+ * Configuration options for the PHY connected to the LPC EMAC.
+ * @{
+ */
+
+/** \brief The PHY address connected the to MII/RMII
+ */
+#define LPC_PHYDEF_PHYADDR 1 /**< The PHY address on the PHY device. */
+
+/** \brief Enable autonegotiation mode.
+ * If this is enabled, the PHY will attempt to auto-negotiate the
+ * best link mode if the PHY supports it. If this is not enabled,
+ * the PHY_USE_FULL_DUPLEX and PHY_USE_100MBS defines will be
+ * used to select the link mode. Note that auto-negotiation may
+ * take a few seconds to complete.
+ */
+#define PHY_USE_AUTONEG 1 /**< Enables auto-negotiation mode. */
+
+/** \brief Sets up the PHY interface to either full duplex operation or
+ * half duplex operation if PHY_USE_AUTONEG is not enabled.
+ */
+#define PHY_USE_FULL_DUPLEX 1 /**< Sets duplex mode to full. */
+
+/** \brief Sets up the PHY interface to either 100MBS operation or 10MBS
+ * operation if PHY_USE_AUTONEG is not enabled.
+ */
+#define PHY_USE_100MBS 1 /**< Sets data rate to 100Mbps. */
+
+/**
+ * @}
+ */
+
+/** @defgroup lwip_emac_config LWIP EMAC configuration
+ * @ingroup lwip_emac
+ *
+ * Configuration options for the LPC EMAC.
+ * @{
+ */
+
+/** \brief Selects RMII or MII connection type in the EMAC peripheral
+ */
+#define LPC_EMAC_RMII 1 /**< Use the RMII or MII driver variant .*/
+
+/** \brief Defines the number of descriptors used for RX. This
+ * must be a minimum value of 2.
+ */
+#define LPC_NUM_BUFF_RXDESCS 3
+
+/** \brief Defines the number of descriptors used for TX. Must
+ * be a minimum value of 2.
+ */
+#define LPC_NUM_BUFF_TXDESCS (TCP_SND_QUEUELEN + 1)
+
+/** \brief Set this define to 1 to enable bounce buffers for transmit pbufs
+ * that cannot be sent via the zero-copy method. Some chained pbufs
+ * may have a payload address that links to an area of memory that
+ * cannot be used for transmit DMA operations. If this define is
+ * set to 1, an extra check will be made with the pbufs. If a buffer
+ * is determined to be non-usable for zero-copy, a temporary bounce
+ * buffer will be created and used instead.
+ */
+#define LPC_TX_PBUF_BOUNCE_EN 1
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LPC_EMAC_CONFIG_H */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy.h
new file mode 100644
index 0000000000..fa53656a77
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy.h
@@ -0,0 +1,151 @@
+/**********************************************************************
+* $Id$ lpc_phy.h 2011-11-20
+*//**
+* @file lpc_phy.h
+* @brief Common PHY definitions used with all PHYs
+* @version 1.0
+* @date 20 Nov. 2011
+* @author NXP MCU SW Application Team
+*
+* Copyright(C) 2011, NXP Semiconductor
+* All rights reserved.
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+#ifndef __LPC_PHY_H_
+#define __LPC_PHY_H_
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* These PHY functions are usually part of the EMAC driver */
+
+/** \brief Phy status update state machine
+ *
+ * This function provides a state machine for maintaining the PHY
+ * status without blocking. It must be occasionally called for the
+ * PHY status to be maintained.
+ *
+ * \param[in] netif NETIF structure
+ */
+s32_t lpc_phy_sts_sm(struct netif *netif);
+
+/** \brief Initialize the PHY
+ *
+ * This function initializes the PHY. It will block until complete.
+ * This function is called as part of the EMAC driver
+ * initialization. Configuration of the PHY at startup is
+ * controlled by setting up configuration defines in lpc_phy.h.
+ *
+ * \param[in] netif NETIF structure
+ * \param[in] rmii If set, configures the PHY for RMII mode
+ * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
+ */
+err_t lpc_phy_init(struct netif *netif, int rmii);
+
+/** \brief Write a value via the MII link (non-blocking)
+ *
+ * This function will write a value on the MII link interface to a PHY
+ * or a connected device. The function will return immediately without
+ * a status. Status needs to be polled later to determine if the write
+ * was successful.
+ *
+ * \param[in] PhyReg PHY register to write to
+ * \param[in] Value Value to write
+ */
+void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value);
+
+/** \brief Write a value via the MII link (blocking)
+ *
+ * This function will write a value on the MII link interface to a PHY
+ * or a connected device. The function will block until complete.
+ *
+ * \param[in] PhyReg PHY register to write to
+ * \param[in] Value Value to write
+ * \returns 0 if the write was successful, otherwise !0
+ */
+err_t lpc_mii_write(u32_t PhyReg, u32_t Value);
+
+/** \brief Reads current MII link busy status
+ *
+ * This function will return the current MII link busy status and is meant to
+ * be used with non-blocking functions for monitor PHY status such as
+ * connection state.
+ *
+ * \returns !0 if the MII link is busy, otherwise 0
+ */
+u32_t lpc_mii_is_busy(void);
+
+/** \brief Starts a read operation via the MII link (non-blocking)
+ *
+ * This function returns the current value in the MII data register. It is
+ * meant to be used with the non-blocking oeprations. This value should
+ * only be read after a non-block read command has been issued and the
+ * MII status has been determined to be good.
+ *
+ * \returns The current value in the MII value register
+ */
+u32_t lpc_mii_read_data(void);
+
+/** \brief Starts a read operation via the MII link (non-blocking)
+ *
+ * This function will start a read operation on the MII link interface
+ * from a PHY or a connected device. The function will not block and
+ * the status mist be polled until complete. Once complete, the data
+ * can be read.
+ *
+ * \param[in] PhyReg PHY register to read from
+ */
+err_t lpc_mii_read(u32_t PhyReg, u32_t *data);
+
+/** \brief Read a value via the MII link (blocking)
+ *
+ * This function will read a value on the MII link interface from a PHY
+ * or a connected device. The function will block until complete.
+ *
+ * \param[in] PhyReg PHY register to read from
+ * \param[in] data Pointer to where to save data read via MII
+ * \returns 0 if the read was successful, otherwise !0
+ */
+void lpc_mii_read_noblock(u32_t PhyReg);
+
+/**
+ * This function provides a method for the PHY to setup the EMAC
+ * for the PHY negotiated duplex mode.
+ *
+ * @param[in] full_duplex 0 = half duplex, 1 = full duplex
+ */
+void lpc_emac_set_duplex(int full_duplex);
+
+/**
+ * This function provides a method for the PHY to setup the EMAC
+ * for the PHY negotiated bit rate.
+ *
+ * @param[in] mbs_100 0 = 10mbs mode, 1 = 100mbs mode
+ */
+void lpc_emac_set_speed(int mbs_100);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LPC_PHY_H_ */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c
new file mode 100644
index 0000000000..14813a561b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c
@@ -0,0 +1,438 @@
+/**********************************************************************
+* $Id$ lpc_phy_dp83848.c 2011-11-20
+*//**
+* @file lpc_phy_dp83848.c
+* @brief DP83848C PHY status and control.
+* @version 1.0
+* @date 20 Nov. 2011
+* @author NXP MCU SW Application Team
+*
+* Copyright(C) 2011, NXP Semiconductor
+* All rights reserved.
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/tcpip.h"
+#include "lwip/snmp.h"
+#include "lpc_emac_config.h"
+#include "lpc_phy.h"
+#include "lpc17xx_emac.h"
+
+/** @defgroup dp83848_phy PHY status and control for the DP83848.
+ * @ingroup lwip_phy
+ *
+ * Various functions for controlling and monitoring the status of the
+ * DP83848 PHY. In polled (standalone) systems, the PHY state must be
+ * monitored as part of the application. In a threaded (RTOS) system,
+ * the PHY state is monitored by the PHY handler thread. The MAC
+ * driver will not transmit unless the PHY link is active.
+ * @{
+ */
+
+/** \brief DP83848 PHY register offsets */
+#define DP8_BMCR_REG 0x0 /**< Basic Mode Control Register */
+#define DP8_BMSR_REG 0x1 /**< Basic Mode Status Reg */
+#define DP8_IDR1_REG 0x2 /**< Basic Mode Status Reg */
+#define DP8_IDR2_REG 0x3 /**< Basic Mode Status Reg */
+#define DP8_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */
+#define DP8_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */
+#define DP8_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */
+#define DP8_PHY_STAT_REG 0x10 /**< PHY Status Register */
+#define DP8_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */
+#define DP8_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */
+#define DP8_PHY_STS_REG 0x19 /**< PHY Status Register */
+
+#define DP8_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */
+
+/** \brief DP83848 Control register definitions */
+#define DP8_RESET (1 << 15) /**< 1= S/W Reset */
+#define DP8_LOOPBACK (1 << 14) /**< 1=loopback Enabled */
+#define DP8_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */
+#define DP8_AUTONEG (1 << 12) /**< 1=Enable auto-negotiation */
+#define DP8_POWER_DOWN (1 << 11) /**< 1=Power down PHY */
+#define DP8_ISOLATE (1 << 10) /**< 1=Isolate PHY */
+#define DP8_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */
+#define DP8_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */
+#define DP8_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */
+
+/** \brief DP83848 Status register definitions */
+#define DP8_100BASE_T4 (1 << 15) /**< T4 mode */
+#define DP8_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */
+#define DP8_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */
+#define DP8_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */
+#define DP8_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */
+#define DP8_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */
+#define DP8_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */
+#define DP8_RMT_FAULT (1 << 4) /**< Fault */
+#define DP8_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */
+#define DP8_LINK_STATUS (1 << 2) /**< 1=Link active */
+#define DP8_JABBER_DETECT (1 << 1) /**< Jabber detect */
+#define DP8_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */
+
+/** \brief DP83848 PHY RBR MII dode definitions */
+#define DP8_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */
+
+/** \brief DP83848 PHY status definitions */
+#define DP8_REMOTEFAULT (1 << 6) /**< Remote fault */
+#define DP8_FULLDUPLEX (1 << 2) /**< 1=full duplex */
+#define DP8_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */
+#define DP8_VALID_LINK (1 << 0) /**< 1=Link active */
+
+/** \brief DP83848 PHY ID register definitions */
+#define DP8_PHYID1_OUI 0x2000 /**< Expected PHY ID1 */
+#define DP8_PHYID2_OUI 0x5c90 /**< Expected PHY ID2 */
+
+/** \brief LAN8720 PHY Special Control/Status Register */
+#define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */
+#define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */
+
+/** \brief Link status bits */
+#define LNK_STAT_VALID 0x01
+#define LNK_STAT_FULLDUPLEX 0x02
+#define LNK_STAT_SPEED10MPS 0x04
+
+/** \brief PHY ID definitions */
+#define DP83848C_ID 0x20005C90 /**< PHY Identifier - DP83848C */
+#define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */
+
+/** \brief PHY status structure used to indicate current status of PHY.
+ */
+typedef struct {
+ u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */
+ u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */
+ u32_t phy_link_active:1; /**< Phy link active flag. */
+} PHY_STATUS_TYPE;
+
+/** \brief PHY update flags */
+static PHY_STATUS_TYPE physts;
+
+/** \brief Last PHY update flags, used for determing if something has changed */
+static PHY_STATUS_TYPE olddphysts;
+
+/** \brief PHY update counter for state machine */
+static s32_t phyustate;
+
+/** \brief Holds the PHY ID */
+static u32_t phy_id;
+
+/** \brief Temporary holder of link status for LAN7420 */
+static u32_t phy_lan7420_sts_tmp;
+
+/* Write a value via the MII link (non-blocking) */
+void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
+{
+ /* Write value at PHY address and register */
+ LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
+ LPC_EMAC->MWTD = Value;
+}
+
+/* Write a value via the MII link (blocking) */
+err_t lpc_mii_write(u32_t PhyReg, u32_t Value)
+{
+ u32_t mst = 250;
+ err_t sts = ERR_OK;
+
+ /* Write value at PHY address and register */
+ lpc_mii_write_noblock(PhyReg, Value);
+
+ /* Wait for unbusy status */
+ while (mst > 0) {
+ sts = LPC_EMAC->MIND;
+ if ((sts & EMAC_MIND_BUSY) == 0)
+ mst = 0;
+ else {
+ mst--;
+ osDelay(1);
+ }
+ }
+
+ if (sts != 0)
+ sts = ERR_TIMEOUT;
+
+ return sts;
+}
+
+/* Reads current MII link busy status */
+u32_t lpc_mii_is_busy(void)
+{
+ return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY);
+}
+
+/* Starts a read operation via the MII link (non-blocking) */
+u32_t lpc_mii_read_data(void)
+{
+ u32_t data = LPC_EMAC->MRDD;
+ LPC_EMAC->MCMD = 0;
+
+ return data;
+}
+
+/* Starts a read operation via the MII link (non-blocking) */
+void lpc_mii_read_noblock(u32_t PhyReg)
+{
+ /* Read value at PHY address and register */
+ LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
+ LPC_EMAC->MCMD = EMAC_MCMD_READ;
+}
+
+/* Read a value via the MII link (blocking) */
+err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
+{
+ u32_t mst = 250;
+ err_t sts = ERR_OK;
+
+ /* Read value at PHY address and register */
+ lpc_mii_read_noblock(PhyReg);
+
+ /* Wait for unbusy status */
+ while (mst > 0) {
+ sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL;
+ if ((sts & EMAC_MIND_BUSY) == 0) {
+ mst = 0;
+ *data = LPC_EMAC->MRDD;
+ } else {
+ mst--;
+ osDelay(1);
+ }
+ }
+
+ LPC_EMAC->MCMD = 0;
+
+ if (sts != 0)
+ sts = ERR_TIMEOUT;
+
+ return sts;
+}
+
+
+
+/** \brief Update PHY status from passed value
+ *
+ * This function updates the current PHY status based on the
+ * passed PHY status word. The PHY status indicate if the link
+ * is active, the connection speed, and duplex.
+ *
+ * \param[in] netif NETIF structure
+ * \param[in] linksts Status word from PHY
+ * \return 1 if the status has changed, otherwise 0
+ */
+static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts)
+{
+ s32_t changed = 0;
+
+ /* Update link active status */
+ if (linksts & LNK_STAT_VALID)
+ physts.phy_link_active = 1;
+ else
+ physts.phy_link_active = 0;
+
+ /* Full or half duplex */
+ if (linksts & LNK_STAT_FULLDUPLEX)
+ physts.phy_full_duplex = 1;
+ else
+ physts.phy_full_duplex = 0;
+
+ /* Configure 100MBit/10MBit mode. */
+ if (linksts & LNK_STAT_SPEED10MPS)
+ physts.phy_speed_100mbs = 0;
+ else
+ physts.phy_speed_100mbs = 1;
+
+ if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
+ changed = 1;
+ if (physts.phy_speed_100mbs) {
+ /* 100MBit mode. */
+ lpc_emac_set_speed(1);
+
+ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
+ }
+ else {
+ /* 10MBit mode. */
+ lpc_emac_set_speed(0);
+
+ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
+ }
+
+ olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
+ }
+
+ if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
+ changed = 1;
+ if (physts.phy_full_duplex)
+ lpc_emac_set_duplex(1);
+ else
+ lpc_emac_set_duplex(0);
+
+ olddphysts.phy_full_duplex = physts.phy_full_duplex;
+ }
+
+ if (physts.phy_link_active != olddphysts.phy_link_active) {
+ changed = 1;
+#if NO_SYS == 1
+ if (physts.phy_link_active)
+ netif_set_link_up(netif);
+ else
+ netif_set_link_down(netif);
+#else
+ if (physts.phy_link_active)
+ tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
+ (void*) netif, 1);
+ else
+ tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
+ (void*) netif, 1);
+#endif
+
+ olddphysts.phy_link_active = physts.phy_link_active;
+ }
+
+ return changed;
+}
+
+/** \brief Initialize the DP83848 PHY.
+ *
+ * This function initializes the DP83848 PHY. It will block until
+ * complete. This function is called as part of the EMAC driver
+ * initialization. Configuration of the PHY at startup is
+ * controlled by setting up configuration defines in lpc_phy.h.
+ *
+ * \param[in] netif NETIF structure
+ * \param[in] rmii If set, configures the PHY for RMII mode
+ * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
+ */
+err_t lpc_phy_init(struct netif *netif, int rmii)
+{
+ u32_t tmp;
+ s32_t i;
+
+ physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0;
+ physts.phy_full_duplex = olddphysts.phy_full_duplex = 0;
+ physts.phy_link_active = olddphysts.phy_link_active = 0;
+ phyustate = 0;
+
+ /* Only first read and write are checked for failure */
+ /* Put the DP83848C in reset mode and wait for completion */
+ if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0)
+ return ERR_TIMEOUT;
+ i = 400;
+ while (i > 0) {
+ osDelay(1); /* 1 ms */
+ if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0)
+ return ERR_TIMEOUT;
+
+ if (!(tmp & (DP8_RESET | DP8_POWER_DOWN)))
+ i = -1;
+ else
+ i--;
+ }
+ /* Timeout? */
+ if (i == 0)
+ return ERR_TIMEOUT;
+
+ // read PHY ID
+ lpc_mii_read(DP8_IDR1_REG, &tmp);
+ phy_id = (tmp << 16);
+ lpc_mii_read(DP8_IDR2_REG, &tmp);
+ phy_id |= (tmp & 0XFFF0);
+
+ /* Setup link based on configuration options */
+#if PHY_USE_AUTONEG==1
+ tmp = DP8_AUTONEG;
+#else
+ tmp = 0;
+#endif
+#if PHY_USE_100MBS==1
+ tmp |= DP8_SPEED_SELECT;
+#endif
+#if PHY_USE_FULL_DUPLEX==1
+ tmp |= DP8_DUPLEX_MODE;
+#endif
+ lpc_mii_write(DP8_BMCR_REG, tmp);
+
+ /* Enable RMII mode for PHY */
+ if (rmii)
+ lpc_mii_write(DP8_PHY_RBR_REG, DP8_RBR_RMII_MODE);
+
+ /* The link is not set active at this point, but will be detected
+ later */
+
+ return ERR_OK;
+}
+
+/* Phy status update state machine */
+s32_t lpc_phy_sts_sm(struct netif *netif)
+{
+ s32_t changed = 0;
+ u32_t data = 0;
+ u32_t tmp;
+
+ switch (phyustate) {
+ default:
+ case 0:
+ if (phy_id == DP83848C_ID) {
+ lpc_mii_read_noblock(DP8_PHY_STAT_REG);
+ phyustate = 2;
+ }
+ else if (phy_id == LAN8720_ID) {
+ lpc_mii_read_noblock(DP8_PHY_SCSR_REG);
+ phyustate = 1;
+ }
+ break;
+
+ case 1:
+ if (phy_id == LAN8720_ID) {
+ tmp = lpc_mii_read_data();
+ // we get speed and duplex here.
+ phy_lan7420_sts_tmp = (tmp & PHY_SCSR_DUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
+ phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS;
+
+ //read the status register to get link status
+ lpc_mii_read_noblock(DP8_BMSR_REG);
+ phyustate = 2;
+ }
+ break;
+
+ case 2:
+ /* Wait for read status state */
+ if (!lpc_mii_is_busy()) {
+ /* Update PHY status */
+ tmp = lpc_mii_read_data();
+
+ if (phy_id == DP83848C_ID) {
+ // STS register contains all needed status bits
+ data = (tmp & DP8_VALID_LINK) ? LNK_STAT_VALID : 0;
+ data |= (tmp & DP8_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
+ data |= (tmp & DP8_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0;
+ }
+ else if (phy_id == LAN8720_ID) {
+ // we only get the link status here.
+ phy_lan7420_sts_tmp |= (tmp & DP8_LINK_STATUS) ? LNK_STAT_VALID : 0;
+ data = phy_lan7420_sts_tmp;
+ }
+
+ changed = lpc_update_phy_sts(netif, data);
+ phyustate = 0;
+ }
+ break;
+ }
+
+ return changed;
+}
+
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h
new file mode 100644
index 0000000000..a117fa6c93
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_CONF_H
+#define LWIPOPTS_CONF_H
+
+#define LWIP_TRANSPORT_ETHERNET 1
+
+#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+#define MEM_SIZE 15360
+#elif defined(TARGET_LPC1768)
+#define MEM_SIZE 16362
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h
new file mode 100644
index 0000000000..1ad186c7a1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_CONF_H
+#define LWIPOPTS_CONF_H
+
+#define LWIP_TRANSPORT_ETHERNET 1
+
+#define MEM_SIZE (1600 * 16)
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c
new file mode 100644
index 0000000000..761679e3b7
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c
@@ -0,0 +1,192 @@
+#include "lwip/opt.h"
+#include "lwip/tcpip.h"
+#include "netif/etharp.h"
+#include "mbed_interface.h"
+#include "ethernet_api.h"
+#include "ethernetext_api.h"
+
+#define RECV_TASK_PRI (osPriorityNormal)
+#define PHY_TASK_PRI (osPriorityNormal)
+#define PHY_TASK_WAIT (200)
+
+/* memory */
+static sys_sem_t recv_ready_sem; /* receive ready semaphore */
+
+/* function */
+static void rza1_recv_task(void *arg);
+static void rza1_phy_task(void *arg);
+static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
+static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p);
+static void rza1_recv_callback(void);
+
+static void rza1_recv_task(void *arg) {
+ struct netif *netif = (struct netif*)arg;
+ struct eth_hdr *ethhdr;
+ u16_t recv_size;
+ struct pbuf *p;
+ struct pbuf *q;
+
+ while (1) {
+ sys_arch_sem_wait(&recv_ready_sem, 0);
+ recv_size = ethernet_receive();
+ if (recv_size != 0) {
+ p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_POOL);
+ if (p != NULL) {
+ for (q = p; q != NULL; q = q->next) {
+ (void)ethernet_read((char *)q->payload, q->len);
+ }
+ ethhdr = p->payload;
+ switch (htons(ethhdr->type)) {
+ case ETHTYPE_IP:
+ case ETHTYPE_ARP:
+#if PPPOE_SUPPORT
+ case ETHTYPE_PPPOEDISC:
+ case ETHTYPE_PPPOE:
+#endif /* PPPOE_SUPPORT */
+ /* full packet send to tcpip_thread to process */
+ if (netif->input(p, netif) != ERR_OK) {
+ /* Free buffer */
+ pbuf_free(p);
+ }
+ break;
+ default:
+ /* Return buffer */
+ pbuf_free(p);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void rza1_phy_task(void *arg) {
+ struct netif *netif = (struct netif*)arg;
+ s32_t connect_sts = 0; /* 0: disconnect, 1:connect */
+ s32_t link_sts;
+ s32_t link_mode_new = NEGO_FAIL;
+ s32_t link_mode_old = NEGO_FAIL;
+
+ while (1) {
+ link_sts = ethernet_link();
+ if (link_sts == 1) {
+ link_mode_new = ethernetext_chk_link_mode();
+ if (link_mode_new != link_mode_old) {
+ if (connect_sts == 1) {
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
+ }
+ if (link_mode_new != NEGO_FAIL) {
+ ethernetext_set_link_mode(link_mode_new);
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
+ connect_sts = 1;
+ }
+ }
+ } else {
+ if (connect_sts != 0) {
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
+ link_mode_new = NEGO_FAIL;
+ connect_sts = 0;
+ }
+ }
+ link_mode_old = link_mode_new;
+ osDelay(PHY_TASK_WAIT);
+ }
+}
+
+static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) {
+ /* Only send packet is link is up */
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+ return etharp_output(netif, q, ipaddr);
+ }
+
+ return ERR_CONN;
+}
+
+static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p) {
+ struct pbuf *q;
+ s32_t cnt;
+ err_t err = ERR_MEM;
+ s32_t write_size = 0;
+
+ if ((p->payload != NULL) && (p->len != 0)) {
+ /* If the first data can't be written, transmit descriptor is full. */
+ for (cnt = 0; cnt < 100; cnt++) {
+ write_size = ethernet_write((char *)p->payload, p->len);
+ if (write_size != 0) {
+ break;
+ }
+ osDelay(1);
+ }
+ if (write_size != 0) {
+ for (q = p->next; q != NULL; q = q->next) {
+ (void)ethernet_write((char *)q->payload, q->len);
+ }
+ if (ethernet_send() == 1) {
+ err = ERR_OK;
+ }
+ }
+ }
+
+ return err;
+}
+
+static void rza1_recv_callback(void) {
+ sys_sem_signal(&recv_ready_sem);
+}
+
+err_t eth_arch_enetif_init(struct netif *netif)
+{
+ ethernet_cfg_t ethcfg;
+
+ /* set MAC hardware address */
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+ netif->hwaddr[0] = MBED_MAC_ADDR_0;
+ netif->hwaddr[1] = MBED_MAC_ADDR_1;
+ netif->hwaddr[2] = MBED_MAC_ADDR_2;
+ netif->hwaddr[3] = MBED_MAC_ADDR_3;
+ netif->hwaddr[4] = MBED_MAC_ADDR_4;
+ netif->hwaddr[5] = MBED_MAC_ADDR_5;
+#else
+ mbed_mac_address((char *)netif->hwaddr);
+#endif
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* maximum transfer unit */
+ netif->mtu = 1500;
+
+ /* device capabilities */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ netif->hostname = "lwiprza1";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ netif->name[0] = 'e';
+ netif->name[1] = 'n';
+
+ netif->output = rza1_etharp_output;
+ netif->linkoutput = rza1_low_level_output;
+
+ /* Initialize the hardware */
+ ethcfg.int_priority = 6;
+ ethcfg.recv_cb = &rza1_recv_callback;
+ ethcfg.ether_mac = (char *)netif->hwaddr;
+ ethernetext_init(&ethcfg);
+
+ /* semaphore */
+ sys_sem_new(&recv_ready_sem, 0);
+
+ /* task */
+ sys_thread_new("rza1_recv_task", rza1_recv_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
+ sys_thread_new("rza1_phy_task", rza1_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
+
+ return ERR_OK;
+}
+
+void eth_arch_enable_interrupts(void) {
+ ethernetext_start_stop(1);
+}
+
+void eth_arch_disable_interrupts(void) {
+ ethernetext_start_stop(0);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/lwipopts_conf.h
new file mode 100644
index 0000000000..0851fd63fe
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/lwipopts_conf.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2015 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_CONF_H
+#define LWIPOPTS_CONF_H
+
+#define LWIP_TRANSPORT_ETHERNET 1
+
+#define MEM_SIZE (1600 * 16)
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/stm32f4_emac.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/stm32f4_emac.c
new file mode 100644
index 0000000000..d7be37bbc8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/eth/lwip-eth/arch/TARGET_STM/stm32f4_emac.c
@@ -0,0 +1,560 @@
+
+#include "stm32f4xx_hal.h"
+#include "lwip/opt.h"
+
+#include "lwip/timers.h"
+#include "netif/etharp.h"
+#include "lwip/tcpip.h"
+#include <string.h>
+#include "cmsis_os.h"
+#include "mbed_interface.h"
+
+/** @defgroup lwipstm32f4xx_emac_DRIVER stm32f4 EMAC driver for LWIP
+ * @ingroup lwip_emac
+ *
+ * @{
+ */
+
+#define RECV_TASK_PRI (osPriorityHigh)
+#define PHY_TASK_PRI (osPriorityLow)
+#define PHY_TASK_WAIT (200)
+
+
+#if defined (__ICCARM__) /*!< IAR Compiler */
+ #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END; /* Ethernet Rx MA Descriptor */
+
+#if defined (__ICCARM__) /*!< IAR Compiler */
+ #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END; /* Ethernet Tx DMA Descriptor */
+
+#if defined (__ICCARM__) /*!< IAR Compiler */
+ #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
+
+#if defined (__ICCARM__) /*!< IAR Compiler */
+ #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
+
+
+ETH_HandleTypeDef heth;
+
+static sys_sem_t rx_ready_sem; /* receive ready semaphore */
+static sys_mutex_t tx_lock_mutex;
+
+/* function */
+static void stm32f4_rx_task(void *arg);
+static void stm32f4_phy_task(void *arg);
+static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
+static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p);
+
+/**
+ * Override HAL Eth Init function
+ */
+void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+ if (heth->Instance == ETH) {
+ /* Peripheral clock enable */
+ __ETH_CLK_ENABLE();
+
+ __GPIOA_CLK_ENABLE();
+ __GPIOB_CLK_ENABLE();
+ __GPIOC_CLK_ENABLE();
+
+ /**ETH GPIO Configuration
+ PC1 ------> ETH_MDC
+ PA1 ------> ETH_REF_CLK
+ PA2 ------> ETH_MDIO
+ PA7 ------> ETH_CRS_DV
+ PC4 ------> ETH_RXD0
+ PC5 ------> ETH_RXD1
+ PB11 ------> ETH_TX_EN
+ PB12 ------> ETH_TXD0
+ PB13 ------> ETH_TXD1
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+ /* Peripheral interrupt init*/
+ /* Sets the priority grouping field */
+ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
+ HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(ETH_IRQn);
+ }
+}
+
+/**
+ * Override HAL Eth DeInit function
+ */
+void HAL_ETH_MspDeInit(ETH_HandleTypeDef* heth)
+{
+ if (heth->Instance == ETH) {
+ /* Peripheral clock disable */
+ __ETH_CLK_DISABLE();
+
+ /**ETH GPIO Configuration
+ PC1 ------> ETH_MDC
+ PA1 ------> ETH_REF_CLK
+ PA2 ------> ETH_MDIO
+ PA7 ------> ETH_CRS_DV
+ PC4 ------> ETH_RXD0
+ PC5 ------> ETH_RXD1
+ PB11 ------> ETH_TX_EN
+ PB12 ------> ETH_TXD0
+ PB13 ------> ETH_TXD1
+ */
+ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
+
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);
+
+ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13);
+
+ /* Peripheral interrupt Deinit*/
+ HAL_NVIC_DisableIRQ(ETH_IRQn);
+ }
+}
+
+/**
+ * Ethernet Rx Transfer completed callback
+ *
+ * @param heth: ETH handle
+ * @retval None
+ */
+void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
+{
+
+ sys_sem_signal(&rx_ready_sem);
+}
+
+
+/**
+ * Ethernet IRQ Handler
+ *
+ * @param None
+ * @retval None
+ */
+void ETH_IRQHandler(void)
+{
+ HAL_ETH_IRQHandler(&heth);
+}
+
+
+
+/**
+ * In this function, the hardware should be initialized.
+ * Called from eth_arch_enetif_init().
+ *
+ * @param netif the already initialized lwip network interface structure
+ * for this ethernetif
+ */
+static void stm32f4_low_level_init(struct netif *netif)
+{
+ uint32_t regvalue = 0;
+ HAL_StatusTypeDef hal_eth_init_status;
+
+ /* Init ETH */
+ uint8_t MACAddr[6];
+ heth.Instance = ETH;
+ heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
+ heth.Init.Speed = ETH_SPEED_10M;
+ heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
+ heth.Init.PhyAddress = 1;
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+ MACAddr[0] = MBED_MAC_ADDR_0;
+ MACAddr[1] = MBED_MAC_ADDR_1;
+ MACAddr[2] = MBED_MAC_ADDR_2;
+ MACAddr[3] = MBED_MAC_ADDR_3;
+ MACAddr[4] = MBED_MAC_ADDR_4;
+ MACAddr[5] = MBED_MAC_ADDR_5;
+#else
+ mbed_mac_address((char *)MACAddr);
+#endif
+ heth.Init.MACAddr = &MACAddr[0];
+ heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
+ heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
+ heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
+ hal_eth_init_status = HAL_ETH_Init(&heth);
+
+ if (hal_eth_init_status == HAL_OK) {
+ /* Set netif link flag */
+ netif->flags |= NETIF_FLAG_LINK_UP;
+ }
+
+ /* Initialize Tx Descriptors list: Chain Mode */
+ HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
+
+ /* Initialize Rx Descriptors list: Chain Mode */
+ HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
+
+ #if LWIP_ARP || LWIP_ETHERNET
+ /* set MAC hardware address length */
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* set MAC hardware address */
+ netif->hwaddr[0] = heth.Init.MACAddr[0];
+ netif->hwaddr[1] = heth.Init.MACAddr[1];
+ netif->hwaddr[2] = heth.Init.MACAddr[2];
+ netif->hwaddr[3] = heth.Init.MACAddr[3];
+ netif->hwaddr[4] = heth.Init.MACAddr[4];
+ netif->hwaddr[5] = heth.Init.MACAddr[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;
+
+ /* Enable MAC and DMA transmission and reception */
+ HAL_ETH_Start(&heth);
+
+ /**** Configure PHY to generate an interrupt when Eth Link state changes ****/
+ /* Read Register Configuration */
+ HAL_ETH_ReadPHYRegister(&heth, PHY_MICR, &regvalue);
+
+ regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);
+
+ /* Enable Interrupts */
+ HAL_ETH_WritePHYRegister(&heth, PHY_MICR, regvalue);
+
+ /* Read Register Configuration */
+ HAL_ETH_ReadPHYRegister(&heth, PHY_MISR, &regvalue);
+
+ regvalue |= PHY_MISR_LINK_INT_EN;
+
+ /* Enable Interrupt on change of link status */
+ HAL_ETH_WritePHYRegister(&heth, PHY_MISR, regvalue);
+#endif
+}
+
+/**
+ * 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 availale since the stack doesn't retry to send a packet
+ * dropped because of memory failure (except for the TCP timers).
+ */
+
+static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p)
+{
+ err_t errval;
+ struct pbuf *q;
+ uint8_t *buffer = (uint8_t*)(heth.TxDesc->Buffer1Addr);
+ __IO ETH_DMADescTypeDef *DmaTxDesc;
+ uint32_t framelength = 0;
+ uint32_t bufferoffset = 0;
+ uint32_t byteslefttocopy = 0;
+ uint32_t payloadoffset = 0;
+ DmaTxDesc = heth.TxDesc;
+ bufferoffset = 0;
+
+
+ sys_mutex_lock(&tx_lock_mutex);
+
+ /* copy frame from pbufs to driver buffers */
+ for (q = p; q != NULL; q = q->next) {
+ /* Is this buffer available? If not, goto error */
+ if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
+ errval = ERR_USE;
+ goto error;
+ }
+
+ /* Get bytes in current lwIP buffer */
+ byteslefttocopy = q->len;
+ payloadoffset = 0;
+
+ /* Check if the length of data to copy is bigger than Tx buffer size*/
+ while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) {
+ /* Copy data to Tx buffer*/
+ memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
+
+ /* Point to next descriptor */
+ DmaTxDesc = (ETH_DMADescTypeDef*)(DmaTxDesc->Buffer2NextDescAddr);
+
+ /* Check if the buffer is available */
+ if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
+ errval = ERR_USE;
+ goto error;
+ }
+
+ buffer = (uint8_t*)(DmaTxDesc->Buffer1Addr);
+
+ byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
+ payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
+ framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
+ bufferoffset = 0;
+ }
+
+ /* Copy the remaining bytes */
+ memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy);
+ bufferoffset = bufferoffset + byteslefttocopy;
+ framelength = framelength + byteslefttocopy;
+ }
+
+ /* Prepare transmit descriptors to give to DMA */
+ HAL_ETH_TransmitFrame(&heth, framelength);
+
+ errval = ERR_OK;
+
+error:
+
+ /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
+ if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
+ /* Clear TUS ETHERNET DMA flag */
+ heth.Instance->DMASR = ETH_DMASR_TUS;
+
+ /* Resume DMA transmission*/
+ heth.Instance->DMATPDR = 0;
+ }
+
+ sys_mutex_unlock(&tx_lock_mutex);
+
+ return errval;
+}
+
+
+/**
+ * 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 * stm32f4_low_level_input(struct netif *netif)
+{
+ struct pbuf *p = NULL;
+ struct pbuf *q;
+ uint16_t len = 0;
+ uint8_t *buffer;
+ __IO ETH_DMADescTypeDef *dmarxdesc;
+ uint32_t bufferoffset = 0;
+ uint32_t payloadoffset = 0;
+ uint32_t byteslefttocopy = 0;
+ uint32_t i = 0;
+
+
+ /* get received frame */
+ if (HAL_ETH_GetReceivedFrame(&heth) != HAL_OK)
+ return NULL;
+
+ /* Obtain the size of the packet and put it into the "len" variable. */
+ len = heth.RxFrameInfos.length;
+ buffer = (uint8_t*)heth.RxFrameInfos.buffer;
+
+ if (len > 0) {
+ /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
+ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+ }
+
+ if (p != NULL) {
+ dmarxdesc = heth.RxFrameInfos.FSRxDesc;
+ bufferoffset = 0;
+ for (q = p; q != NULL; q = q->next) {
+ byteslefttocopy = q->len;
+ payloadoffset = 0;
+
+ /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
+ while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) {
+ /* Copy data to pbuf */
+ memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
+
+ /* Point to next descriptor */
+ dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
+ buffer = (uint8_t*)(dmarxdesc->Buffer1Addr);
+
+ byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
+ payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
+ bufferoffset = 0;
+ }
+ /* Copy remaining data in pbuf */
+ memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
+ bufferoffset = bufferoffset + byteslefttocopy;
+ }
+
+ /* Release descriptors to DMA */
+ /* Point to first descriptor */
+ dmarxdesc = heth.RxFrameInfos.FSRxDesc;
+ /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
+ for (i = 0; i < heth.RxFrameInfos.SegCount; i++) {
+ dmarxdesc->Status |= ETH_DMARXDESC_OWN;
+ dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
+ }
+
+ /* Clear Segment_Count */
+ heth.RxFrameInfos.SegCount = 0;
+ }
+
+ /* When Rx Buffer unavailable flag is set: clear it and resume reception */
+ if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
+ /* Clear RBUS ETHERNET DMA flag */
+ heth.Instance->DMASR = ETH_DMASR_RBUS;
+ /* Resume DMA reception */
+ heth.Instance->DMARPDR = 0;
+ }
+ return p;
+}
+
+/**
+ * This task receives input data
+ *
+ * \param[in] netif the lwip network interface structure
+ */
+static void stm32f4_rx_task(void *arg)
+{
+ struct netif *netif = (struct netif*)arg;
+ struct pbuf *p;
+
+ while (1) {
+ sys_arch_sem_wait(&rx_ready_sem, 0);
+ p = stm32f4_low_level_input(netif);
+ if (p != NULL) {
+ if (netif->input(p, netif) != ERR_OK) {
+ pbuf_free(p);
+ p = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * This task checks phy link status and updates net status
+ *
+ * \param[in] netif the lwip network interface structure
+ */
+static void stm32f4_phy_task(void *arg)
+{
+ struct netif *netif = (struct netif*)arg;
+ uint32_t phy_status = 0;
+
+ while (1) {
+ uint32_t status;
+ if (HAL_ETH_ReadPHYRegister(&heth, PHY_SR, &status) == HAL_OK) {
+ if ((status & PHY_LINK_STATUS) && !(phy_status & PHY_LINK_STATUS)) {
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
+ } else if (!(status & PHY_LINK_STATUS) && (phy_status & PHY_LINK_STATUS)) {
+ tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
+ }
+
+ phy_status = status;
+ }
+
+ osDelay(PHY_TASK_WAIT);
+ }
+}
+
+/**
+ * This function is the ethernet packet send function. It calls
+ * etharp_output after checking link status.
+ *
+ * \param[in] netif the lwip network interface structure for this lpc_enetif
+ * \param[in] q Pointer to pbug to send
+ * \param[in] ipaddr IP address
+ * \return ERR_OK or error code
+ */
+static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
+{
+ /* Only send packet is link is up */
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+ return etharp_output(netif, q, ipaddr);
+ }
+
+ return ERR_CONN;
+}
+
+/**
+ * Should be called at the beginning of the program to set up the
+ * network interface.
+ *
+ * This function should be passed as a parameter to netif_add().
+ *
+ * @param[in] netif the lwip network interface structure for this lpc_enetif
+ * @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 eth_arch_enetif_init(struct netif *netif)
+{
+ /* set MAC hardware address */
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* maximum transfer unit */
+ netif->mtu = 1500;
+
+ /* device capabilities */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ netif->hostname = "lwipstm32f4";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ netif->name[0] = 'e';
+ netif->name[1] = 'n';
+
+ netif->output = stm32f4_etharp_output;
+ netif->linkoutput = stm32f4_low_level_output;
+
+ /* semaphore */
+ sys_sem_new(&rx_ready_sem, 0);
+
+ sys_mutex_new(&tx_lock_mutex);
+
+ /* task */
+ sys_thread_new("stm32f4_recv_task", stm32f4_rx_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
+ sys_thread_new("stm32f4_phy_task", stm32f4_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
+
+ /* initialize the hardware */
+ stm32f4_low_level_init(netif);
+
+ return ERR_OK;
+}
+
+void eth_arch_enable_interrupts(void)
+{
+ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
+ HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(ETH_IRQn);
+}
+
+void eth_arch_disable_interrupts(void)
+{
+ NVIC_DisableIRQ(ETH_IRQn);
+}
+
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.cpp
new file mode 100644
index 0000000000..4fe525357d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.cpp
@@ -0,0 +1,24 @@
+#include "HTTPHeader.h"
+#include <stdlib.h>
+using std::map;
+using std::string;
+
+HTTPHeader::HTTPHeader():
+_status(HTTP_ERROR),
+_fields()
+{
+}
+
+std::string HTTPHeader::getField(const std::string& name)
+{
+ map<string,string>::iterator itor = _fields.find(name);
+ if(itor == _fields.end())
+ return string();
+ return itor->second;
+}
+
+int HTTPHeader::getBodyLength()
+{
+ return atoi(getField("Content-Length").c_str());
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.h
new file mode 100644
index 0000000000..63cfea1b74
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPHeader.h
@@ -0,0 +1,29 @@
+#ifndef HTTPHEADER_H
+#define HTTPHEADER_H
+
+#include <string>
+#include <map>
+
+enum HTTPStatus { HTTP_OK, HTTP_ERROR };
+
+class HTTPSClient;
+
+class HTTPHeader
+{
+ friend class HTTPSClient;
+
+ public :
+
+ HTTPHeader();
+
+ std::string getField(const std::string& name);
+ int getBodyLength();
+
+ private :
+
+ HTTPStatus _status;
+ std::map<std::string, std::string> _fields;
+};
+
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.cpp
new file mode 100644
index 0000000000..76eae5b4a9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.cpp
@@ -0,0 +1,163 @@
+#include "HTTPSClient.h"
+#include "HTTPHeader.h"
+#include <string>
+#include <cstring>
+#include "mbed.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+using std::memset;
+using std::memcpy;
+using std::string;
+
+const static int HTTPS_PORT = 443;
+char buf[256];
+
+HTTPSClient::HTTPSClient() :
+ _is_connected(false),
+ _ssl_ctx(),
+ _ssl(),
+ _host() {
+}
+
+HTTPSClient::~HTTPSClient() {
+ close();
+}
+
+int HTTPSClient::connect(const char* host) {
+ if (init_socket(SOCK_STREAM) < 0)
+ return -1;
+
+ if (set_address(host, HTTPS_PORT) != 0)
+ return -1;
+
+ if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) {
+ close();
+ return -1;
+ }
+
+ if(ssl_ctx_new(&_ssl_ctx, SSL_SERVER_VERIFY_LATER, SSL_DEFAULT_CLNT_SESS) != &_ssl_ctx)
+ return -1;
+
+ _ssl.ssl_ctx = &_ssl_ctx;
+
+ if(ssl_client_new(&_ssl, _sock_fd, NULL, 0) == NULL)
+ {
+ close();
+ return -1;
+ }
+ if(_ssl.hs_status != SSL_OK)
+ {
+ close();
+ return -1;
+ }
+
+ _is_connected = true;
+ _host = host;
+ return 0;
+}
+
+bool HTTPSClient::is_connected(void) {
+ return _is_connected;
+}
+
+int HTTPSClient::send(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ return ssl_write(&_ssl, (uint8_t*)data, length);
+}
+
+
+
+HTTPHeader HTTPSClient::get(char *request)
+{
+ if((_sock_fd < 0) || !_is_connected)
+ return HTTPHeader();
+
+ sprintf(buf, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", request, _host.c_str());
+ printf("buf=%s\n", buf);
+ if(send(buf, strlen(buf)) != strlen(buf))
+ return HTTPHeader();
+ printf("Finished sending request\n");
+ return read_header();
+}
+
+
+HTTPHeader HTTPSClient::read_header()
+{
+ _ssl.bm_read_index = 0;
+ _ssl.bm_index = 0;
+ HTTPHeader hdr;
+ if(read_line())
+ return hdr;
+
+ int status;
+
+ if(sscanf(buf, "HTTP/%*d.%*d %d %*s", &status) == -1)
+ return hdr;
+
+ if(status == 200)
+ hdr._status = HTTP_OK;
+ if(read_line())
+ return hdr;
+ do
+ {
+ string tmp(buf);
+ std::size_t sep = tmp.find(':');
+ string name = tmp.substr(0, sep);
+ string value = tmp.substr(sep+2, tmp.size());
+ hdr._fields[name] = value;
+ if(read_line())
+ return hdr;
+ }while(strlen(buf));
+
+ return hdr;
+}
+
+uint8_t HTTPSClient::read_line()
+{
+ int index = 0;
+ do
+ {
+ if(ssl_read(&_ssl, (uint8_t*)(&buf[index]), 1) != 1)
+ {
+ return 1;
+ }
+ index++;
+ }while(buf[index-1] != '\r' && index < 256);
+ ssl_read(&_ssl, (uint8_t*)(&buf[index-1]), 1); // skip '\n'
+ buf[index-1] = '\0';
+
+ return 0;
+}
+
+// -1:error
+// otherwise return nb of characters read. Cannot be > than len
+int HTTPSClient::read(char *data, int len)
+{
+ return ssl_read(&_ssl, (uint8_t*)data, len);
+}
+/*
+ 0 : must close connection
+ -1 : error
+ else : get data
+
+int HTTPSClient::receive(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ if(read_record(&_ssl) < 0)
+ return -1;
+ return process_data(&_ssl, (uint8_t*)data, length);
+}
+*/
+void HTTPSClient::close()
+{
+ if(!_is_connected)
+ return;
+ ssl_ctx_free(_ssl.ssl_ctx);
+ Socket::close();
+ _is_connected = false;
+ _host.clear();
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.h
new file mode 100644
index 0000000000..92c6908479
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/HTTPSClient.h
@@ -0,0 +1,56 @@
+#ifndef HTTPSCLIENT_H
+#define HTTPSCLIENT_H
+
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+#include "axTLS/ssl/ssl.h"
+#include "HTTPHeader.h"
+
+/**
+TCP socket connection
+*/
+class HTTPSClient : public Socket, public Endpoint {
+
+public:
+ /** TCP socket connection
+ */
+ HTTPSClient();
+
+
+ virtual ~HTTPSClient();
+
+ /** Connects this TCP socket to the server
+ \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS.
+ \param port The host's port to connect to.
+ \return 0 on success, -1 on failure.
+ */
+ int connect(const char* host);
+
+ /** Check if the socket is connected
+ \return true if connected, false otherwise.
+ */
+ bool is_connected(void);
+
+ // Returns the size of the body
+ HTTPHeader get(char *path);
+
+ int read(char *data, int len);
+
+
+ void close();
+
+private:
+
+
+ int send(char* data, int length);
+
+ uint8_t read_line();
+ HTTPHeader read_header();
+
+ bool _is_connected;
+ SSL_CTX _ssl_ctx;
+ SSL _ssl;
+ std::string _host;
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c
new file mode 100644
index 0000000000..2ab1e86d4a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large
+ * submix tables).
+ */
+
+#include <string.h>
+//#include "os_port.h"
+#include "crypto.h"
+#include <lwip/def.h>
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) << 8) | ((x) >> 24))
+
+/*
+ * This cute trick does 4 'mul by two' at once. Stolen from
+ * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001 0000 0000 we then subtract (c) from (b)
+ * d 0111 1111 0000 0000 and now we and with our mask
+ * e 0001 1011 0000 0000
+ */
+#define mt 0x80808080
+#define ml 0x7f7f7f7f
+#define mh 0xfefefefe
+#define mm 0x1b1b1b1b
+#define mul2(x,t) ((t)=((x)&mt), \
+ ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+ (f2)=mul2(x,f2), \
+ (f4)=mul2(f2,f4), \
+ (f8)=mul2(f4,f8), \
+ (f9)=(x)^(f8), \
+ (f8)=((f2)^(f4)^(f8)), \
+ (f2)^=(f9), \
+ (f4)^=(f9), \
+ (f8)^=rot3(f2), \
+ (f8)^=rot2(f4), \
+ (f8)^rot1(f9))
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+ 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+ 0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+ 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+ 0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+ 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+ 0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+ 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+ 0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+ 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+ 0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+ 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+ 0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+ 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+ 0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+ 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+ 0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+ 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+ 0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+ 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+ 0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+ 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+ 0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+ 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+ 0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+ 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+ 0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+ 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+ 0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+ 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+ 0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+ 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+ 0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] =
+{
+ 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+ 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+ 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+ 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+ 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+ 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+ 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+ 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+ 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+ 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+ 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+ 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+ 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+ 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+ 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+ 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+ 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+ 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+ 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+ 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+ 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+ 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+ 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+ 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+ 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+ 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+ 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+ 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+ 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+ 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+ 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+ 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+ 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+ 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+ 0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+ x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+ return (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode)
+{
+ int i, ii;
+ uint32_t *W, tmp, tmp2;
+ const unsigned char *ip;
+ int words;
+
+ switch (mode)
+ {
+ case AES_MODE_128:
+ i = 10;
+ words = 4;
+ break;
+
+ case AES_MODE_256:
+ i = 14;
+ words = 8;
+ break;
+
+ default: /* fail silently */
+ return;
+ }
+
+ ctx->rounds = i;
+ ctx->key_size = words;
+ W = ctx->ks;
+ for (i = 0; i < words; i+=2)
+ {
+ W[i+0]= ((uint32_t)key[ 0]<<24)|
+ ((uint32_t)key[ 1]<<16)|
+ ((uint32_t)key[ 2]<< 8)|
+ ((uint32_t)key[ 3] );
+ W[i+1]= ((uint32_t)key[ 4]<<24)|
+ ((uint32_t)key[ 5]<<16)|
+ ((uint32_t)key[ 6]<< 8)|
+ ((uint32_t)key[ 7] );
+ key += 8;
+ }
+
+ ip = Rcon;
+ ii = 4 * (ctx->rounds+1);
+ for (i = words; i<ii; i++)
+ {
+ tmp = W[i-1];
+
+ if ((i % words) == 0)
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
+ tmp=tmp2^(((unsigned int)*ip)<<24);
+ ip++;
+ }
+
+ if ((words == 8) && ((i % words) == 4))
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
+ tmp=tmp2;
+ }
+
+ W[i]=W[i-words]^tmp;
+ }
+
+ /* copy the iv across */
+ memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+ int i;
+ uint32_t *k,w,t1,t2,t3,t4;
+
+ k = ctx->ks;
+ k += 4;
+
+ for (i= ctx->rounds*4; i > 4; i--)
+ {
+ w= *k;
+ w = inv_mix_col(w,t1,t2,t3,t4);
+ *k++ =w;
+ }
+}
+
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], tout[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ tout[i] = ntohl(iv[i]);
+
+ for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ tin[i] = ntohl(msg_32[i])^tout[i];
+
+ AES_encrypt(ctx, tin);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(tout[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ xor[i] = ntohl(iv[i]);
+ for (length -= 16; length >= 0; length -= 16)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ {
+ tin[i] = ntohl(msg_32[i]);
+ data[i] = tin[i];
+ }
+
+ AES_decrypt(ctx, data);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = data[i]^xor[i];
+ xor[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(xor[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+
+}
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ /* To make this code smaller, generate the sbox entries on the fly.
+ * This will have a really heavy effect upon performance.
+ */
+ uint32_t tmp[4];
+ uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks;
+
+ /* Pre-round key addition */
+ for (row = 0; row < 4; row++)
+ data[row] ^= *(k++);
+
+ /* Encrypt one block. */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 0; row < 4; row++)
+ {
+ a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+ a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+ a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
+ a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd < (rounds - 1))
+ {
+ tmp1 = a0 ^ a1 ^ a2 ^ a3;
+ old_a0 = a0;
+ a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+ a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+ a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+ a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+ }
+
+ tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+ }
+
+ /* KeyAddition - note that it is vital that this loop is separate from
+ the MixColumn operation, which must be atomic...*/
+ for (row = 0; row < 4; row++)
+ data[row] = tmp[row] ^ *(k++);
+ }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ uint32_t tmp[4];
+ uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+ uint32_t a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks + ((rounds+1)*4);
+ /* pre-round key addition */
+ for (row=4; row > 0;row--)
+ data[row-1] ^= *(--k);
+
+ /* Decrypt one block */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 4; row > 0; row--)
+ {
+
+ a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+ a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+ a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+ a3 = aes_isbox[(data[row%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd<(rounds-1))
+ {
+ /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+ are quite large compared to encryption; this
+ operation slows decryption down noticeably. */
+ xt0 = AES_xtime(a0^a1);
+ xt1 = AES_xtime(a1^a2);
+ xt2 = AES_xtime(a2^a3);
+ xt3 = AES_xtime(a3^a0);
+ xt4 = AES_xtime(xt0^xt1);
+ xt5 = AES_xtime(xt1^xt2);
+ xt6 = AES_xtime(xt4^xt5);
+
+ xt0 ^= a1^a2^a3^xt4^xt6;
+ xt1 ^= a0^a2^a3^xt5^xt6;
+ xt2 ^= a0^a1^a3^xt4^xt6;
+ xt3 ^= a0^a1^a2^xt5^xt6;
+ tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+ }
+ else
+ tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+ }
+
+ for (row = 4; row > 0; row--)
+ data[row-1] = tmp[row-1] ^ *(--k);
+ }
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c
new file mode 100644
index 0000000000..7275ed1fc7
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c
@@ -0,0 +1,1515 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small
+ * cache. A bigint context may maintain state by being made "permanent".
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "os_port.h"
+#include "bigint.h"
+
+#define V1 v->comps[v->size-1] /**< v1 for division */
+#define V2 v->comps[v->size-2] /**< v2 for division */
+#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
+#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#else
+#define check(A) /**< disappears in normal production mode */
+#endif
+
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+ /* calloc() sets everything to zero */
+ BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+
+ /* the radix */
+ ctx->bi_radix = alloc(ctx, 2);
+ ctx->bi_radix->comps[0] = 0;
+ ctx->bi_radix->comps[1] = 1;
+ bi_permanent(ctx->bi_radix);
+ return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not
+ * properly freed.
+ * @param ctx [in] The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+ bi_depermanent(ctx->bi_radix);
+ bi_free(ctx, ctx->bi_radix);
+
+ if (ctx->active_count != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_terminate: there were %d un-freed bigints\n",
+ ctx->active_count);
+#endif
+ abort();
+ }
+
+ bi_clear_cache(ctx);
+ free(ctx);
+}
+
+/**
+ *@brief Clear the memory cache.
+ */
+void bi_clear_cache(BI_CTX *ctx)
+{
+ bigint *p, *pn;
+
+ if (ctx->free_list == NULL)
+ return;
+
+ for (p = ctx->free_list; p != NULL; p = pn)
+ {
+ pn = p->next;
+ free(p->comps);
+ free(p);
+ }
+
+ ctx->free_count = 0;
+ ctx->free_list = NULL;
+}
+
+/**
+ * @brief Increment the number of references to this object.
+ * It does not do a full copy.
+ * @param bi [in] The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ bi->refs++;
+ return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in] The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != 1)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_permanent: refs was not 1\n");
+#endif
+ abort();
+ }
+
+ bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in] The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_depermanent: bigint was not permanent\n");
+#endif
+ abort();
+ }
+
+ bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again.
+ *
+ * The memory itself it not actually freed, just tagged as being available
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+ check(bi);
+ if (bi->refs == PERMANENT)
+ {
+ return;
+ }
+
+ if (--bi->refs > 0)
+ {
+ return;
+ }
+
+ bi->next = ctx->free_list;
+ ctx->free_list = bi;
+ ctx->free_count++;
+
+ if (--ctx->active_count < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_free: active_count went negative "
+ "- double-freed bigint?\n");
+#endif
+ abort();
+ }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param i [in] The (unsigned) integer to be converted.
+ *
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+ bigint *biR = alloc(ctx, 1);
+ biR->comps[0] = i;
+ return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+ bigint *biR = alloc(ctx, bi->size);
+ check(bi);
+ memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+ return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ int n;
+ comp carry = 0;
+ comp *pa, *pb;
+
+ check(bia);
+ check(bib);
+
+ n = max(bia->size, bib->size);
+ more_comps(bia, n+1);
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa + *pb++;
+ rl = sl + carry;
+ cy1 = sl < *pa;
+ carry = cy1 | (rl < sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ *pa = carry; /* do overflow */
+ bi_free(ctx, bib);
+ return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx,
+ bigint *bia, bigint *bib, int *is_negative)
+{
+ int n = bia->size;
+ comp *pa, *pb, carry = 0;
+
+ check(bia);
+ check(bib);
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa - *pb++;
+ rl = sl - carry;
+ cy1 = sl > *pa;
+ carry = cy1 | (rl > sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ if (is_negative) /* indicate a negative result */
+ {
+ *is_negative = carry;
+ }
+
+ bi_free(ctx, trim(bib)); /* put bib back to the way it was */
+ return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+ int j = 0, n = bia->size;
+ bigint *biR = alloc(ctx, n + 1);
+ comp carry = 0;
+ comp *r = biR->comps;
+ comp *a = bia->comps;
+
+ check(bia);
+
+ /* clear things to start with */
+ memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+ do
+ {
+ long_comp tmp = *r + (long_comp)a[j]*b + carry;
+ *r++ = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (++j < n);
+
+ *r = carry;
+ bi_free(ctx, bia);
+ return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations.
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in] The bigint session context.
+ * @param u [in] A bigint which is the numerator.
+ * @param v [in] Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+ int n = v->size, m = u->size-n;
+ int j = 0, orig_u_size = u->size;
+ uint8_t mod_offset = ctx->mod_offset;
+ comp d;
+ bigint *quotient, *tmp_u;
+ comp q_dash;
+
+ check(u);
+ check(v);
+
+ /* if doing reduction and we are < mod, then return mod */
+ if (is_mod && bi_compare(v, u) > 0)
+ {
+ bi_free(ctx, v);
+ return u;
+ }
+
+ quotient = alloc(ctx, m+1);
+ tmp_u = alloc(ctx, n+1);
+ v = trim(v); /* make sure we have no leading 0's */
+ d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+ /* clear things to start with */
+ memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+ /* normalise */
+ if (d > 1)
+ {
+ u = bi_int_multiply(ctx, u, d);
+
+ if (is_mod)
+ {
+ v = ctx->bi_normalised_mod[mod_offset];
+ }
+ else
+ {
+ v = bi_int_multiply(ctx, v, d);
+ }
+ }
+
+ if (orig_u_size == u->size) /* new digit position u0 */
+ {
+ more_comps(u, orig_u_size + 1);
+ }
+
+ do
+ {
+ /* get a temporary short version of u */
+ memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+ /* calculate q' */
+ if (U(0) == V1)
+ {
+ q_dash = COMP_RADIX-1;
+ }
+ else
+ {
+ q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+
+ if (v->size > 1 && V2)
+ {
+ /* we are implementing the following:
+ if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) -
+ q_dash*V1)*COMP_RADIX) + U(2))) ... */
+ comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) -
+ (long_comp)q_dash*V1);
+ if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+ {
+ q_dash--;
+ }
+ }
+ }
+
+ /* multiply and subtract */
+ if (q_dash)
+ {
+ int is_negative;
+ tmp_u = bi_subtract(ctx, tmp_u,
+ bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+ more_comps(tmp_u, n+1);
+
+ Q(j) = q_dash;
+
+ /* add back */
+ if (is_negative)
+ {
+ Q(j)--;
+ tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+ /* lop off the carry */
+ tmp_u->size--;
+ v->size--;
+ }
+ }
+ else
+ {
+ Q(j) = 0;
+ }
+
+ /* copy back to u */
+ memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+ } while (++j <= m);
+
+ bi_free(ctx, tmp_u);
+ bi_free(ctx, v);
+
+ if (is_mod) /* get the remainder */
+ {
+ bi_free(ctx, quotient);
+ return bi_int_divide(ctx, trim(u), d);
+ }
+ else /* get the quotient */
+ {
+ bi_free(ctx, u);
+ return trim(quotient);
+ }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
+{
+ int i = biR->size - 1;
+ long_comp r = 0;
+
+ check(biR);
+
+ do
+ {
+ r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+ biR->comps[i] = (comp)(r / denom);
+ r %= denom;
+ } while (--i >= 0);
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the
+ * simple algorithm from an article by Dusse and Kaliski to efficiently
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+ int i;
+ comp t = 1;
+ comp two_2_i_minus_1 = 2; /* 2^(i-1) */
+ long_comp two_2_i = 4; /* 2^i */
+ comp N = bim->comps[0];
+
+ for (i = 2; i <= COMP_BIT_SIZE; i++)
+ {
+ if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+ {
+ t += two_2_i_minus_1;
+ }
+
+ two_2_i_minus_1 <<= 1;
+ two_2_i <<= 1;
+ }
+
+ return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components)
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-num_shifts;
+ comp *x = biR->comps;
+ comp *y = &biR->comps[num_shifts];
+
+ check(biR);
+
+ if (i <= 0) /* have we completely right shifted? */
+ {
+ biR->comps[0] = 0; /* return 0 */
+ biR->size = 1;
+ return biR;
+ }
+
+ do
+ {
+ *x++ = *y++;
+ } while (--i > 0);
+
+ biR->size -= num_shifts;
+ return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components)
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-1;
+ comp *x, *y;
+
+ check(biR);
+
+ if (num_shifts <= 0)
+ {
+ return biR;
+ }
+
+ more_comps(biR, biR->size + num_shifts);
+
+ x = &biR->comps[i+num_shifts];
+ y = &biR->comps[i];
+
+ do
+ {
+ *x-- = *y--;
+ } while (i--);
+
+ memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+ return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+ bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+ int i, j = 0, offset = 0;
+
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ biR->comps[offset] += data[i] << (j*8);
+
+ if (++j == COMP_BYTE_SIZE)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and
+ * convert them into bigints.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+ int size = strlen(data);
+ bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+ int i, j = 0, offset = 0;
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+ biR->comps[offset] += num << (j*4);
+
+ if (++j == COMP_NUM_NIBBLES)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+ int i, j;
+
+ if (x == NULL)
+ {
+ printf("%s: (null)\n", label);
+ return;
+ }
+
+ printf("%s: (size %d)\n", label, x->size);
+ for (i = x->size-1; i >= 0; i--)
+ {
+ for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+ {
+ comp mask = 0x0f << (j*4);
+ comp num = (x->comps[i] & mask) >> (j*4);
+ putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+ }
+ }
+
+ printf("\r\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence.
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in] The bigint session context.
+ * @param x [in] The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+ int i, j, k = size-1;
+
+ check(x);
+ memset(data, 0, size); /* ensure all leading 0's are cleared */
+
+ for (i = 0; i < x->size; i++)
+ {
+ for (j = 0; j < COMP_BYTE_SIZE; j++)
+ {
+ comp mask = 0xff << (j*8);
+ int num = (x->comps[i] & mask) >> (j*8);
+ data[k--] = num;
+
+ if (k < 0)
+ {
+ goto buf_done;
+ }
+ }
+ }
+buf_done:
+
+ bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction.
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in] The bigint session context.
+ * @param bim [in] The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+ int k = bim->size;
+ comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ bigint *R, *R2;
+#endif
+
+ ctx->bi_mod[mod_offset] = bim;
+ bi_permanent(ctx->bi_mod[mod_offset]);
+ ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+ bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ /* set montgomery variables */
+ R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */
+ R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */
+ ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */
+ ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */
+
+ bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+ ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+ ctx->bi_mu[mod_offset] =
+ bi_divide(ctx, comp_left_shift(
+ bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+ bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in] The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+ bi_depermanent(ctx->bi_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+ bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bi_depermanent(ctx->bi_mu[mod_offset]);
+ bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+ bi_depermanent(ctx->bi_normalised_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/**
+ * Perform a standard multiplication between two bigints.
+ *
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods.
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
+ int inner_partial, int outer_partial)
+{
+ int i = 0, j;
+ int n = bia->size;
+ int t = bib->size;
+ bigint *biR = alloc(ctx, n + t);
+ comp *sr = biR->comps;
+ comp *sa = bia->comps;
+ comp *sb = bib->comps;
+
+ check(bia);
+ check(bib);
+
+ /* clear things to start with */
+ memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+
+ do
+ {
+ long_comp tmp;
+ comp carry = 0;
+ int r_index = i;
+ j = 0;
+
+ if (outer_partial && outer_partial-i > 0 && outer_partial < n)
+ {
+ r_index = outer_partial-1;
+ j = outer_partial-i-1;
+ }
+
+ do
+ {
+ if (inner_partial && r_index >= inner_partial)
+ {
+ break;
+ }
+
+ tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry;
+ sr[r_index++] = (comp)tmp; /* downsize */
+ carry = tmp >> COMP_BIT_SIZE;
+ } while (++j < n);
+
+ sr[r_index] = carry;
+ } while (++i < t);
+
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications
+ * being done instead of 4. The additional additions/subtractions are O(N)
+ * rather than O(N^2) and so for big numbers it saves on a few operations
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+ bigint *x0, *x1;
+ bigint *p0, *p1, *p2;
+ int m;
+
+ if (is_square)
+ {
+ m = (bia->size + 1)/2;
+ }
+ else
+ {
+ m = (max(bia->size, bib->size) + 1)/2;
+ }
+
+ x0 = bi_clone(ctx, bia);
+ x0->size = m;
+ x1 = bi_clone(ctx, bia);
+ comp_right_shift(x1, m);
+ bi_free(ctx, bia);
+
+ /* work out the 3 partial products */
+ if (is_square)
+ {
+ p0 = bi_square(ctx, bi_copy(x0));
+ p2 = bi_square(ctx, bi_copy(x1));
+ p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+ }
+ else /* normal multiply */
+ {
+ bigint *y0, *y1;
+ y0 = bi_clone(ctx, bib);
+ y0->size = m;
+ y1 = bi_clone(ctx, bib);
+ comp_right_shift(y1, m);
+ bi_free(ctx, bib);
+
+ p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+ p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+ p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+ }
+
+ p1 = bi_subtract(ctx,
+ bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+ comp_left_shift(p1, m);
+ comp_left_shift(p2, 2*m);
+ return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ check(bia);
+ check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+ {
+ return regular_multiply(ctx, bia, bib, 0, 0);
+ }
+
+ return karatsuba(ctx, bia, bib, 0);
+#else
+ return regular_multiply(ctx, bia, bib, 0, 0);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+ int t = bi->size;
+ int i = 0, j;
+ bigint *biR = alloc(ctx, t*2+1);
+ comp *w = biR->comps;
+ comp *x = bi->comps;
+ long_comp carry;
+ memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+ do
+ {
+ long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+ w[2*i] = (comp)tmp;
+ carry = tmp >> COMP_BIT_SIZE;
+
+ for (j = i+1; j < t; j++)
+ {
+ uint8_t c = 0;
+ long_comp xx = (long_comp)x[i]*x[j];
+ if ((COMP_MAX-xx) < xx)
+ c = 1;
+
+ tmp = (xx<<1);
+
+ if ((COMP_MAX-tmp) < w[i+j])
+ c = 1;
+
+ tmp += w[i+j];
+
+ if ((COMP_MAX-tmp) < carry)
+ c = 1;
+
+ tmp += carry;
+ w[i+j] = (comp)tmp;
+ carry = tmp >> COMP_BIT_SIZE;
+
+ if (c)
+ carry += COMP_RADIX;
+ }
+
+ tmp = w[i+t] + carry;
+ w[i+t] = (comp)tmp;
+ w[i+t+1] = tmp >> COMP_BIT_SIZE;
+ } while (++i < t);
+
+ bi_free(ctx, bi);
+ return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+ check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (bia->size < SQU_KARATSUBA_THRESH)
+ {
+ return regular_square(ctx, bia);
+ }
+
+ return karatsuba(ctx, bia, NULL, 1);
+#else
+ return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+ int r, i;
+
+ check(bia);
+ check(bib);
+
+ if (bia->size > bib->size)
+ r = 1;
+ else if (bia->size < bib->size)
+ r = -1;
+ else
+ {
+ comp *a = bia->comps;
+ comp *b = bib->comps;
+
+ /* Same number of components. Compare starting from the high end
+ * and working down. */
+ r = 0;
+ i = bia->size - 1;
+
+ do
+ {
+ if (a[i] > b[i])
+ {
+ r = 1;
+ break;
+ }
+ else if (a[i] < b[i])
+ {
+ r = -1;
+ break;
+ }
+ } while (--i >= 0);
+ }
+
+ return r;
+}
+
+/*
+ * Allocate and zero more components. Does not consume bi.
+ */
+static void more_comps(bigint *bi, int n)
+{
+ if (n > bi->max_comps)
+ {
+ bi->max_comps = max(bi->max_comps * 2, n);
+ bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+ }
+
+ if (n > bi->size)
+ {
+ memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+ }
+
+ bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+ bigint *biR;
+
+ /* Can we recycle an old bigint? */
+ if (ctx->free_list != NULL)
+ {
+ biR = ctx->free_list;
+ ctx->free_list = biR->next;
+ ctx->free_count--;
+
+ if (biR->refs != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("alloc: refs was not 0\n");
+#endif
+ abort(); /* create a stack trace from a core dump */
+ }
+
+ more_comps(biR, size);
+ }
+ else
+ {
+ /* No free bigints available - create a new one. */
+ biR = (bigint *)malloc(sizeof(bigint));
+ biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+ biR->max_comps = size; /* give some space to spare */
+ }
+
+ biR->size = size;
+ biR->refs = 1;
+ biR->next = NULL;
+ ctx->active_count++;
+ return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+ int i = COMP_BIT_SIZE-1;
+ comp shift = COMP_RADIX/2;
+ comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */
+
+ check(biexp);
+
+ do
+ {
+ if (test & shift)
+ {
+ return i+(biexp->size-1)*COMP_BIT_SIZE;
+ }
+
+ shift >>= 1;
+ } while (i-- != 0);
+
+ return -1; /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+ comp test = biexp->comps[offset / COMP_BIT_SIZE];
+ int num_shifts = offset % COMP_BIT_SIZE;
+ comp shift = 1;
+ int i;
+
+ check(biexp);
+
+ for (i = 0; i < num_shifts; i++)
+ {
+ shift <<= 1;
+ }
+
+ return (test & shift) != 0;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+ if (bi->refs <= 0)
+ {
+ printf("check: zero or negative refs in bigint\n");
+ abort();
+ }
+
+ if (bi->next != NULL)
+ {
+ printf("check: attempt to use a bigint from "
+ "the free list\n");
+ abort();
+ }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+ check(bi);
+
+ while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+ {
+ bi->size--;
+ }
+
+ return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bixy [in] A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+ int i = 0, n;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ comp mod_inv = ctx->N0_dash[mod_offset];
+
+ check(bixy);
+
+ if (ctx->use_classical) /* just use classical instead */
+ {
+ return bi_mod(ctx, bixy);
+ }
+
+ n = bim->size;
+
+ do
+ {
+ bixy = bi_add(ctx, bixy, comp_left_shift(
+ bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+ } while (++i < n);
+
+ comp_right_shift(bixy, n);
+
+ if (bi_compare(bixy, bim) >= 0)
+ {
+ bixy = bi_subtract(ctx, bixy, bim, NULL);
+ }
+
+ return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+ check(bi);
+
+ if (bi->size > mod)
+ {
+ bi->size = mod;
+ }
+
+ return bi;
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+
+ bigint *q1, *q2, *q3, *r1, *r2, *r;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ int k = bim->size;
+
+ check(bi);
+ check(bim);
+
+ /* use Classical method instead - Barrett cannot help here */
+ if (bi->size > k*2)
+ {
+
+ return bi_mod(ctx, bi);
+ }
+ bigint* a = bi_clone(ctx, bi);
+ q1 = comp_right_shift(a, k-1);
+
+ /* do outer partial multiply */
+ q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1);
+ q3 = comp_right_shift(q2, k+1);
+ r1 = comp_mod(bi, k+1);
+
+ /* do inner partial multiply */
+ r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1);
+ r = bi_subtract(ctx, r1, r2, NULL);
+
+ /* if (r >= m) r = r - m; */
+ if (bi_compare(r, bim) >= 0)
+ {
+
+ r = bi_subtract(ctx, r, bim, NULL);
+ }
+
+ return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+ int k = 1, i;
+ bigint *g2;
+
+ for (i = 0; i < window-1; i++) /* compute 2^(window-1) */
+ {
+ k <<= 1;
+ }
+
+ ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, g1);
+ bi_permanent(ctx->g[0]);
+ g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */
+
+ for (i = 1; i < k; i++)
+ {
+ ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+ bi_permanent(ctx->g[i]);
+ }
+
+ bi_free(ctx, g2);
+ ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is
+ * one of the optimisations used for performance.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+ int i = find_max_exp_index(biexp), j, window_size = 1;
+ bigint *biR = int_to_bi(ctx, 1);
+
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ uint8_t mod_offset = ctx->mod_offset;
+ if (!ctx->use_classical)
+ {
+ /* preconvert */
+ bi = bi_mont(ctx,
+ bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */
+ bi_free(ctx, biR);
+ biR = ctx->bi_R_mod_m[mod_offset]; /* A */
+ }
+#endif
+
+ check(bi);
+ check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+ for (j = i; j > 32; j /= 5) /* work out an optimum size */
+ window_size++;
+
+ /* work out the slide constants */
+ precompute_slide_window(ctx, window_size, bi);
+#else /* just one constant */
+ ctx->g = (bigint **)malloc(sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, bi);
+ ctx->window = 1;
+ bi_permanent(ctx->g[0]);
+#endif
+
+ /* if sliding-window is off, then only one bit will be done at a time and
+ * will reduce to standard left-to-right exponentiation */
+ do
+ {
+ if (exp_bit_is_one(biexp, i))
+ {
+ int l = i-window_size+1;
+ int part_exp = 0;
+
+ if (l < 0) /* LSB of exponent will always be 1 */
+ l = 0;
+ else
+ {
+ while (exp_bit_is_one(biexp, l) == 0)
+ l++; /* go back up */
+ }
+ /* build up the section of the exponent */
+ for (j = i; j >= l; j--)
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ if (exp_bit_is_one(biexp, j))
+ part_exp++;
+
+ if (j != l)
+ part_exp <<= 1;
+ }
+ part_exp = (part_exp-1)/2; /* adjust for array */
+ bigint* a = bi_multiply(ctx, biR, ctx->g[part_exp]);
+ biR = bi_residue(ctx, a);
+ i = l-1;
+ }
+ else /* square it */
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ i--;
+ }
+
+ } while (i >= 0);
+
+ /* cleanup */
+ for (i = 0; i < ctx->window; i++)
+ {
+ bi_depermanent(ctx->g[i]);
+ bi_free(ctx, ctx->g[i]);
+ }
+
+ free(ctx->g);
+ bi_free(ctx, bi);
+ bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+ return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+ return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to perform the exp/mod.
+ * @param bim [in] The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+ bigint *biR, *tmp_biR;
+
+ /* Set up a temporary bigint context and transfer what we need between
+ * them. We need to do this since we want to keep the original modulus
+ * which is already in this context. This operation is only called when
+ * doing peer verification, and so is not expensive :-) */
+ BI_CTX *tmp_ctx = bi_initialize();
+ bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+ tmp_biR = bi_mod_power(tmp_ctx,
+ bi_clone(tmp_ctx, bi),
+ bi_clone(tmp_ctx, biexp));
+ biR = bi_clone(ctx, tmp_biR);
+ bi_free(tmp_ctx, tmp_biR);
+ bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+ bi_terminate(tmp_ctx);
+
+ bi_free(ctx, bi);
+ bi_free(ctx, bim);
+ bi_free(ctx, biexp);
+ return biR;
+}
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ *
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to perform the exp/mod.
+ * @param dP [in] CRT's dP bigint
+ * @param dQ [in] CRT's dQ bigint
+ * @param p [in] CRT's p bigint
+ * @param q [in] CRT's q bigint
+ * @param qInv [in] CRT's qInv bigint
+ * @return The result of the CRT operation
+ */
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+ bigint *dP, bigint *dQ,
+ bigint *p, bigint *q, bigint *qInv)
+{
+ bigint *m1, *m2, *h;
+
+ /* Montgomery has a condition the 0 < x, y < m and these products violate
+ * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 1;
+#endif
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ m1 = bi_mod_power(ctx, bi_copy(bi), dP);
+
+ ctx->mod_offset = BIGINT_Q_OFFSET;
+ m2 = bi_mod_power(ctx, bi, dQ);
+
+ h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);
+ h = bi_multiply(ctx, h, qInv);
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 0; /* reset for any further operation */
+#endif
+ return bi_add(ctx, m2, bi_multiply(ctx, q, h));
+}
+#endif
+/** @} */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h
new file mode 100644
index 0000000000..2966a3edb3
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 BIGINT_HEADER
+#define BIGINT_HEADER
+
+#include "crypto.h"
+
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
+ bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B) bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B) bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B) bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+ bigint *dP, bigint *dQ,
+ bigint *p, bigint *q,
+ bigint *qInv);
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h
new file mode 100644
index 0000000000..b9fc2ae24a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
+#define BIGINT_Q_OFFSET 2 /**< q module offset. */
+#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS 1
+#endif
+
+
+/* Architecture specific functions for big ints */
+#if defined(CONFIG_INTEGER_8BIT)
+#define COMP_RADIX 256U /**< Max component + 1 */
+#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
+typedef uint8_t comp; /**< A single precision component. */
+typedef uint16_t long_comp; /**< A double precision component. */
+typedef int16_t slong_comp; /**< A signed double precision component. */
+#elif defined(CONFIG_INTEGER_16BIT)
+#define COMP_RADIX 65536U /**< Max component + 1 */
+#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
+typedef uint16_t comp; /**< A single precision component. */
+typedef uint32_t long_comp; /**< A double precision component. */
+typedef int32_t slong_comp; /**< A signed double precision component. */
+#else /* regular 32 bit */
+#ifdef WIN32
+#define COMP_RADIX 4294967296i64
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
+#else
+#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
+#endif
+#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
+#include <stdint.h>
+typedef uint32_t comp; /**< A single precision component. */
+typedef uint64_t long_comp; /**< A double precision component. */
+typedef int64_t slong_comp; /**< A signed double precision component. */
+#endif
+
+/**
+ * @struct _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+ struct _bigint* next; /**< The next bigint in the cache. */
+ short size; /**< The number of components in this bigint. */
+ short max_comps; /**< The heapsize allocated for this bigint */
+ int refs; /**< An internal reference count. */
+ comp* comps; /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint; /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+ bigint *active_list; /**< Bigints currently used. */
+ bigint *free_list; /**< Bigints not used. */
+ bigint *bi_radix; /**< The radix used. */
+ bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
+ bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
+ comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
+#endif
+ bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+ bigint **g; /**< Used by sliding-window. */
+ int window; /**< The size of the sliding window */
+ int active_count; /**< Number of active bigints. */
+ int free_count; /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ uint8_t use_classical; /**< Use classical reduction. */
+#endif
+ uint8_t mod_offset; /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h
new file mode 100644
index 0000000000..3f32e61424
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bigint_impl.h"
+#include "bigint.h"
+
+#ifndef STDCALL
+#define STDCALL
+#endif
+#ifndef EXP_FUNC
+#define EXP_FUNC
+#endif
+
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE)
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+/**************************************************************************
+ * AES declarations
+ **************************************************************************/
+
+#define AES_MAXROUNDS 14
+#define AES_BLOCKSIZE 16
+#define AES_IV_SIZE 16
+
+typedef struct aes_key_st
+{
+ uint16_t rounds;
+ uint16_t key_size;
+ uint32_t ks[(AES_MAXROUNDS+1)*8];
+ uint8_t iv[AES_IV_SIZE];
+} AES_CTX;
+
+typedef enum
+{
+ AES_MODE_128,
+ AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
+ uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations
+ **************************************************************************/
+
+typedef struct
+{
+ uint8_t x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations
+ **************************************************************************/
+
+#define SHA1_SIZE 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct
+{
+ uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+ uint16_t Message_Block_Index; /* Index into message block array */
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
+
+/**************************************************************************
+ * MD2 declarations
+ **************************************************************************/
+
+#define MD2_SIZE 16
+
+typedef struct
+{
+ unsigned char cksum[16]; /* checksum of the data block */
+ unsigned char state[48]; /* intermediate digest state */
+ unsigned char buffer[16]; /* data block being processed */
+ int left; /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations
+ **************************************************************************/
+
+#define MD5_SIZE 16
+#define MAX_KEYBLOCK_SIZE 136
+typedef struct
+{
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ uint8_t buffer[64]; /* input buffer */
+} MD5_CTX;
+
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
+
+/**************************************************************************
+ * HMAC declarations
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RSA declarations
+ **************************************************************************/
+
+typedef struct
+{
+ bigint *m; /* modulus */
+ bigint *e; /* public exponent */
+ bigint *d; /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+ bigint *p; /* p as in m = pq */
+ bigint *q; /* q as in m = pq */
+ bigint *dP; /* d mod (p-1) */
+ bigint *dQ; /* d mod (q-1) */
+ bigint *qInv; /* q^-1 mod p */
+#endif
+ int num_octets;
+ BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+ int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * RNG declarations
+ **************************************************************************/
+EXP_FUNC void STDCALL RNG_initialize(void);
+EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c
new file mode 100644
index 0000000000..0f9d3dcbfd
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Some misc. routines to help things out
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "os_port.h"
+#include <lwip/def.h>
+#include "sockets.h"
+#include "crypto_misc.h"
+#include "config.h"
+
+#include <time.h>
+#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
+#include "wincrypt.h"
+#endif
+
+#ifndef WIN32
+static int rng_fd = -1;
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+static HCRYPTPROV gCryptProv;
+#endif
+
+#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
+/* change to processor registers as appropriate */
+#define ENTROPY_POOL_SIZE 32
+#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
+#define ENTROPY_COUNTER2 rand()
+static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
+#endif
+
+const char * const unsupported_str = "Error: Feature not supported\n";
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+/**
+ * Retrieve a file and put it into memory
+ * @return The size of the file, or -1 on failure.
+ */
+int get_file(const char *filename, uint8_t **buf)
+{
+ int total_bytes = 0;
+ int bytes_read = 0;
+ int filesize;
+ FILE *stream = fopen(filename, "rb");
+
+ if (stream == NULL)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("file '%s' does not exist\n", filename); TTY_FLUSH();
+#endif
+ return -1;
+ }
+
+ /* Win CE doesn't support stat() */
+ fseek(stream, 0, SEEK_END);
+ filesize = ftell(stream);
+ *buf = (uint8_t *)malloc(filesize);
+ fseek(stream, 0, SEEK_SET);
+
+ do
+ {
+ bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
+ total_bytes += bytes_read;
+ } while (total_bytes < filesize && bytes_read > 0);
+
+ fclose(stream);
+ return filesize;
+}
+#endif
+
+/**
+ * Initialise the Random Number Generator engine.
+ * - On Win32 use the platform SDK's crypto engine.
+ * - On Linux use /dev/urandom
+ * - If none of these work then use a custom RNG.
+ */
+EXP_FUNC void STDCALL RNG_initialize()
+{
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+ rng_fd = ax_open("/dev/urandom", O_RDONLY);
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ if (!CryptAcquireContext(&gCryptProv,
+ NULL, NULL, PROV_RSA_FULL, 0))
+ {
+ if (GetLastError() == NTE_BAD_KEYSET &&
+ !CryptAcquireContext(&gCryptProv,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_NEWKEYSET))
+ {
+ printf("CryptoLib: %x\n", unsupported_str, GetLastError());
+ exit(1);
+ }
+ }
+#else
+ /* start of with a stack to copy across */
+ int i;
+ memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
+ srand((unsigned int)&i);
+#endif
+}
+
+/**
+ * If no /dev/urandom, then initialise the RNG with something interesting.
+ */
+EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size)
+{
+#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ int i;
+
+ for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
+ entropy_pool[i] ^= seed_buf[i];
+#endif
+}
+
+/**
+ * Terminate the RNG engine.
+ */
+EXP_FUNC void STDCALL RNG_terminate(void)
+{
+#ifndef WIN32
+ //close(rng_fd);
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ CryptReleaseContext(gCryptProv, 0);
+#endif
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes can be 0
+ */
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
+{
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+ /* use the Linux default */
+ read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ /* use Microsoft Crypto Libraries */
+ CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
+#else /* nothing else to use, so use a custom RNG */
+ /* The method we use when we've got nothing better. Use RC4, time
+ and a couple of random seeds to generate a random sequence */
+ RC4_CTX rng_ctx;
+ struct timeval tv;
+ MD5_CTX rng_digest_ctx;
+ uint8_t digest[MD5_SIZE];
+ uint64_t *ep;
+ int i;
+
+ /* A proper implementation would use counters etc for entropy */
+ // XXX XXX XX X need to seed this properly
+ gettimeofday(&tv, NULL);
+ ep = (uint64_t *)entropy_pool;
+
+ ep[0] ^= ENTROPY_COUNTER1;
+ ep[1] ^= ENTROPY_COUNTER2;
+
+
+ /* use a digested version of the entropy pool as a key */
+ MD5_Init(&rng_digest_ctx);
+ MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
+ MD5_Final(digest, &rng_digest_ctx);
+
+ /* come up with the random sequence */
+ RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
+ memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
+ num_rand_bytes : ENTROPY_POOL_SIZE);
+ RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
+
+ /* move things along */
+ for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
+ entropy_pool[i] = entropy_pool[i-MD5_SIZE];
+
+ /* insert the digest at the start of the entropy pool */
+ memcpy(entropy_pool, digest, MD5_SIZE);
+#endif
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes are not zero.
+ */
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
+{
+ int i;
+ get_random(num_rand_bytes, rand_data);
+
+ for (i = 0; i < num_rand_bytes; i++)
+ {
+ while (rand_data[i] == 0) /* can't be 0 */
+ rand_data[i] = (uint8_t)(rand());
+ }
+}
+
+/**
+ * Some useful diagnostic routines
+ */
+#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
+int hex_finish;
+int hex_index;
+
+static void print_hex_init(int finish)
+{
+ hex_finish = finish;
+ hex_index = 0;
+}
+
+static void print_hex(uint8_t hex)
+{
+ static int column;
+
+ if (hex_index == 0)
+ {
+ column = 0;
+ }
+
+ printf("%02x ", hex);
+ if (++column == 8)
+ {
+ printf(": ");
+ }
+ else if (column >= 16)
+ {
+ printf("\r\n");
+ column = 0;
+ }
+
+ if (++hex_index >= hex_finish && column > 0)
+ {
+ printf("\r\n");
+ }
+}
+
+/**
+ * Spit out a blob of data for diagnostics. The data is is a nice column format
+ * for easy reading.
+ *
+ * @param format [in] The string (with possible embedded format characters)
+ * @param size [in] The number of numbers to print
+ * @param data [in] The start of data to use
+ * @param ... [in] Any additional arguments
+ */
+EXP_FUNC void STDCALL print_blob(const char *format,
+ const uint8_t *data, int size, ...)
+{
+ int i;
+ char tmp[80];
+ va_list(ap);
+
+ va_start(ap, size);
+ sprintf(tmp, "%s\n", format);
+ vprintf(tmp, ap);
+ print_hex_init(size);
+ for (i = 0; i < size; i++)
+ {
+ print_hex(data[i]);
+ }
+
+ va_end(ap);
+ TTY_FLUSH();
+}
+#elif defined(WIN32)
+/* VC6.0 doesn't handle variadic macros */
+EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
+ int size, ...) {}
+#endif
+
+#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
+/* base64 to binary lookup table */
+static const uint8_t map[128] =
+{
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255
+};
+
+EXP_FUNC int STDCALL base64_decode(const char *in, int len,
+ uint8_t *out, int *outlen)
+{
+ int g, t, x, y, z;
+ uint8_t c;
+ int ret = -1;
+
+ g = 3;
+ for (x = y = z = t = 0; x < len; x++)
+ {
+ if ((c = map[in[x]&0x7F]) == 0xff)
+ continue;
+
+ if (c == 254) /* this is the end... */
+ {
+ c = 0;
+
+ if (--g < 0)
+ goto error;
+ }
+ else if (g != 3) /* only allow = at end */
+ goto error;
+
+ t = (t<<6) | c;
+
+ if (++y == 4)
+ {
+ out[z++] = (uint8_t)((t>>16)&255);
+
+ if (g > 1)
+ out[z++] = (uint8_t)((t>>8)&255);
+
+ if (g > 2)
+ out[z++] = (uint8_t)(t&255);
+
+ y = t = 0;
+ }
+
+ /* check that we don't go past the output buffer */
+ if (z > *outlen)
+ goto error;
+ }
+
+ if (y != 0)
+ goto error;
+
+ *outlen = z;
+ ret = 0;
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret < 0)
+ printf("Error: Invalid base64\n"); TTY_FLUSH();
+#endif
+ TTY_FLUSH();
+ return ret;
+
+}
+#endif
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c
new file mode 100644
index 0000000000..24a04d77ae
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * HMAC implementation - This code was originally taken from RFC2104
+ * See http://www.ietf.org/rfc/rfc2104.txt and
+ * http://www.faqs.org/rfcs/rfc2202.html
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/**
+ * Perform HMAC-MD5
+ * NOTE: does not handle keys larger than the block size.
+ */
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest)
+{
+ MD5_CTX context;
+ uint8_t k_ipad[64];
+ uint8_t k_opad[64];
+ int i;
+
+ memset(k_ipad, 0, sizeof k_ipad);
+ memset(k_opad, 0, sizeof k_opad);
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ for (i = 0; i < 64; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ MD5_Init(&context);
+ MD5_Update(&context, k_ipad, 64);
+ MD5_Update(&context, msg, length);
+ MD5_Final(digest, &context);
+ MD5_Init(&context);
+ MD5_Update(&context, k_opad, 64);
+ MD5_Update(&context, digest, MD5_SIZE);
+ MD5_Final(digest, &context);
+}
+
+/**
+ * Perform HMAC-SHA1
+ * NOTE: does not handle keys larger than the block size.
+ */
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest)
+{
+ SHA1_CTX context;
+ uint8_t k_ipad[64];
+ uint8_t k_opad[64];
+ int i;
+
+ memset(k_ipad, 0, sizeof k_ipad);
+ memset(k_opad, 0, sizeof k_opad);
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ for (i = 0; i < 64; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ SHA1_Init(&context);
+ SHA1_Update(&context, k_ipad, 64);
+ SHA1_Update(&context, msg, length);
+ SHA1_Final(digest, &context);
+ SHA1_Init(&context);
+ SHA1_Update(&context, k_opad, 64);
+ SHA1_Update(&context, digest, SHA1_SIZE);
+ SHA1_Final(digest, &context);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c
new file mode 100644
index 0000000000..0df38c9eba
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/*
+ * RFC 1115/1319 compliant MD2 implementation
+ * The MD2 algorithm was designed by Ron Rivest in 1989.
+ *
+ * http://www.ietf.org/rfc/rfc1115.txt
+ * http://www.ietf.org/rfc/rfc1319.txt
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "crypto.h"
+#include "config.h"
+
+/**
+ * This code is only here to enable the verification of Verisign root
+ * certificates. So only enable it for verification mode.
+ */
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+
+static const uint8_t PI_SUBST[256] =
+{
+ 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
+ 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
+ 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
+ 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
+ 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
+ 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
+ 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
+ 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+ 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
+ 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
+ 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
+ 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
+ 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
+ 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
+ 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
+ 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
+ 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
+ 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
+ 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
+ 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
+ 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
+ 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
+ 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
+ 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
+ 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
+ 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
+};
+
+/*
+ * MD2 context setup
+ */
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+}
+
+static void md2_process(MD2_CTX *ctx)
+{
+ int i, j;
+ uint8_t t = 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ ctx->state[i + 16] = ctx->buffer[i];
+ ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i];
+ }
+
+ for (i = 0; i < 18; i++)
+ {
+ for (j = 0; j < 48; j++)
+ t = (ctx->state[j] ^= PI_SUBST[t]);
+
+ t = (t + i) & 0xFF;
+ }
+
+ t = ctx->cksum[15];
+
+ for (i = 0; i < 16; i++)
+ t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]);
+}
+
+/*
+ * MD2 process buffer
+ */
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen)
+{
+ int fill;
+
+ while (ilen > 0)
+ {
+ if (ctx->left + ilen > 16)
+ fill = 16 - ctx->left;
+ else
+ fill = ilen;
+
+ memcpy(ctx->buffer + ctx->left, input, fill);
+
+ ctx->left += fill;
+ input += fill;
+ ilen -= fill;
+
+ if (ctx->left == 16)
+ {
+ ctx->left = 0;
+ md2_process(ctx);
+ }
+ }
+}
+
+/*
+ * MD2 final digest
+ */
+EXP_FUNC void STDCALL MD2_Final(uint8_t *output, MD2_CTX *ctx)
+{
+ int i;
+ uint8_t x;
+
+ x = (uint8_t)(16 - ctx->left);
+
+ for (i = ctx->left; i < 16; i++)
+ ctx->buffer[i] = x;
+
+ md2_process(ctx);
+
+ memcpy(ctx->buffer, ctx->cksum, 16);
+ md2_process(ctx);
+
+ memcpy(output, ctx->state, 16);
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c
new file mode 100644
index 0000000000..7f50713006
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 implements the MD5 algorithm as defined in RFC1321
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/* ----- static functions ----- */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64]);
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len);
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len);
+
+static const uint8_t PADDING[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ Rotation is separate from addition to prevent recomputation. */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/**
+ * MD5 initialization - begins an MD5 operation, writing a new ctx.
+ */
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *ctx)
+{
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len)
+{
+ uint32_t x;
+ int i, partLen;
+
+ /* Compute number of bytes mod 64 */
+ x = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3))
+ ctx->count[1]++;
+ ctx->count[1] += ((uint32_t)len >> 29);
+
+ partLen = 64 - x;
+
+ /* Transform as many times as possible. */
+ if (len >= partLen)
+ {
+ memcpy(&ctx->buffer[x], msg, partLen);
+ MD5Transform(ctx->state, ctx->buffer);
+
+ for (i = partLen; i + 63 < len; i += 64)
+ MD5Transform(ctx->state, &msg[i]);
+
+ x = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&ctx->buffer[x], &msg[i], len-i);
+}
+
+/**
+ * Return the 128-bit message digest into the user's array
+ */
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *ctx)
+{
+ uint8_t bits[8];
+ uint32_t x, padLen;
+
+ /* Save number of bits */
+ Encode(bits, ctx->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ x = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
+ padLen = (x < 56) ? (56 - x) : (120 - x);
+ MD5_Update(ctx, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5_Update(ctx, bits, 8);
+
+ /* Store state in digest */
+ Encode(digest, ctx->state, MD5_SIZE);
+}
+
+/**
+ * MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64])
+{
+ uint32_t a = state[0], b = state[1], c = state[2],
+ d = state[3], x[MD5_SIZE];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/**
+ * Encodes input (uint32_t) into output (uint8_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len)
+{
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[j] = (uint8_t)(input[i] & 0xff);
+ output[j+1] = (uint8_t)((input[i] >> 8) & 0xff);
+ output[j+2] = (uint8_t)((input[i] >> 16) & 0xff);
+ output[j+3] = (uint8_t)((input[i] >> 24) & 0xff);
+ }
+}
+
+/**
+ * Decodes input (uint8_t) into output (uint32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len)
+{
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+ (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h
new file mode 100644
index 0000000000..8788567238
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file os_int.h
+ *
+ * Ensure a consistent bit size
+ */
+
+#ifndef HEADER_OS_INT_H
+#define HEADER_OS_INT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(WIN32)
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+typedef UINT64 uint64_t;
+typedef INT64 int64_t;
+#else /* Not Win32 */
+
+#ifdef CONFIG_PLATFORM_SOLARIS
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif /* Not Solaris */
+
+#endif /* Not Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c
new file mode 100644
index 0000000000..12a121151d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * An implementation of the RC4/ARC4 algorithm.
+ * Originally written by Christophe Devine.
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/**
+ * Get ready for an encrypt/decrypt operation
+ */
+void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length)
+{
+ int i, j = 0, k = 0, a;
+ uint8_t *m;
+
+ ctx->x = 0;
+ ctx->y = 0;
+ m = ctx->m;
+
+ for (i = 0; i < 256; i++)
+ m[i] = i;
+
+ for (i = 0; i < 256; i++)
+ {
+ a = m[i];
+ j = (uint8_t)(j + a + key[k]);
+ m[i] = m[j];
+ m[j] = a;
+
+ if (++k >= length)
+ k = 0;
+ }
+}
+
+/**
+ * Perform the encrypt/decrypt operation (can use it for either since
+ * this is a stream cipher).
+ * NOTE: *msg and *out must be the same pointer (performance tweak)
+ */
+void RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint8_t *m, x, y, a, b;
+
+ x = ctx->x;
+ y = ctx->y;
+ m = ctx->m;
+
+ for (i = 0; i < length; i++)
+ {
+ a = m[++x];
+ y += a;
+ m[x] = b = m[y];
+ m[y] = a;
+ out[i] ^= m[(uint8_t)(a + b)];
+ }
+
+ ctx->x = x;
+ ctx->y = y;
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c
new file mode 100644
index 0000000000..64282a2627
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "os_port.h"
+#include "crypto.h"
+
+void RSA_priv_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ )
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx;
+ RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+ rsa_ctx = *ctx;
+ bi_ctx = rsa_ctx->bi_ctx;
+ rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+ bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+ rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+ rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+ rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+ rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+ rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+ bi_permanent(rsa_ctx->dP);
+ bi_permanent(rsa_ctx->dQ);
+ bi_permanent(rsa_ctx->qInv);
+ bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+ bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len)
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx;
+
+ if (*ctx) /* if we load multiple certs, dump the old one */
+ RSA_free(*ctx);
+
+ bi_ctx = bi_initialize();
+ *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+ rsa_ctx = *ctx;
+ rsa_ctx->bi_ctx = bi_ctx;
+ rsa_ctx->num_octets = mod_len;
+ rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+ bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+ rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+ bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+ BI_CTX *bi_ctx;
+ if (rsa_ctx == NULL) /* deal with ptrs that are null */
+ return;
+
+ bi_ctx = rsa_ctx->bi_ctx;
+
+ bi_depermanent(rsa_ctx->e);
+ bi_free(bi_ctx, rsa_ctx->e);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+ if (rsa_ctx->d)
+ {
+ bi_depermanent(rsa_ctx->d);
+ bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+ bi_depermanent(rsa_ctx->dP);
+ bi_depermanent(rsa_ctx->dQ);
+ bi_depermanent(rsa_ctx->qInv);
+ bi_free(bi_ctx, rsa_ctx->dP);
+ bi_free(bi_ctx, rsa_ctx->dQ);
+ bi_free(bi_ctx, rsa_ctx->qInv);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+ }
+
+ bi_terminate(bi_ctx);
+ free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
+ uint8_t *out_data, int is_decryption)
+{
+ const int byte_size = ctx->num_octets;
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+ uint8_t *block = (uint8_t *)alloca(byte_size);
+
+ memset(out_data, 0, byte_size); /* initialise */
+
+ /* decrypt */
+ dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ decrypted_bi = is_decryption ? /* decrypt or verify? */
+ RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else /* always a decryption */
+ decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+ /* convert to a normal block */
+ bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+ i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+ {
+ while (block[i++] == 0xff && i < byte_size);
+
+ if (block[i-2] != 0xff)
+ i = byte_size; /*ensure size is 0 */
+ }
+ else /* PKCS1.5 encryption padding is random */
+#endif
+ {
+ while (block[i++] && i < byte_size);
+ }
+ size = byte_size - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ memcpy(out_data, &block[i], size);
+
+ return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+ printf("RSA private\n");
+#ifdef CONFIG_BIGINT_CRT
+ return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);
+#else
+ BI_CTX *ctx = c->bi_ctx;
+ ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx)
+{
+ if (rsa_ctx == NULL)
+ return;
+
+ printf("----------------- RSA DEBUG ----------------\n");
+ printf("Size:\t%d\n", rsa_ctx->num_octets);
+ bi_print("Modulus", rsa_ctx->m);
+ bi_print("Public Key", rsa_ctx->e);
+ bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+ c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing)
+{
+ int byte_size = ctx->num_octets;
+ int num_pads_needed = byte_size-in_len-3;
+ bigint *dat_bi, *encrypt_bi;
+ /* note: in_len+11 must be > byte_size */
+ out_data[0] = 0; /* ensure encryption block is < modulus */
+ if (is_signing)
+ {
+ out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
+ memset(&out_data[2], 0xff, num_pads_needed);
+ }
+ else /* randomize the encryption padding with non-zero bytes */
+ {
+ out_data[1] = 2;
+ get_random_NZ(num_pads_needed, &out_data[2]);
+ }
+
+ out_data[2+num_pads_needed] = 0;
+ memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+ /* now encrypt it */
+ dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+
+ encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
+ RSA_public(ctx, dat_bi);
+
+ bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+ /* save a few bytes of memory */
+ bi_clear_cache(ctx->bi_ctx);
+
+ return byte_size;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c
new file mode 100644
index 0000000000..1082733e7e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
+ * This code was originally taken from RFC3174
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* ----- static functions ----- */
+static void SHA1PadMessage(SHA1_CTX *ctx);
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
+
+/**
+ * Initialize the SHA1 context
+ */
+void SHA1_Init(SHA1_CTX *ctx)
+{
+ ctx->Length_Low = 0;
+ ctx->Length_High = 0;
+ ctx->Message_Block_Index = 0;
+ ctx->Intermediate_Hash[0] = 0x67452301;
+ ctx->Intermediate_Hash[1] = 0xEFCDAB89;
+ ctx->Intermediate_Hash[2] = 0x98BADCFE;
+ ctx->Intermediate_Hash[3] = 0x10325476;
+ ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
+{
+ while (len--)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
+ ctx->Length_Low += 8;
+
+ if (ctx->Length_Low == 0)
+ ctx->Length_High++;
+
+ if (ctx->Message_Block_Index == 64)
+ SHA1ProcessMessageBlock(ctx);
+
+ msg++;
+ }
+}
+
+/**
+ * Return the 160-bit message digest into the user's array
+ */
+void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx)
+{
+ int i;
+
+ SHA1PadMessage(ctx);
+ memset(ctx->Message_Block, 0, 64);
+ ctx->Length_Low = 0; /* and clear length */
+ ctx->Length_High = 0;
+
+ for (i = 0; i < SHA1_SIZE; i++)
+ {
+ digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+ }
+}
+
+/**
+ * Process the next 512 bits of the message stored in the array.
+ */
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = 0; t < 16; t++)
+ {
+ W[t] = ctx->Message_Block[t * 4] << 24;
+ W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+ W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+ W[t] |= ctx->Message_Block[t * 4 + 3];
+ }
+
+ for (t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->Intermediate_Hash[0];
+ B = ctx->Intermediate_Hash[1];
+ C = ctx->Intermediate_Hash[2];
+ D = ctx->Intermediate_Hash[3];
+ E = ctx->Intermediate_Hash[4];
+
+ for (t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ ctx->Intermediate_Hash[0] += A;
+ ctx->Intermediate_Hash[1] += B;
+ ctx->Intermediate_Hash[2] += C;
+ ctx->Intermediate_Hash[3] += D;
+ ctx->Intermediate_Hash[4] += E;
+ ctx->Message_Block_Index = 0;
+}
+
+/*
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * @param ctx [in, out] The SHA1 context
+ */
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (ctx->Message_Block_Index > 55)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 64)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(ctx);
+
+ while (ctx->Message_Block_Index < 56)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 56)
+ {
+
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ ctx->Message_Block[56] = ctx->Length_High >> 24;
+ ctx->Message_Block[57] = ctx->Length_High >> 16;
+ ctx->Message_Block[58] = ctx->Length_High >> 8;
+ ctx->Message_Block[59] = ctx->Length_High;
+ ctx->Message_Block[60] = ctx->Length_Low >> 24;
+ ctx->Message_Block[61] = ctx->Length_Low >> 16;
+ ctx->Message_Block[62] = ctx->Length_Low >> 8;
+ ctx->Message_Block[63] = ctx->Length_Low;
+ SHA1ProcessMessageBlock(ctx);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c
new file mode 100644
index 0000000000..d95c9117c5
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Some primitive asn methods for extraction ASN.1 data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "os_port.h"
+#include "crypto.h"
+#include "crypto_misc.h"
+#include "config.h"
+
+#define SIG_OID_PREFIX_SIZE 8
+#define SIG_IIS6_OID_SIZE 5
+#define SIG_SUBJECT_ALT_NAME_SIZE 3
+
+/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
+static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
+{
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
+};
+
+static const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] =
+{
+ 0x2b, 0x0e, 0x03, 0x02, 0x1d
+};
+
+static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] =
+{
+ 0x55, 0x1d, 0x11
+};
+
+/* CN, O, OU */
+static const uint8_t g_dn_types[] = { 3, 10, 11 };
+
+int get_asn1_length(const uint8_t *buf, int *offset)
+{
+ int len, i;
+
+ if (!(buf[*offset] & 0x80)) /* short form */
+ {
+ len = buf[(*offset)++];
+ }
+ else /* long form */
+ {
+ int length_bytes = buf[(*offset)++]&0x7f;
+ len = 0;
+ for (i = 0; i < length_bytes; i++)
+ {
+ len <<= 8;
+ len += buf[(*offset)++];
+ }
+ }
+
+ return len;
+}
+
+/**
+ * Skip the ASN1.1 object type and its length. Get ready to read the object's
+ * data.
+ */
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ int tmp = get_asn1_length(buf, offset);
+ return tmp;
+}
+
+/**
+ * Skip over an ASN.1 object type completely. Get ready to read the next
+ * object.
+ */
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ int len;
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+ *offset += len;
+ return 0;
+}
+
+/**
+ * Read an integer value for ASN.1 data
+ * Note: This function allocates memory which must be freed by the user.
+ */
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
+{
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
+ goto end_int_array;
+
+ if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */
+ {
+ len--;
+ (*offset)++;
+ }
+
+ *object = (uint8_t *)malloc(len);
+ memcpy(*object, &buf[*offset], len);
+ *offset += len;
+
+end_int_array:
+ return len;
+}
+
+/**
+ * Get all the RSA private key specifics from an ASN.1 encoded file
+ */
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
+{
+ int offset = 7;
+ uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL;
+ int mod_len, priv_len, pub_len;
+#ifdef CONFIG_BIGINT_CRT
+ uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL;
+ int p_len, q_len, dP_len, dQ_len, qInv_len;
+#endif
+
+ /* not in der format */
+ if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: This is not a valid ASN.1 file\n");
+#endif
+ return X509_INVALID_PRIV_KEY;
+ }
+
+ /* Use the private key to mix up the RNG if possible. */
+ RNG_custom_init(buf, len);
+
+ mod_len = asn1_get_int(buf, &offset, &modulus);
+ pub_len = asn1_get_int(buf, &offset, &pub_exp);
+ priv_len = asn1_get_int(buf, &offset, &priv_exp);
+
+ if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+#ifdef CONFIG_BIGINT_CRT
+ p_len = asn1_get_int(buf, &offset, &p);
+ q_len = asn1_get_int(buf, &offset, &q);
+ dP_len = asn1_get_int(buf, &offset, &dP);
+ dQ_len = asn1_get_int(buf, &offset, &dQ);
+ qInv_len = asn1_get_int(buf, &offset, &qInv);
+
+ if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
+ p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
+
+ free(p);
+ free(q);
+ free(dP);
+ free(dQ);
+ free(qInv);
+#else
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
+#endif
+
+ free(modulus);
+ free(priv_exp);
+ free(pub_exp);
+ return X509_OK;
+}
+
+/**
+ * Get the time of a certificate. Ignore hours/minutes/seconds.
+ */
+static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
+{
+ int ret = X509_NOT_OK, len, t_offset;
+ struct tm tm;
+
+ if (buf[(*offset)++] != ASN1_UTC_TIME)
+ goto end_utc_time;
+
+ len = get_asn1_length(buf, offset);
+ t_offset = *offset;
+
+ memset(&tm, 0, sizeof(struct tm));
+ tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
+
+ if (tm.tm_year <= 50) /* 1951-2050 thing */
+ {
+ tm.tm_year += 100;
+ }
+
+ tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
+ tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
+ *t = mktime(&tm);
+ *offset += len;
+ ret = X509_OK;
+
+end_utc_time:
+ return ret;
+}
+
+/**
+ * Get the version type of a certificate (which we don't actually care about)
+ */
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ (*offset) += 2; /* get past explicit tag */
+ if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
+ goto end_version;
+
+ ret = X509_OK;
+end_version:
+ return ret;
+}
+
+/**
+ * Retrieve the notbefore and notafter certificate times.
+ */
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
+}
+
+/**
+ * Get the components of a distinguished name
+ */
+static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
+{
+ int dn_type = 0;
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+ goto end_oid;
+
+ /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
+ components we are interested in. */
+ if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
+ dn_type = buf[(*offset)++];
+ else
+ {
+ *offset += len; /* skip over it */
+ }
+
+end_oid:
+ return dn_type;
+}
+
+/**
+ * Obtain an ASN.1 printable string type.
+ */
+static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
+{
+ int len = X509_NOT_OK;
+ int asn1_type = buf[*offset];
+
+ /* some certs have this awful crud in them for some reason */
+ if (asn1_type != ASN1_PRINTABLE_STR &&
+ asn1_type != ASN1_PRINTABLE_STR2 &&
+ asn1_type != ASN1_TELETEX_STR &&
+ asn1_type != ASN1_IA5_STR &&
+ asn1_type != ASN1_UNICODE_STR)
+ goto end_pnt_str;
+
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+
+ if (asn1_type == ASN1_UNICODE_STR)
+ {
+ int i;
+ *str = (char *)malloc(len/2+1); /* allow for null */
+
+ for (i = 0; i < len; i += 2)
+ (*str)[i/2] = buf[*offset + i + 1];
+
+ (*str)[len/2] = 0; /* null terminate */
+ }
+ else
+ {
+ *str = (char *)malloc(len+1); /* allow for null */
+ memcpy(*str, &buf[*offset], len);
+ (*str)[len] = 0; /* null terminate */
+ }
+
+ *offset += len;
+
+end_pnt_str:
+ return len;
+}
+
+/**
+ * Get the subject name (or the issuer) of a certificate.
+ */
+int asn1_name(const uint8_t *cert, int *offset, char *dn[])
+{
+ int ret = X509_NOT_OK;
+ int dn_type;
+ char *tmp;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_name;
+
+ while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
+ {
+ int i, found = 0;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
+ goto end_name;
+
+ tmp = NULL;
+
+ if (asn1_get_printable_str(cert, offset, &tmp) < 0)
+ {
+ free(tmp);
+ goto end_name;
+ }
+
+ /* find the distinguished named type */
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (dn_type == g_dn_types[i])
+ {
+ if (dn[i] == NULL)
+ {
+ dn[i] = tmp;
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found == 0) /* not found so get rid of it */
+ {
+ free(tmp);
+ }
+ }
+
+ ret = X509_OK;
+end_name:
+ return ret;
+}
+
+/**
+ * Read the modulus and public exponent of a certificate.
+ */
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, mod_len, pub_len;
+ uint8_t *modulus = NULL, *pub_exp = NULL;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
+ asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
+ goto end_pub_key;
+
+ (*offset)++; /* ignore the padding bit field */
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_pub_key;
+
+ mod_len = asn1_get_int(cert, offset, &modulus);
+ pub_len = asn1_get_int(cert, offset, &pub_exp);
+ RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
+ free(modulus);
+ free(pub_exp);
+ ret = X509_OK;
+
+end_pub_key:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Read the signature of the certificate.
+ */
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ if (cert[(*offset)++] != ASN1_BIT_STRING)
+ goto end_sig;
+
+ x509_ctx->sig_len = get_asn1_length(cert, offset)-1;
+ (*offset)++; /* ignore bit string padding bits */
+ x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
+ memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
+ *offset += x509_ctx->sig_len;
+ ret = X509_OK;
+
+end_sig:
+ return ret;
+}
+
+/*
+ * Compare 2 distinguished name components for equality
+ * @return 0 if a match
+ */
+static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
+{
+ int ret;
+
+ if (dn1 == NULL && dn2 == NULL)
+ ret = 0;
+ else
+ ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1;
+
+ return ret;
+}
+
+/**
+ * Clean up all of the CA certificates.
+ */
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
+{
+ int i = 0;
+
+ if (ca_cert_ctx == NULL)
+ return;
+
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ x509_free(ca_cert_ctx->cert[i]);
+ ca_cert_ctx->cert[i++] = NULL;
+ }
+
+ free(ca_cert_ctx);
+}
+
+/*
+ * Compare 2 distinguished names for equality
+ * @return 0 if a match
+ */
+int asn1_compare_dn(char * const dn1[], char * const dn2[])
+{
+ int i;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (asn1_compare_dn_comp(dn1[i], dn2[i]))
+ return 1;
+ }
+
+ return 0; /* all good */
+}
+
+int asn1_find_oid(const uint8_t* cert, int* offset,
+ const uint8_t* oid, int oid_length)
+{
+ int seqlen;
+ if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0)
+ {
+ int end = *offset + seqlen;
+
+ while (*offset < end)
+ {
+ int type = cert[(*offset)++];
+ int length = get_asn1_length(cert, offset);
+ int noffset = *offset + length;
+
+ if (type == ASN1_SEQUENCE)
+ {
+ type = cert[(*offset)++];
+ length = get_asn1_length(cert, offset);
+
+ if (type == ASN1_OID && length == oid_length &&
+ memcmp(cert + *offset, oid, oid_length) == 0)
+ {
+ *offset += oid_length;
+ return 1;
+ }
+ }
+
+ *offset = noffset;
+ }
+ }
+
+ return 0;
+}
+
+int asn1_find_subjectaltname(const uint8_t* cert, int offset)
+{
+ if (asn1_find_oid(cert, &offset, sig_subject_alt_name,
+ SIG_SUBJECT_ALT_NAME_SIZE))
+ {
+ return offset;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/**
+ * Read the signature type of the certificate. We only support RSA-MD5 and
+ * RSA-SHA1 signature types.
+ */
+int asn1_signature_type(const uint8_t *cert,
+ int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, len;
+
+ if (cert[(*offset)++] != ASN1_OID)
+ goto end_check_sig;
+
+ len = get_asn1_length(cert, offset);
+
+ if (len == 5 && memcmp(sig_sha1WithRSAEncrypt, &cert[*offset],
+ SIG_IIS6_OID_SIZE) == 0)
+ {
+ x509_ctx->sig_type = SIG_TYPE_SHA1;
+ }
+ else
+ {
+ if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
+ goto end_check_sig; /* unrecognised cert type */
+
+ x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
+ }
+
+ *offset += len;
+ asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */
+ ret = X509_OK;
+
+end_check_sig:
+ return ret;
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h
new file mode 100644
index 0000000000..48b901b048
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h
@@ -0,0 +1,133 @@
+#ifndef CERT_H
+#define CERT_H
+
+/*
+unsigned char default_certificate[] = {
+ 0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab,
+ 0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34,
+ 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61,
+ 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+ 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32,
+ 0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32,
+ 0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a,
+ 0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81,
+ 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+ 0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76,
+ 0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f,
+ 0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90,
+ 0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14,
+ 0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d,
+ 0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46,
+ 0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa,
+ 0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a,
+ 0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82,
+ 0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32,
+ 0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02,
+ 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40,
+ 0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88,
+ 0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06,
+ 0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b,
+ 0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8,
+ 0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13,
+ 0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac,
+ 0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27,
+ 0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e,
+ 0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80,
+ 0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54,
+ 0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5
+};
+unsigned int default_certificate_len = 475;
+*/
+unsigned char default_certificate[] = {
+ 0x30, 0x82, 0x03, 0xb8, 0x30, 0x82, 0x03, 0x21, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55, 0x5d, 0xa4, 0x8f,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x05, 0x05, 0x00, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
+ 0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
+ 0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
+ 0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
+ 0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
+ 0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35,
+ 0x31, 0x33, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x34,
+ 0x36, 0x30, 0x33, 0x32, 0x31, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a,
+ 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, 0x74, 0x76, 0x69,
+ 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, 0x74, 0x6f, 0x6d,
+ 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+ 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, 0x08, 0x08, 0x31,
+ 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x41, 0x73,
+ 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, 0x73, 0x31, 0x25,
+ 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+ 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x40, 0x61, 0x73,
+ 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
+ 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, 0xe0, 0x59, 0x6a, 0x19, 0x08,
+ 0x0d, 0x21, 0x98, 0x79, 0x96, 0x16, 0x2a, 0x5a, 0x5c, 0x20, 0xeb, 0x66,
+ 0x1e, 0x9e, 0x1e, 0xc4, 0xef, 0x83, 0x42, 0x15, 0xd8, 0x4b, 0x14, 0xd3,
+ 0xe7, 0xba, 0xc8, 0xf6, 0xb4, 0x52, 0xdf, 0x18, 0xa6, 0x6b, 0x8b, 0xca,
+ 0x84, 0xdc, 0x21, 0x26, 0xfd, 0x7c, 0xde, 0xbd, 0x2b, 0x64, 0x0d, 0xd3,
+ 0x20, 0x7c, 0xe7, 0x0c, 0xfc, 0x3c, 0xa9, 0x09, 0xc0, 0xa7, 0x78, 0x3d,
+ 0xe9, 0x48, 0x50, 0x90, 0xd7, 0x3e, 0x46, 0x78, 0x8f, 0xfc, 0xc8, 0xb6,
+ 0x89, 0x41, 0x49, 0x15, 0x47, 0x27, 0x4b, 0x46, 0xcb, 0x11, 0x82, 0xd8,
+ 0x7b, 0x68, 0xb7, 0xc5, 0x64, 0x70, 0xaf, 0xe6, 0x80, 0x63, 0xfe, 0x53,
+ 0x70, 0xee, 0xd2, 0xa9, 0x2c, 0x40, 0x96, 0x9c, 0xd4, 0xa1, 0xcf, 0xd4,
+ 0x51, 0x9d, 0xe1, 0xa7, 0xf0, 0xfb, 0xa6, 0x49, 0x4c, 0x00, 0x05, 0xff,
+ 0x8f, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x02, 0x30,
+ 0x81, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+ 0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
+ 0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0x30, 0x81, 0xcf,
+ 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xc7, 0x30, 0x81, 0xc4, 0x80,
+ 0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
+ 0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0xa1, 0x81, 0xa0,
+ 0xa4, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
+ 0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
+ 0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
+ 0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
+ 0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
+ 0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55,
+ 0x5d, 0xa4, 0x8f, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
+ 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
+ 0x89, 0x79, 0xf2, 0xa8, 0xd3, 0xc7, 0x02, 0x2d, 0x02, 0x68, 0x9a, 0xf1,
+ 0xa7, 0x10, 0xa2, 0x2c, 0x52, 0x12, 0xf2, 0x97, 0x39, 0x52, 0x83, 0x69,
+ 0xd7, 0xe7, 0x73, 0x1f, 0xf1, 0x02, 0x5e, 0xbe, 0x5f, 0xbe, 0x94, 0xa9,
+ 0x4d, 0x8f, 0xb7, 0x3c, 0x52, 0x35, 0x09, 0x0a, 0x69, 0xed, 0x5e, 0x12,
+ 0xc9, 0x4d, 0x59, 0xec, 0x47, 0xfa, 0x82, 0xe5, 0x79, 0xbc, 0x17, 0x9d,
+ 0xae, 0x02, 0x17, 0xb5, 0xfb, 0xca, 0xc7, 0x42, 0xf4, 0xb5, 0x48, 0x19,
+ 0x1c, 0xd4, 0xd6, 0xfb, 0x2a, 0x7b, 0x0e, 0x8b, 0x56, 0xcc, 0x8e, 0x7a,
+ 0xa8, 0xaf, 0x4e, 0x5a, 0xa1, 0xf1, 0x78, 0x37, 0x4d, 0x09, 0x03, 0x9a,
+ 0xde, 0x4c, 0x87, 0xbe, 0xb1, 0x93, 0x1a, 0x39, 0x9a, 0xbb, 0xa0, 0x5c,
+ 0xfe, 0x58, 0x71, 0x62, 0x20, 0x74, 0x04, 0xc5, 0x50, 0x6e, 0x7b, 0xad,
+ 0xbe, 0xb0, 0xaa, 0x64, 0xea, 0x48, 0xa7, 0x9f
+};
+unsigned int default_certificate_len = 956;
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h
new file mode 100644
index 0000000000..f4f4b1422f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h
@@ -0,0 +1,62 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+#define CONFIG_DEBUG
+#define CONFIG_STRIP_UNWANTED_SECTIONS 1
+
+/*
+ * BigInt Options
+ */
+#define CONFIG_BIGINT_BARRETT 1
+#define CONFIG_BIGINT_CRT 1
+#define CONFIG_INTEGER_32BIT 1
+
+/*
+ * SSL Library
+ */
+#define CONFIG_SSL_ENABLE_CLIENT 1
+//#define CONFIG_SSL_SKELETON_MODE
+#define CONFIG_SSL_PROT_LOW 1
+//#undef CONFIG_SSL_PROT_MEDIUM
+//#undef CONFIG_SSL_PROT_HIGH
+#define CONFIG_SSL_USE_DEFAULT_KEY 1
+#define CONFIG_SSL_PRIVATE_KEY_LOCATION ""
+#define CONFIG_SSL_PRIVATE_KEY_PASSWORD ""
+#define CONFIG_SSL_X509_CERT_LOCATION ""
+#undef CONFIG_SSL_GENERATE_X509_CERT
+#define CONFIG_SSL_X509_COMMON_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME ""
+#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+#undef CONFIG_SSL_HAS_PEM
+#undef CONFIG_SSL_USE_PKCS12
+#define CONFIG_SSL_EXPIRY_TIME 24
+#define CONFIG_X509_MAX_CA_CERTS 1
+#define CONFIG_SSL_MAX_CERTS 1
+#undef CONFIG_SSL_CTX_MUTEXING
+#undef CONFIG_USE_DEV_URANDOM
+#undef CONFIG_WIN32_USE_CRYPTO_LIB
+#undef CONFIG_OPENSSL_COMPATIBLE
+#undef CONFIG_PERFORMANCE_TESTING
+#undef CONFIG_SSL_TEST
+#undef CONFIG_AXTLSWRAP
+#undef CONFIG_AXHTTPD
+#undef CONFIG_HTTP_STATIC_BUILD
+#undef CONFIG_HTTP_HAS_CGI
+#define CONFIG_HTTP_CGI_EXTENSIONS ""
+#undef CONFIG_HTTP_ENABLE_LUA
+#define CONFIG_HTTP_LUA_PREFIX ""
+#undef CONFIG_HTTP_BUILD_LUA
+#define CONFIG_HTTP_CGI_LAUNCHER ""
+#undef CONFIG_HTTP_DIRECTORIES
+#undef CONFIG_HTTP_HAS_AUTHORIZATION
+#undef CONFIG_HTTP_HAS_IPV6
+#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER
+#define CONFIG_HTTP_USER ""
+#undef CONFIG_HTTP_VERBOSE
+#undef CONFIG_HTTP_IS_DAEMON
+#define CONFIG_SSL_CERT_VERIFICATION
+#define CONFIG_SSL_FULL_MODE
+
+#define MBED
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h
new file mode 100644
index 0000000000..5c50a11b27
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+*/
+
+/**
+ * @file crypto_misc.h
+ */
+
+#ifndef HEADER_CRYPTO_MISC_H
+#define HEADER_CRYPTO_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crypto.h"
+#include "bigint.h"
+#include "config.h"
+
+/**************************************************************************
+ * X509 declarations
+ **************************************************************************/
+#define X509_OK 0
+#define X509_NOT_OK -1
+#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
+#define X509_VFY_ERROR_BAD_SIGNATURE -3
+#define X509_VFY_ERROR_NOT_YET_VALID -4
+#define X509_VFY_ERROR_EXPIRED -5
+#define X509_VFY_ERROR_SELF_SIGNED -6
+#define X509_VFY_ERROR_INVALID_CHAIN -7
+#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
+#define X509_INVALID_PRIV_KEY -9
+
+/*
+ * The Distinguished Name
+ */
+#define X509_NUM_DN_TYPES 3
+#define X509_COMMON_NAME 0
+#define X509_ORGANIZATION 1
+#define X509_ORGANIZATIONAL_UNIT 2
+
+#include <time.h>
+
+struct _x509_ctx
+{
+ char *ca_cert_dn[X509_NUM_DN_TYPES];
+ char *cert_dn[X509_NUM_DN_TYPES];
+ char **subject_alt_dnsnames;
+ time_t not_before;
+ time_t not_after;
+ uint8_t *signature;
+ uint16_t sig_len;
+ uint8_t sig_type;
+ RSA_CTX *rsa_ctx;
+ bigint *digest;
+ struct _x509_ctx *next;
+};
+
+typedef struct _x509_ctx X509_CTX;
+typedef struct
+{
+ X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+
+#endif
+
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
+const char * x509_display_error(int error);
+#endif
+
+/**************************************************************************
+ * ASN1 declarations
+ **************************************************************************/
+#define ASN1_INTEGER 0x02
+#define ASN1_BIT_STRING 0x03
+#define ASN1_OCTET_STRING 0x04
+#define ASN1_NULL 0x05
+#define ASN1_PRINTABLE_STR2 0x0C
+#define ASN1_OID 0x06
+#define ASN1_PRINTABLE_STR2 0x0C
+#define ASN1_PRINTABLE_STR 0x13
+#define ASN1_TELETEX_STR 0x14
+#define ASN1_IA5_STR 0x16
+#define ASN1_UTC_TIME 0x17
+#define ASN1_UNICODE_STR 0x1e
+#define ASN1_SEQUENCE 0x30
+#define ASN1_CONTEXT_DNSNAME 0x82
+#define ASN1_SET 0x31
+#define ASN1_V3_DATA 0xa3
+#define ASN1_IMPLICIT_TAG 0x80
+#define ASN1_CONTEXT_DNSNAME 0x82
+#define ASN1_EXPLICIT_TAG 0xa0
+#define ASN1_V3_DATA 0xa3
+
+#define SIG_TYPE_MD2 0x02
+#define SIG_TYPE_MD5 0x04
+#define SIG_TYPE_SHA1 0x05
+
+int get_asn1_length(const uint8_t *buf, int *offset);
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_find_subjectaltname(const uint8_t* cert, int offset);
+int asn1_compare_dn(char * const dn1[], char * const dn2[]);
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+int asn1_signature_type(const uint8_t *cert,
+ int *offset, X509_CTX *x509_ctx);
+
+/**************************************************************************
+ * MISC declarations
+ **************************************************************************/
+#define SALT_SIZE 8
+
+extern const char * const unsupported_str;
+
+typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
+typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+int get_file(const char *filename, uint8_t **buf);
+
+#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
+EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...);
+#else
+ #define print_blob(...)
+#endif
+
+EXP_FUNC int STDCALL base64_decode(const char *in, int len,
+ uint8_t *out, int *outlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c
new file mode 100644
index 0000000000..c2fe381eb9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 "config.h"
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+#include <string.h>
+#include <stdlib.h>
+#include "os_port.h"
+#include "ssl.h"
+
+/**
+ * Generate a basic X.509 certificate
+ */
+
+static uint8_t set_gen_length(int len, uint8_t *buf, int *offset)
+{
+ if (len < 0x80) /* short form */
+ {
+ buf[(*offset)++] = len;
+ return 1;
+ }
+ else /* long form */
+ {
+ int i, length_bytes = 0;
+
+ if (len & 0x00FF0000)
+ length_bytes = 3;
+ else if (len & 0x0000FF00)
+ length_bytes = 2;
+ else if (len & 0x000000FF)
+ length_bytes = 1;
+
+ buf[(*offset)++] = 0x80 + length_bytes;
+
+ for (i = length_bytes-1; i >= 0; i--)
+ {
+ buf[*offset+i] = len & 0xFF;
+ len >>= 8;
+ }
+
+ *offset += length_bytes;
+ return length_bytes+1;
+ }
+}
+
+static int pre_adjust_with_size(uint8_t type,
+ int *seq_offset, uint8_t *buf, int *offset)
+{
+ buf[(*offset)++] = type;
+ *seq_offset = *offset;
+ *offset += 4; /* fill in later */
+ return *offset;
+}
+
+static void adjust_with_size(int seq_size, int seq_start,
+ uint8_t *buf, int *offset)
+{
+ uint8_t seq_byte_size;
+ int orig_seq_size = seq_size;
+ int orig_seq_start = seq_start;
+
+ seq_size = *offset-seq_size;
+ seq_byte_size = set_gen_length(seq_size, buf, &seq_start);
+
+ if (seq_byte_size != 4)
+ {
+ memmove(&buf[orig_seq_start+seq_byte_size],
+ &buf[orig_seq_size], seq_size);
+ *offset -= 4-seq_byte_size;
+ }
+}
+
+static void gen_serial_number(uint8_t *buf, int *offset)
+{
+ static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };
+ memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));
+ *offset += sizeof(ser_oid);
+}
+
+static void gen_signature_alg(uint8_t *buf, int *offset)
+{
+ /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
+ static const uint8_t sig_oid[] =
+ {
+ ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ ASN1_NULL, 0x00
+ };
+
+ memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));
+ *offset += sizeof(sig_oid);
+}
+
+static int gen_dn(const char *name, uint8_t dn_type,
+ uint8_t *buf, int *offset)
+{
+ int ret = X509_OK;
+ int name_size = strlen(name);
+
+ if (name_size > 0x70) /* just too big */
+ {
+ ret = X509_NOT_OK;
+ goto error;
+ }
+
+ buf[(*offset)++] = ASN1_SET;
+ set_gen_length(9+name_size, buf, offset);
+ buf[(*offset)++] = ASN1_SEQUENCE;
+ set_gen_length(7+name_size, buf, offset);
+ buf[(*offset)++] = ASN1_OID;
+ buf[(*offset)++] = 3;
+ buf[(*offset)++] = 0x55;
+ buf[(*offset)++] = 0x04;
+ buf[(*offset)++] = dn_type;
+ buf[(*offset)++] = ASN1_PRINTABLE_STR;
+ buf[(*offset)++] = name_size;
+ strcpy(&buf[*offset], name);
+ *offset += name_size;
+
+error:
+ return ret;
+}
+
+static int gen_issuer(const char * dn[], uint8_t *buf, int *offset)
+{
+ int ret = X509_OK;
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+ char fqdn[128];
+
+ /* we need the common name, so if not configured, work out the fully
+ * qualified domain name */
+ if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)
+ {
+ int fqdn_len;
+ gethostname(fqdn, sizeof(fqdn));
+ fqdn_len = strlen(fqdn);
+ fqdn[fqdn_len++] = '.';
+ getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);
+ fqdn_len = strlen(fqdn);
+
+ if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */
+ fqdn[fqdn_len-1] = 0;
+
+ dn[X509_COMMON_NAME] = fqdn;
+ }
+
+ if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))
+ goto error;
+
+ if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)
+ {
+ if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))
+ goto error;
+ }
+
+ if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&
+ strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)
+ {
+ if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))
+ goto error;
+ }
+
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+
+error:
+ return ret;
+}
+
+static void gen_utc_time(uint8_t *buf, int *offset)
+{
+ static const uint8_t time_seq[] =
+ {
+ ASN1_SEQUENCE, 30,
+ ASN1_UTC_TIME, 13,
+ '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z',
+ ASN1_UTC_TIME, 13, /* make it good for 30 or so years */
+ '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'
+ };
+
+ /* fixed time */
+ memcpy(&buf[*offset], time_seq, sizeof(time_seq));
+ *offset += sizeof(time_seq);
+}
+
+static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ static const uint8_t pub_key_seq[] =
+ {
+ ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */
+ };
+
+ int seq_offset;
+ int pub_key_size = rsa_ctx->num_octets;
+ uint8_t *block = (uint8_t *)alloca(pub_key_size);
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+ buf[(*offset)++] = ASN1_INTEGER;
+ bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);
+
+ if (*block & 0x80) /* make integer positive */
+ {
+ set_gen_length(pub_key_size+1, buf, offset);
+ buf[(*offset)++] = 0;
+ }
+ else
+ set_gen_length(pub_key_size, buf, offset);
+
+ memcpy(&buf[*offset], block, pub_key_size);
+ *offset += pub_key_size;
+ memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));
+ *offset += sizeof(pub_key_seq);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_BIT_STRING, &seq_offset, buf, offset);
+ buf[(*offset)++] = 0; /* bit string is multiple of 8 */
+ gen_pub_key2(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ /* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
+ static const uint8_t rsa_enc_oid[] =
+ {
+ ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ ASN1_NULL, 0x00
+ };
+
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+ memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));
+ *offset += sizeof(rsa_enc_oid);
+ gen_pub_key1(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst,
+ uint8_t *buf, int *offset)
+{
+ static const uint8_t asn1_sig[] =
+ {
+ ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05,
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */
+ ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14
+ };
+
+ uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);
+ uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);
+ int sig_size;
+
+ /* add the digest as an embedded asn.1 sequence */
+ memcpy(block, asn1_sig, sizeof(asn1_sig));
+ memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);
+
+ sig_size = RSA_encrypt(rsa_ctx, block,
+ sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);
+
+ buf[(*offset)++] = ASN1_BIT_STRING;
+ set_gen_length(sig_size+1, buf, offset);
+ buf[(*offset)++] = 0; /* bit string is multiple of 8 */
+ memcpy(&buf[*offset], enc_block, sig_size);
+ *offset += sig_size;
+}
+
+static int gen_tbs_cert(const char * dn[],
+ const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,
+ uint8_t *sha_dgst)
+{
+ int ret = X509_OK;
+ SHA1_CTX sha_ctx;
+ int seq_offset;
+ int begin_tbs = *offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+ gen_serial_number(buf, offset);
+ gen_signature_alg(buf, offset);
+
+ /* CA certicate issuer */
+ if ((ret = gen_issuer(dn, buf, offset)))
+ goto error;
+
+ gen_utc_time(buf, offset);
+
+ /* certificate issuer */
+ if ((ret = gen_issuer(dn, buf, offset)))
+ goto error;
+
+ gen_pub_key(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);
+ SHA1_Final(sha_dgst, &sha_ctx);
+
+error:
+ return ret;
+}
+
+/**
+ * Create a new certificate.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)
+{
+ int ret = X509_OK, offset = 0, seq_offset;
+ /* allocate enough space to load a new certificate */
+ uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);
+ uint8_t sha_dgst[SHA1_SIZE];
+ int seq_size = pre_adjust_with_size(ASN1_SEQUENCE,
+ &seq_offset, buf, &offset);
+
+ if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)
+ goto error;
+
+ gen_signature_alg(buf, &offset);
+ gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);
+ adjust_with_size(seq_size, seq_offset, buf, &offset);
+ *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */
+ memcpy(*cert_data, buf, offset);
+
+error:
+ return ret < 0 ? ret : offset;
+}
+
+#endif
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c
new file mode 100644
index 0000000000..8cc80d9c77
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Load certificates/keys into memory. These can be in many different formats.
+ * PEM support and other formats can be processed here.
+ *
+ * The PEM private keys may be optionally encrypted with AES128 or AES256.
+ * The encrypted PEM keys were generated with something like:
+ *
+ * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+#include "config.h"
+
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password);
+#ifdef CONFIG_SSL_HAS_PEM
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password);
+#endif
+
+/*
+ * Load a file into memory that is in binary DER (or ascii PEM) format.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type,
+ const char *filename, const char *password)
+{
+#ifndef CONFIG_SSL_SKELETON_MODE
+ static const char * const begin = "-----BEGIN";
+ int ret = SSL_OK;
+ SSLObjLoader *ssl_obj = NULL;
+
+ if (filename == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+ ssl_obj->len = get_file(filename, &ssl_obj->buf);
+ if (ssl_obj->len <= 0)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ /* is the file a PEM file? */
+ if (strstr((char *)ssl_obj->buf, begin) != NULL)
+ {
+#ifdef CONFIG_SSL_HAS_PEM
+ ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
+#else
+ printf(unsupported_str);
+ ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+ }
+ else
+ ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
+
+error:
+ ssl_obj_free(ssl_obj);
+ return ret;
+#else
+ printf(unsupported_str);
+ return SSL_ERROR_NOT_SUPPORTED;
+#endif /* CONFIG_SSL_SKELETON_MODE */
+}
+
+/*
+ * Transfer binary data into the object loader.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type,
+ const uint8_t *data, int len, const char *password)
+{
+ int ret;
+ SSLObjLoader ssl_obj;
+ ssl_obj.buf = data;
+ ssl_obj.len = len;
+ ret = do_obj(ssl_ctx, mem_type, &ssl_obj, password);
+
+ return ret;
+}
+
+/*
+ * Actually work out what we are doing
+ */
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password)
+{
+ int ret = SSL_OK;
+
+ switch (obj_type)
+ {
+ case SSL_OBJ_RSA_KEY:
+ ret = add_private_key(ssl_ctx, ssl_obj);
+ break;
+
+ case SSL_OBJ_X509_CERT:
+ ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+ break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case SSL_OBJ_X509_CACERT:
+ add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+ break;
+#endif
+
+#ifdef CONFIG_SSL_USE_PKCS12
+ case SSL_OBJ_PKCS8:
+ ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
+ break;
+
+ case SSL_OBJ_PKCS12:
+ ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
+ break;
+#endif
+ default:
+ printf(unsupported_str);
+ ret = SSL_ERROR_NOT_SUPPORTED;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Clean up our mess.
+ */
+void ssl_obj_free(SSLObjLoader *ssl_obj)
+{
+ if (ssl_obj)
+ {
+ free(ssl_obj->buf);
+ free(ssl_obj);
+ }
+}
+
+/*
+ * Support for PEM encoded keys/certificates.
+ */
+#ifdef CONFIG_SSL_HAS_PEM
+
+#define NUM_PEM_TYPES 4
+#define IV_SIZE 16
+#define IS_RSA_PRIVATE_KEY 0
+#define IS_ENCRYPTED_PRIVATE_KEY 1
+#define IS_PRIVATE_KEY 2
+#define IS_CERTIFICATE 3
+
+static const char * const begins[NUM_PEM_TYPES] =
+{
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+ "-----BEGIN PRIVATE KEY-----",
+ "-----BEGIN CERTIFICATE-----",
+};
+
+static const char * const ends[NUM_PEM_TYPES] =
+{
+ "-----END RSA PRIVATE KEY-----",
+ "-----END ENCRYPTED PRIVATE KEY-----",
+ "-----END PRIVATE KEY-----",
+ "-----END CERTIFICATE-----",
+};
+
+static const char * const aes_str[2] =
+{
+ "DEK-Info: AES-128-CBC,",
+ "DEK-Info: AES-256-CBC,"
+};
+
+/**
+ * Take a base64 blob of data and decrypt it (using AES) into its
+ * proper ASN.1 form.
+ */
+static int pem_decrypt(const char *where, const char *end,
+ const char *password, SSLObjLoader *ssl_obj)
+{
+ int ret = -1;
+ int is_aes_256 = 0;
+ char *start = NULL;
+ uint8_t iv[IV_SIZE];
+ int i, pem_size;
+ MD5_CTX md5_ctx;
+ AES_CTX aes_ctx;
+ uint8_t key[32]; /* AES256 size */
+
+ if (password == NULL || strlen(password) == 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
+#endif
+ goto error;
+ }
+
+ if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */
+ {
+ start += strlen(aes_str[0]);
+ }
+ else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */
+ {
+ is_aes_256 = 1;
+ start += strlen(aes_str[1]);
+ }
+ else
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
+#endif
+ goto error;
+ }
+
+ /* convert from hex to binary - assumes uppercase hex */
+ for (i = 0; i < IV_SIZE; i++)
+ {
+ char c = *start++ - '0';
+ iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
+ c = *start++ - '0';
+ iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
+ }
+
+ while (*start == '\r' || *start == '\n')
+ start++;
+
+ /* turn base64 into binary */
+ pem_size = (int)(end-start);
+ if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
+ goto error;
+
+ /* work out the key */
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+ MD5_Update(&md5_ctx, iv, SALT_SIZE);
+ MD5_Final(key, &md5_ctx);
+
+ if (is_aes_256)
+ {
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, key, MD5_SIZE);
+ MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+ MD5_Update(&md5_ctx, iv, SALT_SIZE);
+ MD5_Final(&key[MD5_SIZE], &md5_ctx);
+ }
+
+ /* decrypt using the key/iv */
+ AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
+ AES_convert_key(&aes_ctx);
+ AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
+ ret = 0;
+
+error:
+ return ret;
+}
+
+/**
+ * Take a base64 blob of data and turn it into its proper ASN.1 form.
+ */
+static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where,
+ int remain, const char *password)
+{
+ int ret = SSL_ERROR_BAD_CERTIFICATE;
+ SSLObjLoader *ssl_obj = NULL;
+
+ while (remain > 0)
+ {
+ int i, pem_size, obj_type;
+ char *start = NULL, *end = NULL;
+
+ for (i = 0; i < NUM_PEM_TYPES; i++)
+ {
+ if ((start = strstr(where, begins[i])) &&
+ (end = strstr(where, ends[i])))
+ {
+ remain -= (int)(end-where);
+ start += strlen(begins[i]);
+ pem_size = (int)(end-start);
+
+ ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+
+ /* 4/3 bigger than what we need but so what */
+ ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
+ ssl_obj->len = pem_size;
+
+ if (i == IS_RSA_PRIVATE_KEY &&
+ strstr(start, "Proc-Type:") &&
+ strstr(start, "4,ENCRYPTED"))
+ {
+ /* check for encrypted PEM file */
+ if (pem_decrypt(start, end, password, ssl_obj) < 0)
+ {
+ ret = SSL_ERROR_BAD_CERTIFICATE;
+ goto error;
+ }
+ }
+ else
+ {
+ ssl_obj->len = pem_size;
+ if (base64_decode(start, pem_size,
+ ssl_obj->buf, &ssl_obj->len) != 0)
+ {
+ ret = SSL_ERROR_BAD_CERTIFICATE;
+ goto error;
+ }
+ }
+
+ switch (i)
+ {
+ case IS_RSA_PRIVATE_KEY:
+ obj_type = SSL_OBJ_RSA_KEY;
+ break;
+
+ case IS_ENCRYPTED_PRIVATE_KEY:
+ case IS_PRIVATE_KEY:
+ obj_type = SSL_OBJ_PKCS8;
+ break;
+
+ case IS_CERTIFICATE:
+ obj_type = is_cacert ?
+ SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
+ break;
+
+ default:
+ ret = SSL_ERROR_BAD_CERTIFICATE;
+ goto error;
+ }
+
+ /* In a format we can now understand - so process it */
+ if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
+ goto error;
+
+ end += strlen(ends[i]);
+ remain -= strlen(ends[i]);
+ while (remain > 0 && (*end == '\r' || *end == '\n'))
+ {
+ end++;
+ remain--;
+ }
+
+ where = end;
+ break;
+ }
+ }
+
+ ssl_obj_free(ssl_obj);
+ ssl_obj = NULL;
+ if (start == NULL)
+ break;
+ }
+error:
+ ssl_obj_free(ssl_obj);
+ return ret;
+}
+
+/*
+ * Load a file into memory that is in ASCII PEM format.
+ */
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password)
+{
+ char *start;
+
+ /* add a null terminator */
+ ssl_obj->len++;
+ ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
+ ssl_obj->buf[ssl_obj->len-1] = 0;
+ start = (char *)ssl_obj->buf;
+ return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
+ start, ssl_obj->len, password);
+}
+#endif /* CONFIG_SSL_HAS_PEM */
+
+/**
+ * Load the key/certificates in memory depending on compile-time and user
+ * options.
+ */
+int load_key_certs(SSL_CTX *ssl_ctx)
+{
+ int ret = SSL_OK;
+ uint32_t options = ssl_ctx->options;
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+ uint8_t *cert_data = NULL;
+ int cert_size;
+ static const char *dn[] =
+ {
+ CONFIG_SSL_X509_COMMON_NAME,
+ CONFIG_SSL_X509_ORGANIZATION_NAME,
+ CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
+ };
+#endif
+
+ /* do the private key first */
+ if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
+ {
+ if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY,
+ CONFIG_SSL_PRIVATE_KEY_LOCATION,
+ CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
+ goto error;
+ }
+ else if (!(options & SSL_NO_DEFAULT_KEY))
+ {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+// static const /* saves a few more bytes */
+//#include "private_key.h"
+// ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
+ // default_private_key_len, NULL);
+#endif
+ }
+
+ /* now load the certificate */
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+ if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
+ {
+ ret = cert_size;
+ goto error;
+ }
+
+ ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
+ free(cert_data);
+#else
+ if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
+ {
+ if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT,
+ CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
+ goto error;
+ }
+ else if (!(options & SSL_NO_DEFAULT_KEY))
+ {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+ static const /* saves a few bytes and RAM */
+#include "cert.h"
+ ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT,
+ default_certificate, default_certificate_len, NULL);
+#endif
+ }
+#endif
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret)
+ {
+ printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
+ }
+#endif
+
+ return ret;
+
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c
new file mode 100644
index 0000000000..6b5c4d8ee9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/*
+ * Enable a subset of openssl compatible functions. We don't aim to be 100%
+ * compatible - just to be able to do basic ports etc.
+ *
+ * Only really tested on mini_httpd, so I'm not too sure how extensive this
+ * port is.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "os_port.h"
+#include "ssl.h"
+
+#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr)
+
+static char *key_password = NULL;
+
+void *SSLv23_server_method(void) { return NULL; }
+void *SSLv3_server_method(void) { return NULL; }
+void *TLSv1_server_method(void) { return NULL; }
+void *SSLv23_client_method(void) { return NULL; }
+void *SSLv3_client_method(void) { return NULL; }
+void *TLSv1_client_method(void) { return NULL; }
+
+typedef void * (*ssl_func_type_t)(void);
+typedef void * (*bio_func_type_t)(void);
+
+typedef struct
+{
+ ssl_func_type_t ssl_func_type;
+} OPENSSL_CTX;
+
+SSL_CTX * SSL_CTX_new(ssl_func_type_t meth)
+{
+ SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5);
+ ssl_ctx->bonus_attr = malloc(sizeof(OPENSSL_CTX));
+ OPENSSL_CTX_ATTR->ssl_func_type = meth;
+ return ssl_ctx;
+}
+
+void SSL_CTX_free(SSL_CTX * ssl_ctx)
+{
+ free(ssl_ctx->bonus_attr);
+ ssl_ctx_free(ssl_ctx);
+}
+
+SSL * SSL_new(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ ssl_func_type_t ssl_func_type;
+
+ ssl = ssl_new(ssl_ctx, -1); /* fd is set later */
+ ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type;
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ if (ssl_func_type == SSLv23_client_method ||
+ ssl_func_type == SSLv3_client_method ||
+ ssl_func_type == TLSv1_client_method)
+ {
+ SET_SSL_FLAG(SSL_IS_CLIENT);
+ }
+ else
+#endif
+ {
+ ssl->next_state = HS_CLIENT_HELLO;
+ }
+
+ return ssl;
+}
+
+int SSL_set_fd(SSL *s, int fd)
+{
+ s->client_fd = fd;
+ return 1; /* always succeeds */
+}
+
+int SSL_accept(SSL *ssl)
+{
+ while (ssl_read(ssl, NULL) == SSL_OK)
+ {
+ if (ssl->next_state == HS_CLIENT_HELLO)
+ return 1; /* we're done */
+ }
+
+ return -1;
+}
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int SSL_connect(SSL *ssl)
+{
+ return do_client_connect(ssl) == SSL_OK ? 1 : -1;
+}
+#endif
+
+void SSL_free(SSL *ssl)
+{
+ ssl_free(ssl);
+}
+
+int SSL_read(SSL *ssl, void *buf, int num)
+{
+ uint8_t *read_buf;
+ int ret;
+
+ while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
+
+ if (ret > SSL_OK)
+ {
+ memcpy(buf, read_buf, ret > num ? num : ret);
+ }
+
+ return ret;
+}
+
+int SSL_write(SSL *ssl, const void *buf, int num)
+{
+ return ssl_write(ssl, buf, num);
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+ return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+ return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK);
+}
+
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d)
+{
+ return (ssl_obj_memory_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK);
+}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len)
+{
+ return 1;
+}
+
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+{
+ return 1;
+}
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file)
+{
+ return (ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_shutdown(SSL *ssl)
+{
+ return 1;
+}
+
+/*** get/set session ***/
+SSL_SESSION *SSL_get1_session(SSL *ssl)
+{
+ return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */
+}
+
+int SSL_set_session(SSL *ssl, SSL_SESSION *session)
+{
+ memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE);
+ return 1;
+}
+
+void SSL_SESSION_free(SSL_SESSION *session) { }
+/*** end get/set session ***/
+
+long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+{
+ return 0;
+}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+ int (*verify_callback)(int, void *)) { }
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { }
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+ const char *CApath)
+{
+ return 1;
+}
+
+void *SSL_load_client_CA_file(const char *file)
+{
+ return (void *)file;
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file)
+{
+
+ ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL);
+}
+
+void SSLv23_method(void) { }
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { }
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)
+{
+ key_password = (char *)u;
+}
+
+int SSL_peek(SSL *ssl, void *buf, int num)
+{
+ memcpy(buf, ssl->bm_data, num);
+ return num;
+}
+
+void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { }
+
+long SSL_get_verify_result(const SSL *ssl)
+{
+ return ssl_handshake_status(ssl);
+}
+
+int SSL_state(SSL *ssl)
+{
+ return 0x03; // ok state
+}
+
+/** end of could do better list */
+
+void *SSL_get_peer_certificate(const SSL *ssl)
+{
+ return &ssl->ssl_ctx->certs[0];
+}
+
+int SSL_clear(SSL *ssl)
+{
+ return 1;
+}
+
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+{
+ return 1;
+}
+
+int SSL_CTX_set_cipher_list(SSL *s, const char *str)
+{
+ return 1;
+}
+
+int SSL_get_error(const SSL *ssl, int ret)
+{
+ ssl_display_error(ret);
+ return 0; /* TODO: return proper return code */
+}
+
+void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {}
+int SSL_library_init(void ) { return 1; }
+void SSL_load_error_strings(void ) {}
+void ERR_print_errors_fp(FILE *fp) {}
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) {
+ return CONFIG_SSL_EXPIRY_TIME*3600; }
+long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) {
+ return SSL_CTX_get_timeout(ssl_ctx); }
+#endif
+void BIO_printf(FILE *f, const char *format, ...)
+{
+ va_list(ap);
+ va_start(ap, format);
+ vfprintf(f, format, ap);
+ va_end(ap);
+}
+
+void* BIO_s_null(void) { return NULL; }
+FILE *BIO_new(bio_func_type_t func)
+{
+ if (func == BIO_s_null)
+ return fopen("/dev/null", "r");
+ else
+ return NULL;
+}
+
+FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; }
+int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; }
+
+
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c
new file mode 100644
index 0000000000..a0627bf620
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file os_port.c
+ *
+ * OS specific functions.
+ */
+#include <time.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "os_port.h"
+#include <stdio.h>
+#include "sockets.h"
+
+static int memory_buf[400];
+static char enable = 1;
+static int nb_entries = 0;
+static int nb_alloc = 0;
+
+void disable_memory_buf(void)
+{
+ enable = 0;
+}
+void enable_memory_buf(void)
+{
+ enable = 1;
+}
+void init_memory_buf(void)
+{
+ for(int i = 0; i < 400; i += 2)
+ {
+ memory_buf[i] = -1;
+ memory_buf[i+1] = 0;
+ }
+}
+void print_buf_stats(void)
+{
+ if(enable)
+ {
+ int used = 0;
+ for(int i = 1; i < 400; i += 2)
+ used += memory_buf[i];
+ printf("%d\n", used);
+ }
+}
+
+void print_all_buf_stats(void)
+{
+ int used = 0;
+ for(int i = 1; i < 400; i += 2)
+ used += memory_buf[i];
+ printf("used: %d bytes\n", used);
+
+ for(int i = 0; i < 400; i += 2)
+ if(memory_buf[i] != -1)
+ printf("ptr:%X, size:%d\n", memory_buf[i], memory_buf[i+1]);
+}
+
+static void add_entry(void *x, size_t s, const char* f, const int l)
+{
+ nb_entries++;
+ for(int i = 0; i < 400; i += 2)
+ {
+ if(memory_buf[i] == -1)
+ {
+ if(enable)
+ printf("new ptr:%X, size:%d at %s:%d\n", x, s, f, l);
+ memory_buf[i] = (int)(x);
+ memory_buf[i+1] = s;
+ return;
+ }
+ }
+ if(enable)
+ printf("No space left in buffer\n");
+}
+
+static void remove_entry(void *x, const char* f, const int l)
+{
+ nb_entries--;
+ for(int i = 0; i < 400; i += 2)
+ {
+ if(memory_buf[i] == (int)(x))
+ {
+ if(enable)
+ printf("free ptr:%X, size:%d at %s:%d\n", memory_buf[i], memory_buf[i+1], f, l);
+ memory_buf[i] = -1;
+ memory_buf[i+1] = 0;
+ return;
+ }
+ }
+ if(enable)
+ printf("not found\n");
+}
+
+#ifdef MBED
+/**
+ * gettimeofday() not in mbed
+ */
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
+{
+ t->tv_sec = time(NULL);
+ t->tv_usec = 0; /* 1sec precision only */
+}
+
+#endif
+
+#ifdef WIN32
+/**
+ * gettimeofday() not in Win32
+ */
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
+{
+#if defined(_WIN32_WCE)
+ t->tv_sec = time(NULL);
+ t->tv_usec = 0; /* 1sec precision only */
+#else
+ struct _timeb timebuffer;
+ _ftime(&timebuffer);
+ t->tv_sec = (long)timebuffer.time;
+ t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */
+#endif
+}
+
+
+/**
+ * strcasecmp() not in Win32
+ */
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2)
+{
+ while (tolower(*s1) == tolower(*s2++))
+ {
+ if (*s1++ == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);
+}
+
+
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size)
+{
+ HKEY hKey;
+ unsigned long datatype;
+ unsigned long bufferlength = buf_size;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
+ 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
+ return -1;
+
+ RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength);
+ RegCloseKey(hKey);
+ return 0;
+}
+#endif
+
+#undef malloc
+#undef realloc
+#undef calloc
+#undef free
+
+static const char * out_of_mem_str = "out of memory";
+static const char * file_open_str = "Could not open file \"%s\"";
+
+/*
+ * Some functions that call display some error trace and then call abort().
+ * This just makes life much easier on embedded systems, since we're
+ * suffering major trauma...
+ */
+EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l)
+{
+ if(enable)
+ printf("malloc\t");
+
+ void *x;
+
+ if ((x = malloc(s)) == NULL)
+ exit_now(out_of_mem_str);
+ add_entry(x,s, f, l);
+ print_buf_stats();
+
+ return x;
+}
+
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l)
+{
+ if(enable)
+ printf("realloc\t");
+
+ void *x;
+
+ if ((x = realloc(y, s)) == NULL)
+ exit_now(out_of_mem_str);
+ remove_entry(y, f, l);
+ add_entry(x,s, f, l);
+ print_buf_stats();
+ return x;
+}
+
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l)
+{
+ if(enable)
+ printf("calloc\t");
+ void *x;
+
+ if ((x = calloc(n, s)) == NULL) {
+ exit_now(out_of_mem_str);
+ }
+
+ add_entry(x,n*s, f, l);
+ print_buf_stats();
+ return x;
+}
+
+EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l)
+{
+ if(enable)
+ printf("free\t");
+
+ remove_entry(y, f, l);
+ print_buf_stats();
+ free(y);
+}
+/*
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags)
+{
+ int x;
+
+ if ((x = open(pathname, flags)) < 0)
+ exit_now(file_open_str, pathname);
+
+ return x;
+}
+*/
+
+/**
+ * This is a call which will deliberately exit an application, but will
+ * display some information before dying.
+ */
+void exit_now(const char *format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ vfprintf(stderr, format, argp);
+ va_end(argp);
+ abort();
+}
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h
new file mode 100644
index 0000000000..3937261a75
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+
+//#include <Thread.h>
+#define SSL_CTX_MUTEX_TYPE //Mutex
+#define SSL_CTX_MUTEX_INIT(A) //pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A) //pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A) //pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A) //pthread_mutex_unlock(&A)
+
+#define malloc(A) ax_malloc(A, __FILE__, __LINE__)
+#ifndef realloc
+#define realloc(A,B) ax_realloc(A,B, __FILE__, __LINE__)
+#endif
+#define calloc(A,B) ax_calloc(A,B, __FILE__, __LINE__)
+#define free(A) ax_free(A, __FILE__, __LINE__)
+
+#define STDCALL
+#define EXP_FUNC
+void init_memory_buf(void);
+void disable_memory_buf(void);
+void enable_memory_buf(void);
+void print_buf_stats(void);
+void print_all_buf_stats(void);
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l);
+EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l);
+
+//EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);
+
+#define SOCKET_READ(A,B,C) lwip_read(A,B,C)
+#define SOCKET_WRITE(A,B,C) lwip_write(A,B,C)
+#define SOCKET_CLOSE(A) closesocket(A)
+#define TTY_FLUSH()
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h
new file mode 100644
index 0000000000..a9ac7393d7
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file os_port.h
+ *
+ * Some stuff to minimise the differences between windows and linux/unix
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "os_int.h"
+#include <stdio.h>
+
+#if defined(WIN32)
+#define STDCALL __stdcall
+#define EXP_FUNC __declspec(dllexport)
+#else
+#define STDCALL
+#define EXP_FUNC
+#endif
+
+#if defined(_WIN32_WCE)
+#undef WIN32
+#define WIN32
+#endif
+
+#ifdef WIN32
+
+/* Windows CE stuff */
+#if defined(_WIN32_WCE)
+#include <basetsd.h>
+#define abort() exit(1)
+#else
+#include <io.h>
+#include <process.h>
+#include <sys/timeb.h>
+#include <fcntl.h>
+#endif /* _WIN32_WCE */
+
+#include <winsock.h>
+#include <direct.h>
+#undef getpid
+#undef open
+#undef close
+#undef sleep
+#undef gettimeofday
+#undef dup2
+#undef unlink
+
+#define SOCKET_READ(A,B,C) recv(A,B,C,0)
+#define SOCKET_WRITE(A,B,C) send(A,B,C,0)
+#define SOCKET_CLOSE(A) closesocket(A)
+#define srandom(A) srand(A)
+#define random() rand()
+#define getpid() _getpid()
+#define snprintf _snprintf
+#define open(A,B) _open(A,B)
+#define dup2(A,B) _dup2(A,B)
+#define unlink(A) _unlink(A)
+#define close(A) _close(A)
+#define read(A,B,C) _read(A,B,C)
+#define write(A,B,C) _write(A,B,C)
+#define sleep(A) Sleep(A*1000)
+#define usleep(A) Sleep(A/1000)
+#define strdup(A) _strdup(A)
+#define chroot(A) _chdir(A)
+#define chdir(A) _chdir(A)
+#define alloca(A) _alloca(A)
+
+
+#ifndef lseek
+#define lseek(A,B,C) _lseek(A,B,C)
+
+#endif
+
+/* This fix gets around a problem where a win32 application on a cygwin xterm
+ doesn't display regular output (until a certain buffer limit) - but it works
+ fine under a normal DOS window. This is a hack to get around the issue -
+ see http://www.khngai.com/emacs/tty.php */
+#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout);
+
+/*
+ * automatically build some library dependencies.
+ */
+#pragma comment(lib, "WS2_32.lib")
+#pragma comment(lib, "AdvAPI32.lib")
+
+typedef int socklen_t;
+
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone);
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2);
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size);
+
+#else /* Not Win32 */
+
+//#include <unistd.h>
+//#include <pwd.h>
+//#include <netdb.h>
+//#include <dirent.h>
+//#include <fcntl.h>
+#include <errno.h>
+//#include <sys/stat.h>
+#include <time.h>
+#include <socket.h>
+//#include <sys/wait.h>
+#include <netinet/in.h>
+#include <inet.h>
+
+#define SOCKET_READ(A,B,C) read(A,B,C)
+#define SOCKET_WRITE(A,B,C) write(A,B,C)
+#define SOCKET_CLOSE(A) if (A >= 0) close(A)
+#define TTY_FLUSH()
+
+#endif /* Not Win32 */
+
+/* some functions to mutate the way these work */
+#define malloc(A) ax_malloc(A)
+#ifndef realloc
+#define realloc(A,B) ax_realloc(A,B)
+#endif
+#define calloc(A,B) ax_calloc(A,B)
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);
+
+#ifdef CONFIG_PLATFORM_LINUX
+void exit_now(const char *format, ...) __attribute((noreturn));
+#else
+void exit_now(const char *format, ...);
+#endif
+
+/* Mutexing definitions */
+#if defined(CONFIG_SSL_CTX_MUTEXING)
+#if defined(WIN32)
+#define SSL_CTX_MUTEX_TYPE HANDLE
+#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0)
+#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A)
+#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE)
+#define SSL_CTX_UNLOCK(A) ReleaseMutex(A)
+#else
+#include <pthread.h>
+#define SSL_CTX_MUTEX_TYPE pthread_mutex_t
+#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A)
+#endif
+#else /* no mutexing */
+#define SSL_CTX_MUTEX_INIT(A)
+#define SSL_CTX_MUTEX_DESTROY(A)
+#define SSL_CTX_LOCK(A)
+#define SSL_CTX_UNLOCK(A)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c
new file mode 100644
index 0000000000..2bafaf7eaf
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Process PKCS#8/PKCS#12 keys.
+ *
+ * The decoding of a PKCS#12 key is fairly specific - this code was tested on a
+ * key generated with:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128
+ * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
+ *
+ * or with a certificate chain:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
+ * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
+ *
+ * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
+ * private/public keys/certs have to use RSA encryption. Both the integrity
+ * and privacy passwords are the same.
+ *
+ * The PKCS#8 files were generated with something like:
+ *
+ * PEM format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
+ * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
+ *
+ * DER format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
+ * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+/* all commented out if not used */
+#ifdef CONFIG_SSL_USE_PKCS12
+
+#define BLOCK_SIZE 64
+#define PKCS12_KEY_ID 1
+#define PKCS12_IV_ID 2
+#define PKCS12_MAC_ID 3
+
+static char *make_uni_pass(const char *password, int *uni_pass_len);
+static int p8_decrypt(const char *uni_pass, int uni_pass_len,
+ const uint8_t *salt, int iter,
+ uint8_t *priv_key, int priv_key_len, int id);
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
+static int get_pbe_params(uint8_t *buf, int *offset,
+ const uint8_t **salt, int *iterations);
+
+/*
+ * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
+ */
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+ uint8_t *buf = ssl_obj->buf;
+ int len, offset = 0;
+ int iterations;
+ int ret = SSL_NOT_OK;
+ uint8_t *version = NULL;
+ const uint8_t *salt;
+ uint8_t *priv_key;
+ int uni_pass_len;
+ char *uni_pass = make_uni_pass(password, &uni_pass_len);
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Invalid p8 ASN.1 file\n");
+#endif
+ goto error;
+ }
+
+ /* unencrypted key? */
+ if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
+ {
+ ret = p8_add_key(ssl_ctx, buf);
+ goto error;
+ }
+
+ if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
+ goto error;
+
+ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ priv_key = &buf[offset];
+
+ p8_decrypt(uni_pass, uni_pass_len, salt,
+ iterations, priv_key, len, PKCS12_KEY_ID);
+ ret = p8_add_key(ssl_ctx, priv_key);
+
+error:
+ free(version);
+ free(uni_pass);
+ return ret;
+}
+
+/*
+ * Take the unencrypted pkcs8 and turn it into a private key
+ */
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
+{
+ uint8_t *buf = priv_key;
+ int len, offset = 0;
+ int ret = SSL_NOT_OK;
+
+ /* Skip the preamble and go straight to the private key.
+ We only support rsaEncryption (1.2.840.113549.1.1.1) */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
+
+error:
+ return ret;
+}
+
+/*
+ * Create the unicode password
+ */
+static char *make_uni_pass(const char *password, int *uni_pass_len)
+{
+ int pass_len = 0, i;
+ char *uni_pass;
+
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ uni_pass = (char *)malloc((strlen(password)+1)*2);
+
+ /* modify the password into a unicode version */
+ for (i = 0; i < (int)strlen(password); i++)
+ {
+ uni_pass[pass_len++] = 0;
+ uni_pass[pass_len++] = password[i];
+ }
+
+ uni_pass[pass_len++] = 0; /* null terminate */
+ uni_pass[pass_len++] = 0;
+ *uni_pass_len = pass_len;
+ return uni_pass;
+}
+
+/*
+ * Decrypt a pkcs8 block.
+ */
+static int p8_decrypt(const char *uni_pass, int uni_pass_len,
+ const uint8_t *salt, int iter,
+ uint8_t *priv_key, int priv_key_len, int id)
+{
+ uint8_t p[BLOCK_SIZE*2];
+ uint8_t d[BLOCK_SIZE];
+ uint8_t Ai[SHA1_SIZE];
+ SHA1_CTX sha_ctx;
+ RC4_CTX rc4_ctx;
+ int i;
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ {
+ p[i] = salt[i % SALT_SIZE];
+ p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
+ d[i] = id;
+ }
+
+ /* get the key - no IV since we are using RC4 */
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, d, sizeof(d));
+ SHA1_Update(&sha_ctx, p, sizeof(p));
+ SHA1_Final(Ai, &sha_ctx);
+
+ for (i = 1; i < iter; i++)
+ {
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
+ SHA1_Final(Ai, &sha_ctx);
+ }
+
+ /* do the decryption */
+ if (id == PKCS12_KEY_ID)
+ {
+ RC4_setup(&rc4_ctx, Ai, 16);
+ RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
+ }
+ else /* MAC */
+ memcpy(priv_key, Ai, SHA1_SIZE);
+
+ return 0;
+}
+
+/*
+ * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
+ * and keys.
+ */
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+ uint8_t *buf = ssl_obj->buf;
+ int len, iterations, auth_safes_start,
+ auth_safes_end, auth_safes_len, key_offset, offset = 0;
+ int all_certs = 0;
+ uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
+ uint8_t key[SHA1_SIZE];
+ uint8_t mac[SHA1_SIZE];
+ const uint8_t *salt;
+ int uni_pass_len, ret = SSL_OK;
+ char *uni_pass = make_uni_pass(password, &uni_pass_len);
+ static const uint8_t pkcs_data[] = /* pkc7 data */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
+ static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
+ static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Invalid p12 ASN.1 file\n");
+#endif
+ goto error;
+ }
+
+ if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
+ {
+ ret = SSL_ERROR_INVALID_VERSION;
+ goto error;
+ }
+
+ /* remove all the boring pcks7 bits */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
+ goto error;
+
+ /* work out the MAC start/end points (done on AuthSafes) */
+ auth_safes_start = offset;
+ auth_safes_end = offset;
+ if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
+ goto error;
+
+ auth_safes_len = auth_safes_end - auth_safes_start;
+ auth_safes = malloc(auth_safes_len);
+
+ memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ (len != sizeof(pkcs_encrypted) ||
+ memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ /* work out the salt for the certificate */
+ if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
+ goto error;
+
+ /* decrypt the certificate */
+ cert = &buf[offset];
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
+ len, PKCS12_KEY_ID)) < 0)
+ goto error;
+
+ offset += len;
+
+ /* load the certificate */
+ key_offset = 0;
+ all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
+
+ /* keep going until all certs are loaded */
+ while (key_offset < all_certs)
+ {
+ int cert_offset = key_offset;
+
+ if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+ (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
+ goto error;
+
+ key_offset = cert_offset;
+ }
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ (len != sizeof(pkcs8_key_bag)) ||
+ memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
+ goto error;
+
+ offset += len;
+
+ /* work out the salt for the private key */
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ /* decrypt the private key */
+ cert = &buf[offset];
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
+ len, PKCS12_KEY_ID)) < 0)
+ goto error;
+
+ offset += len;
+
+ /* load the private key */
+ if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
+ goto error;
+
+ /* miss out on friendly name, local key id etc */
+ if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
+ goto error;
+
+ /* work out the MAC */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
+ len != SHA1_SIZE)
+ goto error;
+
+ orig_mac = &buf[offset];
+ offset += len;
+
+ /* get the salt */
+ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
+ goto error;
+
+ salt = &buf[offset];
+
+ /* work out what the mac should be */
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations,
+ key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
+ goto error;
+
+ hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
+
+ if (memcmp(mac, orig_mac, SHA1_SIZE))
+ {
+ ret = SSL_ERROR_INVALID_HMAC;
+ goto error;
+ }
+
+error:
+ free(version);
+ free(uni_pass);
+ free(auth_safes);
+ return ret;
+}
+
+/*
+ * Retrieve the salt/iteration details from a PBE block.
+ */
+static int get_pbe_params(uint8_t *buf, int *offset,
+ const uint8_t **salt, int *iterations)
+{
+ static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
+
+ int i, len;
+ uint8_t *iter = NULL;
+ int error_code = SSL_ERROR_NOT_SUPPORTED;
+
+ /* Get the PBE type */
+ if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+ goto error;
+
+ /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1)
+ which is the only algorithm we support */
+ if (len != sizeof(pbeSH1RC4) ||
+ memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
+#endif
+ goto error;
+ }
+
+ *offset += len;
+
+ if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 ||
+ len != 8)
+ goto error;
+
+ *salt = &buf[*offset];
+ *offset += len;
+
+ if ((len = asn1_get_int(buf, offset, &iter)) < 0)
+ goto error;
+
+ *iterations = 0;
+ for (i = 0; i < len; i++)
+ {
+ (*iterations) <<= 8;
+ (*iterations) += iter[i];
+ }
+
+ free(iter);
+ error_code = SSL_OK; /* got here - we are ok */
+
+error:
+ return error_code;
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h
new file mode 100644
index 0000000000..ce7985c5a7
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h
@@ -0,0 +1,54 @@
+unsigned char default_private_key[] = {
+ 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd,
+ 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e,
+ 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29,
+ 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf,
+ 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7,
+ 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60,
+ 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84,
+ 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04,
+ 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14,
+ 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe,
+ 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91,
+ 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2,
+ 0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24,
+ 0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c,
+ 0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5,
+ 0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1,
+ 0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab,
+ 0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad,
+ 0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60,
+ 0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e,
+ 0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d,
+ 0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1,
+ 0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0,
+ 0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d,
+ 0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5,
+ 0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c,
+ 0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16,
+ 0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb,
+ 0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3,
+ 0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8,
+ 0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57,
+ 0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7,
+ 0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26,
+ 0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c,
+ 0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28,
+ 0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38,
+ 0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf,
+ 0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63,
+ 0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e,
+ 0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62,
+ 0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea,
+ 0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5,
+ 0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46,
+ 0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a,
+ 0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89,
+ 0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37,
+ 0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e,
+ 0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c,
+ 0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3,
+ 0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5
+};
+unsigned int default_private_key_len = 609;
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h
new file mode 100644
index 0000000000..9625896d11
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @mainpage axTLS API
+ *
+ * @image html axolotl.jpg
+ *
+ * The axTLS library has features such as:
+ * - The TLSv1 SSL client/server protocol
+ * - No requirement to use any openssl libraries.
+ * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
+ * - RSA encryption/decryption with variable sized keys (up to 4096 bits).
+ * - Certificate chaining and peer authentication.
+ * - Session resumption, session renegotiation.
+ * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
+ * - Highly configurable compile time options.
+ * - Portable across many platforms (written in ANSI C), and has language
+ * bindings in C, C#, VB.NET, Java, Perl and Lua.
+ * - Partial openssl API compatibility (via a wrapper).
+ * - A very small footprint (around 50-60kB for the library in 'server-only'
+ * mode).
+ * - No dependencies on sockets - can use serial connections for example.
+ * - A very simple API - ~ 20 functions/methods.
+ *
+ * A list of these functions/methods are described below.
+ *
+ * @ref c_api
+ *
+ * @ref bigint_api
+ *
+ * @ref csharp_api
+ *
+ * @ref java_api
+ */
+#ifndef HEADER_SSL_H
+#define HEADER_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+
+/* need to predefine before ssl_lib.h gets to it */
+#define SSL_SESSION_ID_SIZE 32
+
+#include "tls1.h"
+
+/* The optional parameters that can be given to the client/server SSL engine */
+#define SSL_CLIENT_AUTHENTICATION 0x00010000
+#define SSL_SERVER_VERIFY_LATER 0x00020000
+#define SSL_NO_DEFAULT_KEY 0x00040000
+#define SSL_DISPLAY_STATES 0x00080000
+#define SSL_DISPLAY_BYTES 0x00100000
+#define SSL_DISPLAY_CERTS 0x00200000
+#define SSL_DISPLAY_RSA 0x00400000
+#define SSL_CONNECT_IN_PARTS 0x00800000
+
+/* errors that can be generated */
+#define SSL_OK 0
+#define SSL_NOT_OK -1
+#define SSL_ERROR_DEAD -2
+#define SSL_CLOSE_NOTIFY -3
+#define SSL_ERROR_CONN_LOST -256
+#define SSL_ERROR_SOCK_SETUP_FAILURE -258
+#define SSL_ERROR_INVALID_HANDSHAKE -260
+#define SSL_ERROR_INVALID_PROT_MSG -261
+#define SSL_ERROR_INVALID_HMAC -262
+#define SSL_ERROR_INVALID_VERSION -263
+#define SSL_ERROR_INVALID_SESSION -265
+#define SSL_ERROR_NO_CIPHER -266
+#define SSL_ERROR_BAD_CERTIFICATE -268
+#define SSL_ERROR_INVALID_KEY -269
+#define SSL_ERROR_FINISHED_INVALID -271
+#define SSL_ERROR_NO_CERT_DEFINED -272
+#define SSL_ERROR_NO_CLIENT_RENOG -273
+#define SSL_ERROR_NOT_SUPPORTED -274
+#define SSL_X509_OFFSET -512
+#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A)
+
+/* alert types that are recognized */
+#define SSL_ALERT_TYPE_WARNING 1
+#define SLL_ALERT_TYPE_FATAL 2
+
+/* these are all the alerts that are recognized */
+#define SSL_ALERT_CLOSE_NOTIFY 0
+#define SSL_ALERT_UNEXPECTED_MESSAGE 10
+#define SSL_ALERT_BAD_RECORD_MAC 20
+#define SSL_ALERT_HANDSHAKE_FAILURE 40
+#define SSL_ALERT_BAD_CERTIFICATE 42
+#define SSL_ALERT_ILLEGAL_PARAMETER 47
+#define SSL_ALERT_DECODE_ERROR 50
+#define SSL_ALERT_DECRYPT_ERROR 51
+#define SSL_ALERT_INVALID_VERSION 70
+#define SSL_ALERT_NO_RENEGOTIATION 100
+
+/* The ciphers that are supported */
+#define SSL_AES128_SHA 0x2f
+#define SSL_AES256_SHA 0x35
+#define SSL_RC4_128_SHA 0x05
+#define SSL_RC4_128_MD5 0x04
+
+/* build mode ids' */
+#define SSL_BUILD_SKELETON_MODE 0x01
+#define SSL_BUILD_SERVER_ONLY 0x02
+#define SSL_BUILD_ENABLE_VERIFICATION 0x03
+#define SSL_BUILD_ENABLE_CLIENT 0x04
+#define SSL_BUILD_FULL_MODE 0x05
+
+/* offsets to retrieve configuration information */
+#define SSL_BUILD_MODE 0
+#define SSL_MAX_CERT_CFG_OFFSET 1
+#define SSL_MAX_CA_CERT_CFG_OFFSET 2
+#define SSL_HAS_PEM 3
+
+/* default session sizes */
+#define SSL_DEFAULT_SVR_SESS 5
+#define SSL_DEFAULT_CLNT_SESS 1
+
+/* X.509/X.520 distinguished name types */
+#define SSL_X509_CERT_COMMON_NAME 0
+#define SSL_X509_CERT_ORGANIZATION 1
+#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2
+#define SSL_X509_CA_CERT_COMMON_NAME 3
+#define SSL_X509_CA_CERT_ORGANIZATION 4
+#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5
+
+/* SSL object loader types */
+#define SSL_OBJ_X509_CERT 1
+#define SSL_OBJ_X509_CACERT 2
+#define SSL_OBJ_RSA_KEY 3
+#define SSL_OBJ_PKCS8 4
+#define SSL_OBJ_PKCS12 5
+
+/**
+ * @defgroup c_api Standard C API
+ * @brief The standard interface in C.
+ * @{
+ */
+
+/**
+ * @brief Establish a new client/server context.
+ *
+ * This function is called before any client/server SSL connections are made.
+ *
+ * Each new connection will use the this context's private key and
+ * certificate chain. If a different certificate chain is required, then a
+ * different context needs to be be used.
+ *
+ * There are two threading models supported - a single thread with one
+ * SSL_CTX can support any number of SSL connections - and multiple threads can
+ * support one SSL_CTX object each (the default). But if a single SSL_CTX
+ * object uses many SSL objects in individual threads, then the
+ * CONFIG_SSL_CTX_MUTEXING option needs to be configured.
+ *
+ * @param options [in] Any particular options. At present the options
+ * supported are:
+ * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
+ * authentication fails. The certificate can be authenticated later with a
+ * call to ssl_verify_cert().
+ * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
+ * i.e. each handshake will include a "certificate request" message from the
+ * server. Only available if verification has been enabled.
+ * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
+ * during the handshake.
+ * - SSL_DISPLAY_STATES (full mode build only): Display the state changes
+ * during the handshake.
+ * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
+ * are passed during a handshake.
+ * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
+ * are passed during a handshake.
+ * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of
+ * ssl_client_new().
+ * @param num_sessions [in] The number of sessions to be used for session
+ * caching. If this value is 0, then there is no session caching. This option
+ * is not used in skeleton mode.
+ * @return A client/server context.
+ */
+EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(SSL_CTX *ssl_ctx, uint32_t options, int num_sessions);
+
+/**
+ * @brief Remove a client/server context.
+ *
+ * Frees any used resources used by this context. Each connection will be
+ * sent a "Close Notify" alert (if possible).
+ * @param ssl_ctx [in] The client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);
+
+/**
+ * @brief (server only) Establish a new SSL connection to an SSL client.
+ *
+ * It is up to the application to establish the logical connection (whether it
+ * is a socket, serial connection etc).
+ * @param ssl_ctx [in] The server context.
+ * @param client_fd [in] The client's file descriptor.
+ * @return An SSL object reference.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief (client only) Establish a new SSL connection to an SSL server.
+ *
+ * It is up to the application to establish the initial logical connection
+ * (whether it is a socket, serial connection etc).
+ *
+ * This is a normally a blocking call - it will finish when the handshake is
+ * complete (or has failed). To use in non-blocking mode, set
+ * SSL_CONNECT_IN_PARTS in ssl_ctx_new().
+ * @param ssl_ctx [in] The client context.
+ * @param client_fd [in] The client's file descriptor.
+ * @param session_id [in] A 32 byte session id for session resumption. This
+ * can be null if no session resumption is being used or required. This option
+ * is not used in skeleton mode.
+ * @param sess_id_size The size of the session id (max 32)
+ * @return An SSL object reference. Use ssl_handshake_status() to check
+ * if a handshake succeeded.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL *ssl, int client_fd, const uint8_t *session_id, uint8_t sess_id_size);
+
+/**
+ * @brief Free any used resources on this connection.
+
+ * A "Close Notify" message is sent on this connection (if possible). It is up
+ * to the application to close the socket or file descriptor.
+ * @param ssl [in] The ssl object reference.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl);
+
+/**
+ * @brief Read the SSL data stream.
+ * If the socket is non-blocking and data is blocked then SSO_OK will be
+ * returned.
+ * @param ssl [in] An SSL object reference.
+ * @param in_data [out] If the read was successful, a pointer to the read
+ * buffer will be here. Do NOT ever free this memory as this buffer is used in
+ * sucessive calls. If the call was unsuccessful, this value will be null.
+ * @return The number of decrypted bytes:
+ * - if > 0, then the handshaking is complete and we are returning the number
+ * of decrypted bytes.
+ * - SSL_OK if the handshaking stage is successful (but not yet complete).
+ * - < 0 if an error.
+ * @see ssl.h for the error code list.
+ * @note Use in_data before doing any successive ssl calls.
+ */
+//EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);
+
+/**
+ * @brief Write to the SSL data stream.
+ * if the socket is non-blocking and data is blocked then a check is made
+ * to ensure that all data is sent (i.e. blocked mode is forced).
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @param out_len [in] The number of bytes to be written.
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);
+
+/**
+ * @brief Find an ssl object based on a file descriptor.
+ *
+ * Goes through the list of SSL objects maintained in a client/server context
+ * to look for a file descriptor match.
+ * @param ssl_ctx [in] The client/server context.
+ * @param client_fd [in] The file descriptor.
+ * @return A reference to the SSL object. Returns null if the object could not
+ * be found.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief Get the session id for a handshake.
+ *
+ * This will be a 32 byte sequence and is available after the first
+ * handshaking messages are sent.
+ * @param ssl [in] An SSL object reference.
+ * @return The session id as a 32 byte sequence.
+ * @note A SSLv23 handshake may have only 16 valid bytes.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);
+
+/**
+ * @brief Get the session id size for a handshake.
+ *
+ * This will normally be 32 but could be 0 (no session id) or something else.
+ * @param ssl [in] An SSL object reference.
+ * @return The size of the session id.
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);
+
+/**
+ * @brief Return the cipher id (in the SSL form).
+ * @param ssl [in] An SSL object reference.
+ * @return The cipher id. This will be one of the following:
+ * - SSL_AES128_SHA (0x2f)
+ * - SSL_AES256_SHA (0x35)
+ * - SSL_RC4_128_SHA (0x05)
+ * - SSL_RC4_128_MD5 (0x04)
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);
+
+/**
+ * @brief Return the status of the handshake.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the handshake is complete and ok.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);
+
+/**
+ * @brief Retrieve various parameters about the axTLS engine.
+ * @param offset [in] The configuration offset. It will be one of the following:
+ * - SSL_BUILD_MODE The build mode. This will be one of the following:
+ * - SSL_BUILD_SERVER_ONLY (basic server mode)
+ * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication)
+ * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties)
+ * - SSL_BUILD_FULL_MODE (client/server with diagnostics)
+ * - SSL_BUILD_SKELETON_MODE (skeleton mode)
+ * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
+ * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
+ * - SSL_HAS_PEM 1 if supported
+ * @return The value of the requested parameter.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset);
+
+/**
+ * @brief Display why the handshake failed.
+ *
+ * This call is only useful in a 'full mode' build. The output is to stdout.
+ * @param error_code [in] An error code.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code);
+
+/**
+ * @brief Authenticate a received certificate.
+ *
+ * This call is usually made by a client after a handshake is complete and the
+ * context is in SSL_SERVER_VERIFY_LATER mode.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the certificate is verified.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
+
+/**
+ * @brief Retrieve an X.509 distinguished name component.
+ *
+ * When a handshake is complete and a certificate has been exchanged, then the
+ * details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's common
+ * name matches the URL.
+ *
+ * @param ssl [in] An SSL object reference.
+ * @param component [in] one of:
+ * - SSL_X509_CERT_COMMON_NAME
+ * - SSL_X509_CERT_ORGANIZATION
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME
+ * - SSL_X509_CA_CERT_COMMON_NAME
+ * - SSL_X509_CA_CERT_ORGANIZATION
+ * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
+ * @return The appropriate string (or null if not defined)
+ * @note Verification build mode must be enabled.
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
+
+/**
+ * @brief Retrieve a Subject Alternative DNSName
+ *
+ * When a handshake is complete and a certificate has been exchanged, then the
+ * details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's DNS
+ * name matches the URL.
+ *
+ * @param ssl [in] An SSL object reference.
+ * @param dnsindex [in] The index of the DNS name to retrieve.
+ * @return The appropriate string (or null if not defined)
+ * @note Verification build mode must be enabled.
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);
+
+/**
+ * @brief Force the client to perform its handshake again.
+ *
+ * For a client this involves sending another "client hello" message.
+ * For the server is means sending a "hello request" message.
+ *
+ * This is a blocking call on the client (until the handshake completes).
+ *
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if renegotiation instantiation was ok
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);
+
+/**
+ * @brief Process a file that is in binary DER or ASCII PEM format.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the file. Can be one of:
+ * - SSL_OBJ_X509_CERT (no password required)
+ * - SSL_OBJ_X509_CACERT (no password required)
+ * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
+ * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
+ * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
+ *
+ * PEM files are automatically detected (if supported). The object type is
+ * also detected, and so is not relevant for these types of files.
+ * @param filename [in] The location of a file in DER/PEM format.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @note Not available in skeleton build mode.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);
+
+/**
+ * @brief Process binary data.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the memory data.
+ * @param data [in] The binary data to be loaded.
+ * @param len [in] The amount of data to be loaded.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @see ssl_obj_load for more details on obj_type.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+/**
+ * @brief Create an X.509 certificate.
+ *
+ * This certificate is a self-signed v1 cert with a fixed start/stop validity
+ * times. It is signed with an internal private key in ssl_ctx.
+ *
+ * @param ssl_ctx [in] The client/server context.
+ * @param options [in] Not used yet.
+ * @param dn [in] An array of distinguished name strings. The array is defined
+ * by:
+ * - SSL_X509_CERT_COMMON_NAME (0)
+ * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the
+ * hostname will be used.
+ * - SSL_X509_CERT_ORGANIZATION (1)
+ * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME
+ * will be used.
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
+ * @param cert_data [out] The certificate as a sequence of bytes.
+ * @return < 0 if an error, or the size of the certificate in bytes.
+ * @note cert_data must be freed when there is no more need for it.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);
+#endif
+
+/**
+ * @brief Return the axTLS library version as a string.
+ */
+EXP_FUNC const char * STDCALL ssl_version(void);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c
new file mode 100644
index 0000000000..ab1e86d155
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c
@@ -0,0 +1,2324 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * Common ssl/tlsv1 code to both the client and server implementations.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+
+
+
+#include "lwip/sockets.h"
+#include "os_port.h"
+#include "ssl.h"
+#include "arch.h"
+
+
+/* The session expiry time */
+#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600)
+
+static const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 };
+static const uint8_t g_chg_cipher_spec_pkt[] = { 1 };
+static const char * server_finished = "server finished";
+static const char * client_finished = "client finished";
+
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len);
+static int set_key_block(SSL *ssl, int is_write);
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len);
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt);
+static int send_raw_packet(SSL *ssl, uint8_t protocol);
+
+/**
+ * The server will pick the cipher based on the order that the order that the
+ * ciphers are listed. This order is defined at compile time.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] =
+{ SSL_RC4_128_SHA };
+#else
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index);
+
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] =
+#ifdef CONFIG_SSL_PROT_LOW /* low security, fast speed */
+{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 };
+#elif CONFIG_SSL_PROT_MEDIUM /* medium security, medium speed */
+{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };
+#else /* CONFIG_SSL_PROT_HIGH */ /* high security, low speed */
+{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };
+#endif
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/**
+ * The cipher map containing all the essentials for each cipher.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] =
+{
+ { /* RC4-SHA */
+ SSL_RC4_128_SHA, /* RC4-SHA */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(SHA1_SIZE+16), /* key block size */
+ 0, /* no padding */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+};
+#else
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] =
+{
+ { /* AES128-SHA */
+ SSL_AES128_SHA, /* AES128-SHA */
+ 16, /* key size */
+ 16, /* iv size */
+ 2*(SHA1_SIZE+16+16), /* key block size */
+ 16, /* block padding size */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)AES_cbc_encrypt, /* encrypt */
+ (crypt_func)AES_cbc_decrypt /* decrypt */
+ },
+ { /* AES256-SHA */
+ SSL_AES256_SHA, /* AES256-SHA */
+ 32, /* key size */
+ 16, /* iv size */
+ 2*(SHA1_SIZE+32+16), /* key block size */
+ 16, /* block padding size */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)AES_cbc_encrypt, /* encrypt */
+ (crypt_func)AES_cbc_decrypt /* decrypt */
+ },
+ { /* RC4-SHA */
+ SSL_RC4_128_SHA, /* RC4-SHA */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(SHA1_SIZE+16), /* key block size */
+ 0, /* no padding */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+ /*
+ * This protocol is from SSLv2 days and is unlikely to be used - but was
+ * useful for testing different possible digest algorithms.
+ */
+ { /* RC4-MD5 */
+ SSL_RC4_128_MD5, /* RC4-MD5 */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(MD5_SIZE+16), /* key block size */
+ 0, /* no padding */
+ MD5_SIZE, /* digest size */
+ hmac_md5, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+};
+#endif
+
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+ uint8_t *out, int olen);
+static const cipher_info_t *get_cipher_info(uint8_t cipher);
+static void increment_read_sequence(SSL *ssl);
+static void increment_write_sequence(SSL *ssl);
+static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header,
+ const uint8_t *buf, int buf_len, uint8_t *hmac_buf);
+
+/* win32 VC6.0 doesn't have variadic macros */
+#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE)
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...) {}
+#endif
+
+/**
+ * Establish a new client/server context.
+ */
+EXP_FUNC SSL_CTX *STDCALL ssl_ctx_new(SSL_CTX *ssl_ctx, uint32_t options, int num_sessions)
+{
+ ssl_ctx->options = options;
+ RNG_initialize();
+
+ if (load_key_certs(ssl_ctx) < 0)
+ {
+ printf("error loading key certs\r\n");
+ //free(ssl_ctx); /* can't load our key/certificate pair, so die */
+ return NULL;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl_ctx->num_sessions = num_sessions;
+#endif
+
+ SSL_CTX_MUTEX_INIT(ssl_ctx->mutex);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (num_sessions)
+ {
+ ssl_ctx->ssl_sessions = (SSL_SESSION **)
+ calloc(1, num_sessions*sizeof(SSL_SESSION *));
+ }
+#endif
+
+ return ssl_ctx;
+}
+
+/*
+ * Remove a client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ int i;
+
+ if (ssl_ctx == NULL)
+ return;
+
+ ssl = ssl_ctx->head;
+
+ /* clear out all the ssl entries */
+ while (ssl)
+ {
+ SSL *next = ssl->next;
+ ssl_free(ssl);
+ ssl = next;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* clear out all the sessions */
+ for (i = 0; i < ssl_ctx->num_sessions; i++)
+ session_free(ssl_ctx->ssl_sessions, i);
+
+ free(ssl_ctx->ssl_sessions);
+#endif
+
+ i = 0;
+ //while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf)
+ {
+ //free(ssl_ctx->certs[i].buf);
+ //ssl_ctx->certs[i++].buf = NULL;
+ }
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ remove_ca_certs(ssl_ctx->ca_cert_ctx);
+#endif
+ ssl_ctx->chain_length = 0;
+ SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex);
+ RSA_free(ssl_ctx->rsa_ctx);
+ RNG_terminate();
+ //free(ssl_ctx);
+}
+
+/*
+ * Free any used resources used by this connection.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl)
+{
+ SSL_CTX *ssl_ctx;
+
+ if (ssl == NULL) /* just ignore null pointers */
+ return;
+
+ /* only notify if we weren't notified first */
+ /* spec says we must notify when we are dying */
+ if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY))
+ send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+
+ ssl_ctx = ssl->ssl_ctx;
+
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+
+ /* adjust the server SSL list */
+ if (ssl->prev)
+ ssl->prev->next = ssl->next;
+ else
+ ssl_ctx->head = ssl->next;
+
+ if (ssl->next)
+ ssl->next->prev = ssl->prev;
+ else
+ ssl_ctx->tail = ssl->prev;
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+
+ /* may already be free - but be sure */
+ free(ssl->encrypt_ctx);
+ free(ssl->decrypt_ctx);
+ disposable_free(ssl);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ x509_free(ssl->x509_ctx);
+#endif
+ //free(ssl->ssl_ctx);
+ //free(ssl);
+}
+
+/*
+ * Write application data to the client
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len)
+{
+ int n = out_len, nw, i, tot = 0;
+
+ /* maximum size of a TLS packet is around 16kB, so fragment */
+ do
+ {
+ nw = n;
+
+ if (nw > RT_MAX_PLAIN_LENGTH) /* fragment if necessary */
+ nw = RT_MAX_PLAIN_LENGTH;
+
+ if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA,
+ &out_data[tot], nw)) <= 0)
+ {
+ out_len = i; /* an error */
+ break;
+ }
+
+ tot += i;
+ n -= i;
+ } while (n > 0);
+
+ return out_len;
+}
+
+/**
+ * Add a certificate to the certificate chain.
+ */
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+ int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0;
+ SSL_CERT *ssl_cert;
+ X509_CTX *cert = NULL;
+ int offset;
+
+ while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS)
+ i++;
+
+ if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: maximum number of certs added (%d) - change of "
+ "compile-time configuration required\n",
+ CONFIG_SSL_MAX_CERTS);
+#endif
+ goto error;
+ }
+
+ if ((ret = x509_new(buf, &offset, &cert)))
+ goto error;
+
+#if defined (CONFIG_SSL_FULL_MODE)
+ if (ssl_ctx->options & SSL_DISPLAY_CERTS)
+ x509_print(cert, NULL);
+#endif
+
+ ssl_cert = &ssl_ctx->certs[i];
+ ssl_cert->size = len;
+ ssl_cert->buf = buf;
+ ssl_ctx->chain_length++;
+ len -= offset;
+ ret = SSL_OK; /* ok so far */
+
+ /* recurse? */
+ if (len > 0)
+ {
+ ret = add_cert(ssl_ctx, &buf[offset], len);
+ }
+
+error:
+ x509_free(cert); /* don't need anymore */
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Add a certificate authority.
+ */
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+ int ret = SSL_OK; /* ignore errors for now */
+ int i = 0;
+ CA_CERT_CTX *ca_cert_ctx;
+
+ if (ssl_ctx->ca_cert_ctx == NULL)
+ ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX));
+
+ ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ i++;
+
+ while (len > 0)
+ {
+ int offset;
+ if (i >= CONFIG_X509_MAX_CA_CERTS)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: maximum number of CA certs added (%d) - change of "
+ "compile-time configuration required\n",
+ CONFIG_X509_MAX_CA_CERTS);
+#endif
+ break;
+ }
+
+
+ /* ignore the return code */
+ if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK)
+ {
+#if defined (CONFIG_SSL_FULL_MODE)
+ if (ssl_ctx->options & SSL_DISPLAY_CERTS)
+ x509_print(ca_cert_ctx->cert[i], NULL);
+#endif
+ }
+
+ i++;
+ len -= offset;
+ }
+
+ return ret;
+}
+
+/*
+ * Retrieve an X.509 distinguished name component
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+ if (ssl->x509_ctx == NULL)
+ return NULL;
+
+ switch (component)
+ {
+ case SSL_X509_CERT_COMMON_NAME:
+ return ssl->x509_ctx->cert_dn[X509_COMMON_NAME];
+
+ case SSL_X509_CERT_ORGANIZATION:
+ return ssl->x509_ctx->cert_dn[X509_ORGANIZATION];
+
+ case SSL_X509_CERT_ORGANIZATIONAL_NAME:
+ return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+ case SSL_X509_CA_CERT_COMMON_NAME:
+ return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME];
+
+ case SSL_X509_CA_CERT_ORGANIZATION:
+ return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION];
+
+ case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME:
+ return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Retrieve a "Subject Alternative Name" from a v3 certificate
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl,
+ int dnsindex)
+{
+ int i;
+
+ if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL)
+ return NULL;
+
+ for (i = 0; i < dnsindex; ++i)
+ {
+ if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL)
+ return NULL;
+ }
+
+ return ssl->x509_ctx->subject_alt_dnsnames[dnsindex];
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/*
+ * Find an ssl object based on the client's file descriptor.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd)
+{
+ SSL *ssl;
+
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+ ssl = ssl_ctx->head;
+
+ /* search through all the ssl entries */
+ while (ssl)
+ {
+ if (ssl->client_fd == client_fd)
+ {
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return ssl;
+ }
+
+ ssl = ssl->next;
+ }
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return NULL;
+}
+
+/*
+ * Force the client to perform its handshake again.
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl)
+{
+ int ret = SSL_OK;
+
+ disposable_new(ssl);
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ if (IS_SET_SSL_FLAG(SSL_IS_CLIENT))
+ {
+ ret = do_client_connect(ssl);
+ }
+ else
+#endif
+ {
+ send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_hello_request, sizeof(g_hello_request));
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Get what we need for key info.
+ * @param cipher [in] The cipher information we are after
+ * @param key_size [out] The key size for the cipher
+ * @param iv_size [out] The iv size for the cipher
+ * @return The amount of key information we need.
+ */
+static const cipher_info_t *get_cipher_info(uint8_t cipher)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROTOCOLS; i++)
+ {
+ if (cipher_info[i].cipher == cipher)
+ {
+ return &cipher_info[i];
+ }
+ }
+
+ return NULL; /* error */
+}
+
+/*
+ * Get a new ssl context for a new connection.
+ */
+SSL *ssl_new(SSL *ssl, int client_fd)
+{
+ SSL_CTX* ssl_ctx = ssl->ssl_ctx;
+ ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */
+ ssl->client_fd = 0;
+ ssl->flag = SSL_NEED_RECORD;
+ ssl->bm_data = ssl->bm_all_data + BM_RECORD_OFFSET;
+ ssl->bm_read_index = 0;
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+#ifdef CONFIG_ENABLE_VERIFICATION
+ ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+#endif
+ disposable_new(ssl);
+
+ /* a bit hacky but saves a few bytes of memory */
+ ssl->flag |= ssl_ctx->options;
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+
+ if (ssl_ctx->head == NULL)
+ {
+ ssl_ctx->head = ssl;
+ ssl_ctx->tail = ssl;
+ }
+ else
+ {
+ ssl->prev = ssl_ctx->tail;
+ ssl_ctx->tail->next = ssl;
+ ssl_ctx->tail = ssl;
+ }
+ ssl->encrypt_ctx = NULL;
+ ssl->decrypt_ctx = NULL;
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return ssl;
+}
+
+/*
+ * Add a private key to a context.
+ */
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj)
+{
+ int ret = SSL_OK;
+
+ /* get the private key details */
+ if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */
+static void increment_read_sequence(SSL *ssl)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ if (++ssl->read_sequence[i])
+ break;
+ }
+}
+
+/**
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */
+static void increment_write_sequence(SSL *ssl)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ if (++ssl->write_sequence[i])
+ break;
+ }
+}
+
+/**
+ * Work out the HMAC digest in a packet.
+ */
+static void add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header,
+ const uint8_t *buf, int buf_len, uint8_t *hmac_buf)
+{
+ int hmac_len = buf_len + 8 + SSL_RECORD_SIZE;
+ uint8_t *t_buf = (uint8_t *)alloca(hmac_len+10);
+
+ memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ?
+ ssl->write_sequence : ssl->read_sequence, 8);
+ memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE);
+ memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len);
+
+ ssl->cipher_info->hmac(t_buf, hmac_len,
+ (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ?
+ ssl->server_mac : ssl->client_mac,
+ ssl->cipher_info->digest_size, hmac_buf);
+
+#if 0
+ print_blob("record", hmac_header, SSL_RECORD_SIZE);
+ print_blob("buf", buf, buf_len);
+ if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE)
+ {
+ print_blob("write seq", ssl->write_sequence, 8);
+ }
+ else
+ {
+ print_blob("read seq", ssl->read_sequence, 8);
+ }
+
+ if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ)
+ {
+ print_blob("server mac",
+ ssl->server_mac, ssl->cipher_info->digest_size);
+ }
+ else
+ {
+ print_blob("client mac",
+ ssl->client_mac, ssl->cipher_info->digest_size);
+ }
+ print_blob("hmac", hmac_buf, SHA1_SIZE);
+#endif
+}
+
+/**
+ * Verify that the digest of a packet is correct.
+ */
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len)
+{
+ uint8_t hmac_buf[SHA1_SIZE];
+ int hmac_offset;
+
+ if (ssl->cipher_info->padding_size)
+ {
+ int last_blk_size = buf[read_len-1], i;
+ hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1;
+
+ /* guard against a timing attack - make sure we do the digest */
+ if (hmac_offset < 0)
+ {
+ hmac_offset = 0;
+ }
+ else
+ {
+ /* already looked at last byte */
+ for (i = 1; i < last_blk_size; i++)
+ {
+ if (buf[read_len-i] != last_blk_size)
+ {
+ hmac_offset = 0;
+ break;
+ }
+ }
+ }
+ }
+ else /* stream cipher */
+ {
+ hmac_offset = read_len - ssl->cipher_info->digest_size;
+
+ if (hmac_offset < 0)
+ {
+ hmac_offset = 0;
+ }
+ }
+
+ /* sanity check the offset */
+ ssl->hmac_header[3] = hmac_offset >> 8; /* insert size */
+ ssl->hmac_header[4] = hmac_offset & 0xff;
+ add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf);
+
+ if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size))
+ {
+ return SSL_ERROR_INVALID_HMAC;
+ }
+
+ return hmac_offset;
+}
+
+/**
+ * Add a packet to the end of our sent and received packets, so that we may use
+ * it to calculate the hash at the end.
+ */
+void add_packet(SSL *ssl, const uint8_t *pkt, int len)
+{
+ MD5_Update(&ssl->dc->md5_ctx, pkt, len);
+ SHA1_Update(&ssl->dc->sha1_ctx, pkt, len);
+}
+
+/**
+ * Work out the MD5 PRF.
+ */
+static void p_hash_md5(const uint8_t *sec, int sec_len,
+ uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+ uint8_t a1[128];
+
+ /* A(1) */
+ hmac_md5(seed, seed_len, sec, sec_len, a1);
+ memcpy(&a1[MD5_SIZE], seed, seed_len);
+ hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+
+ while (olen > MD5_SIZE)
+ {
+ uint8_t a2[MD5_SIZE];
+ out += MD5_SIZE;
+ olen -= MD5_SIZE;
+
+ /* A(N) */
+ hmac_md5(a1, MD5_SIZE, sec, sec_len, a2);
+ memcpy(a1, a2, MD5_SIZE);
+
+ /* work out the actual hash */
+ hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+ }
+}
+
+/**
+ * Work out the SHA1 PRF.
+ */
+static void p_hash_sha1(const uint8_t *sec, int sec_len,
+ uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+ uint8_t a1[128];
+
+ /* A(1) */
+ hmac_sha1(seed, seed_len, sec, sec_len, a1);
+ memcpy(&a1[SHA1_SIZE], seed, seed_len);
+ hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+
+ while (olen > SHA1_SIZE)
+ {
+ uint8_t a2[SHA1_SIZE];
+ out += SHA1_SIZE;
+ olen -= SHA1_SIZE;
+
+ /* A(N) */
+ hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2);
+ memcpy(a1, a2, SHA1_SIZE);
+
+ /* work out the actual hash */
+ hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+ }
+}
+
+/**
+ * Work out the PRF.
+ */
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+ uint8_t *out, int olen)
+{
+ int len, i;
+ const uint8_t *S1, *S2;
+ uint8_t xbuf[256]; /* needs to be > the amount of key data */
+ uint8_t ybuf[256]; /* needs to be > the amount of key data */
+
+ len = sec_len/2;
+ S1 = sec;
+ S2 = &sec[len];
+ len += (sec_len & 1); /* add for odd, make longer */
+
+ p_hash_md5(S1, len, seed, seed_len, xbuf, olen);
+ p_hash_sha1(S2, len, seed, seed_len, ybuf, olen);
+
+ for (i = 0; i < olen; i++)
+ out[i] = xbuf[i] ^ ybuf[i];
+}
+
+/**
+ * Generate a master secret based on the client/server random data and the
+ * premaster secret.
+ */
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret)
+{
+ uint8_t buf[128]; /* needs to be > 13+32+32 in size */
+ strcpy((char *)buf, "master secret");
+ memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE);
+ memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE);
+ prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret,
+ SSL_SECRET_SIZE);
+}
+
+/**
+ * Generate a 'random' blob of data used for the generation of keys.
+ */
+static void generate_key_block(uint8_t *client_random, uint8_t *server_random,
+ uint8_t *master_secret, uint8_t *key_block, int key_block_size)
+{
+ uint8_t buf[128];
+ strcpy((char *)buf, "key expansion");
+ memcpy(&buf[13], server_random, SSL_RANDOM_SIZE);
+ memcpy(&buf[45], client_random, SSL_RANDOM_SIZE);
+ prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size);
+}
+
+/**
+ * Calculate the digest used in the finished message. This function also
+ * doubles up as a certificate verify function.
+ */
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest)
+{
+ uint8_t mac_buf[128];
+ uint8_t *q = mac_buf;
+ MD5_CTX md5_ctx = ssl->dc->md5_ctx;
+ SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx;
+
+ if (label)
+ {
+ strcpy((char *)q, label);
+ q += strlen(label);
+ }
+
+ MD5_Final(q, &md5_ctx);
+ q += MD5_SIZE;
+
+ SHA1_Final(q, &sha1_ctx);
+ q += SHA1_SIZE;
+
+ if (label)
+ {
+ prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf),
+ digest, SSL_FINISHED_HASH_SIZE);
+ }
+ else /* for use in a certificate verify */
+ {
+ memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE);
+ }
+
+#if 0
+ printf("label: %s\r\n", label);
+ print_blob("master secret", ssl->dc->master_secret, 48);
+ print_blob("mac_buf", mac_buf, q-mac_buf);
+ print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE);
+#endif
+}
+
+/**
+ * Retrieve (and initialise) the context of a cipher.
+ */
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)
+{
+ switch (ssl->cipher)
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ case SSL_AES128_SHA:
+ {
+ AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+ AES_set_key(aes_ctx, key, iv, AES_MODE_128);
+
+ if (is_decrypt)
+ {
+ AES_convert_key(aes_ctx);
+ }
+
+ return (void *)aes_ctx;
+ }
+
+ case SSL_AES256_SHA:
+ {
+ AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+ AES_set_key(aes_ctx, key, iv, AES_MODE_256);
+
+ if (is_decrypt)
+ {
+ AES_convert_key(aes_ctx);
+ }
+
+ return (void *)aes_ctx;
+ }
+
+ case SSL_RC4_128_MD5:
+#endif
+ case SSL_RC4_128_SHA:
+ {
+ RC4_CTX *rc4_ctx = (RC4_CTX *)malloc(sizeof(RC4_CTX));
+ RC4_setup(rc4_ctx, key, 16);
+ return (void *)rc4_ctx;
+ }
+ }
+
+ return NULL; /* its all gone wrong */
+}
+
+
+/**
+ * Send a packet over the socket.
+ */
+static int send_raw_packet(SSL *ssl, uint8_t protocol)
+{
+ uint8_t *rec_buf = ssl->bm_all_data;
+ int pkt_size = SSL_RECORD_SIZE+ssl->bm_index;
+ int sent = 0;
+ int ret = SSL_OK;
+ rec_buf[0] = protocol;
+ rec_buf[1] = 0x03; /* version = 3.1 or higher */
+ rec_buf[2] = ssl->version & 0x0f;
+ rec_buf[3] = ssl->bm_index >> 8;
+ rec_buf[4] = ssl->bm_index & 0xff;
+
+ DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data,
+ pkt_size, pkt_size);
+
+
+
+ while (sent < pkt_size)
+ {
+ ret = SOCKET_WRITE(ssl->client_fd,
+ &ssl->bm_all_data[sent], pkt_size-sent);
+ if (ret >= 0)
+ sent += ret;
+ else
+ {
+
+#ifdef WIN32
+ if (GetLastError() != WSAEWOULDBLOCK)
+#else
+ if (errno != EAGAIN && errno != EWOULDBLOCK)
+#endif
+ return SSL_ERROR_CONN_LOST;
+ }
+
+ /* keep going until the write buffer has some space */
+ if (sent != pkt_size)
+ {
+ fd_set wfds;
+ FD_ZERO(&wfds);
+ FD_SET(ssl->client_fd, &wfds);
+
+ /* block and wait for it */
+ if (lwip_select(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0)
+ return SSL_ERROR_CONN_LOST;
+
+ }
+ }
+ fd_set wfds;
+ FD_ZERO(&wfds);
+ FD_SET(ssl->client_fd, &wfds);
+
+ /* block and wait for it */
+ if (lwip_select(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0)
+ return SSL_ERROR_CONN_LOST;
+
+ SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */
+ ssl->bm_index = 0;
+
+ if (protocol != PT_APP_PROTOCOL_DATA)
+ {
+ /* always return SSL_OK during handshake */
+ ret = SSL_OK;
+ }
+
+ return ret;
+}
+
+/**
+ * Send an encrypted packet with padding bytes if necessary.
+ */
+int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length)
+{
+ int ret, msg_length = 0;
+
+ /* if our state is bad, don't bother */
+ if (ssl->hs_status == SSL_ERROR_DEAD)
+ return SSL_ERROR_CONN_LOST;
+
+ if (in) /* has the buffer already been initialised? */
+ {
+ memcpy(ssl->bm_data, in, length);
+ }
+
+ msg_length += length;
+
+ if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED))
+ {
+ int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?
+ SSL_CLIENT_WRITE : SSL_SERVER_WRITE;
+ uint8_t hmac_header[SSL_RECORD_SIZE] =
+ {
+ protocol,
+ 0x03, /* version = 3.1 or higher */
+ ssl->version & 0x0f,
+ msg_length >> 8,
+ msg_length & 0xff
+ };
+
+ if (protocol == PT_HANDSHAKE_PROTOCOL)
+ {
+ DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+ if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+ {
+ add_packet(ssl, ssl->bm_data, msg_length);
+ }
+ }
+
+ /* add the packet digest */
+ add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length,
+ &ssl->bm_data[msg_length]);
+ msg_length += ssl->cipher_info->digest_size;
+
+ /* add padding? */
+ if (ssl->cipher_info->padding_size)
+ {
+ int last_blk_size = msg_length%ssl->cipher_info->padding_size;
+ int pad_bytes = ssl->cipher_info->padding_size - last_blk_size;
+
+ /* ensure we always have at least 1 padding byte */
+ if (pad_bytes == 0)
+ pad_bytes += ssl->cipher_info->padding_size;
+
+ memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes);
+ msg_length += pad_bytes;
+ }
+
+ DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length);
+ increment_write_sequence(ssl);
+
+ /* add the explicit IV for TLS1.1 */
+ if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&
+ ssl->cipher_info->iv_size)
+ {
+ uint8_t iv_size = ssl->cipher_info->iv_size;
+ uint8_t *t_buf = alloca(msg_length + iv_size);
+ memcpy(t_buf + iv_size, ssl->bm_data, msg_length);
+ get_random(iv_size, t_buf);
+ msg_length += iv_size;
+ memcpy(ssl->bm_data, t_buf, msg_length);
+ }
+
+ /* now encrypt the packet */
+ ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data,
+ ssl->bm_data, msg_length);
+ }
+ else if (protocol == PT_HANDSHAKE_PROTOCOL)
+ {
+ DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+ if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+ {
+ add_packet(ssl, ssl->bm_data, length);
+ }
+ }
+
+ ssl->bm_index = msg_length;
+ if ((ret = send_raw_packet(ssl, protocol)) <= 0)
+ return ret;
+
+ return length; /* just return what we wanted to send */
+}
+
+/**
+ * Work out the cipher keys we are going to use for this session based on the
+ * master secret.
+ */
+static int set_key_block(SSL *ssl, int is_write)
+{
+ const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher);
+ uint8_t *q;
+ uint8_t client_key[32], server_key[32]; /* big enough for AES256 */
+ uint8_t client_iv[16], server_iv[16]; /* big enough for AES128/256 */
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+ if (ciph_info == NULL)
+ return -1;
+
+ uint8_t key_tmp[MAX_KEYBLOCK_SIZE] = {0};
+ /* only do once in a handshake */
+ if (memcmp(ssl->dc->key_block, key_tmp, MAX_KEYBLOCK_SIZE) == 0)
+ {
+#if 0
+ print_blob("client", ssl->dc->client_random, 32);
+ print_blob("server", ssl->dc->server_random, 32);
+ print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE);
+#endif
+ generate_key_block(ssl->dc->client_random, ssl->dc->server_random,
+ ssl->dc->master_secret, ssl->dc->key_block,
+ ciph_info->key_block_size);
+#if 0
+ print_blob("keyblock", ssl->dc->key_block, ciph_info->key_block_size);
+#endif
+ }
+
+ q = ssl->dc->key_block;
+
+ if ((is_client && is_write) || (!is_client && !is_write))
+ {
+ memcpy(ssl->client_mac, q, ciph_info->digest_size);
+ }
+
+ q += ciph_info->digest_size;
+
+ if ((!is_client && is_write) || (is_client && !is_write))
+ {
+ memcpy(ssl->server_mac, q, ciph_info->digest_size);
+ }
+
+ q += ciph_info->digest_size;
+ memcpy(client_key, q, ciph_info->key_size);
+ q += ciph_info->key_size;
+ memcpy(server_key, q, ciph_info->key_size);
+ q += ciph_info->key_size;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (ciph_info->iv_size) /* RC4 has no IV, AES does */
+ {
+ memcpy(client_iv, q, ciph_info->iv_size);
+ q += ciph_info->iv_size;
+ memcpy(server_iv, q, ciph_info->iv_size);
+ q += ciph_info->iv_size;
+ }
+#endif
+
+ if( (is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx) != NULL)
+ free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx);
+
+ /* now initialise the ciphers */
+ if (is_client)
+ {
+ finished_digest(ssl, server_finished, ssl->dc->final_finish_mac);
+
+ if (is_write)
+ ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0);
+ else
+ ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1);
+ }
+ else
+ {
+ finished_digest(ssl, client_finished, ssl->dc->final_finish_mac);
+
+ if (is_write)
+ ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0);
+ else
+ ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1);
+ }
+
+ ssl->cipher_info = ciph_info;
+ return 0;
+}
+
+/**
+ * Blocking read
+ * data must be valid buffer of size length at least
+ * length
+ */
+int basic_read2(SSL *ssl, uint8_t *data, uint32_t length)
+{
+ // printf("basic_read2\n");
+ if(data == NULL)
+ return -1;
+
+ int ret = 0;
+
+ do
+ {
+ //printf("before_lwip_select\n");
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(ssl->client_fd, &rfds);
+
+ /* block and wait for it */
+ if (lwip_select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0)
+ return SSL_ERROR_CONN_LOST;
+ // printf("after_lwip_select\n");
+
+ int read_len = SOCKET_READ(ssl->client_fd, &data[ret], length-ret);
+ // printf("read_len = %d\n", read_len);
+
+ if (read_len < 0)
+ {
+
+#ifdef WIN32
+ if (GetLastError() == WSAEWOULDBLOCK)
+#else
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+#endif
+ continue;
+ }
+
+ /* connection has gone, so die */
+ if (read_len <= 0)
+ {
+ printf("SSL_ERROR_CONN_LOST\n");
+ ssl->hs_status = SSL_ERROR_DEAD; /* make sure it stays dead */
+ return SSL_ERROR_CONN_LOST;
+ }
+
+ ret += read_len;
+
+ }while(ret < length);
+ DISPLAY_BYTES(ssl, "received %d bytes", data, ret, ret);
+ return ret;
+}
+
+int read_record(SSL *ssl)
+{
+ if(!IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+ return 0;
+ uint8_t record[SSL_RECORD_SIZE];
+ int ret = basic_read2(ssl, record, SSL_RECORD_SIZE);
+ if(ret != SSL_RECORD_SIZE)
+ return ret;
+
+ /* check for sslv2 "client hello" */
+ if (record[0] & 0x80 && record[2] == 1)
+ {
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+ uint8_t version = (record[3] << 4) + record[4];
+ DISPLAY_BYTES(ssl, "ssl2 record", record, 5);
+
+ /* should be v3.1 (TLSv1) or better */
+ ssl->version = ssl->client_version = version;
+
+ if (version > SSL_PROTOCOL_VERSION_MAX)
+ {
+ /* use client's version */
+ ssl->version = SSL_PROTOCOL_VERSION_MAX;
+ }
+ else if (version < SSL_PROTOCOL_MIN_VERSION)
+ {
+ ret = SSL_ERROR_INVALID_VERSION;
+ ssl_display_error(ret);
+ return ret;
+ }
+
+ add_packet(ssl, &record[2], 3);
+ ret = process_sslv23_client_hello(ssl);
+#else
+ printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH();
+ ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+ return ret;
+ }
+
+ ssl->need_bytes = (record[3] << 8) + record[4];
+
+
+ memcpy(ssl->hmac_header, record, 3); /* store for hmac */
+ ssl->record_type = record[0];
+ CLR_SSL_FLAG(SSL_NEED_RECORD);
+ return SSL_OK;
+}
+
+int basic_decrypt(SSL *ssl, uint8_t *buf, int len)
+{
+ if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+ {
+ ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, len);
+
+ if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&
+ ssl->cipher_info->iv_size)
+ {
+ buf += ssl->cipher_info->iv_size;
+ ssl->need_bytes -= ssl->cipher_info->iv_size;
+ }
+ if(ssl->record_type != PT_APP_PROTOCOL_DATA)
+ len = verify_digest(ssl,
+ IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, len);
+
+ /* does the hmac work? */
+ if (ssl->need_bytes < 0)
+ {
+ return ssl->need_bytes;
+ }
+
+ DISPLAY_BYTES(ssl, "decrypted", buf, len);
+ increment_read_sequence(ssl);
+ }
+ return len;
+}
+
+int ssl_read(SSL *ssl, uint8_t *in_data, int len)
+{
+ if(len <= 0 || in_data == NULL)
+ return 0;
+
+ if(IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+ {
+ read_record(ssl);
+ }
+
+ return process_data(ssl, in_data, len);
+}
+
+int process_data(SSL* ssl, uint8_t *in_data, int len)
+{
+ /* The main part of the SSL packet */
+ switch (ssl->record_type)
+ {
+ case PT_HANDSHAKE_PROTOCOL:
+
+ if (ssl->dc != NULL)
+ {
+ ssl->dc->bm_proc_index = 0;
+ int ret = do_handshake(ssl, NULL, 0);
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ return ret;
+ }
+ else /* no client renegotiation allowed */
+ {
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ return SSL_ERROR_NO_CLIENT_RENOG;
+ }
+
+ case PT_CHANGE_CIPHER_SPEC:
+
+ if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+ return -1;
+ ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);
+ if(ssl->need_bytes < 0)
+ return -1;
+
+ if (ssl->next_state != HS_FINISHED)
+ {
+ return SSL_ERROR_INVALID_HANDSHAKE;
+ }
+
+ /* all encrypted from now on */
+ SET_SSL_FLAG(SSL_RX_ENCRYPTED);
+ if (set_key_block(ssl, 0) < 0)
+ {
+ return SSL_ERROR_INVALID_HANDSHAKE;
+ }
+
+ memset(ssl->read_sequence, 0, 8);
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ break;
+
+ case PT_APP_PROTOCOL_DATA:
+ if(len <= 0)
+ return 0;
+ if(ssl->need_bytes == 0)
+ return 0;
+ if (in_data)
+ {
+ uint16_t index = ssl->bm_index % 2048;
+ if(ssl->bm_read_index == 0)
+ {
+ int read_len = len;
+ if(read_len > 2048-index)
+ read_len = 2048-index;
+ if(read_len > ssl->need_bytes)
+ read_len = ssl->need_bytes;
+ read_len -= read_len % AES_BLOCKSIZE;
+
+ if(read_len <= 0)
+ read_len = AES_BLOCKSIZE;
+ if(ssl->need_bytes < AES_BLOCKSIZE)
+ read_len = AES_BLOCKSIZE;
+ int ret = basic_read2(ssl, ssl->bm_all_data + index, read_len);
+ if(ret != read_len)
+ return 0;
+
+ ssl->bm_read_index = basic_decrypt(ssl, ssl->bm_all_data + index, read_len);
+ ssl->need_bytes -= ssl->bm_read_index;
+ if(ssl->need_bytes == 0)
+ {
+ ssl->bm_read_index = 0;
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ return ssl_read(ssl, in_data, len);
+ }
+ }
+ if(len > ssl->bm_read_index)
+ len = ssl->bm_read_index;
+ memcpy(in_data, ssl->bm_all_data+index, len);
+ ssl->bm_index += len;
+ ssl->bm_read_index -= len;
+
+ if(ssl->need_bytes == 0)
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ if(ssl->bm_index >= 2048)
+ ssl->bm_index = 0;
+ return len;
+ }
+ return 0;
+
+ case PT_ALERT_PROTOCOL:
+ if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+ return -1;
+ ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);
+ if(ssl->need_bytes < 0)
+ return -1;
+
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+
+ /* return the alert # with alert bit set */
+ if(ssl->bm_data[0] == SSL_ALERT_TYPE_WARNING &&
+ ssl->bm_data[1] == SSL_ALERT_CLOSE_NOTIFY)
+ {
+ send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+ SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY);
+ return SSL_CLOSE_NOTIFY;
+ }
+ else
+ {
+ int ret = -ssl->bm_data[1];
+ DISPLAY_ALERT(ssl, -ret);
+ return ret;
+ }
+
+ default:
+ return SSL_ERROR_INVALID_PROT_MSG;
+
+ }
+}
+
+
+/**
+ * Do some basic checking of data and then perform the appropriate handshaking.
+ */
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len)
+{
+ uint8_t hs_hdr[SSL_HS_HDR_SIZE];
+ if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+ {
+ if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+ return -1;
+ ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);
+ if(ssl->need_bytes < 0)
+ return -1;
+ buf = ssl->bm_data;
+ }
+ else
+ {
+ if(basic_read2(ssl, hs_hdr, SSL_HS_HDR_SIZE) != SSL_HS_HDR_SIZE)
+ return -1;
+ buf = hs_hdr;
+ }
+
+ int hs_len = (buf[2]<<8) + buf[3];
+ uint8_t handshake_type = buf[0];
+ int ret = SSL_OK;
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+ /* some integrity checking on the handshake */
+ //PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len);
+
+ if (handshake_type != ssl->next_state)
+ {
+ /* handle a special case on the client */
+ if (!is_client || handshake_type != HS_CERT_REQ ||
+ ssl->next_state != HS_SERVER_HELLO_DONE)
+ {
+ return SSL_ERROR_INVALID_HANDSHAKE;
+ }
+ }
+
+ //hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */
+ ssl->bm_index = hs_len+SSL_HS_HDR_SIZE; /* store the size and check later */
+ DISPLAY_STATE(ssl, 0, handshake_type, 0);
+
+ if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+ {
+ add_packet(ssl, buf, SSL_HS_HDR_SIZE);
+ }
+
+ if(!IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+ {
+ if(hs_len != 0 && handshake_type != HS_CERTIFICATE)
+ {
+ if(basic_read2(ssl, ssl->bm_data, hs_len) != hs_len)
+ return -1;
+ hs_len = basic_decrypt(ssl, ssl->bm_data, hs_len);
+ if(hs_len < 0)
+ return -1;
+
+ buf = ssl->bm_data;
+ if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+ add_packet(ssl, buf, hs_len);
+ }
+ }
+ else if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+ add_packet(ssl, ssl->bm_data+SSL_HS_HDR_SIZE, hs_len-SSL_HS_HDR_SIZE);
+
+#if defined(CONFIG_SSL_ENABLE_CLIENT)
+ ret = is_client ?
+ do_clnt_handshake(ssl, handshake_type, buf, hs_len) :
+ do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#else
+ ret = do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#endif
+
+ /* just use recursion to get the rest */
+ //if (hs_len < read_len && ret == SSL_OK)
+ //ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len);
+
+ return ret;
+}
+
+/**
+ * Sends the change cipher spec message. We have just read a finished message
+ * from the client.
+ */
+int send_change_cipher_spec(SSL *ssl)
+{
+ int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC,
+ g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt));
+ SET_SSL_FLAG(SSL_TX_ENCRYPTED);
+
+ if (ret >= 0 && set_key_block(ssl, 1) < 0)
+ ret = SSL_ERROR_INVALID_HANDSHAKE;
+
+ memset(ssl->write_sequence, 0, 8);
+ return ret;
+}
+
+/**
+ * Send a "finished" message
+ */
+int send_finished(SSL *ssl)
+{
+ uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = {
+ HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE };
+
+ /* now add the finished digest mac (12 bytes) */
+ finished_digest(ssl,
+ IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?
+ client_finished : server_finished, &buf[4]);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* store in the session cache */
+ if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions)
+ {
+ memcpy(ssl->session->master_secret,
+ ssl->dc->master_secret, SSL_SECRET_SIZE);
+ }
+#endif
+
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ buf, SSL_FINISHED_HASH_SIZE+4);
+}
+
+/**
+ * Send an alert message.
+ * Return 1 if the alert was an "error".
+ */
+int send_alert(SSL *ssl, int error_code)
+{
+ int alert_num = 0;
+ int is_warning = 0;
+ uint8_t buf[2];
+
+ /* Don't bother we're already dead */
+ if (ssl->hs_status == SSL_ERROR_DEAD)
+ {
+ return SSL_ERROR_CONN_LOST;
+ }
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ ssl_display_error(error_code);
+#endif
+
+ switch (error_code)
+ {
+ case SSL_ALERT_CLOSE_NOTIFY:
+ is_warning = 1;
+ alert_num = SSL_ALERT_CLOSE_NOTIFY;
+ break;
+
+ case SSL_ERROR_CONN_LOST: /* don't send alert just yet */
+ is_warning = 1;
+ break;
+
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ case SSL_ERROR_INVALID_PROT_MSG:
+ alert_num = SSL_ALERT_HANDSHAKE_FAILURE;
+ break;
+
+ case SSL_ERROR_INVALID_HMAC:
+ case SSL_ERROR_FINISHED_INVALID:
+ alert_num = SSL_ALERT_BAD_RECORD_MAC;
+ break;
+
+ case SSL_ERROR_INVALID_VERSION:
+ alert_num = SSL_ALERT_INVALID_VERSION;
+ break;
+
+ case SSL_ERROR_INVALID_SESSION:
+ case SSL_ERROR_NO_CIPHER:
+ case SSL_ERROR_INVALID_KEY:
+ alert_num = SSL_ALERT_ILLEGAL_PARAMETER;
+ break;
+
+ case SSL_ERROR_BAD_CERTIFICATE:
+ alert_num = SSL_ALERT_BAD_CERTIFICATE;
+ break;
+
+ case SSL_ERROR_NO_CLIENT_RENOG:
+ alert_num = SSL_ALERT_NO_RENEGOTIATION;
+ break;
+
+ default:
+ /* a catch-all for any badly verified certificates */
+ alert_num = (error_code <= SSL_X509_OFFSET) ?
+ SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE;
+ break;
+ }
+
+ buf[0] = is_warning ? 1 : 2;
+ buf[1] = alert_num;
+
+ send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf));
+ DISPLAY_ALERT(ssl, alert_num);
+ return is_warning ? 0 : 1;
+}
+
+/**
+ * Process a client finished message.
+ */
+int process_finished(SSL *ssl, uint8_t *buf, int hs_len)
+{
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+ int ret = SSL_OK;
+ int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME);
+
+ PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE);
+
+ /* check that we all work before we continue */
+ if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE))
+ {
+ return SSL_ERROR_FINISHED_INVALID;
+ }
+ if ((!is_client && !resume) || (is_client && resume))
+ {
+ if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ ret = send_finished(ssl);
+ }
+
+ /* if we ever renegotiate */
+ ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO;
+ ssl->hs_status = ret; /* set the final handshake status */
+error:
+ return ret;
+}
+
+/**
+ * Send a certificate.
+ */
+int send_certificate(SSL *ssl)
+{
+ int i = 0;
+ uint8_t *buf = ssl->bm_data;
+ int offset = 7;
+ int chain_length;
+
+ buf[0] = HS_CERTIFICATE;
+ buf[1] = 0;
+ buf[4] = 0;
+
+ while (i < ssl->ssl_ctx->chain_length)
+ {
+ SSL_CERT *cert = &ssl->ssl_ctx->certs[i];
+ buf[offset++] = 0;
+ buf[offset++] = cert->size >> 8; /* cert 1 length */
+ buf[offset++] = cert->size & 0xff;
+ memcpy(&buf[offset], cert->buf, cert->size);
+ offset += cert->size;
+ i++;
+ }
+
+ chain_length = offset - 7;
+ buf[5] = chain_length >> 8; /* cert chain length */
+ buf[6] = chain_length & 0xff;
+ chain_length += 3;
+ buf[2] = chain_length >> 8; /* handshake length */
+ buf[3] = chain_length & 0xff;
+ ssl->bm_index = offset;
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/**
+ * Create a blob of memory that we'll get rid of once the handshake is
+ * complete.
+ */
+void disposable_new(SSL *ssl)
+{
+ if (ssl->dc == NULL)
+ {
+ ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX));
+ memset(ssl->dc->key_block, 0, MAX_KEYBLOCK_SIZE);
+ MD5_Init(&ssl->dc->md5_ctx);
+ SHA1_Init(&ssl->dc->sha1_ctx);
+ }
+}
+
+/**
+ * Remove the temporary blob of memory.
+ */
+void disposable_free(SSL *ssl)
+{
+ if (ssl->dc)
+ {
+ //free(ssl->dc->key_block);
+ memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX));
+ free(ssl->dc);
+ ssl->dc = NULL;
+ }
+
+}
+
+#ifndef CONFIG_SSL_SKELETON_MODE /* no session resumption in this mode */
+/**
+ * Find if an existing session has the same session id. If so, use the
+ * master secret from this session for session resumption.
+ */
+SSL_SESSION *ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[],
+ SSL *ssl, const uint8_t *session_id)
+{
+ time_t tm = time(NULL);
+ time_t oldest_sess_time = tm;
+ SSL_SESSION *oldest_sess = NULL;
+ int i;
+
+ /* no sessions? Then bail */
+ if (max_sessions == 0)
+ return NULL;
+
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ if (session_id)
+ {
+ for (i = 0; i < max_sessions; i++)
+ {
+ if (ssl_sessions[i])
+ {
+ /* kill off any expired sessions (including those in
+ the future) */
+ if ((tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME) ||
+ (tm < ssl_sessions[i]->conn_time))
+ {
+ session_free(ssl_sessions, i);
+ continue;
+ }
+
+ /* if the session id matches, it must still be less than
+ the expiry time */
+ if (memcmp(ssl_sessions[i]->session_id, session_id,
+ SSL_SESSION_ID_SIZE) == 0)
+ {
+ ssl->session_index = i;
+ memcpy(ssl->dc->master_secret,
+ ssl_sessions[i]->master_secret, SSL_SECRET_SIZE);
+ SET_SSL_FLAG(SSL_SESSION_RESUME);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return ssl_sessions[i]; /* a session was found */
+ }
+ }
+ }
+ }
+
+ /* If we've got here, no matching session was found - so create one */
+ for (i = 0; i < max_sessions; i++)
+ {
+ if (ssl_sessions[i] == NULL)
+ {
+ /* perfect, this will do */
+ ssl_sessions[i] = (SSL_SESSION *)calloc(1, sizeof(SSL_SESSION));
+ ssl_sessions[i]->conn_time = tm;
+ ssl->session_index = i;
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return ssl_sessions[i]; /* return the session object */
+ }
+ else if (ssl_sessions[i]->conn_time <= oldest_sess_time)
+ {
+ /* find the oldest session */
+ oldest_sess_time = ssl_sessions[i]->conn_time;
+ oldest_sess = ssl_sessions[i];
+ ssl->session_index = i;
+ }
+ }
+
+ /* ok, we've used up all of our sessions. So blow the oldest session away */
+ oldest_sess->conn_time = tm;
+ memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE));
+ memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE));
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return oldest_sess;
+}
+
+/**
+ * Free an existing session.
+ */
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index)
+{
+ if (ssl_sessions[sess_index])
+ {
+ free(ssl_sessions[sess_index]);
+ ssl_sessions[sess_index] = NULL;
+ }
+}
+
+/**
+ * This ssl object doesn't want this session anymore.
+ */
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl)
+{
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+
+ if (ssl->ssl_ctx->num_sessions)
+ {
+ session_free(ssl_sessions, ssl->session_index);
+ ssl->session = NULL;
+ }
+
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+}
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/*
+ * Get the session id for a handshake. This will be a 32 byte sequence.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl)
+{
+ return ssl->session_id;
+}
+
+/*
+ * Get the session id size for a handshake.
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl)
+{
+ return ssl->sess_id_size;
+}
+
+/*
+ * Return the cipher id (in the SSL form).
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl)
+{
+ return ssl->cipher;
+}
+
+/*
+ * Return the status of the handshake.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl)
+{
+ return ssl->hs_status;
+}
+
+/*
+ * Retrieve various parameters about the SSL engine.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset)
+{
+ switch (offset)
+ {
+ /* return the appropriate build mode */
+ case SSL_BUILD_MODE:
+#if defined(CONFIG_SSL_FULL_MODE)
+ return SSL_BUILD_FULL_MODE;
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+ return SSL_BUILD_ENABLE_CLIENT;
+#elif defined(CONFIG_ENABLE_VERIFICATION)
+ return SSL_BUILD_ENABLE_VERIFICATION;
+#elif defined(CONFIG_SSL_SERVER_ONLY )
+ return SSL_BUILD_SERVER_ONLY;
+#else
+ return SSL_BUILD_SKELETON_MODE;
+#endif
+
+ case SSL_MAX_CERT_CFG_OFFSET:
+ return CONFIG_SSL_MAX_CERTS;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case SSL_MAX_CA_CERT_CFG_OFFSET:
+ return CONFIG_X509_MAX_CA_CERTS;
+#endif
+#ifdef CONFIG_SSL_HAS_PEM
+ case SSL_HAS_PEM:
+ return 1;
+#endif
+ default:
+ return 0;
+ }
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Authenticate a received certificate.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+ int ret;
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (ret) /* modify into an SSL error type */
+ {
+ ret = SSL_X509_ERROR(ret);
+ }
+
+ return ret;
+}
+
+/**
+ * Process a certificate message.
+ */
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx)
+{
+ int ret = SSL_OK;
+
+ uint8_t cert_hdr[3];
+ if(basic_read2(ssl, cert_hdr, 3) != 3)
+ {
+ ret = SSL_NOT_OK;
+ return ret;
+ }
+
+ add_packet(ssl, cert_hdr, 3);
+ int len = 5;
+ int pkt_size = ssl->bm_index;
+ int cert_size;
+ int total_cert_size = (cert_hdr[1]<<8) + cert_hdr[2];
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+ X509_CTX **chain = x509_ctx;
+ len += 2;
+ PARANOIA_CHECK(total_cert_size, 3);
+
+ while (len < total_cert_size)
+ {
+
+ if(basic_read2(ssl, cert_hdr, 3) != 3)
+ {
+ ret = SSL_NOT_OK;
+ return ret;
+ }
+
+ add_packet(ssl, cert_hdr, 3);
+
+ cert_size = (cert_hdr[1]<<8) + cert_hdr[2];
+ if(cert_size > RT_MAX_PLAIN_LENGTH)
+ {
+ ret = SSL_NOT_OK;
+ return ret;
+ }
+
+ len += 3;
+
+ if(basic_read2(ssl, ssl->bm_data, cert_size) != cert_size)
+ {
+ return SSL_NOT_OK;
+ }
+
+ add_packet(ssl, ssl->bm_data, cert_size);
+
+ if (x509_new(ssl->bm_data, NULL, chain))
+ {
+ ret = SSL_ERROR_BAD_CERTIFICATE;
+ goto error;
+ }
+
+ chain = &((*chain)->next);
+ len += cert_size;
+ }
+ PARANOIA_CHECK(pkt_size, len);
+
+ /* if we are client we can do the verify now or later */
+ if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER))
+ {
+ ret = ssl_verify_cert(ssl);
+ }
+
+ ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG;
+ ssl->dc->bm_proc_index += len;
+error:
+
+ return ret;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/**
+ * Debugging routine to display SSL handshaking stuff.
+ */
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Debugging routine to display SSL states.
+ */
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok)
+{
+ const char *str;
+
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ return;
+
+ printf(not_ok ? "Error - invalid State:\t" : "State:\t");
+ printf(is_send ? "sending " : "receiving ");
+
+ switch (state)
+ {
+ case HS_HELLO_REQUEST:
+ str = "Hello Request (0)";
+ break;
+
+ case HS_CLIENT_HELLO:
+ str = "Client Hello (1)";
+ break;
+
+ case HS_SERVER_HELLO:
+ str = "Server Hello (2)";
+ break;
+
+ case HS_CERTIFICATE:
+ str = "Certificate (11)";
+ break;
+
+ case HS_SERVER_KEY_XCHG:
+ str = "Certificate Request (12)";
+ break;
+
+ case HS_CERT_REQ:
+ str = "Certificate Request (13)";
+ break;
+
+ case HS_SERVER_HELLO_DONE:
+ str = "Server Hello Done (14)";
+ break;
+
+ case HS_CERT_VERIFY:
+ str = "Certificate Verify (15)";
+ break;
+
+ case HS_CLIENT_KEY_XCHG:
+ str = "Client Key Exchange (16)";
+ break;
+
+ case HS_FINISHED:
+ str = "Finished (16)";
+ break;
+
+ default:
+ str = "Error (Unknown)";
+
+ break;
+ }
+
+ printf("%s\r\n", str);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display RSA objects
+ */
+void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx)
+{
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA))
+ return;
+
+ RSA_print(rsa_ctx);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking bytes.
+ */
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...)
+{
+ va_list(ap);
+
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES))
+ return;
+
+ va_start(ap, size);
+ print_blob(format, data, size, va_arg(ap, char *));
+ va_end(ap);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking errors.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code)
+{
+ if (error_code == SSL_OK)
+ return;
+
+ printf("Error: ");
+
+ /* X509 error? */
+ if (error_code < SSL_X509_OFFSET)
+ {
+ printf("%s\r\n", x509_display_error(error_code - SSL_X509_OFFSET));
+ return;
+ }
+
+ /* SSL alert error code */
+ if (error_code > SSL_ERROR_CONN_LOST)
+ {
+ printf("SSL error %d\n", -error_code);
+ return;
+ }
+
+ switch (error_code)
+ {
+ case SSL_ERROR_DEAD:
+ printf("connection dead");
+ break;
+
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ printf("invalid handshake");
+ break;
+
+ case SSL_ERROR_INVALID_PROT_MSG:
+ printf("invalid protocol message");
+ break;
+
+ case SSL_ERROR_INVALID_HMAC:
+ printf("invalid mac");
+ break;
+
+ case SSL_ERROR_INVALID_VERSION:
+ printf("invalid version");
+ break;
+
+ case SSL_ERROR_INVALID_SESSION:
+ printf("invalid session");
+ break;
+
+ case SSL_ERROR_NO_CIPHER:
+ printf("no cipher");
+ break;
+
+ case SSL_ERROR_CONN_LOST:
+ printf("connection lost");
+ break;
+
+ case SSL_ERROR_BAD_CERTIFICATE:
+ printf("bad certificate");
+ break;
+
+ case SSL_ERROR_INVALID_KEY:
+ printf("invalid key");
+ break;
+
+ case SSL_ERROR_FINISHED_INVALID:
+ printf("finished invalid");
+ break;
+
+ case SSL_ERROR_NO_CERT_DEFINED:
+ printf("no certificate defined");
+ break;
+
+ case SSL_ERROR_NO_CLIENT_RENOG:
+ printf("client renegotiation not supported");
+ break;
+
+ case SSL_ERROR_NOT_SUPPORTED:
+ printf("Option not supported");
+ break;
+
+ default:
+ printf("undefined as yet - %d", error_code);
+ break;
+ }
+
+ printf("\r\n");
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display alerts.
+ */
+void DISPLAY_ALERT(SSL *ssl, int alert)
+{
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ return;
+
+ printf("Alert: ");
+
+ switch (alert)
+ {
+ case SSL_ALERT_CLOSE_NOTIFY:
+ printf("close notify");
+ break;
+
+ case SSL_ALERT_INVALID_VERSION:
+ printf("invalid version");
+ break;
+
+ case SSL_ALERT_BAD_CERTIFICATE:
+ printf("bad certificate");
+ break;
+
+ case SSL_ALERT_UNEXPECTED_MESSAGE:
+ printf("unexpected message");
+ break;
+
+ case SSL_ALERT_BAD_RECORD_MAC:
+ printf("bad record mac");
+ break;
+
+ case SSL_ALERT_HANDSHAKE_FAILURE:
+ printf("handshake failure");
+ break;
+
+ case SSL_ALERT_ILLEGAL_PARAMETER:
+ printf("illegal parameter");
+ break;
+
+ case SSL_ALERT_DECODE_ERROR:
+ printf("decode error");
+ break;
+
+ case SSL_ALERT_DECRYPT_ERROR:
+ printf("decrypt error");
+ break;
+
+ case SSL_ALERT_NO_RENEGOTIATION:
+ printf("no renegotiation");
+ break;
+
+ default:
+ printf("alert - (unknown %d)", alert);
+ break;
+ }
+
+ printf("\r\n");
+ TTY_FLUSH();
+}
+
+#endif /* CONFIG_SSL_FULL_MODE */
+
+/**
+ * Return the version of this library.
+ */
+EXP_FUNC const char * STDCALL ssl_version()
+{
+ static const char * axtls_version = AXTLS_VERSION;
+ return axtls_version;
+}
+
+/**
+ * Enable the various language bindings to work regardless of the
+ * configuration - they just return an error statement and a bad return code.
+ */
+#if !defined(CONFIG_SSL_FULL_MODE)
+EXP_FUNC void STDCALL ssl_display_error(int error_code) {}
+#endif
+
+#ifdef CONFIG_BINDINGS
+#if !defined(CONFIG_SSL_ENABLE_CLIENT)
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
+ uint8_t *session_id, uint8_t sess_id_size)
+{
+ printf(unsupported_str);
+ return NULL;
+}
+#endif
+
+#if !defined(CONFIG_SSL_CERT_VERIFICATION)
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+ printf(unsupported_str);
+ return -1;
+}
+
+
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+ printf(unsupported_str);
+ return NULL;
+}
+
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index)
+{
+ printf(unsupported_str);
+ return NULL;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+#endif /* CONFIG_BINDINGS */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h
new file mode 100644
index 0000000000..4a4f453fe2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file tls1.h
+ *
+ * @brief The definitions for the TLS library.
+ */
+#ifndef HEADER_SSL_LIB_H
+#define HEADER_SSL_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "version.h"
+#include "os_int.h"
+#include "crypto.h"
+#include "crypto_misc.h"
+
+#include "config.h"
+
+#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */
+#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */
+#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */
+#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */
+#define SSL_RANDOM_SIZE 32
+#define SSL_SECRET_SIZE 48
+#define SSL_FINISHED_HASH_SIZE 12
+#define SSL_RECORD_SIZE 5
+#define SSL_SERVER_READ 0
+#define SSL_SERVER_WRITE 1
+#define SSL_CLIENT_READ 2
+#define SSL_CLIENT_WRITE 3
+#define SSL_HS_HDR_SIZE 4
+
+/* the flags we use while establishing a connection */
+#define SSL_NEED_RECORD 0x0001
+#define SSL_TX_ENCRYPTED 0x0002
+#define SSL_RX_ENCRYPTED 0x0004
+#define SSL_SESSION_RESUME 0x0008
+#define SSL_IS_CLIENT 0x0010
+#define SSL_HAS_CERT_REQ 0x0020
+#define SSL_SENT_CLOSE_NOTIFY 0x0040
+
+/* some macros to muck around with flag bits */
+#define SET_SSL_FLAG(A) (ssl->flag |= A)
+#define CLR_SSL_FLAG(A) (ssl->flag &= ~A)
+#define IS_SET_SSL_FLAG(A) (ssl->flag & A)
+
+#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */
+#define RT_MAX_PLAIN_LENGTH 2048//16384
+#define RT_EXTRA 512//1024
+#define BM_RECORD_OFFSET 5
+#define BM_ALL_DATA_SIZE (RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)
+
+#ifdef CONFIG_SSL_SKELETON_MODE
+#define NUM_PROTOCOLS 1
+#else
+#define NUM_PROTOCOLS 4
+#endif
+
+#define PARANOIA_CHECK(A, B) if (A < B) { \
+ ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }
+
+/* protocol types */
+enum
+{
+ PT_CHANGE_CIPHER_SPEC = 20,
+ PT_ALERT_PROTOCOL,
+ PT_HANDSHAKE_PROTOCOL,
+ PT_APP_PROTOCOL_DATA
+};
+
+/* handshaking types */
+enum
+{
+ HS_HELLO_REQUEST,
+ HS_CLIENT_HELLO,
+ HS_SERVER_HELLO,
+ HS_CERTIFICATE = 11,
+ HS_SERVER_KEY_XCHG,
+ HS_CERT_REQ,
+ HS_SERVER_HELLO_DONE,
+ HS_CERT_VERIFY,
+ HS_CLIENT_KEY_XCHG,
+ HS_FINISHED = 20
+};
+
+typedef struct
+{
+ uint8_t cipher;
+ uint8_t key_size;
+ uint8_t iv_size;
+ uint8_t key_block_size;
+ uint8_t padding_size;
+ uint8_t digest_size;
+ hmac_func hmac;
+ crypt_func encrypt;
+ crypt_func decrypt;
+} cipher_info_t;
+
+struct _SSLObjLoader
+{
+ uint8_t *buf;
+ int len;
+};
+
+typedef struct _SSLObjLoader SSLObjLoader;
+
+typedef struct
+{
+ time_t conn_time;
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+ uint8_t master_secret[SSL_SECRET_SIZE];
+} SSL_SESSION;
+
+typedef struct
+{
+ uint8_t *buf;
+ int size;
+} SSL_CERT;
+
+typedef struct
+{
+ MD5_CTX md5_ctx;
+ SHA1_CTX sha1_ctx;
+ uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];
+ uint8_t key_block[MAX_KEYBLOCK_SIZE];
+ uint8_t master_secret[SSL_SECRET_SIZE];
+ uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */
+ uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */
+ uint16_t bm_proc_index;
+} DISPOSABLE_CTX;
+
+struct _SSL
+{
+ uint32_t flag;
+ uint16_t need_bytes;
+ uint16_t got_bytes;
+ uint8_t record_type;
+ uint8_t cipher;
+ uint8_t sess_id_size;
+ uint8_t version;
+ uint8_t client_version;
+ int16_t next_state;
+ int16_t hs_status;
+ DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */
+ int client_fd;
+ void *connection;
+ const cipher_info_t *cipher_info;
+ void *encrypt_ctx;
+ void *decrypt_ctx;
+ uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH];
+ uint8_t *bm_data;
+ uint16_t bm_index;
+ uint16_t bm_read_index;
+ struct _SSL *next; /* doubly linked list */
+ struct _SSL *prev;
+ struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */
+#ifndef CONFIG_SSL_SKELETON_MODE
+ uint16_t session_index;
+ SSL_SESSION *session;
+#endif
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ X509_CTX *x509_ctx;
+#endif
+
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+ uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */
+ uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */
+ uint8_t read_sequence[8]; /* 64 bit sequence number */
+ uint8_t write_sequence[8]; /* 64 bit sequence number */
+ uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */
+};
+
+typedef struct _SSL SSL;
+
+struct _SSL_CTX
+{
+ uint32_t options;
+ uint8_t chain_length;
+ RSA_CTX *rsa_ctx;
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ CA_CERT_CTX *ca_cert_ctx;
+#endif
+ SSL *head;
+ SSL *tail;
+ SSL_CERT certs[CONFIG_SSL_MAX_CERTS];
+#ifndef CONFIG_SSL_SKELETON_MODE
+ uint16_t num_sessions;
+ SSL_SESSION **ssl_sessions;
+#endif
+#ifdef CONFIG_SSL_CTX_MUTEXING
+ SSL_CTX_MUTEX_TYPE mutex;
+#endif
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+ void *bonus_attr;
+#endif
+};
+
+typedef struct _SSL_CTX SSL_CTX;
+
+/* backwards compatibility */
+typedef struct _SSL_CTX SSLCTX;
+
+extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];
+
+SSL *ssl_new(SSL *ssl, int client_fd);
+void disposable_new(SSL *ssl);
+void disposable_free(SSL *ssl);
+int send_packet(SSL *ssl, uint8_t protocol,
+ const uint8_t *in, int length);
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int process_finished(SSL *ssl, uint8_t *buf, int hs_len);
+int process_sslv23_client_hello(SSL *ssl);
+int send_alert(SSL *ssl, int error_code);
+int send_finished(SSL *ssl);
+int send_certificate(SSL *ssl);
+int basic_read2(SSL *ssl, uint8_t *data, uint32_t length);
+int read_record(SSL *ssl);
+int basic_decrypt(SSL *ssl, uint8_t *buf, int len);
+int process_data(SSL* ssl, uint8_t *in_data, int len);
+int ssl_read(SSL *ssl, uint8_t *in_data, int len);
+int send_change_cipher_spec(SSL *ssl);
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest);
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);
+void add_packet(SSL *ssl, const uint8_t *pkt, int len);
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);
+void ssl_obj_free(SSLObjLoader *ssl_obj);
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int load_key_certs(SSL_CTX *ssl_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);
+#endif
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int do_client_connect(SSL *ssl);
+#endif
+
+#ifdef CONFIG_SSL_FULL_MODE
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...);
+void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);
+void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx);
+void DISPLAY_ALERT(SSL *ssl, int alert);
+#else
+#define DISPLAY_STATE(A,B,C,D)
+#define DISPLAY_CERT(A,B)
+#define DISPLAY_RSA(A,B)
+#define DISPLAY_ALERT(A, B)
+#ifdef WIN32
+void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */
+ const uint8_t *data, int size, ...);
+#else
+#define DISPLAY_BYTES(A,B,C,D,...)
+#endif
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx);
+#endif
+
+SSL_SESSION *ssl_session_update(int max_sessions,
+ SSL_SESSION *ssl_sessions[], SSL *ssl,
+ const uint8_t *session_id);
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c
new file mode 100644
index 0000000000..5595716556
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */
+
+static int send_client_hello(SSL *ssl);
+static int process_server_hello(SSL *ssl);
+static int process_server_hello_done(SSL *ssl);
+static int send_client_key_xchg(SSL *ssl);
+static int process_cert_req(SSL *ssl);
+static int send_cert_verify(SSL *ssl);
+
+/*
+ * Establish a new SSL connection to an SSL server.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL *ssl, int client_fd, const
+ uint8_t *session_id, uint8_t sess_id_size)
+{
+ SSL_CTX *ssl_ctx = ssl->ssl_ctx;
+ ssl_new(ssl, client_fd);
+ ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */
+
+ if (session_id && ssl_ctx->num_sessions)
+ {
+ if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
+ {
+ ssl_free(ssl);
+ return NULL;
+ }
+
+ memcpy(ssl->session_id, session_id, sess_id_size);
+ ssl->sess_id_size = sess_id_size;
+ SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */
+ }
+
+ SET_SSL_FLAG(SSL_IS_CLIENT);
+ do_client_connect(ssl);
+ return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+ int ret;
+
+ /* To get here the state must be valid */
+ switch (handshake_type)
+ {
+ case HS_SERVER_HELLO:
+ ret = process_server_hello(ssl);
+ break;
+
+ case HS_CERTIFICATE:
+ ret = process_certificate(ssl, &ssl->x509_ctx);
+ break;
+
+ case HS_SERVER_HELLO_DONE:
+ if ((ret = process_server_hello_done(ssl)) == SSL_OK)
+ {
+ if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))
+ {
+ if ((ret = send_certificate(ssl)) == SSL_OK &&
+ (ret = send_client_key_xchg(ssl)) == SSL_OK)
+ {
+ send_cert_verify(ssl);
+ }
+ }
+ else
+ {
+ ret = send_client_key_xchg(ssl);
+ }
+
+ if (ret == SSL_OK &&
+ (ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ {
+ ret = send_finished(ssl);
+ }
+ }
+ break;
+
+ case HS_CERT_REQ:
+ ret = process_cert_req(ssl);
+ break;
+
+ case HS_FINISHED:
+ ret = process_finished(ssl, buf, hs_len);
+ disposable_free(ssl); /* free up some memory */
+ /* note: client renegotiation is not allowed after this */
+ break;
+
+ case HS_HELLO_REQUEST:
+ disposable_new(ssl);
+ ret = do_client_connect(ssl);
+ break;
+
+ default:
+ ret = SSL_ERROR_INVALID_HANDSHAKE;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Do the handshaking from the beginning.
+ */
+int do_client_connect(SSL *ssl)
+{
+ int ret = SSL_OK;
+
+ send_client_hello(ssl); /* send the client hello */
+ ssl->bm_read_index = 0;
+ ssl->next_state = HS_SERVER_HELLO;
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+
+ /* sit in a loop until it all looks good */
+ if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))
+ {
+ while (ssl->hs_status != SSL_OK)
+ {
+ ret = read_record(ssl);
+ if (ret < SSL_OK)
+ break;
+ ret = process_data(ssl, NULL, 0);
+ if (ret < SSL_OK)
+ break;
+ }
+ ssl->hs_status = ret; /* connected? */
+ }
+ return ret;
+}
+
+static int compute_size_send_client_hello(SSL *ssl)
+{
+ int size = 6 + SSL_RANDOM_SIZE;
+ size++;
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+ {
+
+ size += ssl->sess_id_size;
+ }
+ size += 2;
+ int i;
+ for (i = 0; i < NUM_PROTOCOLS; i++)
+ size += 2;
+ size += 2;
+ return size+BM_RECORD_OFFSET;
+}
+
+/*
+ * Send the initial client hello.
+ */
+static int send_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ time_t tm = time(NULL);
+ uint8_t *tm_ptr = &buf[6]; /* time will go here */
+ int i, offset;
+
+ buf[0] = HS_CLIENT_HELLO;
+ buf[1] = 0;
+ buf[2] = 0;
+ /* byte 3 is calculated later */
+ buf[4] = 0x03;
+ buf[5] = ssl->version & 0x0f;
+
+ /* client random value - spec says that 1st 4 bytes are big endian time */
+ *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));
+ get_random(SSL_RANDOM_SIZE-4, &buf[10]);
+ memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+ offset = 6 + SSL_RANDOM_SIZE;
+
+ /* give session resumption a go */
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */
+ {
+ buf[offset++] = ssl->sess_id_size;
+ memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);
+ offset += ssl->sess_id_size;
+ CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */
+ }
+ else
+ {
+ /* no session id - because no session resumption just yet */
+ buf[offset++] = 0;
+ }
+
+ buf[offset++] = 0; /* number of ciphers */
+ buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */
+
+ /* put all our supported protocols in our request */
+ for (i = 0; i < NUM_PROTOCOLS; i++)
+ {
+ buf[offset++] = 0; /* cipher we are using */
+ buf[offset++] = ssl_prot_prefs[i];
+ }
+
+ buf[offset++] = 1; /* no compression */
+ buf[offset++] = 0;
+ buf[3] = offset - 4; /* handshake size */
+
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Process the server hello.
+ */
+static int process_server_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int pkt_size = ssl->bm_index;
+ int num_sessions = ssl->ssl_ctx->num_sessions;
+ uint8_t sess_id_size;
+ int offset, ret = SSL_OK;
+
+ /* check that we are talking to a TLSv1 server */
+ uint8_t version = (buf[0] << 4) + buf[1];
+ if (version > SSL_PROTOCOL_VERSION_MAX)
+ {
+ version = SSL_PROTOCOL_VERSION_MAX;
+ }
+ else if (ssl->version < SSL_PROTOCOL_MIN_VERSION)
+ {
+ ret = SSL_ERROR_INVALID_VERSION;
+ ssl_display_error(ret);
+ goto error;
+ }
+
+ ssl->version = version;
+
+ /* get the server random value */
+ memcpy(ssl->dc->server_random, &buf[2], SSL_RANDOM_SIZE);
+ offset = 2 + SSL_RANDOM_SIZE; /* skip of session id size */
+ sess_id_size = buf[offset++];
+
+ if (sess_id_size > SSL_SESSION_ID_SIZE)
+ {
+ ret = SSL_ERROR_INVALID_SESSION;
+ goto error;
+ }
+
+ if (num_sessions)
+ {
+ ssl->session = ssl_session_update(num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);
+ memcpy(ssl->session->session_id, &buf[offset], sess_id_size);
+
+ /* pad the rest with 0's */
+ if (sess_id_size < SSL_SESSION_ID_SIZE)
+ {
+ memset(&ssl->session->session_id[sess_id_size], 0,
+ SSL_SESSION_ID_SIZE-sess_id_size);
+ }
+ }
+
+ memcpy(ssl->session_id, &buf[offset], sess_id_size);
+ ssl->sess_id_size = sess_id_size;
+ offset += sess_id_size;
+
+ /* get the real cipher we are using */
+ ssl->cipher = buf[++offset];
+ ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ?
+ HS_FINISHED : HS_CERTIFICATE;
+
+ offset++; // skip the compr
+ PARANOIA_CHECK(pkt_size, offset);
+ ssl->dc->bm_proc_index = offset+1;
+
+error:
+ return ret;
+}
+
+/**
+ * Process the server hello done message.
+ */
+static int process_server_hello_done(SSL *ssl)
+{
+ ssl->next_state = HS_FINISHED;
+ return SSL_OK;
+}
+
+/*
+ * Send a client key exchange message.
+ */
+static int send_client_key_xchg(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t premaster_secret[SSL_SECRET_SIZE];
+ int enc_secret_size = -1;
+
+ buf[0] = HS_CLIENT_KEY_XCHG;
+ buf[1] = 0;
+
+ premaster_secret[0] = 0x03; /* encode the version number */
+ premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */
+ get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);
+ DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,
+ SSL_SECRET_SIZE, &buf[6], 0);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ buf[2] = (enc_secret_size + 2) >> 8;
+ buf[3] = (enc_secret_size + 2) & 0xff;
+ buf[4] = enc_secret_size >> 8;
+ buf[5] = enc_secret_size & 0xff;
+
+ generate_master_secret(ssl, premaster_secret);
+
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);
+}
+
+/*
+ * Process the certificate request.
+ */
+static int process_cert_req(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int ret = SSL_OK;
+ int offset = (buf[2] << 4) + buf[3];
+ int pkt_size = ssl->bm_index;
+
+ /* don't do any processing - we will send back an RSA certificate anyway */
+ ssl->next_state = HS_SERVER_HELLO_DONE;
+ SET_SSL_FLAG(SSL_HAS_CERT_REQ);
+ ssl->dc->bm_proc_index += offset;
+ PARANOIA_CHECK(pkt_size, offset);
+error:
+ return ret;
+}
+
+/*
+ * Send a certificate verify message.
+ */
+static int send_cert_verify(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+ RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+ int n = 0, ret;
+
+ DISPLAY_RSA(ssl, rsa_ctx);
+
+ buf[0] = HS_CERT_VERIFY;
+ buf[1] = 0;
+
+ finished_digest(ssl, NULL, dgst); /* calculate the digest */
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ if (rsa_ctx)
+ {
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (n == 0)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+ }
+
+ buf[4] = n >> 8; /* add the RSA size (not officially documented) */
+ buf[5] = n & 0xff;
+ n += 2;
+ buf[2] = n >> 8;
+ buf[3] = n & 0xff;
+ ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);
+
+error:
+ return ret;
+}
+
+#endif /* CONFIG_SSL_ENABLE_CLIENT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c
new file mode 100644
index 0000000000..51c9d76e8d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 };
+
+static int process_client_hello(SSL *ssl);
+static int send_server_hello_sequence(SSL *ssl);
+static int send_server_hello(SSL *ssl);
+static int send_server_hello_done(SSL *ssl);
+static int process_client_key_xchg(SSL *ssl);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static int send_certificate_request(SSL *ssl);
+static int process_cert_verify(SSL *ssl);
+#endif
+
+/*
+ * Establish a new SSL connection to an SSL client.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd)
+{
+ SSL *ssl;
+
+ ssl = ssl_new(ssl_ctx, client_fd);
+ ssl->next_state = HS_CLIENT_HELLO;
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ssl_ctx->chain_length == 0)
+ printf("Warning - no server certificate defined\n"); TTY_FLUSH();
+#endif
+
+ return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+ int ret = SSL_OK;
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+
+ /* To get here the state must be valid */
+ switch (handshake_type)
+ {
+ case HS_CLIENT_HELLO:
+ if ((ret = process_client_hello(ssl)) == SSL_OK)
+ ret = send_server_hello_sequence(ssl);
+ break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case HS_CERTIFICATE:/* the client sends its cert */
+ ret = process_certificate(ssl, &ssl->x509_ctx);
+
+ if (ret == SSL_OK) /* verify the cert */
+ {
+ int cert_res;
+ cert_res = x509_verify(
+ ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+ ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
+ }
+ break;
+
+ case HS_CERT_VERIFY:
+ ret = process_cert_verify(ssl);
+ add_packet(ssl, buf, hs_len); /* needs to be done after */
+ break;
+#endif
+ case HS_CLIENT_KEY_XCHG:
+ ret = process_client_key_xchg(ssl);
+ break;
+
+ case HS_FINISHED:
+ ret = process_finished(ssl, buf, hs_len);
+ disposable_free(ssl); /* free up some memory */
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Process a client hello message.
+ */
+static int process_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t *record_buf = ssl->hmac_header;
+ int pkt_size = ssl->bm_index;
+ int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE;
+ int ret = SSL_OK;
+
+ uint8_t version = (buf[4] << 4) + buf[5];
+ ssl->version = ssl->client_version = version;
+
+ if (version > SSL_PROTOCOL_VERSION_MAX)
+ {
+ /* use client's version instead */
+ ssl->version = SSL_PROTOCOL_VERSION_MAX;
+ }
+ else if (version < SSL_PROTOCOL_MIN_VERSION) /* old version supported? */
+ {
+ ret = SSL_ERROR_INVALID_VERSION;
+ ssl_display_error(ret);
+ goto error;
+ }
+
+ memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+
+ /* process the session id */
+ id_len = buf[offset++];
+ if (id_len > SSL_SESSION_ID_SIZE)
+ {
+ return SSL_ERROR_INVALID_SESSION;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+ offset += id_len;
+ cs_len = (buf[offset]<<8) + buf[offset+1];
+ offset += 3; /* add 1 due to all cipher suites being 8 bit */
+
+ PARANOIA_CHECK(pkt_size, offset);
+
+ /* work out what cipher suite we are going to use - client defines
+ the preference */
+ for (i = 0; i < cs_len; i += 2)
+ {
+ for (j = 0; j < NUM_PROTOCOLS; j++)
+ {
+ if (ssl_prot_prefs[j] == buf[offset+i]) /* got a match? */
+ {
+ ssl->cipher = ssl_prot_prefs[j];
+ goto do_state;
+ }
+ }
+ }
+
+ /* ouch! protocol is not supported */
+ ret = SSL_ERROR_NO_CIPHER;
+
+do_state:
+error:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+/*
+ * Some browsers use a hybrid SSLv2 "client hello"
+ */
+int process_sslv23_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1];
+ int ret = SSL_OK;
+
+ /* we have already read 3 extra bytes so far */
+ int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3);
+ int cs_len = buf[1];
+ int id_len = buf[3];
+ int ch_len = buf[5];
+ int i, j, offset = 8; /* start at first cipher */
+ int random_offset = 0;
+
+ DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len);
+
+ add_packet(ssl, buf, read_len);
+
+ /* connection has gone, so die */
+ if (bytes_needed < 0)
+ {
+ return SSL_ERROR_CONN_LOST;
+ }
+
+ /* now work out what cipher suite we are going to use */
+ for (j = 0; j < NUM_PROTOCOLS; j++)
+ {
+ for (i = 0; i < cs_len; i += 3)
+ {
+ if (ssl_prot_prefs[j] == buf[offset+i])
+ {
+ ssl->cipher = ssl_prot_prefs[j];
+ goto server_hello;
+ }
+ }
+ }
+
+ /* ouch! protocol is not supported */
+ ret = SSL_ERROR_NO_CIPHER;
+ goto error;
+
+server_hello:
+ /* get the session id */
+ offset += cs_len - 2; /* we've gone 2 bytes past the end */
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+ /* get the client random data */
+ offset += id_len;
+
+ /* random can be anywhere between 16 and 32 bytes long - so it is padded
+ * with 0's to the left */
+ if (ch_len == 0x10)
+ {
+ random_offset += 0x10;
+ }
+
+ memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len);
+ ret = send_server_hello_sequence(ssl);
+
+error:
+ return ret;
+}
+#endif
+
+/*
+ * Send the entire server hello sequence
+ */
+static int send_server_hello_sequence(SSL *ssl)
+{
+ int ret;
+
+ if ((ret = send_server_hello(ssl)) == SSL_OK)
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* resume handshake? */
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+ {
+ if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ {
+ ret = send_finished(ssl);
+ ssl->next_state = HS_FINISHED;
+ }
+ }
+ else
+#endif
+ if ((ret = send_certificate(ssl)) == SSL_OK)
+ {
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ /* ask the client for its certificate */
+ if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION))
+ {
+ if ((ret = send_certificate_request(ssl)) == SSL_OK)
+ {
+ ret = send_server_hello_done(ssl);
+ ssl->next_state = HS_CERTIFICATE;
+ }
+ }
+ else
+#endif
+ {
+ ret = send_server_hello_done(ssl);
+ ssl->next_state = HS_CLIENT_KEY_XCHG;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Send a server hello message.
+ */
+static int send_server_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int offset = 0;
+
+ buf[0] = HS_SERVER_HELLO;
+ buf[1] = 0;
+ buf[2] = 0;
+ /* byte 3 is calculated later */
+ buf[4] = 0x03;
+ buf[5] = ssl->version & 0x0f;
+
+ /* server random value */
+ get_random(SSL_RANDOM_SIZE, &buf[6]);
+ memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
+ offset = 6 + SSL_RANDOM_SIZE;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+ {
+ /* retrieve id from session cache */
+ buf[offset++] = SSL_SESSION_ID_SIZE;
+ memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE);
+ memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE);
+ ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+ offset += SSL_SESSION_ID_SIZE;
+ }
+ else /* generate our own session id */
+#endif
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ buf[offset++] = SSL_SESSION_ID_SIZE;
+ get_random(SSL_SESSION_ID_SIZE, &buf[offset]);
+ memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE);
+ ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+
+ /* store id in session cache */
+ if (ssl->ssl_ctx->num_sessions)
+ {
+ memcpy(ssl->session->session_id,
+ ssl->session_id, SSL_SESSION_ID_SIZE);
+ }
+
+ offset += SSL_SESSION_ID_SIZE;
+#else
+ buf[offset++] = 0; /* don't bother with session id in skelton mode */
+#endif
+ }
+
+ buf[offset++] = 0; /* cipher we are using */
+ buf[offset++] = ssl->cipher;
+ buf[offset++] = 0; /* no compression */
+ buf[3] = offset - 4; /* handshake size */
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Send the server hello done message.
+ */
+static int send_server_hello_done(SSL *ssl)
+{
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_hello_done, sizeof(g_hello_done));
+}
+
+/*
+ * Pull apart a client key exchange message. Decrypt the pre-master key (using
+ * our RSA private key) and then work out the master key. Initialise the
+ * ciphers.
+ */
+static int process_client_key_xchg(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int pkt_size = ssl->bm_index;
+ int premaster_size, secret_length = (buf[2] << 8) + buf[3];
+ uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];
+ RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+ int offset = 4;
+ int ret = SSL_OK;
+
+ if (rsa_ctx == NULL)
+ {
+ ret = SSL_ERROR_NO_CERT_DEFINED;
+ goto error;
+ }
+
+ /* is there an extra size field? */
+ if ((secret_length - 2) == rsa_ctx->num_octets)
+ offset += 2;
+
+ PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (premaster_size != SSL_SECRET_SIZE ||
+ premaster_secret[0] != 0x03 || /* must be the same as client
+ offered version */
+ premaster_secret[1] != (ssl->client_version & 0x0f))
+ {
+ /* guard against a Bleichenbacher attack */
+ get_random(SSL_SECRET_SIZE, premaster_secret);
+ /* and continue - will die eventually when checking the mac */
+ }
+
+#if 0
+ print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE);
+#endif
+
+ generate_master_secret(ssl, premaster_secret);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?
+ HS_CERT_VERIFY : HS_FINISHED;
+#else
+ ssl->next_state = HS_FINISHED;
+#endif
+
+ ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;
+error:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 };
+
+/*
+ * Send the certificate request message.
+ */
+static int send_certificate_request(SSL *ssl)
+{
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_cert_request, sizeof(g_cert_request));
+}
+
+/*
+ * Ensure the client has the private key by first decrypting the packet and
+ * then checking the packet digests.
+ */
+static int process_cert_verify(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int pkt_size = ssl->bm_index;
+ uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
+ uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+ X509_CTX *x509_ctx = ssl->x509_ctx;
+ int ret = SSL_OK;
+ int n;
+
+ PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);
+ DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (n != SHA1_SIZE + MD5_SIZE)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto end_cert_vfy;
+ }
+
+ finished_digest(ssl, NULL, dgst); /* calculate the digest */
+ if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ }
+
+end_cert_vfy:
+ ssl->next_state = HS_FINISHED;
+error:
+ return ret;
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h
new file mode 100644
index 0000000000..e8158cc0d9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h
@@ -0,0 +1 @@
+#define AXTLS_VERSION "1.4.9"
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c
new file mode 100644
index 0000000000..4f88c8738d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project 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 OWNER 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.
+ */
+
+/**
+ * @file x509.c
+ *
+ * Certificate processing.
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "os_port.h"
+#include "crypto_misc.h"
+#include "sockets.h"
+#include "config.h"
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Retrieve the signature from a certificate.
+ */
+static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
+{
+ int offset = 0;
+ const uint8_t *ptr = NULL;
+
+ if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
+ goto end_get_sig;
+
+ if (asn1_sig[offset++] != ASN1_OCTET_STRING)
+ goto end_get_sig;
+ *len = get_asn1_length(asn1_sig, &offset);
+ ptr = &asn1_sig[offset]; /* all ok */
+
+end_get_sig:
+ return ptr;
+}
+
+#endif
+
+/**
+ * Construct a new x509 object.
+ * @return 0 if ok. < 0 if there was a problem.
+ */
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
+{
+
+ int begin_tbs, end_tbs;
+ int ret = X509_NOT_OK, offset = 0, cert_size = 0;
+ X509_CTX *x509_ctx;
+ BI_CTX *bi_ctx;
+ *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
+ x509_ctx = *ctx;
+ /* get the certificate size */
+ asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
+
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ begin_tbs = offset; /* start of the tbs */
+ end_tbs = begin_tbs; /* work out the end of the tbs */
+ asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+ if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
+ {
+ if (asn1_version(cert, &offset, x509_ctx))
+ goto end_cert;
+ }
+ if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
+ asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ {
+ goto end_cert;
+ }
+ /* make sure the signature is ok */
+ if (asn1_signature_type(cert, &offset, x509_ctx))
+ {
+ ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
+ goto end_cert;
+ }
+ if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
+ asn1_validity(cert, &offset, x509_ctx) ||
+ asn1_name(cert, &offset, x509_ctx->cert_dn) ||
+ asn1_public_key(cert, &offset, x509_ctx))
+ {
+ goto end_cert;
+ }
+ bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
+#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
+
+ /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
+ if (x509_ctx->sig_type == SIG_TYPE_MD5)
+ {
+ MD5_CTX md5_ctx;
+ uint8_t md5_dgst[MD5_SIZE];
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ MD5_Final(md5_dgst, &md5_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
+ }
+ else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
+ {
+ SHA1_CTX sha_ctx;
+ uint8_t sha_dgst[SHA1_SIZE];
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ SHA1_Final(sha_dgst, &sha_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
+ }
+ else if (x509_ctx->sig_type == SIG_TYPE_MD2)
+ {
+ MD2_CTX md2_ctx;
+ uint8_t md2_dgst[MD2_SIZE];
+ MD2_Init(&md2_ctx);
+ MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ MD2_Final(md2_dgst, &md2_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
+ }
+
+ if (cert[offset] == ASN1_V3_DATA)
+ {
+ int suboffset;
+
+ ++offset;
+ get_asn1_length(cert, &offset);
+
+ if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
+ {
+ if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
+ {
+ int altlen;
+
+ if ((altlen = asn1_next_obj(cert,
+ &suboffset, ASN1_SEQUENCE)) > 0)
+ {
+ int endalt = suboffset + altlen;
+ int totalnames = 0;
+
+ while (suboffset < endalt)
+ {
+ int type = cert[suboffset++];
+ int dnslen = get_asn1_length(cert, &suboffset);
+
+ if (type == ASN1_CONTEXT_DNSNAME)
+ {
+ x509_ctx->subject_alt_dnsnames = (char**)
+ realloc(x509_ctx->subject_alt_dnsnames,
+ (totalnames + 2) * sizeof(char*));
+ x509_ctx->subject_alt_dnsnames[totalnames] =
+ (char*)malloc(dnslen + 1);
+ x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
+ memcpy(x509_ctx->subject_alt_dnsnames[totalnames],
+ cert + suboffset, dnslen);
+ x509_ctx->subject_alt_dnsnames[
+ totalnames][dnslen] = 0;
+ ++totalnames;
+ }
+
+ suboffset += dnslen;
+ }
+ }
+ }
+ }
+ }
+
+ offset = end_tbs; /* skip the rest of v3 data */
+ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
+ asn1_signature(cert, &offset, x509_ctx))
+ goto end_cert;
+
+#endif
+ ret = X509_OK;
+end_cert:
+ if (len)
+ {
+ *len = cert_size;
+ }
+
+ if (ret)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Invalid X509 ASN.1 file (%s)\n",
+ x509_display_error(ret));
+#endif
+ x509_free(x509_ctx);
+ *ctx = NULL;
+ }
+ return ret;
+}
+
+/**
+ * Free an X.509 object's resources.
+ */
+void x509_free(X509_CTX *x509_ctx)
+{
+ X509_CTX *next;
+ int i;
+
+ if (x509_ctx == NULL) /* if already null, then don't bother */
+ return;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ free(x509_ctx->ca_cert_dn[i]);
+ free(x509_ctx->cert_dn[i]);
+ }
+
+ free(x509_ctx->signature);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (x509_ctx->digest)
+ {
+ bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
+ }
+
+ if (x509_ctx->subject_alt_dnsnames)
+ {
+ for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
+ free(x509_ctx->subject_alt_dnsnames[i]);
+
+ free(x509_ctx->subject_alt_dnsnames);
+ }
+#endif
+
+ RSA_free(x509_ctx->rsa_ctx);
+ next = x509_ctx->next;
+ free(x509_ctx);
+ x509_free(next); /* clear the chain */
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Take a signature and decrypt it.
+ */
+static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp)
+{
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+ bigint *bir = NULL;
+ uint8_t *block = (uint8_t *)alloca(sig_len);
+
+ /* decrypt */
+ dat_bi = bi_import(ctx, sig, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ /* convert to a normal block */
+ decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
+
+ bi_export(ctx, decrypted_bi, block, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ i = 10; /* start at the first possible non-padded byte */
+ while (block[i++] && i < sig_len);
+ size = sig_len - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ {
+ int len;
+ const uint8_t *sig_ptr = get_signature(&block[i], &len);
+
+ if (sig_ptr)
+ {
+ bir = bi_import(ctx, sig_ptr, len);
+ }
+ }
+
+ /* save a few bytes of memory */
+ bi_clear_cache(ctx);
+ return bir;
+}
+
+/**
+ * Do some basic checks on the certificate chain.
+ *
+ * Certificate verification consists of a number of checks:
+ * - The date of the certificate is after the start date.
+ * - The date of the certificate is before the finish date.
+ * - A root certificate exists in the certificate store.
+ * - That the certificate(s) are not self-signed.
+ * - The certificate chain is valid.
+ * - The signature of the certificate is valid.
+ */
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
+{
+ int ret = X509_OK, i = 0;
+ bigint *cert_sig;
+ X509_CTX *next_cert = NULL;
+ BI_CTX *ctx = NULL;
+ bigint *mod = NULL, *expn = NULL;
+ int match_ca_cert = 0;
+ struct timeval tv;
+ uint8_t is_self_signed = 0;
+
+ if (cert == NULL)
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+
+ /* a self-signed certificate that is not in the CA store - use this
+ to check the signature */
+ if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
+ {
+ printf("self signed cert\r\n");
+ is_self_signed = 1;
+ ctx = cert->rsa_ctx->bi_ctx;
+ mod = cert->rsa_ctx->m;
+ expn = cert->rsa_ctx->e;
+ }
+
+ gettimeofday(&tv, NULL);
+
+ /* check the not before date */
+ if (tv.tv_sec < cert->not_before)
+ {
+ ret = X509_VFY_ERROR_NOT_YET_VALID;
+ goto end_verify;
+ }
+
+ /* check the not after date */
+ if (tv.tv_sec > cert->not_after)
+ {
+ ret = X509_VFY_ERROR_EXPIRED;
+ goto end_verify;
+ }
+
+ next_cert = cert->next;
+
+ /* last cert in the chain - look for a trusted cert */
+ if (next_cert == NULL)
+ {
+ if (ca_cert_ctx != NULL)
+ {
+ /* go thu the CA store */
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ if (asn1_compare_dn(cert->ca_cert_dn,
+ ca_cert_ctx->cert[i]->cert_dn) == 0)
+ {
+ /* use this CA certificate for signature verification */
+ match_ca_cert = 1;
+ ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
+ mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
+ expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ /* couldn't find a trusted cert (& let self-signed errors
+ be returned) */
+ if (!match_ca_cert && !is_self_signed)
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+ }
+ else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
+ {
+ /* check the chain */
+ ret = X509_VFY_ERROR_INVALID_CHAIN;
+ goto end_verify;
+ }
+ else /* use the next certificate in the chain for signature verify */
+ {
+ ctx = next_cert->rsa_ctx->bi_ctx;
+ mod = next_cert->rsa_ctx->m;
+ expn = next_cert->rsa_ctx->e;
+ }
+
+ /* cert is self signed */
+ if (!match_ca_cert && is_self_signed)
+ {
+ ret = X509_VFY_ERROR_SELF_SIGNED;
+ goto end_verify;
+ }
+
+ /* check the signature */
+ cert_sig = sig_verify(ctx, cert->signature, cert->sig_len,
+ bi_clone(ctx, mod), bi_clone(ctx, expn));
+
+ if (cert_sig && cert->digest)
+ {
+ if (bi_compare(cert_sig, cert->digest) != 0)
+ ret = X509_VFY_ERROR_BAD_SIGNATURE;
+
+
+ bi_free(ctx, cert_sig);
+ }
+ else
+ {
+ ret = X509_VFY_ERROR_BAD_SIGNATURE;
+ }
+
+ if (ret)
+ goto end_verify;
+
+ /* go down the certificate chain using recursion. */
+ if (next_cert != NULL)
+ {
+ ret = x509_verify(ca_cert_ctx, next_cert);
+ }
+
+end_verify:
+ return ret;
+}
+#endif
+
+#if defined (CONFIG_SSL_FULL_MODE)
+/**
+ * Used for diagnostics.
+ */
+static const char *not_part_of_cert = "<Not Part Of Certificate>";
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
+{
+ if (cert == NULL)
+ return;
+
+ printf("=== CERTIFICATE ISSUED TO ===\n");
+ printf("Common Name (CN):\t\t");
+ printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
+ cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+ printf("Organization (O):\t\t");
+ printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
+ cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+ printf("Organizational Unit (OU):\t");
+ printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+ cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+ printf("=== CERTIFICATE ISSUED BY ===\r\n");
+ printf("Common Name (CN):\t\t");
+ printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
+ cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+ printf("Organization (O):\t\t");
+ printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
+ cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+ printf("Organizational Unit (OU):\t");
+ printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+ cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+ printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
+ printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
+ printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
+ printf("Sig Type:\t\t\t");
+ switch (cert->sig_type)
+ {
+ case SIG_TYPE_MD5:
+ printf("MD5\r\n");
+ break;
+ case SIG_TYPE_SHA1:
+ printf("SHA1\r\n");
+ break;
+ case SIG_TYPE_MD2:
+ printf("MD2\r\n");
+ break;
+ default:
+ printf("Unrecognized: %d\r\n", cert->sig_type);
+ break;
+ }
+
+ if (ca_cert_ctx)
+ {
+ printf("Verify:\t\t\t\t%s\r\n",
+ x509_display_error(x509_verify(ca_cert_ctx, cert)));
+ }
+
+#if 0
+ print_blob("Signature", cert->signature, cert->sig_len);
+ bi_print("Modulus", cert->rsa_ctx->m);
+ bi_print("Pub Exp", cert->rsa_ctx->e);
+#endif
+
+ if (ca_cert_ctx)
+ {
+ x509_print(cert->next, ca_cert_ctx);
+ }
+
+ TTY_FLUSH();
+}
+
+const char * x509_display_error(int error)
+{
+ switch (error)
+ {
+ case X509_OK:
+ return "Certificate verify successful";
+
+ case X509_NOT_OK:
+ return "X509 not ok";
+
+ case X509_VFY_ERROR_NO_TRUSTED_CERT:
+ return "No trusted cert is available";
+
+ case X509_VFY_ERROR_BAD_SIGNATURE:
+ return "Bad signature";
+
+ case X509_VFY_ERROR_NOT_YET_VALID:
+ return "Cert is not yet valid";
+
+ case X509_VFY_ERROR_EXPIRED:
+ return "Cert has expired";
+
+ case X509_VFY_ERROR_SELF_SIGNED:
+ return "Cert is self-signed";
+
+ case X509_VFY_ERROR_INVALID_CHAIN:
+ return "Chain is invalid (check order of certs)";
+
+ case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
+ return "Unsupported digest";
+
+ case X509_INVALID_PRIV_KEY:
+ return "Invalid private key";
+
+ default:
+ return "Unknown";
+ }
+}
+#endif /* CONFIG_SSL_FULL_MODE */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.cpp
new file mode 100644
index 0000000000..25688d0e29
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.cpp
@@ -0,0 +1,73 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+#include <cstring>
+#include <cstdio>
+
+Endpoint::Endpoint() {
+ reset_address();
+}
+Endpoint::~Endpoint() {}
+
+void Endpoint::reset_address(void) {
+ std::memset(&_remoteHost, 0, sizeof(struct sockaddr_in));
+ _ipAddress[0] = '\0';
+}
+
+#include "stdio.h"
+
+int Endpoint::set_address(const char* host, const int port) {
+ reset_address();
+
+ // IP Address
+ char address[5];
+ char *p_address = address;
+
+ // Dot-decimal notation
+ int result = std::sscanf(host, "%3u.%3u.%3u.%3u",
+ (unsigned int*)&address[0], (unsigned int*)&address[1],
+ (unsigned int*)&address[2], (unsigned int*)&address[3]);
+
+ if (result != 4) {
+ // Resolve address with DNS
+ struct hostent *host_address = lwip_gethostbyname(host);
+ if (host_address == NULL)
+ return -1; //Could not resolve address
+ p_address = (char*)host_address->h_addr_list[0];
+ }
+ std::memcpy((char*)&_remoteHost.sin_addr.s_addr, p_address, 4);
+
+ // Address family
+ _remoteHost.sin_family = AF_INET;
+
+ // Set port
+ _remoteHost.sin_port = htons(port);
+
+ return 0;
+}
+
+char* Endpoint::get_address() {
+ if ((_ipAddress[0] == '\0') && (_remoteHost.sin_addr.s_addr != 0))
+ inet_ntoa_r(_remoteHost.sin_addr, _ipAddress, sizeof(_ipAddress));
+ return _ipAddress;
+}
+
+int Endpoint::get_port() {
+ return ntohs(_remoteHost.sin_port);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.h
new file mode 100644
index 0000000000..788a0a8217
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Endpoint.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef ENDPOINT_H
+#define ENDPOINT_H
+
+class UDPSocket;
+
+/**
+IP Endpoint (address, port)
+*/
+class Endpoint {
+ friend class UDPSocket;
+
+public:
+ /** IP Endpoint (address, port)
+ */
+ Endpoint(void);
+
+ ~Endpoint(void);
+
+ /** Reset the address of this endpoint
+ */
+ void reset_address(void);
+
+ /** Set the address of this endpoint
+ \param host The endpoint address (it can either be an IP Address or a hostname that will be resolved with DNS).
+ \param port The endpoint port
+ \return 0 on success, -1 on failure (when an hostname cannot be resolved by DNS).
+ */
+ int set_address(const char* host, const int port);
+
+ /** Get the IP address of this endpoint
+ \return The IP address of this endpoint.
+ */
+ char* get_address(void);
+
+ /** Get the port of this endpoint
+ \return The port of this endpoint
+ */
+ int get_port(void);
+
+protected:
+ char _ipAddress[17];
+ struct sockaddr_in _remoteHost;
+
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.cpp
new file mode 100644
index 0000000000..04a883c158
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.cpp
@@ -0,0 +1,91 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "Socket/Socket.h"
+#include <cstring>
+
+using std::memset;
+
+Socket::Socket() : _sock_fd(-1), _blocking(true), _timeout(1500) {
+
+}
+
+void Socket::set_blocking(bool blocking, unsigned int timeout) {
+ _blocking = blocking;
+ _timeout = timeout;
+}
+
+int Socket::init_socket(int type) {
+ if (_sock_fd != -1)
+ return -1;
+
+ int fd = lwip_socket(AF_INET, type, 0);
+ if (fd < 0)
+ return -1;
+
+ _sock_fd = fd;
+ return 0;
+}
+
+int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen) {
+ return lwip_setsockopt(_sock_fd, level, optname, optval, optlen);
+}
+
+int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) {
+ return lwip_getsockopt(_sock_fd, level, optname, optval, optlen);
+}
+
+int Socket::select(struct timeval *timeout, bool read, bool write) {
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(_sock_fd, &fdSet);
+
+ fd_set* readset = (read ) ? (&fdSet) : (NULL);
+ fd_set* writeset = (write) ? (&fdSet) : (NULL);
+
+ int ret = lwip_select(FD_SETSIZE, readset, writeset, NULL, timeout);
+ return (ret <= 0 || !FD_ISSET(_sock_fd, &fdSet)) ? (-1) : (0);
+}
+
+int Socket::wait_readable(TimeInterval& timeout) {
+ return select(&timeout._time, true, false);
+}
+
+int Socket::wait_writable(TimeInterval& timeout) {
+ return select(&timeout._time, false, true);
+}
+
+int Socket::close(bool shutdown) {
+ if (_sock_fd < 0)
+ return -1;
+
+ if (shutdown)
+ lwip_shutdown(_sock_fd, SHUT_RDWR);
+ lwip_close(_sock_fd);
+ _sock_fd = -1;
+
+ return 0;
+}
+
+Socket::~Socket() {
+ close(); //Don't want to leak
+}
+
+TimeInterval::TimeInterval(unsigned int ms) {
+ _time.tv_sec = ms / 1000;
+ _time.tv_usec = (ms - (_time.tv_sec * 1000)) * 1000;
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.h
new file mode 100644
index 0000000000..e2e1803e85
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/Socket.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef SOCKET_H_
+#define SOCKET_H_
+
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+
+//DNS
+inline struct hostent *gethostbyname(const char *name) {
+ return lwip_gethostbyname(name);
+}
+
+inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) {
+ return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
+}
+
+class TimeInterval;
+
+/** Socket file descriptor and select wrapper
+ */
+class Socket {
+public:
+ /** Socket
+ */
+ Socket();
+
+ /** Set blocking or non-blocking mode of the socket and a timeout on
+ blocking socket operations
+ \param blocking true for blocking mode, false for non-blocking mode.
+ \param timeout timeout in ms [Default: (1500)ms].
+ */
+ void set_blocking(bool blocking, unsigned int timeout=1500);
+
+ /** Set socket options
+ \param level stack level (see: lwip/sockets.h)
+ \param optname option ID
+ \param optval option value
+ \param socklen_t length of the option value
+ \return 0 on success, -1 on failure
+ */
+ int set_option(int level, int optname, const void *optval, socklen_t optlen);
+
+ /** Get socket options
+ \param level stack level (see: lwip/sockets.h)
+ \param optname option ID
+ \param optval buffer pointer where to write the option value
+ \param socklen_t length of the option value
+ \return 0 on success, -1 on failure
+ */
+ int get_option(int level, int optname, void *optval, socklen_t *optlen);
+
+ /** Close the socket
+ \param shutdown free the left-over data in message queues
+ */
+ int close(bool shutdown=true);
+
+ ~Socket();
+
+protected:
+ int _sock_fd;
+ int init_socket(int type);
+
+ int wait_readable(TimeInterval& timeout);
+ int wait_writable(TimeInterval& timeout);
+
+ bool _blocking;
+ unsigned int _timeout;
+
+private:
+ int select(struct timeval *timeout, bool read, bool write);
+};
+
+/** Time interval class used to specify timeouts
+ */
+class TimeInterval {
+ friend class Socket;
+
+public:
+ /** Time Interval
+ \param ms time interval expressed in milliseconds
+ */
+ TimeInterval(unsigned int ms);
+
+private:
+ struct timeval _time;
+};
+
+#endif /* SOCKET_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.cpp
new file mode 100644
index 0000000000..b853304099
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.cpp
@@ -0,0 +1,133 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "TCPSocketConnection.h"
+#include <cstring>
+
+using std::memset;
+using std::memcpy;
+
+TCPSocketConnection::TCPSocketConnection() :
+ _is_connected(false) {
+}
+
+int TCPSocketConnection::connect(const char* host, const int port) {
+ if (init_socket(SOCK_STREAM) < 0)
+ return -1;
+
+ if (set_address(host, port) != 0)
+ return -1;
+
+ if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) {
+ close();
+ return -1;
+ }
+ _is_connected = true;
+
+ return 0;
+}
+
+bool TCPSocketConnection::is_connected(void) {
+ return _is_connected;
+}
+
+int TCPSocketConnection::send(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ if (!_blocking) {
+ TimeInterval timeout(_timeout);
+ if (wait_writable(timeout) != 0)
+ return -1;
+ }
+
+ int n = lwip_send(_sock_fd, data, length, 0);
+ _is_connected = (n != 0);
+
+ return n;
+}
+
+// -1 if unsuccessful, else number of bytes written
+int TCPSocketConnection::send_all(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ int writtenLen = 0;
+ TimeInterval timeout(_timeout);
+ while (writtenLen < length) {
+ if (!_blocking) {
+ // Wait for socket to be writeable
+ if (wait_writable(timeout) != 0)
+ return writtenLen;
+ }
+
+ int ret = lwip_send(_sock_fd, data + writtenLen, length - writtenLen, 0);
+ if (ret > 0) {
+ writtenLen += ret;
+ continue;
+ } else if (ret == 0) {
+ _is_connected = false;
+ return writtenLen;
+ } else {
+ return -1; //Connnection error
+ }
+ }
+ return writtenLen;
+}
+
+int TCPSocketConnection::receive(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ if (!_blocking) {
+ TimeInterval timeout(_timeout);
+ if (wait_readable(timeout) != 0)
+ return -1;
+ }
+
+ int n = lwip_recv(_sock_fd, data, length, 0);
+ _is_connected = (n != 0);
+
+ return n;
+}
+
+// -1 if unsuccessful, else number of bytes received
+int TCPSocketConnection::receive_all(char* data, int length) {
+ if ((_sock_fd < 0) || !_is_connected)
+ return -1;
+
+ int readLen = 0;
+ TimeInterval timeout(_timeout);
+ while (readLen < length) {
+ if (!_blocking) {
+ //Wait for socket to be readable
+ if (wait_readable(timeout) != 0)
+ return readLen;
+ }
+
+ int ret = lwip_recv(_sock_fd, data + readLen, length - readLen, 0);
+ if (ret > 0) {
+ readLen += ret;
+ } else if (ret == 0) {
+ _is_connected = false;
+ return readLen;
+ } else {
+ return -1; //Connnection error
+ }
+ }
+ return readLen;
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.h
new file mode 100644
index 0000000000..7af7bf624c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketConnection.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TCPSOCKET_H
+#define TCPSOCKET_H
+
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+
+/**
+TCP socket connection
+*/
+class TCPSocketConnection : public Socket, public Endpoint {
+ friend class TCPSocketServer;
+
+public:
+ /** TCP socket connection
+ */
+ TCPSocketConnection();
+
+ /** Connects this TCP socket to the server
+ \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS.
+ \param port The host's port to connect to.
+ \return 0 on success, -1 on failure.
+ */
+ int connect(const char* host, const int port);
+
+ /** Check if the socket is connected
+ \return true if connected, false otherwise.
+ */
+ bool is_connected(void);
+
+ /** Send data to the remote host.
+ \param data The buffer to send to the host.
+ \param length The length of the buffer to send.
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int send(char* data, int length);
+
+ /** Send all the data to the remote host.
+ \param data The buffer to send to the host.
+ \param length The length of the buffer to send.
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int send_all(char* data, int length);
+
+ /** Receive data from the remote host.
+ \param data The buffer in which to store the data received from the host.
+ \param length The maximum length of the buffer.
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receive(char* data, int length);
+
+ /** Receive all the data from the remote host.
+ \param data The buffer in which to store the data received from the host.
+ \param length The maximum length of the buffer.
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receive_all(char* data, int length);
+
+private:
+ bool _is_connected;
+
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.cpp
new file mode 100644
index 0000000000..d894b94e39
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.cpp
@@ -0,0 +1,78 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "TCPSocketServer.h"
+
+#include <cstring>
+
+using std::memset;
+using std::memcpy;
+
+TCPSocketServer::TCPSocketServer() {
+
+}
+
+int TCPSocketServer::bind(int port) {
+ if (init_socket(SOCK_STREAM) < 0)
+ return -1;
+
+ struct sockaddr_in localHost;
+ memset(&localHost, 0, sizeof(localHost));
+
+ localHost.sin_family = AF_INET;
+ localHost.sin_port = htons(port);
+ localHost.sin_addr.s_addr = INADDR_ANY;
+
+ if (lwip_bind(_sock_fd, (const struct sockaddr *) &localHost, sizeof(localHost)) < 0) {
+ close();
+ return -1;
+ }
+
+ return 0;
+}
+
+int TCPSocketServer::listen(int max) {
+ if (_sock_fd < 0)
+ return -1;
+
+ if (lwip_listen(_sock_fd, max) < 0) {
+ close();
+ return -1;
+ }
+
+ return 0;
+}
+
+int TCPSocketServer::accept(TCPSocketConnection& connection) {
+ if (_sock_fd < 0)
+ return -1;
+
+ if (!_blocking) {
+ TimeInterval timeout(_timeout);
+ if (wait_readable(timeout) != 0)
+ return -1;
+ }
+ connection.reset_address();
+ socklen_t newSockRemoteHostLen = sizeof(connection._remoteHost);
+ int fd = lwip_accept(_sock_fd, (struct sockaddr*) &connection._remoteHost, &newSockRemoteHostLen);
+ if (fd < 0)
+ return -1; //Accept failed
+ connection._sock_fd = fd;
+ connection._is_connected = true;
+
+ return 0;
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.h
new file mode 100644
index 0000000000..214791ce45
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/TCPSocketServer.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef TCPSOCKETSERVER_H
+#define TCPSOCKETSERVER_H
+
+#include "Socket/Socket.h"
+#include "TCPSocketConnection.h"
+
+/** TCP Server.
+ */
+class TCPSocketServer : public Socket {
+ public:
+ /** Instantiate a TCP Server.
+ */
+ TCPSocketServer();
+
+ /** Bind a socket to a specific port.
+ \param port The port to listen for incoming connections on.
+ \return 0 on success, -1 on failure.
+ */
+ int bind(int port);
+
+ /** Start listening for incoming connections.
+ \param backlog number of pending connections that can be queued up at any
+ one time [Default: 1].
+ \return 0 on success, -1 on failure.
+ */
+ int listen(int backlog=1);
+
+ /** Accept a new connection.
+ \param connection A TCPSocketConnection instance that will handle the incoming connection.
+ \return 0 on success, -1 on failure.
+ */
+ int accept(TCPSocketConnection& connection);
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.cpp
new file mode 100644
index 0000000000..baf845b203
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.cpp
@@ -0,0 +1,94 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Socket/UDPSocket.h"
+
+#include <cstring>
+
+using std::memset;
+
+UDPSocket::UDPSocket() {
+}
+
+int UDPSocket::init(void) {
+ return init_socket(SOCK_DGRAM);
+}
+
+// Server initialization
+int UDPSocket::bind(int port) {
+ if (init_socket(SOCK_DGRAM) < 0)
+ return -1;
+
+ struct sockaddr_in localHost;
+ std::memset(&localHost, 0, sizeof(localHost));
+
+ localHost.sin_family = AF_INET;
+ localHost.sin_port = htons(port);
+ localHost.sin_addr.s_addr = INADDR_ANY;
+
+ if (lwip_bind(_sock_fd, (const struct sockaddr *) &localHost, sizeof(localHost)) < 0) {
+ close();
+ return -1;
+ }
+
+ return 0;
+}
+
+int UDPSocket::join_multicast_group(const char* address) {
+ struct ip_mreq mreq;
+
+ // Set up group address
+ mreq.imr_multiaddr.s_addr = inet_addr(address);
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ return set_option(IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+}
+
+int UDPSocket::set_broadcasting(bool broadcast) {
+ int option = (broadcast) ? (1) : (0);
+ return set_option(SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
+}
+
+// -1 if unsuccessful, else number of bytes written
+int UDPSocket::sendTo(Endpoint &remote, char *packet, int length) {
+ if (_sock_fd < 0)
+ return -1;
+
+ if (!_blocking) {
+ TimeInterval timeout(_timeout);
+ if (wait_writable(timeout) != 0)
+ return 0;
+ }
+
+ return lwip_sendto(_sock_fd, packet, length, 0, (const struct sockaddr *) &remote._remoteHost, sizeof(remote._remoteHost));
+}
+
+// -1 if unsuccessful, else number of bytes received
+int UDPSocket::receiveFrom(Endpoint &remote, char *buffer, int length) {
+ if (_sock_fd < 0)
+ return -1;
+
+ if (!_blocking) {
+ TimeInterval timeout(_timeout);
+ if (wait_readable(timeout) != 0)
+ return 0;
+ }
+ remote.reset_address();
+ socklen_t remoteHostLen = sizeof(remote._remoteHost);
+ return lwip_recvfrom(_sock_fd, buffer, length, 0, (struct sockaddr*) &remote._remoteHost, &remoteHostLen);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.h
new file mode 100644
index 0000000000..734b256be8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/Socket/UDPSocket.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UDPSOCKET_H
+#define UDPSOCKET_H
+
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+
+/**
+UDP Socket
+*/
+class UDPSocket : public Socket {
+
+public:
+ /** Instantiate an UDP Socket.
+ */
+ UDPSocket();
+
+ /** Init the UDP Client Socket without binding it to any specific port
+ \return 0 on success, -1 on failure.
+ */
+ int init(void);
+
+ /** Bind a UDP Server Socket to a specific port
+ \param port The port to listen for incoming connections on
+ \return 0 on success, -1 on failure.
+ */
+ int bind(int port);
+
+ /** Join the multicast group at the given address
+ \param address The address of the multicast group
+ \return 0 on success, -1 on failure.
+ */
+ int join_multicast_group(const char* address);
+
+ /** Set the socket in broadcasting mode
+ \return 0 on success, -1 on failure.
+ */
+ int set_broadcasting(bool broadcast=true);
+
+ /** Send a packet to a remote endpoint
+ \param remote The remote endpoint
+ \param packet The packet to be sent
+ \param length The length of the packet to be sent
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int sendTo(Endpoint &remote, char *packet, int length);
+
+ /** Receive a packet from a remote endpoint
+ \param remote The remote endpoint
+ \param buffer The buffer for storing the incoming packet data. If a packet
+ is too long to fit in the supplied buffer, excess bytes are discarded
+ \param length The length of the buffer
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receiveFrom(Endpoint &remote, char *buffer, int length);
+};
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/cc.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/cc.h
new file mode 100644
index 0000000000..00b6782d3b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/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 <adam@sics.se>
+ *
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+#include <stdint.h>
+
+/* Types based on stdint.h */
+typedef uint8_t u8_t;
+typedef int8_t s8_t;
+typedef uint16_t u16_t;
+typedef int16_t s16_t;
+typedef uint32_t u32_t;
+typedef int32_t s32_t;
+typedef uintptr_t mem_ptr_t;
+
+/* Define (sn)printf formatters for these lwIP types */
+#define U16_F "hu"
+#define S16_F "hd"
+#define X16_F "hx"
+#define U32_F "lu"
+#define S32_F "ld"
+#define X32_F "lx"
+#define SZT_F "uz"
+
+/* ARM/LPC17xx is little endian only */
+#define BYTE_ORDER LITTLE_ENDIAN
+
+/* Use LWIP error codes */
+#define LWIP_PROVIDE_ERRNO
+
+#if defined(__arm__) && defined(__ARMCC_VERSION)
+ /* Keil uVision4 tools */
+ #define PACK_STRUCT_BEGIN __packed
+ #define PACK_STRUCT_STRUCT
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(fld) fld
+ #define ALIGNED(n) __align(n)
+#elif defined (__IAR_SYSTEMS_ICC__)
+ /* IAR Embedded Workbench tools */
+ #define PACK_STRUCT_BEGIN __packed
+ #define PACK_STRUCT_STRUCT
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(fld) fld
+ #define IAR_STR(a) #a
+ #define ALIGNED(n) _Pragma(IAR_STR(data_alignment= ## n ##))
+#else
+ /* GCC tools (CodeSourcery) */
+ #define PACK_STRUCT_BEGIN
+ #define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(fld) fld
+ #define ALIGNED(n) __attribute__((aligned (n)))
+#endif
+
+/* Provide Thumb-2 routines for GCC to improve performance */
+#if defined(TOOLCHAIN_GCC) && defined(__thumb2__)
+ #define MEMCPY(dst,src,len) thumb2_memcpy(dst,src,len)
+ #define LWIP_CHKSUM thumb2_checksum
+ /* Set algorithm to 0 so that unused lwip_standard_chksum function
+ doesn't generate compiler warning */
+ #define LWIP_CHKSUM_ALGORITHM 0
+
+ void* thumb2_memcpy(void* pDest, const void* pSource, size_t length);
+ u16_t thumb2_checksum(void* pData, int length);
+#else
+ /* Used with IP headers only */
+ #define LWIP_CHKSUM_ALGORITHM 1
+#endif
+
+
+#ifdef LWIP_DEBUG
+
+#include "stdio.h"
+
+void assert_printf(char *msg, int line, char *file);
+
+/* Plaform specific diagnostic output */
+#define LWIP_PLATFORM_DIAG(vars) printf vars
+#define LWIP_PLATFORM_ASSERT(flag) { assert_printf((flag), __LINE__, __FILE__); }
+#else
+#define LWIP_PLATFORM_DIAG(msg) { ; }
+#define LWIP_PLATFORM_ASSERT(flag) { ; }
+#endif
+
+#include "cmsis.h"
+#define LWIP_PLATFORM_HTONS(x) __REV16(x)
+#define LWIP_PLATFORM_HTONL(x) __REV(x)
+
+#endif /* __CC_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/checksum.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/checksum.c
new file mode 100644
index 0000000000..e97aef39d0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/checksum.c
@@ -0,0 +1,126 @@
+/* Copyright (C) 2013 - Adam Green (https://github.com/adamgreen)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#if defined(TOOLCHAIN_GCC) && defined(__thumb2__)
+
+
+/* This is a hand written Thumb-2 assembly language version of the
+ algorithm 3 version of lwip_standard_chksum in lwIP's inet_chksum.c. It
+ performs the checksumming 32-bits at a time and even unrolls the loop to
+ perform two of these 32-bit adds per loop iteration.
+
+ Returns:
+ 16-bit 1's complement summation (not inversed).
+
+ NOTE: This function does return a uint16_t from the assembly language code
+ but is marked as void so that GCC doesn't issue warning because it
+ doesn't know about this low level return.
+*/
+__attribute__((naked)) void /*uint16_t*/ thumb2_checksum(const void* pData, int length)
+{
+ __asm (
+ ".syntax unified\n"
+ ".thumb\n"
+
+ // Push non-volatile registers we use on stack. Push link register too to
+ // keep stack 8-byte aligned and allow single pop to restore and return.
+ " push {r4, lr}\n"
+ // Initialize sum, r2, to 0.
+ " movs r2, #0\n"
+ // Remember whether pData was at odd address in r3. This is used later to
+ // know if it needs to swap the result since the summation will be done at
+ // an offset of 1, rather than 0.
+ " ands r3, r0, #1\n"
+ // Need to 2-byte align? If not skip ahead.
+ " beq 1$\n"
+ // We can return if there are no bytes to sum.
+ " cbz r1, 9$\n"
+
+ // 2-byte align.
+ // Place the first data byte in odd summation location since it needs to be
+ // swapped later. It's ok to overwrite r2 here as it only had a value of 0
+ // up until now. Advance r0 pointer and decrement r1 length as we go.
+ " ldrb r2, [r0], #1\n"
+ " lsls r2, r2, #8\n"
+ " subs r1, r1, #1\n"
+
+ // Need to 4-byte align? If not skip ahead.
+ "1$:\n"
+ " ands r4, r0, #3\n"
+ " beq 2$\n"
+ // Have more than 1 byte left to align? If not skip ahead to take care of
+ // trailing byte.
+ " cmp r1, #2\n"
+ " blt 7$\n"
+
+ // 4-byte align.
+ " ldrh r4, [r0], #2\n"
+ " adds r2, r2, r4\n"
+ " subs r1, r1, #2\n"
+
+ // Main summing loop which sums up data 2 words at a time.
+ // Make sure that we have more than 7 bytes left to sum.
+ "2$:\n"
+ " cmp r1, #8\n"
+ " blt 3$\n"
+ // Sum next two words. Applying previous upper 16-bit carry to
+ // lower 16-bits.
+ " ldr r4, [r0], #4\n"
+ " adds r2, r4\n"
+ " adc r2, r2, #0\n"
+ " ldr r4, [r0], #4\n"
+ " adds r2, r4\n"
+ " adc r2, r2, #0\n"
+ " subs r1, r1, #8\n"
+ " b 2$\n"
+
+ // Sum up any remaining half-words.
+ "3$:\n"
+ // Make sure that we have more than 1 byte left to sum.
+ " cmp r1, #2\n"
+ " blt 7$\n"
+ // Sum up next half word, continue to apply carry.
+ " ldrh r4, [r0], #2\n"
+ " adds r2, r4\n"
+ " adc r2, r2, #0\n"
+ " subs r1, r1, #2\n"
+ " b 3$\n"
+
+ // Handle trailing byte, if it exists
+ "7$:\n"
+ " cbz r1, 8$\n"
+ " ldrb r4, [r0]\n"
+ " adds r2, r4\n"
+ " adc r2, r2, #0\n"
+
+ // Fold 32-bit checksum into 16-bit checksum.
+ "8$:\n"
+ " ubfx r4, r2, #16, #16\n"
+ " ubfx r2, r2, #0, #16\n"
+ " adds r2, r4\n"
+ " ubfx r4, r2, #16, #16\n"
+ " ubfx r2, r2, #0, #16\n"
+ " adds r2, r4\n"
+
+ // Swap bytes if started at odd address
+ " cbz r3, 9$\n"
+ " rev16 r2, r2\n"
+
+ // Return final sum.
+ "9$: mov r0, r2\n"
+ " pop {r4, pc}\n"
+ );
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/memcpy.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/memcpy.c
new file mode 100644
index 0000000000..fefbcda3c2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/memcpy.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2013 - Adam Green (https://github.com/adamgreen)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#if defined(TOOLCHAIN_GCC) && defined(__thumb2__)
+
+#include <stdio.h>
+
+
+/* This is a hand written Thumb-2 assembly language version of the
+ standard C memcpy() function that can be used by the lwIP networking
+ stack to improve its performance. It copies 4 bytes at a time and
+ unrolls the loop to perform 4 of these copies per loop iteration.
+*/
+__attribute__((naked)) void thumb2_memcpy(void* pDest, const void* pSource, size_t length)
+{
+ __asm (
+ ".syntax unified\n"
+ ".thumb\n"
+
+ // Copy 16 bytes at a time first.
+ " lsrs r3, r2, #4\n"
+ " beq.n 2$\n"
+ "1$: ldr r12, [r1], #4\n"
+ " str r12, [r0], #4\n"
+ " ldr r12, [r1], #4\n"
+ " str r12, [r0], #4\n"
+ " ldr r12, [r1], #4\n"
+ " str r12, [r0], #4\n"
+ " ldr r12, [r1], #4\n"
+ " str r12, [r0], #4\n"
+ " subs r3, #1\n"
+ " bne 1$\n"
+
+ // Copy byte by byte for what is left.
+ "2$:\n"
+ " ands r3, r2, #0xf\n"
+ " beq.n 4$\n"
+ "3$: ldrb r12, [r1], #1\n"
+ " strb r12, [r0], #1\n"
+ " subs r3, #1\n"
+ " bne 3$\n"
+
+ // Return to caller.
+ "4$: bx lr\n"
+ );
+}
+
+#endif
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/perf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/perf.h
new file mode 100644
index 0000000000..334d42af8c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/perf.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 <adam@sics.se>
+ *
+ */
+#ifndef __PERF_H__
+#define __PERF_H__
+
+#define PERF_START /* null definition */
+#define PERF_STOP(x) /* null definition */
+
+#endif /* __PERF_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.c
new file mode 100644
index 0000000000..331b0a2257
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.c
@@ -0,0 +1,463 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <string.h>
+
+/* mbed includes */
+#include "mbed_error.h"
+#include "mbed_interface.h"
+#include "us_ticker_api.h"
+
+/* lwIP includes. */
+#include "lwip/opt.h"
+#include "lwip/debug.h"
+#include "lwip/def.h"
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+
+ #if NO_SYS==1
+#include "cmsis.h"
+
+/* Saved total time in ms since timer was enabled */
+static volatile u32_t systick_timems;
+
+/* Enable systick rate and interrupt */
+void SysTick_Init(void) {
+ if (SysTick_Config(SystemCoreClock / 1000)) {
+ while (1); /* Capture error */
+ }
+}
+
+/** \brief SysTick IRQ handler and timebase management
+ *
+ * This function keeps a timebase for the sysTick that can be
+ * used for other functions. It also calls an external function
+ * (SysTick_User) that must be defined outside this handler.
+ */
+void SysTick_Handler(void) {
+ systick_timems++;
+}
+
+/* Delay for the specified number of milliSeconds */
+void osDelay(uint32_t ms) {
+ uint32_t to = ms + systick_timems;
+ while (to > systick_timems);
+}
+
+/* Returns the current time in mS. This is needed for the LWIP timers */
+u32_t sys_now(void) {
+ return (u32_t) systick_timems;
+}
+
+#else
+/* CMSIS-RTOS implementation of the lwip operating system abstraction */
+#include "arch/sys_arch.h"
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_mbox_new
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Creates a new mailbox
+ * Inputs:
+ * sys_mbox_t mbox -- Handle of mailbox
+ * int queue_sz -- Size of elements in the mailbox
+ * Outputs:
+ * err_t -- ERR_OK if message posted, else ERR_MEM
+ *---------------------------------------------------------------------------*/
+err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
+ if (queue_sz > MB_SIZE)
+ error("sys_mbox_new size error\n");
+
+#ifdef CMSIS_OS_RTX
+ memset(mbox->queue, 0, sizeof(mbox->queue));
+ mbox->def.pool = mbox->queue;
+ mbox->def.queue_sz = queue_sz;
+#endif
+ mbox->id = osMessageCreate(&mbox->def, NULL);
+ return (mbox->id == NULL) ? (ERR_MEM) : (ERR_OK);
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_mbox_free
+ *---------------------------------------------------------------------------*
+ * Description:
+ * 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.
+ * Inputs:
+ * sys_mbox_t *mbox -- Handle of mailbox
+ *---------------------------------------------------------------------------*/
+void sys_mbox_free(sys_mbox_t *mbox) {
+ osEvent event = osMessageGet(mbox->id, 0);
+ if (event.status == osEventMessage)
+ error("sys_mbox_free error\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_mbox_post
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Post the "msg" to the mailbox.
+ * Inputs:
+ * sys_mbox_t mbox -- Handle of mailbox
+ * void *msg -- Pointer to data to post
+ *---------------------------------------------------------------------------*/
+void sys_mbox_post(sys_mbox_t *mbox, void *msg) {
+ if (osMessagePut(mbox->id, (uint32_t)msg, osWaitForever) != osOK)
+ error("sys_mbox_post error\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_mbox_trypost
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Try to post the "msg" to the mailbox. Returns immediately with
+ * error if cannot.
+ * Inputs:
+ * sys_mbox_t mbox -- Handle of mailbox
+ * void *msg -- Pointer to data to post
+ * Outputs:
+ * err_t -- ERR_OK if message posted, else ERR_MEM
+ * if not.
+ *---------------------------------------------------------------------------*/
+err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) {
+ osStatus status = osMessagePut(mbox->id, (uint32_t)msg, 0);
+ return (status == osOK) ? (ERR_OK) : (ERR_MEM);
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_arch_mbox_fetch
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Blocks the thread until a message arrives in the mailbox, but does
+ * not block the thread longer than "timeout" milliseconds (similar to
+ * the sys_arch_sem_wait() function). The "msg" argument is a result
+ * parameter that is set by the function (i.e., by doing "*msg =
+ * ptr"). The "msg" parameter maybe NULL to indicate that the message
+ * should be dropped.
+ *
+ * The return values are the same as for the sys_arch_sem_wait() function:
+ * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
+ * timeout.
+ *
+ * Note that a function with a similar name, sys_mbox_fetch(), is
+ * implemented by lwIP.
+ * Inputs:
+ * sys_mbox_t mbox -- Handle of mailbox
+ * void **msg -- Pointer to pointer to msg received
+ * u32_t timeout -- Number of milliseconds until timeout
+ * Outputs:
+ * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number
+ * of milliseconds until received.
+ *---------------------------------------------------------------------------*/
+u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) {
+ u32_t start = us_ticker_read();
+
+ osEvent event = osMessageGet(mbox->id, (timeout != 0)?(timeout):(osWaitForever));
+ if (event.status != osEventMessage)
+ return SYS_ARCH_TIMEOUT;
+
+ *msg = (void *)event.value.v;
+
+ return (us_ticker_read() - start) / 1000;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_arch_mbox_tryfetch
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Similar to sys_arch_mbox_fetch, but if message is not ready
+ * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is
+ * returned.
+ * Inputs:
+ * sys_mbox_t mbox -- Handle of mailbox
+ * void **msg -- Pointer to pointer to msg received
+ * Outputs:
+ * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,
+ * return ERR_OK.
+ *---------------------------------------------------------------------------*/
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) {
+ osEvent event = osMessageGet(mbox->id, 0);
+ if (event.status != osEventMessage)
+ return SYS_MBOX_EMPTY;
+
+ *msg = (void *)event.value.v;
+
+ return ERR_OK;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_sem_new
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Creates and returns a new semaphore. The "ucCount" argument specifies
+ * the initial state of the semaphore.
+ * NOTE: Currently this routine only creates counts of 1 or 0
+ * Inputs:
+ * sys_sem_t sem -- Handle of semaphore
+ * u8_t count -- Initial count of semaphore
+ * Outputs:
+ * err_t -- ERR_OK if semaphore created
+ *---------------------------------------------------------------------------*/
+err_t sys_sem_new(sys_sem_t *sem, u8_t count) {
+#ifdef CMSIS_OS_RTX
+ memset(sem->data, 0, sizeof(uint32_t)*2);
+ sem->def.semaphore = sem->data;
+#endif
+ sem->id = osSemaphoreCreate(&sem->def, count);
+ if (sem->id == NULL)
+ error("sys_sem_new create error\n");
+
+ return ERR_OK;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_arch_sem_wait
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Blocks the thread while waiting for the semaphore to be
+ * signaled. If the "timeout" argument is non-zero, the thread should
+ * only be blocked for the specified time (measured in
+ * milliseconds).
+ *
+ * If the timeout argument is non-zero, the return value is the number of
+ * milliseconds spent waiting for the semaphore to be signaled. If the
+ * semaphore wasn't signaled within the specified time, the return value is
+ * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
+ * (i.e., it was already signaled), the function may return zero.
+ *
+ * Notice that lwIP implements a function with a similar name,
+ * sys_sem_wait(), that uses the sys_arch_sem_wait() function.
+ * Inputs:
+ * sys_sem_t sem -- Semaphore to wait on
+ * u32_t timeout -- Number of milliseconds until timeout
+ * Outputs:
+ * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.
+ *---------------------------------------------------------------------------*/
+u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) {
+ u32_t start = us_ticker_read();
+
+ if (osSemaphoreWait(sem->id, (timeout != 0)?(timeout):(osWaitForever)) < 1)
+ return SYS_ARCH_TIMEOUT;
+
+ return (us_ticker_read() - start) / 1000;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_sem_signal
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Signals (releases) a semaphore
+ * Inputs:
+ * sys_sem_t sem -- Semaphore to signal
+ *---------------------------------------------------------------------------*/
+void sys_sem_signal(sys_sem_t *data) {
+ if (osSemaphoreRelease(data->id) != osOK)
+ mbed_die(); /* Can be called by ISR do not use printf */
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_sem_free
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Deallocates a semaphore
+ * Inputs:
+ * sys_sem_t sem -- Semaphore to free
+ *---------------------------------------------------------------------------*/
+void sys_sem_free(sys_sem_t *sem) {}
+
+/** Create a new mutex
+ * @param mutex pointer to the mutex to create
+ * @return a new mutex */
+err_t sys_mutex_new(sys_mutex_t *mutex) {
+#ifdef CMSIS_OS_RTX
+ memset(mutex->data, 0, sizeof(int32_t)*3);
+ mutex->def.mutex = mutex->data;
+#endif
+ mutex->id = osMutexCreate(&mutex->def);
+ if (mutex->id == NULL)
+ return ERR_MEM;
+
+ return ERR_OK;
+}
+
+/** Lock a mutex
+ * @param mutex the mutex to lock */
+void sys_mutex_lock(sys_mutex_t *mutex) {
+ if (osMutexWait(mutex->id, osWaitForever) != osOK)
+ error("sys_mutex_lock error\n");
+}
+
+/** Unlock a mutex
+ * @param mutex the mutex to unlock */
+void sys_mutex_unlock(sys_mutex_t *mutex) {
+ if (osMutexRelease(mutex->id) != osOK)
+ error("sys_mutex_unlock error\n");
+}
+
+/** Delete a mutex
+ * @param mutex the mutex to delete */
+void sys_mutex_free(sys_mutex_t *mutex) {}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_init
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Initialize sys arch
+ *---------------------------------------------------------------------------*/
+osMutexId lwip_sys_mutex;
+osMutexDef(lwip_sys_mutex);
+
+void sys_init(void) {
+ us_ticker_read(); // Init sys tick
+ lwip_sys_mutex = osMutexCreate(osMutex(lwip_sys_mutex));
+ if (lwip_sys_mutex == NULL)
+ error("sys_init error\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_jiffies
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Used by PPP as a timestamp-ish value
+ *---------------------------------------------------------------------------*/
+u32_t sys_jiffies(void) {
+ static u32_t jiffies = 0;
+ jiffies += 1 + (us_ticker_read()/10000);
+ return jiffies;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_arch_protect
+ *---------------------------------------------------------------------------*
+ * Description:
+ * 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.
+ * Outputs:
+ * sys_prot_t -- Previous protection level (not used here)
+ *---------------------------------------------------------------------------*/
+sys_prot_t sys_arch_protect(void) {
+ if (osMutexWait(lwip_sys_mutex, osWaitForever) != osOK)
+ error("sys_arch_protect error\n");
+ return (sys_prot_t) 1;
+}
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_arch_unprotect
+ *---------------------------------------------------------------------------*
+ * Description:
+ * 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.
+ * Inputs:
+ * sys_prot_t -- Previous protection level (not used here)
+ *---------------------------------------------------------------------------*/
+void sys_arch_unprotect(sys_prot_t p) {
+ if (osMutexRelease(lwip_sys_mutex) != osOK)
+ error("sys_arch_unprotect error\n");
+}
+
+u32_t sys_now(void) {
+ return us_ticker_read() / 1000;
+}
+
+void sys_msleep(u32_t ms) {
+ osDelay(ms);
+}
+
+// Keep a pool of thread structures
+static int thread_pool_index = 0;
+static sys_thread_data_t thread_pool[SYS_THREAD_POOL_N];
+
+/*---------------------------------------------------------------------------*
+ * Routine: sys_thread_new
+ *---------------------------------------------------------------------------*
+ * Description:
+ * Starts a new thread with priority "prio" that will begin its
+ * execution in the function "thread()". The "arg" argument will be
+ * passed as an argument to the thread() function. The id of the new
+ * thread is returned. Both the id and the priority are system
+ * dependent.
+ * Inputs:
+ * char *name -- Name of thread
+ * void (*thread)(void *arg) -- Pointer to function to run.
+ * void *arg -- Argument passed into function
+ * int stacksize -- Required stack amount in bytes
+ * int priority -- Thread priority
+ * Outputs:
+ * sys_thread_t -- Pointer to thread handle.
+ *---------------------------------------------------------------------------*/
+sys_thread_t sys_thread_new(const char *pcName,
+ void (*thread)(void *arg),
+ void *arg, int stacksize, int priority) {
+ LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName));
+
+ if (thread_pool_index >= SYS_THREAD_POOL_N)
+ error("sys_thread_new number error\n");
+ sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index];
+ thread_pool_index++;
+
+#ifdef CMSIS_OS_RTX
+ t->def.pthread = (os_pthread)thread;
+ t->def.tpriority = (osPriority)priority;
+ t->def.stacksize = stacksize;
+#ifndef __MBED_CMSIS_RTOS_CA9
+ t->def.stack_pointer = (uint32_t*)malloc(stacksize);
+ if (t->def.stack_pointer == NULL) {
+ error("Error allocating the stack memory");
+ }
+#endif
+#endif
+ t->id = osThreadCreate(&t->def, arg);
+ if (t->id == NULL)
+ error("sys_thread_new create error\n");
+
+ return t;
+}
+
+#endif
+
+#ifdef LWIP_DEBUG
+
+/** \brief Displays an error message on assertion
+
+ This function will display an error message on an assertion
+ to the debug output.
+
+ \param[in] msg Error message to display
+ \param[in] line Line number in file with error
+ \param[in] file Filename with error
+ */
+void assert_printf(char *msg, int line, char *file) {
+ if (msg)
+ error("%s:%d in file %s\n", msg, line, file);
+ else
+ error("LWIP ASSERT\n");
+}
+
+#endif /* LWIP_DEBUG */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.h
new file mode 100644
index 0000000000..909532eb2f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip-sys/arch/sys_arch.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_SYS_ARCH_H__
+#define __ARCH_SYS_ARCH_H__
+
+#include "lwip/opt.h"
+
+#if NO_SYS == 0
+#include "cmsis_os.h"
+
+// === SEMAPHORE ===
+typedef struct {
+ osSemaphoreId id;
+ osSemaphoreDef_t def;
+#ifdef CMSIS_OS_RTX
+ uint32_t data[2];
+#endif
+} sys_sem_t;
+
+#define sys_sem_valid(x) (((*x).id == NULL) ? 0 : 1)
+#define sys_sem_set_invalid(x) ( (*x).id = NULL)
+
+// === MUTEX ===
+typedef struct {
+ osMutexId id;
+ osMutexDef_t def;
+#ifdef CMSIS_OS_RTX
+ int32_t data[3];
+#endif
+} sys_mutex_t;
+
+// === MAIL BOX ===
+#define MB_SIZE 8
+
+typedef struct {
+ osMessageQId id;
+ osMessageQDef_t def;
+#ifdef CMSIS_OS_RTX
+ uint32_t queue[4+MB_SIZE]; /* The +4 is required for RTX OS_MCB overhead. */
+#endif
+} sys_mbox_t;
+
+#define SYS_MBOX_NULL ((uint32_t) NULL)
+#define sys_mbox_valid(x) (((*x).id == NULL) ? 0 : 1 )
+#define sys_mbox_set_invalid(x) ( (*x).id = NULL )
+
+#if ((DEFAULT_RAW_RECVMBOX_SIZE) > (MB_SIZE)) || \
+ ((DEFAULT_UDP_RECVMBOX_SIZE) > (MB_SIZE)) || \
+ ((DEFAULT_TCP_RECVMBOX_SIZE) > (MB_SIZE)) || \
+ ((DEFAULT_ACCEPTMBOX_SIZE) > (MB_SIZE)) || \
+ ((TCPIP_MBOX_SIZE) > (MB_SIZE))
+# error Mailbox size not supported
+#endif
+
+// === THREAD ===
+typedef struct {
+ osThreadId id;
+ osThreadDef_t def;
+} sys_thread_data_t;
+typedef sys_thread_data_t* sys_thread_t;
+
+#define SYS_THREAD_POOL_N 6
+#define SYS_DEFAULT_THREAD_STACK_DEPTH DEFAULT_STACK_SIZE
+
+// === PROTECTION ===
+typedef int sys_prot_t;
+
+#else
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \brief Init systick to 1ms rate
+ *
+ * This init the systick to 1ms rate. This function is only used in standalone
+ * systems.
+ */
+void SysTick_Init(void);
+
+
+/** \brief Get the current systick time in milliSeconds
+ *
+ * Returns the current systick time in milliSeconds. This function is only
+ * used in standalone systems.
+ *
+ * /returns current systick time in milliSeconds
+ */
+uint32_t SysTick_GetMS(void);
+
+/** \brief Delay for the specified number of milliSeconds
+ *
+ * For standalone systems. This function will block for the specified
+ * number of milliSconds. For RTOS based systems, this function will delay
+ * the task by the specified number of milliSeconds.
+ *
+ * \param[in] ms Time in milliSeconds to delay
+ */
+void osDelay(uint32_t ms);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif /* __ARCH_SYS_ARCH_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/COPYING b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/COPYING
new file mode 100644
index 0000000000..e23898b5e8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/COPYING
@@ -0,0 +1,33 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_lib.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_lib.c
new file mode 100644
index 0000000000..b1a9e5253d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_lib.c
@@ -0,0 +1,740 @@
+/**
+ * @file
+ * Sequential API External module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+/* This is the part of the API that is linked with
+ the application */
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/api.h"
+#include "lwip/tcpip.h"
+#include "lwip/memp.h"
+
+#include "lwip/ip.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include <string.h>
+
+/**
+ * Create a new netconn (of a specific type) that has a callback function.
+ * The corresponding pcb is also created.
+ *
+ * @param t the type of 'connection' to create (@see enum netconn_type)
+ * @param proto the IP protocol for RAW IP pcbs
+ * @param callback a function to call on status changes (RX available, TX'ed)
+ * @return a newly allocated struct netconn or
+ * NULL on memory error
+ */
+struct netconn*
+netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
+{
+ struct netconn *conn;
+ struct api_msg msg;
+
+ conn = netconn_alloc(t, callback);
+ if (conn != NULL) {
+ msg.function = do_newconn;
+ msg.msg.msg.n.proto = proto;
+ msg.msg.conn = conn;
+ if (TCPIP_APIMSG(&msg) != ERR_OK) {
+ LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
+ LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
+ LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
+#if LWIP_TCP
+ LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
+#endif /* LWIP_TCP */
+ sys_sem_free(&conn->op_completed);
+ sys_mbox_free(&conn->recvmbox);
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+ }
+ return conn;
+}
+
+/**
+ * Close a netconn 'connection' and free its resources.
+ * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
+ * after this returns.
+ *
+ * @param conn the netconn to delete
+ * @return ERR_OK if the connection was deleted
+ */
+err_t
+netconn_delete(struct netconn *conn)
+{
+ struct api_msg msg;
+
+ /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
+ if (conn == NULL) {
+ return ERR_OK;
+ }
+
+ msg.function = do_delconn;
+ msg.msg.conn = conn;
+ tcpip_apimsg(&msg);
+
+ netconn_free(conn);
+
+ /* don't care for return value of do_delconn since it only calls void functions */
+
+ return ERR_OK;
+}
+
+/**
+ * Get the local or remote IP address and port of a netconn.
+ * For RAW netconns, this returns the protocol instead of a port!
+ *
+ * @param conn the netconn to query
+ * @param addr a pointer to which to save the IP address
+ * @param port a pointer to which to save the port (or protocol for RAW)
+ * @param local 1 to get the local IP address, 0 to get the remote one
+ * @return ERR_CONN for invalid connections
+ * ERR_OK if the information was retrieved
+ */
+err_t
+netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
+
+ msg.function = do_getaddr;
+ msg.msg.conn = conn;
+ msg.msg.msg.ad.ipaddr = addr;
+ msg.msg.msg.ad.port = port;
+ msg.msg.msg.ad.local = local;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Bind a netconn to a specific local IP address and port.
+ * Binding one netconn twice might not always be checked correctly!
+ *
+ * @param conn the netconn to bind
+ * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
+ * to bind to all addresses)
+ * @param port the local port to bind the netconn to (not used for RAW)
+ * @return ERR_OK if bound, any other err_t on failure
+ */
+err_t
+netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_bind;
+ msg.msg.conn = conn;
+ msg.msg.msg.bc.ipaddr = addr;
+ msg.msg.msg.bc.port = port;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Connect a netconn to a specific remote IP address and port.
+ *
+ * @param conn the netconn to connect
+ * @param addr the remote IP address to connect to
+ * @param port the remote port to connect to (no used for RAW)
+ * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
+ */
+err_t
+netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_connect;
+ msg.msg.conn = conn;
+ msg.msg.msg.bc.ipaddr = addr;
+ msg.msg.msg.bc.port = port;
+ /* This is the only function which need to not block tcpip_thread */
+ err = tcpip_apimsg(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Disconnect a netconn from its current peer (only valid for UDP netconns).
+ *
+ * @param conn the netconn to disconnect
+ * @return TODO: return value is not set here...
+ */
+err_t
+netconn_disconnect(struct netconn *conn)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_disconnect;
+ msg.msg.conn = conn;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Set a TCP netconn into listen mode
+ *
+ * @param conn the tcp netconn to set to listen mode
+ * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
+ * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
+ * don't return any error (yet?))
+ */
+err_t
+netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
+{
+#if LWIP_TCP
+ struct api_msg msg;
+ err_t err;
+
+ /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
+ LWIP_UNUSED_ARG(backlog);
+
+ LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_listen;
+ msg.msg.conn = conn;
+#if TCP_LISTEN_BACKLOG
+ msg.msg.msg.lb.backlog = backlog;
+#endif /* TCP_LISTEN_BACKLOG */
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(conn);
+ LWIP_UNUSED_ARG(backlog);
+ return ERR_ARG;
+#endif /* LWIP_TCP */
+}
+
+/**
+ * Accept a new connection on a TCP listening netconn.
+ *
+ * @param conn the TCP listen netconn
+ * @param new_conn pointer where the new connection is stored
+ * @return ERR_OK if a new connection has been received or an error
+ * code otherwise
+ */
+err_t
+netconn_accept(struct netconn *conn, struct netconn **new_conn)
+{
+#if LWIP_TCP
+ struct netconn *newconn;
+ err_t err;
+#if TCP_LISTEN_BACKLOG
+ struct api_msg msg;
+#endif /* TCP_LISTEN_BACKLOG */
+
+ LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
+ *new_conn = NULL;
+ LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
+
+ err = conn->last_err;
+ if (ERR_IS_FATAL(err)) {
+ /* don't recv on fatal errors: this might block the application task
+ waiting on acceptmbox forever! */
+ return err;
+ }
+
+#if LWIP_SO_RCVTIMEO
+ if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
+ NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
+ return ERR_TIMEOUT;
+ }
+#else
+ sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
+#endif /* LWIP_SO_RCVTIMEO*/
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
+
+ if (newconn == NULL) {
+ /* connection has been aborted */
+ NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
+ return ERR_ABRT;
+ }
+#if TCP_LISTEN_BACKLOG
+ /* Let the stack know that we have accepted the connection. */
+ msg.function = do_recv;
+ msg.msg.conn = conn;
+ /* don't care for the return value of do_recv */
+ TCPIP_APIMSG(&msg);
+#endif /* TCP_LISTEN_BACKLOG */
+
+ *new_conn = newconn;
+ /* don't set conn->last_err: it's only ERR_OK, anyway */
+ return ERR_OK;
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(conn);
+ LWIP_UNUSED_ARG(new_conn);
+ return ERR_ARG;
+#endif /* LWIP_TCP */
+}
+
+/**
+ * Receive data: actual implementation that doesn't care whether pbuf or netbuf
+ * is received
+ *
+ * @param conn the netconn from which to receive data
+ * @param new_buf pointer where a new pbuf/netbuf is stored when received data
+ * @return ERR_OK if data has been received, an error code otherwise (timeout,
+ * memory error or another error)
+ */
+static err_t
+netconn_recv_data(struct netconn *conn, void **new_buf)
+{
+ void *buf = NULL;
+ u16_t len;
+ err_t err;
+#if LWIP_TCP
+ struct api_msg msg;
+#endif /* LWIP_TCP */
+
+ LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
+ *new_buf = NULL;
+ LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
+
+ err = conn->last_err;
+ if (ERR_IS_FATAL(err)) {
+ /* don't recv on fatal errors: this might block the application task
+ waiting on recvmbox forever! */
+ /* @todo: this does not allow us to fetch data that has been put into recvmbox
+ before the fatal error occurred - is that a problem? */
+ return err;
+ }
+
+#if LWIP_SO_RCVTIMEO
+ if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
+ NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
+ return ERR_TIMEOUT;
+ }
+#else
+ sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
+#endif /* LWIP_SO_RCVTIMEO*/
+
+#if LWIP_TCP
+ if (conn->type == NETCONN_TCP) {
+ if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
+ /* Let the stack know that we have taken the data. */
+ /* TODO: Speedup: Don't block and wait for the answer here
+ (to prevent multiple thread-switches). */
+ msg.function = do_recv;
+ msg.msg.conn = conn;
+ if (buf != NULL) {
+ msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
+ } else {
+ msg.msg.msg.r.len = 1;
+ }
+ /* don't care for the return value of do_recv */
+ TCPIP_APIMSG(&msg);
+ }
+
+ /* If we are closed, we indicate that we no longer wish to use the socket */
+ if (buf == NULL) {
+ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
+ /* Avoid to lose any previous error code */
+ NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
+ return ERR_CLSD;
+ }
+ len = ((struct pbuf *)buf)->tot_len;
+ }
+#endif /* LWIP_TCP */
+#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
+ else
+#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
+#if (LWIP_UDP || LWIP_RAW)
+ {
+ LWIP_ASSERT("buf != NULL", buf != NULL);
+ len = netbuf_len((struct netbuf *)buf);
+ }
+#endif /* (LWIP_UDP || LWIP_RAW) */
+
+#if LWIP_SO_RCVBUF
+ SYS_ARCH_DEC(conn->recv_avail, len);
+#endif /* LWIP_SO_RCVBUF */
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
+
+ LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
+
+ *new_buf = buf;
+ /* don't set conn->last_err: it's only ERR_OK, anyway */
+ return ERR_OK;
+}
+
+/**
+ * Receive data (in form of a pbuf) from a TCP netconn
+ *
+ * @param conn the netconn from which to receive data
+ * @param new_buf pointer where a new pbuf is stored when received data
+ * @return ERR_OK if data has been received, an error code otherwise (timeout,
+ * memory error or another error)
+ * ERR_ARG if conn is not a TCP netconn
+ */
+err_t
+netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
+{
+ LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
+ netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
+
+ return netconn_recv_data(conn, (void **)new_buf);
+}
+
+/**
+ * Receive data (in form of a netbuf containing a packet buffer) from a netconn
+ *
+ * @param conn the netconn from which to receive data
+ * @param new_buf pointer where a new netbuf is stored when received data
+ * @return ERR_OK if data has been received, an error code otherwise (timeout,
+ * memory error or another error)
+ */
+err_t
+netconn_recv(struct netconn *conn, struct netbuf **new_buf)
+{
+#if LWIP_TCP
+ struct netbuf *buf = NULL;
+ err_t err;
+#endif /* LWIP_TCP */
+
+ LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
+ *new_buf = NULL;
+ LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
+
+#if LWIP_TCP
+ if (conn->type == NETCONN_TCP) {
+ struct pbuf *p = NULL;
+ /* This is not a listening netconn, since recvmbox is set */
+
+ buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
+ if (buf == NULL) {
+ NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
+ return ERR_MEM;
+ }
+
+ err = netconn_recv_data(conn, (void **)&p);
+ if (err != ERR_OK) {
+ memp_free(MEMP_NETBUF, buf);
+ return err;
+ }
+ LWIP_ASSERT("p != NULL", p != NULL);
+
+ buf->p = p;
+ buf->ptr = p;
+ buf->port = 0;
+ ip_addr_set_any(&buf->addr);
+ *new_buf = buf;
+ /* don't set conn->last_err: it's only ERR_OK, anyway */
+ return ERR_OK;
+ } else
+#endif /* LWIP_TCP */
+ {
+#if (LWIP_UDP || LWIP_RAW)
+ return netconn_recv_data(conn, (void **)new_buf);
+#endif /* (LWIP_UDP || LWIP_RAW) */
+ }
+}
+
+/**
+ * TCP: update the receive window: by calling this, the application
+ * tells the stack that it has processed data and is able to accept
+ * new data.
+ * ATTENTION: use with care, this is mainly used for sockets!
+ * Can only be used when calling netconn_set_noautorecved(conn, 1) before.
+ *
+ * @param conn the netconn for which to update the receive window
+ * @param length amount of data processed (ATTENTION: this must be accurate!)
+ */
+void
+netconn_recved(struct netconn *conn, u32_t length)
+{
+#if LWIP_TCP
+ if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
+ (netconn_get_noautorecved(conn))) {
+ struct api_msg msg;
+ /* Let the stack know that we have taken the data. */
+ /* TODO: Speedup: Don't block and wait for the answer here
+ (to prevent multiple thread-switches). */
+ msg.function = do_recv;
+ msg.msg.conn = conn;
+ msg.msg.msg.r.len = length;
+ /* don't care for the return value of do_recv */
+ TCPIP_APIMSG(&msg);
+ }
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(conn);
+ LWIP_UNUSED_ARG(length);
+#endif /* LWIP_TCP */
+}
+
+/**
+ * Send data (in form of a netbuf) to a specific remote IP address and port.
+ * Only to be used for UDP and RAW netconns (not TCP).
+ *
+ * @param conn the netconn over which to send data
+ * @param buf a netbuf containing the data to send
+ * @param addr the remote IP address to which to send the data
+ * @param port the remote port to which to send the data
+ * @return ERR_OK if data was sent, any other err_t on error
+ */
+err_t
+netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
+{
+ if (buf != NULL) {
+ ip_addr_set(&buf->addr, addr);
+ buf->port = port;
+ return netconn_send(conn, buf);
+ }
+ return ERR_VAL;
+}
+
+/**
+ * Send data over a UDP or RAW netconn (that is already connected).
+ *
+ * @param conn the UDP or RAW netconn over which to send data
+ * @param buf a netbuf containing the data to send
+ * @return ERR_OK if data was sent, any other err_t on error
+ */
+err_t
+netconn_send(struct netconn *conn, struct netbuf *buf)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
+ msg.function = do_send;
+ msg.msg.conn = conn;
+ msg.msg.msg.b = buf;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Send data over a TCP netconn.
+ *
+ * @param conn the TCP netconn over which to send data
+ * @param dataptr pointer to the application buffer that contains the data to send
+ * @param size size of the application data to send
+ * @param apiflags combination of following flags :
+ * - NETCONN_COPY: data will be copied into memory belonging to the stack
+ * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
+ * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
+ * @return ERR_OK if data was sent, any other err_t on error
+ */
+err_t
+netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
+ if (size == 0) {
+ return ERR_OK;
+ }
+
+ /* @todo: for non-blocking write, check if 'size' would ever fit into
+ snd_queue or snd_buf */
+ msg.function = do_write;
+ msg.msg.conn = conn;
+ msg.msg.msg.w.dataptr = dataptr;
+ msg.msg.msg.w.apiflags = apiflags;
+ msg.msg.msg.w.len = size;
+ /* 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. */
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Close ot shutdown a TCP netconn (doesn't delete it).
+ *
+ * @param conn the TCP netconn to close or shutdown
+ * @param how fully close or only shutdown one side?
+ * @return ERR_OK if the netconn was closed, any other err_t on error
+ */
+static err_t
+netconn_close_shutdown(struct netconn *conn, u8_t how)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_close;
+ msg.msg.conn = conn;
+ /* shutting down both ends is the same as closing */
+ msg.msg.msg.sd.shut = how;
+ /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
+ don't use TCPIP_APIMSG here */
+ err = tcpip_apimsg(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Close a TCP netconn (doesn't delete it).
+ *
+ * @param conn the TCP netconn to close
+ * @return ERR_OK if the netconn was closed, any other err_t on error
+ */
+err_t
+netconn_close(struct netconn *conn)
+{
+ /* shutting down both ends is the same as closing */
+ return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
+}
+
+/**
+ * Shut down one or both sides of a TCP netconn (doesn't delete it).
+ *
+ * @param conn the TCP netconn to shut down
+ * @return ERR_OK if the netconn was closed, any other err_t on error
+ */
+err_t
+netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
+{
+ return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
+}
+
+#if LWIP_IGMP
+/**
+ * Join multicast groups for UDP netconns.
+ *
+ * @param conn the UDP netconn for which to change multicast addresses
+ * @param multiaddr IP address of the multicast group to join or leave
+ * @param netif_addr the IP address of the network interface on which to send
+ * the igmp message
+ * @param join_or_leave flag whether to send a join- or leave-message
+ * @return ERR_OK if the action was taken, any err_t on error
+ */
+err_t
+netconn_join_leave_group(struct netconn *conn,
+ ip_addr_t *multiaddr,
+ ip_addr_t *netif_addr,
+ enum netconn_igmp join_or_leave)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_join_leave_group;
+ msg.msg.conn = conn;
+ msg.msg.msg.jl.multiaddr = multiaddr;
+ msg.msg.msg.jl.netif_addr = netif_addr;
+ msg.msg.msg.jl.join_or_leave = join_or_leave;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+#endif /* LWIP_IGMP */
+
+#if LWIP_DNS
+/**
+ * Execute a DNS query, only one IP address is returned
+ *
+ * @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
+ * @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
+ */
+err_t
+netconn_gethostbyname(const char *name, ip_addr_t *addr)
+{
+ struct dns_api_msg msg;
+ err_t err;
+ sys_sem_t sem;
+
+ LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
+
+ err = sys_sem_new(&sem, 0);
+ if (err != ERR_OK) {
+ return err;
+ }
+
+ msg.name = name;
+ msg.addr = addr;
+ msg.err = &err;
+ msg.sem = &sem;
+
+ tcpip_callback(do_gethostbyname, &msg);
+ sys_sem_wait(&sem);
+ sys_sem_free(&sem);
+
+ return err;
+}
+#endif /* LWIP_DNS*/
+
+#endif /* LWIP_NETCONN */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_msg.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_msg.c
new file mode 100644
index 0000000000..448f96dda0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/api_msg.c
@@ -0,0 +1,1535 @@
+/**
+ * @file
+ * Sequential API Internal module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/api_msg.h"
+
+#include "lwip/ip.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+#include "lwip/raw.h"
+
+#include "lwip/memp.h"
+#include "lwip/tcpip.h"
+#include "lwip/igmp.h"
+#include "lwip/dns.h"
+
+#include <string.h>
+
+#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \
+ (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
+} else { \
+ (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
+#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
+
+/* forward declarations */
+#if LWIP_TCP
+static err_t do_writemore(struct netconn *conn);
+static void do_close_internal(struct netconn *conn);
+#endif
+
+#if LWIP_RAW
+/**
+ * Receive callback function for RAW netconns.
+ * Doesn't 'eat' the packet, only references it and sends it to
+ * conn->recvmbox
+ *
+ * @see raw.h (struct raw_pcb.recv) for parameters and return value
+ */
+static u8_t
+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+ ip_addr_t *addr)
+{
+ struct pbuf *q;
+ struct netbuf *buf;
+ struct netconn *conn;
+
+ LWIP_UNUSED_ARG(addr);
+ conn = (struct netconn *)arg;
+
+ if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
+#if LWIP_SO_RCVBUF
+ int recv_avail;
+ SYS_ARCH_GET(conn->recv_avail, recv_avail);
+ if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
+ return 0;
+ }
+#endif /* LWIP_SO_RCVBUF */
+ /* copy the whole packet into new pbufs */
+ q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+ if(q != NULL) {
+ if (pbuf_copy(q, p) != ERR_OK) {
+ pbuf_free(q);
+ q = NULL;
+ }
+ }
+
+ if (q != NULL) {
+ u16_t len;
+ buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
+ if (buf == NULL) {
+ pbuf_free(q);
+ return 0;
+ }
+
+ buf->p = q;
+ buf->ptr = q;
+ ip_addr_copy(buf->addr, *ip_current_src_addr());
+ buf->port = pcb->protocol;
+
+ len = q->tot_len;
+ if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
+ netbuf_delete(buf);
+ return 0;
+ } else {
+#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);
+ }
+ }
+ }
+
+ return 0; /* do not eat the packet */
+}
+#endif /* LWIP_RAW*/
+
+#if LWIP_UDP
+/**
+ * Receive callback function for UDP netconns.
+ * Posts the packet to conn->recvmbox or deletes it on memory error.
+ *
+ * @see udp.h (struct udp_pcb.recv) for parameters
+ */
+static void
+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *addr, u16_t port)
+{
+ struct netbuf *buf;
+ struct netconn *conn;
+ u16_t len;
+#if LWIP_SO_RCVBUF
+ int recv_avail;
+#endif /* LWIP_SO_RCVBUF */
+
+ LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
+ LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
+ LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
+ conn = (struct netconn *)arg;
+ LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
+
+#if LWIP_SO_RCVBUF
+ SYS_ARCH_GET(conn->recv_avail, recv_avail);
+ if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
+ ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
+#else /* LWIP_SO_RCVBUF */
+ if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
+#endif /* LWIP_SO_RCVBUF */
+ pbuf_free(p);
+ return;
+ }
+
+ buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
+ if (buf == NULL) {
+ pbuf_free(p);
+ return;
+ } else {
+ buf->p = p;
+ buf->ptr = p;
+ ip_addr_set(&buf->addr, addr);
+ buf->port = port;
+#if LWIP_NETBUF_RECVINFO
+ {
+ const struct ip_hdr* iphdr = ip_current_header();
+ /* get the UDP header - always in the first pbuf, ensured by udp_input */
+ const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
+#if LWIP_CHECKSUM_ON_COPY
+ buf->flags = NETBUF_FLAG_DESTADDR;
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ ip_addr_set(&buf->toaddr, ip_current_dest_addr());
+ buf->toport_chksum = udphdr->dest;
+ }
+#endif /* LWIP_NETBUF_RECVINFO */
+ }
+
+ len = p->tot_len;
+ if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
+ netbuf_delete(buf);
+ return;
+ } else {
+#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);
+ }
+}
+#endif /* LWIP_UDP */
+
+#if LWIP_TCP
+/**
+ * Receive callback function for TCP netconns.
+ * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
+ *
+ * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
+ */
+static err_t
+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+ struct netconn *conn;
+ u16_t len;
+
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
+ LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
+ conn = (struct netconn *)arg;
+ LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+ if (!sys_mbox_valid(&conn->recvmbox)) {
+ /* recvmbox already deleted */
+ if (p != NULL) {
+ tcp_recved(pcb, p->tot_len);
+ pbuf_free(p);
+ }
+ return ERR_OK;
+ }
+ /* Unlike for UDP or RAW pcbs, don't check for available space
+ using recv_avail since that could break the connection
+ (data is already ACKed) */
+
+ /* don't overwrite fatal errors! */
+ NETCONN_SET_SAFE_ERR(conn, err);
+
+ if (p != NULL) {
+ len = p->tot_len;
+ } else {
+ len = 0;
+ }
+
+ if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
+ /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
+ return ERR_MEM;
+ } else {
+#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);
+ }
+
+ return ERR_OK;
+}
+
+/**
+ * Poll callback function for TCP netconns.
+ * Wakes up an application thread that waits for a connection to close
+ * or data to be sent. The application thread then takes the
+ * appropriate action to go on.
+ *
+ * Signals the conn->sem.
+ * netconn_close waits for conn->sem if closing failed.
+ *
+ * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
+ */
+static err_t
+poll_tcp(void *arg, struct tcp_pcb *pcb)
+{
+ struct netconn *conn = (struct netconn *)arg;
+
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_ASSERT("conn != NULL", (conn != NULL));
+
+ if (conn->state == NETCONN_WRITE) {
+ do_writemore(conn);
+ } else if (conn->state == NETCONN_CLOSE) {
+ do_close_internal(conn);
+ }
+ /* @todo: implement connect timeout here? */
+
+ /* Did a nonblocking write fail before? Then check available write-space. */
+ if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
+ /* 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)) {
+ conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
+ API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+ }
+ }
+
+ return ERR_OK;
+}
+
+/**
+ * Sent callback function for TCP netconns.
+ * Signals the conn->sem and calls API_EVENT.
+ * netconn_write waits for conn->sem if send buffer is low.
+ *
+ * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
+ */
+static err_t
+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+ struct netconn *conn = (struct netconn *)arg;
+
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_ASSERT("conn != NULL", (conn != NULL));
+
+ if (conn->state == NETCONN_WRITE) {
+ do_writemore(conn);
+ } else if (conn->state == NETCONN_CLOSE) {
+ do_close_internal(conn);
+ }
+
+ if (conn) {
+ /* 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)) {
+ conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
+ API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
+ }
+ }
+
+ return ERR_OK;
+}
+
+/**
+ * Error callback function for TCP netconns.
+ * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
+ * The application thread has then to decide what to do.
+ *
+ * @see tcp.h (struct tcp_pcb.err) for parameters
+ */
+static void
+err_tcp(void *arg, err_t err)
+{
+ struct netconn *conn;
+ enum netconn_state old_state;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ conn = (struct netconn *)arg;
+ LWIP_ASSERT("conn != NULL", (conn != NULL));
+
+ conn->pcb.tcp = NULL;
+
+ /* no check since this is always fatal! */
+ SYS_ARCH_PROTECT(lev);
+ conn->last_err = err;
+ SYS_ARCH_UNPROTECT(lev);
+
+ /* reset conn->state now before waking up other threads */
+ old_state = conn->state;
+ conn->state = NETCONN_NONE;
+
+ /* Notify the user layer about a connection error. Used to signal
+ select. */
+ API_EVENT(conn, NETCONN_EVT_ERROR, 0);
+ /* Try to release selects pending on 'read' or 'write', too.
+ They will get an error if they actually try to read or write. */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
+ API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+
+ /* pass NULL-message to recvmbox to wake up pending recv */
+ if (sys_mbox_valid(&conn->recvmbox)) {
+ /* use trypost to prevent deadlock */
+ sys_mbox_trypost(&conn->recvmbox, NULL);
+ }
+ /* pass NULL-message to acceptmbox to wake up pending accept */
+ if (sys_mbox_valid(&conn->acceptmbox)) {
+ /* use trypost to preven deadlock */
+ sys_mbox_trypost(&conn->acceptmbox, NULL);
+ }
+
+ if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
+ (old_state == NETCONN_CONNECT)) {
+ /* calling do_writemore/do_close_internal is not necessary
+ since the pcb has already been deleted! */
+ int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
+ SET_NONBLOCKING_CONNECT(conn, 0);
+
+ if (!was_nonblocking_connect) {
+ /* set error return code */
+ LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
+ conn->current_msg->err = err;
+ conn->current_msg = NULL;
+ /* wake up the waiting task */
+ sys_sem_signal(&conn->op_completed);
+ }
+ } else {
+ LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
+ }
+}
+
+/**
+ * Setup a tcp_pcb with the correct callback function pointers
+ * and their arguments.
+ *
+ * @param conn the TCP netconn to setup
+ */
+static void
+setup_tcp(struct netconn *conn)
+{
+ struct tcp_pcb *pcb;
+
+ pcb = conn->pcb.tcp;
+ tcp_arg(pcb, conn);
+ tcp_recv(pcb, recv_tcp);
+ tcp_sent(pcb, sent_tcp);
+ tcp_poll(pcb, poll_tcp, 4);
+ tcp_err(pcb, err_tcp);
+}
+
+/**
+ * Accept callback function for TCP netconns.
+ * Allocates a new netconn and posts that to conn->acceptmbox.
+ *
+ * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
+ */
+static err_t
+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+ struct netconn *newconn;
+ struct netconn *conn = (struct netconn *)arg;
+
+ LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
+
+ if (!sys_mbox_valid(&conn->acceptmbox)) {
+ LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
+ return ERR_VAL;
+ }
+
+ /* We have to set the callback here even though
+ * the new socket is unknown. conn->socket is marked as -1. */
+ newconn = netconn_alloc(conn->type, conn->callback);
+ if (newconn == NULL) {
+ return ERR_MEM;
+ }
+ newconn->pcb.tcp = newpcb;
+ setup_tcp(newconn);
+ /* no protection: when creating the pcb, the netconn is not yet known
+ to the application thread */
+ newconn->last_err = err;
+
+ if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
+ /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
+ so do nothing here! */
+ newconn->pcb.tcp = NULL;
+ /* no need to drain since we know the recvmbox is empty. */
+ sys_mbox_free(&newconn->recvmbox);
+ sys_mbox_set_invalid(&newconn->recvmbox);
+ netconn_free(newconn);
+ return ERR_MEM;
+ } else {
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
+ }
+
+ return ERR_OK;
+}
+#endif /* LWIP_TCP */
+
+/**
+ * Create a new pcb of a specific type.
+ * Called from do_newconn().
+ *
+ * @param msg the api_msg_msg describing the connection type
+ * @return msg->conn->err, but the return value is currently ignored
+ */
+static void
+pcb_new(struct api_msg_msg *msg)
+{
+ LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
+
+ /* Allocate a PCB for this connection */
+ switch(NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
+ if(msg->conn->pcb.raw == NULL) {
+ msg->err = ERR_MEM;
+ break;
+ }
+ raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ msg->conn->pcb.udp = udp_new();
+ if(msg->conn->pcb.udp == NULL) {
+ msg->err = ERR_MEM;
+ break;
+ }
+#if LWIP_UDPLITE
+ if (msg->conn->type==NETCONN_UDPLITE) {
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+ }
+#endif /* LWIP_UDPLITE */
+ if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+ }
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->conn->pcb.tcp = tcp_new();
+ if(msg->conn->pcb.tcp == NULL) {
+ msg->err = ERR_MEM;
+ break;
+ }
+ setup_tcp(msg->conn);
+ break;
+#endif /* LWIP_TCP */
+ default:
+ /* Unsupported netconn type, e.g. protocol disabled */
+ msg->err = ERR_VAL;
+ break;
+ }
+}
+
+/**
+ * Create a new pcb of a specific type inside a netconn.
+ * Called from netconn_new_with_proto_and_callback.
+ *
+ * @param msg the api_msg_msg describing the connection type
+ */
+void
+do_newconn(struct api_msg_msg *msg)
+{
+ msg->err = ERR_OK;
+ if(msg->conn->pcb.tcp == NULL) {
+ pcb_new(msg);
+ }
+ /* Else? This "new" connection already has a PCB allocated. */
+ /* Is this an error condition? Should it be deleted? */
+ /* We currently just are happy and return. */
+
+ TCPIP_APIMSG_ACK(msg);
+}
+
+/**
+ * Create a new netconn (of a specific type) that has a callback function.
+ * The corresponding pcb is NOT created!
+ *
+ * @param t the type of 'connection' to create (@see enum netconn_type)
+ * @param proto the IP protocol for RAW IP pcbs
+ * @param callback a function to call on status changes (RX available, TX'ed)
+ * @return a newly allocated struct netconn or
+ * NULL on memory error
+ */
+struct netconn*
+netconn_alloc(enum netconn_type t, netconn_callback callback)
+{
+ struct netconn *conn;
+ int size;
+
+ conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
+ if (conn == NULL) {
+ return NULL;
+ }
+
+ conn->last_err = ERR_OK;
+ conn->type = t;
+ conn->pcb.tcp = NULL;
+
+#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
+ (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
+ size = DEFAULT_RAW_RECVMBOX_SIZE;
+#else
+ switch(NETCONNTYPE_GROUP(t)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ size = DEFAULT_RAW_RECVMBOX_SIZE;
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ size = DEFAULT_UDP_RECVMBOX_SIZE;
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ size = DEFAULT_TCP_RECVMBOX_SIZE;
+ break;
+#endif /* LWIP_TCP */
+ default:
+ LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
+ break;
+ }
+#endif
+
+ if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+ if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
+ sys_sem_free(&conn->op_completed);
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+
+#if LWIP_TCP
+ 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 = callback;
+#if LWIP_TCP
+ conn->current_msg = NULL;
+ conn->write_offset = 0;
+#endif /* LWIP_TCP */
+#if LWIP_SO_RCVTIMEO
+ conn->recv_timeout = 0;
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
+ conn->recv_avail = 0;
+#endif /* LWIP_SO_RCVBUF */
+ conn->flags = 0;
+ return conn;
+}
+
+/**
+ * Delete a netconn and all its resources.
+ * The pcb is NOT freed (since we might not be in the right thread context do this).
+ *
+ * @param conn the netconn to free
+ */
+void
+netconn_free(struct netconn *conn)
+{
+ LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
+ LWIP_ASSERT("recvmbox must be deallocated before calling this function",
+ !sys_mbox_valid(&conn->recvmbox));
+#if LWIP_TCP
+ LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
+ !sys_mbox_valid(&conn->acceptmbox));
+#endif /* LWIP_TCP */
+
+ sys_sem_free(&conn->op_completed);
+ sys_sem_set_invalid(&conn->op_completed);
+
+ memp_free(MEMP_NETCONN, conn);
+}
+
+/**
+ * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
+ * these mboxes
+ *
+ * @param conn the netconn to free
+ * @bytes_drained bytes drained from recvmbox
+ * @accepts_drained pending connections drained from acceptmbox
+ */
+static void
+netconn_drain(struct netconn *conn)
+{
+ void *mem;
+#if LWIP_TCP
+ struct pbuf *p;
+#endif /* LWIP_TCP */
+
+ /* This runs in tcpip_thread, so we don't need to lock against rx packets */
+
+ /* Delete and drain the recvmbox. */
+ if (sys_mbox_valid(&conn->recvmbox)) {
+ while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
+#if LWIP_TCP
+ if (conn->type == NETCONN_TCP) {
+ if(mem != NULL) {
+ p = (struct pbuf*)mem;
+ /* pcb might be set to NULL already by err_tcp() */
+ if (conn->pcb.tcp != NULL) {
+ tcp_recved(conn->pcb.tcp, p->tot_len);
+ }
+ pbuf_free(p);
+ }
+ } else
+#endif /* LWIP_TCP */
+ {
+ netbuf_delete((struct netbuf *)mem);
+ }
+ }
+ sys_mbox_free(&conn->recvmbox);
+ sys_mbox_set_invalid(&conn->recvmbox);
+ }
+
+ /* Delete and drain the acceptmbox. */
+#if LWIP_TCP
+ if (sys_mbox_valid(&conn->acceptmbox)) {
+ while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
+ struct netconn *newconn = (struct netconn *)mem;
+ /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
+ /* pcb might be set to NULL already by err_tcp() */
+ if (conn->pcb.tcp != NULL) {
+ tcp_accepted(conn->pcb.tcp);
+ }
+ /* drain recvmbox */
+ netconn_drain(newconn);
+ if (newconn->pcb.tcp != NULL) {
+ tcp_abort(newconn->pcb.tcp);
+ newconn->pcb.tcp = NULL;
+ }
+ netconn_free(newconn);
+ }
+ sys_mbox_free(&conn->acceptmbox);
+ sys_mbox_set_invalid(&conn->acceptmbox);
+ }
+#endif /* LWIP_TCP */
+}
+
+#if LWIP_TCP
+/**
+ * Internal helper function to close a TCP netconn: since this sometimes
+ * doesn't work at the first attempt, this function is called from multiple
+ * places.
+ *
+ * @param conn the TCP netconn to close
+ */
+static void
+do_close_internal(struct netconn *conn)
+{
+ err_t err;
+ u8_t shut, shut_rx, shut_tx, close;
+
+ LWIP_ASSERT("invalid conn", (conn != NULL));
+ LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
+ LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
+ LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
+ LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
+
+ shut = conn->current_msg->msg.sd.shut;
+ shut_rx = shut & NETCONN_SHUT_RD;
+ shut_tx = shut & NETCONN_SHUT_WR;
+ /* shutting down both ends is the same as closing */
+ close = shut == NETCONN_SHUT_RDWR;
+
+ /* Set back some callback pointers */
+ if (close) {
+ tcp_arg(conn->pcb.tcp, NULL);
+ }
+ if (conn->pcb.tcp->state == LISTEN) {
+ tcp_accept(conn->pcb.tcp, NULL);
+ } else {
+ /* some callbacks have to be reset if tcp_close is not successful */
+ if (shut_rx) {
+ tcp_recv(conn->pcb.tcp, NULL);
+ tcp_accept(conn->pcb.tcp, NULL);
+ }
+ if (shut_tx) {
+ tcp_sent(conn->pcb.tcp, NULL);
+ }
+ if (close) {
+ tcp_poll(conn->pcb.tcp, NULL, 4);
+ tcp_err(conn->pcb.tcp, NULL);
+ }
+ }
+ /* Try to close the connection */
+ if (shut == NETCONN_SHUT_RDWR) {
+ err = tcp_close(conn->pcb.tcp);
+ } else {
+ err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
+ }
+ if (err == ERR_OK) {
+ /* Closing succeeded */
+ conn->current_msg->err = ERR_OK;
+ conn->current_msg = NULL;
+ conn->state = NETCONN_NONE;
+ /* Set back some callback pointers as conn is going away */
+ conn->pcb.tcp = NULL;
+ /* Trigger select() in socket layer. Make sure everybody notices activity
+ on the connection, error first! */
+ if (close) {
+ API_EVENT(conn, NETCONN_EVT_ERROR, 0);
+ }
+ if (shut_rx) {
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
+ }
+ if (shut_tx) {
+ API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+ }
+ /* wake up the application task */
+ sys_sem_signal(&conn->op_completed);
+ } else {
+ /* Closing failed, restore some of the callbacks */
+ /* Closing of listen pcb will never fail! */
+ LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
+ tcp_sent(conn->pcb.tcp, sent_tcp);
+ tcp_poll(conn->pcb.tcp, poll_tcp, 4);
+ tcp_err(conn->pcb.tcp, err_tcp);
+ tcp_arg(conn->pcb.tcp, conn);
+ /* don't restore recv callback: we don't want to receive any more data */
+ }
+ /* If closing didn't succeed, we get called again either
+ from poll_tcp or from sent_tcp */
+}
+#endif /* LWIP_TCP */
+
+/**
+ * Delete the pcb inside a netconn.
+ * Called from netconn_delete.
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_delconn(struct api_msg_msg *msg)
+{
+ /* @todo TCP: abort running write/connect? */
+ if ((msg->conn->state != NETCONN_NONE) &&
+ (msg->conn->state != NETCONN_LISTEN) &&
+ (msg->conn->state != NETCONN_CONNECT)) {
+ /* this only happens for TCP netconns */
+ LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
+ msg->err = ERR_INPROGRESS;
+ } else {
+ LWIP_ASSERT("blocking connect in progress",
+ (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
+ /* Drain and delete mboxes */
+ netconn_drain(msg->conn);
+
+ if (msg->conn->pcb.tcp != NULL) {
+
+ switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ raw_remove(msg->conn->pcb.raw);
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ msg->conn->pcb.udp->recv_arg = NULL;
+ udp_remove(msg->conn->pcb.udp);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
+ msg->conn->write_offset == 0);
+ msg->conn->state = NETCONN_CLOSE;
+ msg->msg.sd.shut = NETCONN_SHUT_RDWR;
+ msg->conn->current_msg = msg;
+ do_close_internal(msg->conn);
+ /* API_EVENT is called inside do_close_internal, before releasing
+ the application thread, so we can return at this point! */
+ return;
+#endif /* LWIP_TCP */
+ default:
+ break;
+ }
+ msg->conn->pcb.tcp = NULL;
+ }
+ /* tcp netconns don't come here! */
+
+ /* @todo: this lets select make the socket readable and writable,
+ which is wrong! errfd instead? */
+ API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
+ API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
+ }
+ if (sys_sem_valid(&msg->conn->op_completed)) {
+ sys_sem_signal(&msg->conn->op_completed);
+ }
+}
+
+/**
+ * Bind a pcb contained in a netconn
+ * Called from netconn_bind.
+ *
+ * @param msg the api_msg_msg pointing to the connection and containing
+ * the IP address and port to bind to
+ */
+void
+do_bind(struct api_msg_msg *msg)
+{
+ if (ERR_IS_FATAL(msg->conn->last_err)) {
+ msg->err = msg->conn->last_err;
+ } else {
+ msg->err = ERR_VAL;
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+ break;
+#endif /* LWIP_TCP */
+ default:
+ break;
+ }
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+#if LWIP_TCP
+/**
+ * TCP callback function if a connection (opened by tcp_connect/do_connect) has
+ * been established (or reset by the remote host).
+ *
+ * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
+ */
+static err_t
+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+ struct netconn *conn;
+ int was_blocking;
+
+ LWIP_UNUSED_ARG(pcb);
+
+ conn = (struct netconn *)arg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ 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));
+
+ if (conn->current_msg != NULL) {
+ conn->current_msg->err = err;
+ }
+ if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
+ setup_tcp(conn);
+ }
+ was_blocking = !IN_NONBLOCKING_CONNECT(conn);
+ SET_NONBLOCKING_CONNECT(conn, 0);
+ conn->current_msg = NULL;
+ conn->state = NETCONN_NONE;
+ if (!was_blocking) {
+ NETCONN_SET_SAFE_ERR(conn, ERR_OK);
+ }
+ API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+
+ if (was_blocking) {
+ sys_sem_signal(&conn->op_completed);
+ }
+ return ERR_OK;
+}
+#endif /* LWIP_TCP */
+
+/**
+ * Connect a pcb contained inside a netconn
+ * Called from netconn_connect.
+ *
+ * @param msg the api_msg_msg pointing to the connection and containing
+ * the IP address and port to connect to
+ */
+void
+do_connect(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp == NULL) {
+ /* This may happen when calling netconn_connect() a second time */
+ msg->err = ERR_CLSD;
+ } else {
+ switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ /* Prevent connect while doing any other action. */
+ if (msg->conn->state != NETCONN_NONE) {
+ msg->err = ERR_ISCONN;
+ } else {
+ setup_tcp(msg->conn);
+ msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
+ msg->msg.bc.port, do_connected);
+ if (msg->err == ERR_OK) {
+ u8_t non_blocking = netconn_is_nonblocking(msg->conn);
+ msg->conn->state = NETCONN_CONNECT;
+ SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
+ if (non_blocking) {
+ msg->err = ERR_INPROGRESS;
+ } else {
+ msg->conn->current_msg = msg;
+ /* sys_sem_signal() is called from do_connected (or err_tcp()),
+ * when the connection is established! */
+ return;
+ }
+ }
+ }
+ break;
+#endif /* LWIP_TCP */
+ default:
+ LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
+ break;
+ }
+ }
+ sys_sem_signal(&msg->conn->op_completed);
+}
+
+/**
+ * Connect a pcb contained inside a netconn
+ * Only used for UDP netconns.
+ * Called from netconn_disconnect.
+ *
+ * @param msg the api_msg_msg pointing to the connection to disconnect
+ */
+void
+do_disconnect(struct api_msg_msg *msg)
+{
+#if LWIP_UDP
+ if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
+ udp_disconnect(msg->conn->pcb.udp);
+ msg->err = ERR_OK;
+ } else
+#endif /* LWIP_UDP */
+ {
+ msg->err = ERR_VAL;
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+#if LWIP_TCP
+/**
+ * Set a TCP pcb contained in a netconn into listen mode
+ * Called from netconn_listen.
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_listen(struct api_msg_msg *msg)
+{
+ if (ERR_IS_FATAL(msg->conn->last_err)) {
+ msg->err = msg->conn->last_err;
+ } else {
+ msg->err = ERR_CONN;
+ if (msg->conn->pcb.tcp != NULL) {
+ if (msg->conn->type == NETCONN_TCP) {
+ if (msg->conn->state == NETCONN_NONE) {
+#if TCP_LISTEN_BACKLOG
+ struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
+#else /* TCP_LISTEN_BACKLOG */
+ struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
+#endif /* TCP_LISTEN_BACKLOG */
+ if (lpcb == NULL) {
+ /* in this case, the old pcb is still allocated */
+ msg->err = ERR_MEM;
+ } else {
+ /* delete the recvmbox and allocate the acceptmbox */
+ if (sys_mbox_valid(&msg->conn->recvmbox)) {
+ /** @todo: should we drain the recvmbox here? */
+ sys_mbox_free(&msg->conn->recvmbox);
+ sys_mbox_set_invalid(&msg->conn->recvmbox);
+ }
+ msg->err = ERR_OK;
+ if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
+ msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
+ }
+ if (msg->err == ERR_OK) {
+ msg->conn->state = NETCONN_LISTEN;
+ msg->conn->pcb.tcp = lpcb;
+ tcp_arg(msg->conn->pcb.tcp, msg->conn);
+ tcp_accept(msg->conn->pcb.tcp, accept_function);
+ } else {
+ /* since the old pcb is already deallocated, free lpcb now */
+ tcp_close(lpcb);
+ msg->conn->pcb.tcp = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+#endif /* LWIP_TCP */
+
+/**
+ * Send some data on a RAW or UDP pcb contained in a netconn
+ * Called from netconn_send
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_send(struct api_msg_msg *msg)
+{
+ if (ERR_IS_FATAL(msg->conn->last_err)) {
+ msg->err = msg->conn->last_err;
+ } else {
+ msg->err = ERR_CONN;
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ if (ip_addr_isany(&msg->msg.b->addr)) {
+ msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
+ } else {
+ msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
+ }
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDP:
+#if LWIP_CHECKSUM_ON_COPY
+ if (ip_addr_isany(&msg->msg.b->addr)) {
+ msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
+ msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
+ } else {
+ msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
+ &msg->msg.b->addr, msg->msg.b->port,
+ msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
+ }
+#else /* LWIP_CHECKSUM_ON_COPY */
+ if (ip_addr_isany(&msg->msg.b->addr)) {
+ msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
+ } else {
+ msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
+ }
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ break;
+#endif /* LWIP_UDP */
+ default:
+ break;
+ }
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+#if LWIP_TCP
+/**
+ * Indicate data has been received from a TCP pcb contained in a netconn
+ * Called from netconn_recv
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_recv(struct api_msg_msg *msg)
+{
+ msg->err = ERR_OK;
+ if (msg->conn->pcb.tcp != NULL) {
+ if (msg->conn->type == NETCONN_TCP) {
+#if TCP_LISTEN_BACKLOG
+ if (msg->conn->pcb.tcp->state == LISTEN) {
+ tcp_accepted(msg->conn->pcb.tcp);
+ } else
+#endif /* TCP_LISTEN_BACKLOG */
+ {
+ u32_t remaining = msg->msg.r.len;
+ do {
+ u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
+ tcp_recved(msg->conn->pcb.tcp, recved);
+ remaining -= recved;
+ }while(remaining != 0);
+ }
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+/**
+ * See if more data needs to be written from a previous call to netconn_write.
+ * Called initially from do_write. If the first call can't send all data
+ * (because of low memory or empty send-buffer), this function is called again
+ * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
+ * blocking application thread (waiting in netconn_write) is released.
+ *
+ * @param conn netconn (that is currently in state NETCONN_WRITE) to process
+ * @return ERR_OK
+ * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
+ */
+static err_t
+do_writemore(struct netconn *conn)
+{
+ err_t err = ERR_OK;
+ void *dataptr;
+ u16_t len, available;
+ u8_t write_finished = 0;
+ size_t diff;
+ u8_t dontblock = netconn_is_nonblocking(conn) ||
+ (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
+ u8_t apiflags = conn->current_msg->msg.w.apiflags;
+
+ LWIP_ASSERT("conn != NULL", conn != NULL);
+ LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
+ LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
+ LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
+ LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
+ conn->write_offset < conn->current_msg->msg.w.len);
+
+ dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
+ diff = conn->current_msg->msg.w.len - conn->write_offset;
+ if (diff > 0xffffUL) { /* max_u16_t */
+ len = 0xffff;
+#if LWIP_TCPIP_CORE_LOCKING
+ conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+#endif
+ apiflags |= TCP_WRITE_FLAG_MORE;
+ } else {
+ len = (u16_t)diff;
+ }
+ available = tcp_sndbuf(conn->pcb.tcp);
+ if (available < len) {
+ /* don't try to write more than sendbuf */
+ len = available;
+#if LWIP_TCPIP_CORE_LOCKING
+ conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+#endif
+ apiflags |= TCP_WRITE_FLAG_MORE;
+ }
+ if (dontblock && (len < conn->current_msg->msg.w.len)) {
+ /* failed to send all data at once -> nonblocking write not possible */
+ err = ERR_MEM;
+ }
+ if (err == ERR_OK) {
+ LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
+ err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
+ }
+ if (dontblock && (err == ERR_MEM)) {
+ /* nonblocking write failed */
+ write_finished = 1;
+ err = ERR_WOULDBLOCK;
+ /* let poll_tcp check writable space to mark the pcb
+ writable again */
+ conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
+ /* let select mark this pcb as non-writable. */
+ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+ } else {
+ /* if OK or memory error, check available space */
+ if (((err == ERR_OK) || (err == ERR_MEM)) &&
+ ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
+ (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
+ /* The queued byte- or pbuf-count exceeds the configured low-water limit,
+ let select mark this pcb as non-writable. */
+ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+ }
+
+ if (err == ERR_OK) {
+ conn->write_offset += len;
+ if (conn->write_offset == conn->current_msg->msg.w.len) {
+ /* everything was written */
+ write_finished = 1;
+ conn->write_offset = 0;
+ }
+ tcp_output(conn->pcb.tcp);
+ } else if (err == ERR_MEM) {
+ /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
+ we do NOT return to the application thread, since ERR_MEM is
+ only a temporary error! */
+
+ /* tcp_write returned ERR_MEM, try tcp_output anyway */
+ tcp_output(conn->pcb.tcp);
+
+ #if LWIP_TCPIP_CORE_LOCKING
+ conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+ #endif
+ } else {
+ /* On errors != ERR_MEM, we don't try writing any more but return
+ the error to the application thread. */
+ write_finished = 1;
+ }
+ }
+
+ if (write_finished) {
+ /* everything was written: set back connection state
+ and back to application task */
+ conn->current_msg->err = err;
+ conn->current_msg = NULL;
+ conn->state = NETCONN_NONE;
+#if LWIP_TCPIP_CORE_LOCKING
+ if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
+#endif
+ {
+ sys_sem_signal(&conn->op_completed);
+ }
+ }
+#if LWIP_TCPIP_CORE_LOCKING
+ else
+ return ERR_MEM;
+#endif
+ return ERR_OK;
+}
+#endif /* LWIP_TCP */
+
+/**
+ * Send some data on a TCP pcb contained in a netconn
+ * Called from netconn_write
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_write(struct api_msg_msg *msg)
+{
+ if (ERR_IS_FATAL(msg->conn->last_err)) {
+ msg->err = msg->conn->last_err;
+ } else {
+ if (msg->conn->type == NETCONN_TCP) {
+#if LWIP_TCP
+ if (msg->conn->state != NETCONN_NONE) {
+ /* netconn is connecting, closing or in blocking write */
+ msg->err = ERR_INPROGRESS;
+ } else if (msg->conn->pcb.tcp != NULL) {
+ msg->conn->state = NETCONN_WRITE;
+ /* set all the variables used by do_writemore */
+ LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
+ msg->conn->write_offset == 0);
+ LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
+ msg->conn->current_msg = msg;
+ msg->conn->write_offset = 0;
+#if LWIP_TCPIP_CORE_LOCKING
+ msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
+ if (do_writemore(msg->conn) != ERR_OK) {
+ LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
+ UNLOCK_TCPIP_CORE();
+ sys_arch_sem_wait(&msg->conn->op_completed, 0);
+ LOCK_TCPIP_CORE();
+ LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
+ }
+#else /* LWIP_TCPIP_CORE_LOCKING */
+ do_writemore(msg->conn);
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+ /* for both cases: if do_writemore was called, don't ACK the APIMSG
+ since do_writemore ACKs it! */
+ return;
+ } else {
+ msg->err = ERR_CONN;
+ }
+#else /* LWIP_TCP */
+ msg->err = ERR_VAL;
+#endif /* LWIP_TCP */
+#if (LWIP_UDP || LWIP_RAW)
+ } else {
+ msg->err = ERR_VAL;
+#endif /* (LWIP_UDP || LWIP_RAW) */
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+/**
+ * Return a connection's local or remote address
+ * Called from netconn_getaddr
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_getaddr(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.ip != NULL) {
+ *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
+ msg->conn->pcb.ip->remote_ip);
+
+ msg->err = ERR_OK;
+ switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ if (msg->msg.ad.local) {
+ *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
+ } else {
+ /* return an error as connecting is only a helper for upper layers */
+ msg->err = ERR_CONN;
+ }
+ break;
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ case NETCONN_UDP:
+ if (msg->msg.ad.local) {
+ *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
+ } else {
+ if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
+ msg->err = ERR_CONN;
+ } else {
+ *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
+ }
+ }
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
+ break;
+#endif /* LWIP_TCP */
+ default:
+ LWIP_ASSERT("invalid netconn_type", 0);
+ break;
+ }
+ } else {
+ msg->err = ERR_CONN;
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+
+/**
+ * Close a TCP pcb contained in a netconn
+ * Called from netconn_close
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_close(struct api_msg_msg *msg)
+{
+#if LWIP_TCP
+ /* @todo: abort running write/connect? */
+ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
+ /* this only happens for TCP netconns */
+ LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
+ msg->err = ERR_INPROGRESS;
+ } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
+ if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
+ /* LISTEN doesn't support half shutdown */
+ msg->err = ERR_CONN;
+ } else {
+ if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
+ /* Drain and delete mboxes */
+ netconn_drain(msg->conn);
+ }
+ LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
+ msg->conn->write_offset == 0);
+ msg->conn->state = NETCONN_CLOSE;
+ msg->conn->current_msg = msg;
+ do_close_internal(msg->conn);
+ /* for tcp netconns, do_close_internal ACKs the message */
+ return;
+ }
+ } else
+#endif /* LWIP_TCP */
+ {
+ msg->err = ERR_VAL;
+ }
+ sys_sem_signal(&msg->conn->op_completed);
+}
+
+#if LWIP_IGMP
+/**
+ * Join multicast groups for UDP netconns.
+ * Called from netconn_join_leave_group
+ *
+ * @param msg the api_msg_msg pointing to the connection
+ */
+void
+do_join_leave_group(struct api_msg_msg *msg)
+{
+ if (ERR_IS_FATAL(msg->conn->last_err)) {
+ msg->err = msg->conn->last_err;
+ } else {
+ if (msg->conn->pcb.tcp != NULL) {
+ if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
+#if LWIP_UDP
+ if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
+ msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
+ } else {
+ msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
+ }
+#endif /* LWIP_UDP */
+#if (LWIP_TCP || LWIP_RAW)
+ } else {
+ msg->err = ERR_VAL;
+#endif /* (LWIP_TCP || LWIP_RAW) */
+ }
+ } else {
+ msg->err = ERR_CONN;
+ }
+ }
+ TCPIP_APIMSG_ACK(msg);
+}
+#endif /* LWIP_IGMP */
+
+#if LWIP_DNS
+/**
+ * Callback function that is called when DNS name is resolved
+ * (or on timeout). A waiting application thread is waked up by
+ * signaling the semaphore.
+ */
+static void
+do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
+{
+ struct dns_api_msg *msg = (struct dns_api_msg*)arg;
+
+ LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
+ LWIP_UNUSED_ARG(name);
+
+ if (ipaddr == NULL) {
+ /* timeout or memory error */
+ *msg->err = ERR_VAL;
+ } else {
+ /* address was resolved */
+ *msg->err = ERR_OK;
+ *msg->addr = *ipaddr;
+ }
+ /* wake up the application task waiting in netconn_gethostbyname */
+ sys_sem_signal(msg->sem);
+}
+
+/**
+ * Execute a DNS query
+ * Called from netconn_gethostbyname
+ *
+ * @param arg the dns_api_msg pointing to the query
+ */
+void
+do_gethostbyname(void *arg)
+{
+ struct dns_api_msg *msg = (struct dns_api_msg*)arg;
+
+ *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
+ if (*msg->err != ERR_INPROGRESS) {
+ /* on error or immediate success, wake up the application
+ * task waiting in netconn_gethostbyname */
+ sys_sem_signal(msg->sem);
+ }
+}
+#endif /* LWIP_DNS */
+
+#endif /* LWIP_NETCONN */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/err.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/err.c
new file mode 100644
index 0000000000..92fa8b7dba
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/err.c
@@ -0,0 +1,75 @@
+/**
+ * @file
+ * Error Management module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/err.h"
+
+#ifdef LWIP_DEBUG
+
+static const char *err_strerr[] = {
+ "Ok.", /* ERR_OK 0 */
+ "Out of memory error.", /* ERR_MEM -1 */
+ "Buffer error.", /* ERR_BUF -2 */
+ "Timeout.", /* ERR_TIMEOUT -3 */
+ "Routing problem.", /* ERR_RTE -4 */
+ "Operation in progress.", /* ERR_INPROGRESS -5 */
+ "Illegal value.", /* ERR_VAL -6 */
+ "Operation would block.", /* ERR_WOULDBLOCK -7 */
+ "Address in use.", /* ERR_USE -8 */
+ "Already connected.", /* ERR_ISCONN -9 */
+ "Connection aborted.", /* ERR_ABRT -10 */
+ "Connection reset.", /* ERR_RST -11 */
+ "Connection closed.", /* ERR_CLSD -12 */
+ "Not connected.", /* ERR_CONN -13 */
+ "Illegal argument.", /* ERR_ARG -14 */
+ "Low-level netif error.", /* ERR_IF -15 */
+};
+
+/**
+ * Convert an lwip internal error to a string representation.
+ *
+ * @param err an lwip internal err_t
+ * @return a string representation for err
+ */
+const char *
+lwip_strerr(err_t err)
+{
+ return err_strerr[-err];
+
+}
+
+#endif /* LWIP_DEBUG */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netbuf.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netbuf.c
new file mode 100644
index 0000000000..9390c9ee98
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netbuf.c
@@ -0,0 +1,245 @@
+/**
+ * @file
+ * Network buffer management
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/netbuf.h"
+#include "lwip/memp.h"
+
+#include <string.h>
+
+/**
+ * Create (allocate) and initialize a new netbuf.
+ * The netbuf doesn't yet contain a packet buffer!
+ *
+ * @return a pointer to a new netbuf
+ * NULL on lack of memory
+ */
+struct
+netbuf *netbuf_new(void)
+{
+ struct netbuf *buf;
+
+ buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
+ if (buf != NULL) {
+ buf->p = NULL;
+ buf->ptr = NULL;
+ ip_addr_set_any(&buf->addr);
+ buf->port = 0;
+#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
+#if LWIP_CHECKSUM_ON_COPY
+ buf->flags = 0;
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ buf->toport_chksum = 0;
+#if LWIP_NETBUF_RECVINFO
+ ip_addr_set_any(&buf->toaddr);
+#endif /* LWIP_NETBUF_RECVINFO */
+#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Deallocate a netbuf allocated by netbuf_new().
+ *
+ * @param buf pointer to a netbuf allocated by netbuf_new()
+ */
+void
+netbuf_delete(struct netbuf *buf)
+{
+ if (buf != NULL) {
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ buf->p = buf->ptr = NULL;
+ }
+ memp_free(MEMP_NETBUF, buf);
+ }
+}
+
+/**
+ * Allocate memory for a packet buffer for a given netbuf.
+ *
+ * @param buf the netbuf for which to allocate a packet buffer
+ * @param size the size of the packet buffer to allocate
+ * @return pointer to the allocated memory
+ * NULL if no memory could be allocated
+ */
+void *
+netbuf_alloc(struct netbuf *buf, u16_t size)
+{
+ LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
+
+ /* Deallocate any previously allocated memory. */
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
+ if (buf->p == NULL) {
+ return NULL;
+ }
+ LWIP_ASSERT("check that first pbuf can hold size",
+ (buf->p->len >= size));
+ buf->ptr = buf->p;
+ return buf->p->payload;
+}
+
+/**
+ * Free the packet buffer included in a netbuf
+ *
+ * @param buf pointer to the netbuf which contains the packet buffer to free
+ */
+void
+netbuf_free(struct netbuf *buf)
+{
+ LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = buf->ptr = NULL;
+}
+
+/**
+ * Let a netbuf reference existing (non-volatile) data.
+ *
+ * @param buf netbuf which should reference the data
+ * @param dataptr pointer to the data to reference
+ * @param size size of the data
+ * @return ERR_OK if data is referenced
+ * ERR_MEM if data couldn't be referenced due to lack of memory
+ */
+err_t
+netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
+{
+ LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+ if (buf->p == NULL) {
+ buf->ptr = NULL;
+ return ERR_MEM;
+ }
+ buf->p->payload = (void*)dataptr;
+ buf->p->len = buf->p->tot_len = size;
+ buf->ptr = buf->p;
+ return ERR_OK;
+}
+
+/**
+ * Chain one netbuf to another (@see pbuf_chain)
+ *
+ * @param head the first netbuf
+ * @param tail netbuf to chain after head, freed by this function, may not be reference after returning
+ */
+void
+netbuf_chain(struct netbuf *head, struct netbuf *tail)
+{
+ LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
+ LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
+ pbuf_cat(head->p, tail->p);
+ head->ptr = head->p;
+ memp_free(MEMP_NETBUF, tail);
+}
+
+/**
+ * Get the data pointer and length of the data inside a netbuf.
+ *
+ * @param buf netbuf to get the data from
+ * @param dataptr pointer to a void pointer where to store the data pointer
+ * @param len pointer to an u16_t where the length of the data is stored
+ * @return ERR_OK if the information was retreived,
+ * ERR_BUF on error.
+ */
+err_t
+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
+{
+ LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
+ LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
+ LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
+
+ if (buf->ptr == NULL) {
+ return ERR_BUF;
+ }
+ *dataptr = buf->ptr->payload;
+ *len = buf->ptr->len;
+ return ERR_OK;
+}
+
+/**
+ * Move the current data pointer of a packet buffer contained in a netbuf
+ * to the next part.
+ * The packet buffer itself is not modified.
+ *
+ * @param buf the netbuf to modify
+ * @return -1 if there is no next part
+ * 1 if moved to the next part but now there is no next part
+ * 0 if moved to the next part and there are still more parts
+ */
+s8_t
+netbuf_next(struct netbuf *buf)
+{
+ LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
+ if (buf->ptr->next == NULL) {
+ return -1;
+ }
+ buf->ptr = buf->ptr->next;
+ if (buf->ptr->next == NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Move the current data pointer of a packet buffer contained in a netbuf
+ * to the beginning of the packet.
+ * The packet buffer itself is not modified.
+ *
+ * @param buf the netbuf to modify
+ */
+void
+netbuf_first(struct netbuf *buf)
+{
+ LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
+ buf->ptr = buf->p;
+}
+
+#endif /* LWIP_NETCONN */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netdb.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netdb.c
new file mode 100644
index 0000000000..a7e4e06bca
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netdb.c
@@ -0,0 +1,352 @@
+/**
+ * @file
+ * API functions for name resolving
+ *
+ */
+
+/*
+ * 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/netdb.h"
+
+#if LWIP_DNS && LWIP_SOCKET
+
+#include "lwip/err.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/api.h"
+#include "lwip/dns.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+/** helper struct for gethostbyname_r to access the char* buffer */
+struct gethostbyname_r_helper {
+ ip_addr_t *addrs;
+ ip_addr_t addr;
+ char *aliases;
+};
+
+/** h_errno is exported in netdb.h for access by applications. */
+#if LWIP_DNS_API_DECLARE_H_ERRNO
+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 */
+#ifndef LWIP_DNS_API_HOSTENT_STORAGE
+#define LWIP_DNS_API_HOSTENT_STORAGE 0
+#endif
+
+/** define "hostent" variables storage */
+#if LWIP_DNS_API_HOSTENT_STORAGE
+#define HOSTENT_STORAGE
+#else
+#define HOSTENT_STORAGE static
+#endif /* LWIP_DNS_API_STATIC_HOSTENT */
+
+/**
+ * Returns an entry containing addresses of address family AF_INET
+ * for the host with name name.
+ * Due to dns_gethostbyname limitations, only one address is returned.
+ *
+ * @param name the hostname to resolve
+ * @return an entry containing addresses of address family AF_INET
+ * for the host with name name
+ */
+struct hostent*
+lwip_gethostbyname(const char *name)
+{
+ err_t err;
+ ip_addr_t addr;
+
+ /* buffer variables for lwip_gethostbyname() */
+ HOSTENT_STORAGE struct hostent s_hostent;
+ HOSTENT_STORAGE char *s_aliases;
+ HOSTENT_STORAGE ip_addr_t s_hostent_addr;
+ HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
+
+ /* query host IP address */
+ err = netconn_gethostbyname(name, &addr);
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ /* fill hostent */
+ s_hostent_addr = addr;
+ s_phostent_addr[0] = &s_hostent_addr;
+ s_phostent_addr[1] = NULL;
+ s_hostent.h_name = (char*)name;
+ s_hostent.h_aliases = &s_aliases;
+ s_hostent.h_addrtype = AF_INET;
+ s_hostent.h_length = sizeof(ip_addr_t);
+ s_hostent.h_addr_list = (char**)&s_phostent_addr;
+
+#if DNS_DEBUG
+ /* dump hostent */
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
+ if (s_hostent.h_aliases != NULL) {
+ u8_t idx;
+ for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
+ }
+ }
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
+ if (s_hostent.h_addr_list != NULL) {
+ u8_t idx;
+ for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
+ }
+ }
+#endif /* DNS_DEBUG */
+
+#if LWIP_DNS_API_HOSTENT_STORAGE
+ /* this function should return the "per-thread" hostent after copy from s_hostent */
+ return sys_thread_hostent(&s_hostent);
+#else
+ return &s_hostent;
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
+}
+
+/**
+ * Thread-safe variant of lwip_gethostbyname: instead of using a static
+ * buffer, this function takes buffer and errno pointers as arguments
+ * and uses these for the result.
+ *
+ * @param name the hostname to resolve
+ * @param ret pre-allocated struct where to store the result
+ * @param buf pre-allocated buffer where to store additional data
+ * @param buflen the size of buf
+ * @param result pointer to a hostent pointer that is set to ret on success
+ * and set to zero on error
+ * @param h_errnop pointer to an int where to store errors (instead of modifying
+ * the global h_errno)
+ * @return 0 on success, non-zero on error, additional error information
+ * is stored in *h_errnop instead of h_errno to be thread-safe
+ */
+int
+lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop)
+{
+ err_t err;
+ struct gethostbyname_r_helper *h;
+ char *hostname;
+ size_t namelen;
+ int lh_errno;
+
+ if (h_errnop == NULL) {
+ /* ensure h_errnop is never NULL */
+ h_errnop = &lh_errno;
+ }
+
+ if (result == NULL) {
+ /* not all arguments given */
+ *h_errnop = EINVAL;
+ return -1;
+ }
+ /* first thing to do: set *result to nothing */
+ *result = NULL;
+ if ((name == NULL) || (ret == NULL) || (buf == 0)) {
+ /* not all arguments given */
+ *h_errnop = EINVAL;
+ return -1;
+ }
+
+ namelen = strlen(name);
+ if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
+ /* buf can't hold the data needed + a copy of name */
+ *h_errnop = ERANGE;
+ return -1;
+ }
+
+ h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
+ hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
+
+ /* query host IP address */
+ err = netconn_gethostbyname(name, &(h->addr));
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
+ *h_errnop = ENSRNOTFOUND;
+ return -1;
+ }
+
+ /* copy the hostname into buf */
+ MEMCPY(hostname, name, namelen);
+ hostname[namelen] = 0;
+
+ /* fill hostent */
+ h->addrs = &(h->addr);
+ h->aliases = NULL;
+ ret->h_name = (char*)hostname;
+ ret->h_aliases = &(h->aliases);
+ ret->h_addrtype = AF_INET;
+ ret->h_length = sizeof(ip_addr_t);
+ ret->h_addr_list = (char**)&(h->addrs);
+
+ /* set result != NULL */
+ *result = ret;
+
+ /* return success */
+ return 0;
+}
+
+/**
+ * Frees one or more addrinfo structures returned by getaddrinfo(), along with
+ * any additional storage associated with those structures. If the ai_next field
+ * of the structure is not null, the entire list of structures is freed.
+ *
+ * @param ai struct addrinfo to free
+ */
+void
+lwip_freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *next;
+
+ while (ai != NULL) {
+ next = ai->ai_next;
+ memp_free(MEMP_NETDB, ai);
+ ai = next;
+ }
+}
+
+/**
+ * Translates the name of a service location (for example, a host name) and/or
+ * a service name and returns a set of socket addresses and associated
+ * information to be used in creating a socket with which to address the
+ * specified service.
+ * Memory for the result is allocated internally and must be freed by calling
+ * lwip_freeaddrinfo()!
+ *
+ * Due to a limitation in dns_gethostbyname, only the first address of a
+ * host is returned.
+ * Also, service names are not supported (only port numbers)!
+ *
+ * @param nodename descriptive name or address string of the host
+ * (may be NULL -> local address)
+ * @param servname port number as string of NULL
+ * @param hints structure containing input values that set socktype and protocol
+ * @param res pointer to a pointer where to store the result (set to NULL on failure)
+ * @return 0 on success, non-zero on failure
+ */
+int
+lwip_getaddrinfo(const char *nodename, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ err_t err;
+ ip_addr_t addr;
+ struct addrinfo *ai;
+ struct sockaddr_in *sa = NULL;
+ int port_nr = 0;
+ size_t total_size;
+ size_t namelen = 0;
+
+ if (res == NULL) {
+ return EAI_FAIL;
+ }
+ *res = NULL;
+ if ((nodename == NULL) && (servname == NULL)) {
+ return EAI_NONAME;
+ }
+
+ if (servname != NULL) {
+ /* service name specified: convert to port number
+ * @todo?: currently, only ASCII integers (port numbers) are supported! */
+ port_nr = atoi(servname);
+ if ((port_nr <= 0) || (port_nr > 0xffff)) {
+ return EAI_SERVICE;
+ }
+ }
+
+ if (nodename != NULL) {
+ /* service location specified, try to resolve */
+ err = netconn_gethostbyname(nodename, &addr);
+ if (err != ERR_OK) {
+ return EAI_FAIL;
+ }
+ } else {
+ /* service location specified, use loopback address */
+ ip_addr_set_loopback(&addr);
+ }
+
+ total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
+ if (nodename != NULL) {
+ namelen = strlen(nodename);
+ LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
+ total_size += namelen + 1;
+ }
+ /* If this fails, please report to lwip-devel! :-) */
+ LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
+ total_size <= NETDB_ELEM_SIZE);
+ ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
+ if (ai == NULL) {
+ goto memerr;
+ }
+ memset(ai, 0, total_size);
+ sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
+ /* set up sockaddr */
+ inet_addr_from_ipaddr(&sa->sin_addr, &addr);
+ sa->sin_family = AF_INET;
+ sa->sin_len = sizeof(struct sockaddr_in);
+ sa->sin_port = htons((u16_t)port_nr);
+
+ /* set up addrinfo */
+ ai->ai_family = AF_INET;
+ if (hints != NULL) {
+ /* copy socktype & protocol from hints if specified */
+ ai->ai_socktype = hints->ai_socktype;
+ ai->ai_protocol = hints->ai_protocol;
+ }
+ if (nodename != NULL) {
+ /* copy nodename to canonname if specified */
+ ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+ MEMCPY(ai->ai_canonname, nodename, namelen);
+ ai->ai_canonname[namelen] = 0;
+ }
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ ai->ai_addr = (struct sockaddr*)sa;
+
+ *res = ai;
+
+ return 0;
+memerr:
+ if (ai != NULL) {
+ memp_free(MEMP_NETDB, ai);
+ }
+ return EAI_MEMORY;
+}
+
+#endif /* LWIP_DNS && LWIP_SOCKET */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netifapi.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netifapi.c
new file mode 100644
index 0000000000..43e47203a9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/netifapi.c
@@ -0,0 +1,160 @@
+/**
+ * @file
+ * Network Interface Sequential API 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_NETIF_API /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/netifapi.h"
+#include "lwip/tcpip.h"
+
+/**
+ * Call netif_add() inside the tcpip_thread context.
+ */
+void
+do_netifapi_netif_add(struct netifapi_msg_msg *msg)
+{
+ if (!netif_add( msg->netif,
+ msg->msg.add.ipaddr,
+ msg->msg.add.netmask,
+ msg->msg.add.gw,
+ msg->msg.add.state,
+ msg->msg.add.init,
+ msg->msg.add.input)) {
+ msg->err = ERR_IF;
+ } else {
+ msg->err = ERR_OK;
+ }
+ TCPIP_NETIFAPI_ACK(msg);
+}
+
+/**
+ * Call netif_set_addr() inside the tcpip_thread context.
+ */
+void
+do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
+{
+ netif_set_addr( msg->netif,
+ msg->msg.add.ipaddr,
+ msg->msg.add.netmask,
+ msg->msg.add.gw);
+ msg->err = ERR_OK;
+ TCPIP_NETIFAPI_ACK(msg);
+}
+
+/**
+ * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
+ * tcpip_thread context.
+ */
+void
+do_netifapi_netif_common(struct netifapi_msg_msg *msg)
+{
+ if (msg->msg.common.errtfunc != NULL) {
+ msg->err = msg->msg.common.errtfunc(msg->netif);
+ } else {
+ msg->err = ERR_OK;
+ msg->msg.common.voidfunc(msg->netif);
+ }
+ TCPIP_NETIFAPI_ACK(msg);
+}
+
+/**
+ * Call netif_add() in a thread-safe way by running that function inside the
+ * tcpip_thread context.
+ *
+ * @note for params @see netif_add()
+ */
+err_t
+netifapi_netif_add(struct netif *netif,
+ ip_addr_t *ipaddr,
+ ip_addr_t *netmask,
+ ip_addr_t *gw,
+ void *state,
+ netif_init_fn init,
+ netif_input_fn input)
+{
+ struct netifapi_msg msg;
+ msg.function = do_netifapi_netif_add;
+ msg.msg.netif = netif;
+ msg.msg.msg.add.ipaddr = ipaddr;
+ msg.msg.msg.add.netmask = netmask;
+ msg.msg.msg.add.gw = gw;
+ msg.msg.msg.add.state = state;
+ msg.msg.msg.add.init = init;
+ msg.msg.msg.add.input = input;
+ TCPIP_NETIFAPI(&msg);
+ return msg.msg.err;
+}
+
+/**
+ * Call netif_set_addr() in a thread-safe way by running that function inside the
+ * tcpip_thread context.
+ *
+ * @note for params @see netif_set_addr()
+ */
+err_t
+netifapi_netif_set_addr(struct netif *netif,
+ ip_addr_t *ipaddr,
+ ip_addr_t *netmask,
+ ip_addr_t *gw)
+{
+ struct netifapi_msg msg;
+ msg.function = do_netifapi_netif_set_addr;
+ msg.msg.netif = netif;
+ msg.msg.msg.add.ipaddr = ipaddr;
+ msg.msg.msg.add.netmask = netmask;
+ msg.msg.msg.add.gw = gw;
+ TCPIP_NETIFAPI(&msg);
+ return msg.msg.err;
+}
+
+/**
+ * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
+ * way by running that function inside the tcpip_thread context.
+ *
+ * @note use only for functions where there is only "netif" parameter.
+ */
+err_t
+netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
+ netifapi_errt_fn errtfunc)
+{
+ struct netifapi_msg msg;
+ msg.function = do_netifapi_netif_common;
+ msg.msg.netif = netif;
+ msg.msg.msg.common.voidfunc = voidfunc;
+ msg.msg.msg.common.errtfunc = errtfunc;
+ TCPIP_NETIFAPI(&msg);
+ return msg.msg.err;
+}
+
+#endif /* LWIP_NETIF_API */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/sockets.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/sockets.c
new file mode 100644
index 0000000000..e36012ce43
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/sockets.c
@@ -0,0 +1,2347 @@
+/**
+ * @file
+ * Sockets BSD-Like API module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/sockets.h"
+#include "lwip/api.h"
+#include "lwip/sys.h"
+#include "lwip/igmp.h"
+#include "lwip/inet.h"
+#include "lwip/tcp.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcpip.h"
+#include "lwip/pbuf.h"
+#if LWIP_CHECKSUM_ON_COPY
+#include "lwip/inet_chksum.h"
+#endif
+
+#include <string.h>
+
+#define NUM_SOCKETS MEMP_NUM_NETCONN
+
+/** 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 */
+ void *lastdata;
+ /** offset in the data that was left from the previous read */
+ u16_t lastoffset;
+ /** 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;
+ /** last error that occurred on this socket */
+ int err;
+ /** counter of how many threads are waiting for this socket using select */
+ int select_waiting;
+};
+
+/** Description for a task waiting in select */
+struct lwip_select_cb {
+ /** Pointer to the next waiting task */
+ struct lwip_select_cb *next;
+ /** Pointer to the previous waiting task */
+ struct lwip_select_cb *prev;
+ /** readset passed to select */
+ fd_set *readset;
+ /** writeset passed to select */
+ fd_set *writeset;
+ /** unimplemented: exceptset passed to select */
+ fd_set *exceptset;
+ /** don't signal the same semaphore twice: set to 1 when signalled */
+ int sem_signalled;
+ /** semaphore to wake up a task waiting for select */
+ sys_sem_t sem;
+};
+
+/** This struct is used to pass data to the set/getsockopt_internal
+ * functions running in tcpip_thread context (only a void* is allowed) */
+struct lwip_setgetsockopt_data {
+ /** socket struct for which to change options */
+ struct lwip_sock *sock;
+#ifdef LWIP_DEBUG
+ /** socket index for which to change options */
+ int s;
+#endif /* LWIP_DEBUG */
+ /** level of the option to process */
+ int level;
+ /** name of the option to process */
+ int optname;
+ /** set: value to set the option to
+ * get: value of the option is stored here */
+ void *optval;
+ /** size of *optval */
+ socklen_t *optlen;
+ /** if an error occures, it is temporarily stored here */
+ err_t err;
+};
+
+/** The global array of available sockets */
+static struct lwip_sock sockets[NUM_SOCKETS];
+/** The global list of tasks waiting for select */
+static struct lwip_select_cb *select_cb_list;
+/** This counter is increased from lwip_select when the list is chagned
+ and checked in event_callback to see if it has changed. */
+static volatile int select_cb_ctr;
+
+/** Table to quickly map an lwIP error (err_t) to a socket error
+ * by using -err as an index */
+static const int err_to_errno_table[] = {
+ 0, /* ERR_OK 0 No error, everything OK. */
+ ENOMEM, /* ERR_MEM -1 Out of memory error. */
+ ENOBUFS, /* ERR_BUF -2 Buffer error. */
+ EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
+ EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
+ EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
+ EINVAL, /* ERR_VAL -6 Illegal value. */
+ EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
+ EADDRINUSE, /* ERR_USE -8 Address in use. */
+ EALREADY, /* ERR_ISCONN -9 Already connected. */
+ ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
+ ECONNRESET, /* ERR_RST -11 Connection reset. */
+ ENOTCONN, /* ERR_CLSD -12 Connection closed. */
+ ENOTCONN, /* ERR_CONN -13 Not connected. */
+ EIO, /* ERR_ARG -14 Illegal argument. */
+ -1, /* ERR_IF -15 Low-level netif error */
+};
+
+#define ERR_TO_ERRNO_TABLE_SIZE \
+ (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
+
+#define err_to_errno(err) \
+ ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
+ err_to_errno_table[-(err)] : EIO)
+
+#ifdef ERRNO
+#ifndef set_errno
+#define set_errno(err) errno = (err)
+#endif
+#else /* ERRNO */
+#define set_errno(err)
+#endif /* ERRNO */
+
+#define sock_set_errno(sk, e) do { \
+ sk->err = (e); \
+ set_errno(sk->err); \
+} while (0)
+
+/* Forward delcaration of some functions */
+static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
+static void lwip_getsockopt_internal(void *arg);
+static void lwip_setsockopt_internal(void *arg);
+
+/**
+ * Initialize this module. This function has to be called before any other
+ * functions in this module!
+ */
+void
+lwip_socket_init(void)
+{
+}
+
+/**
+ * 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 struct lwip_sock *
+get_socket(int s)
+{
+ struct lwip_sock *sock;
+
+ if ((s < 0) || (s >= NUM_SOCKETS)) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
+ set_errno(EBADF);
+ return NULL;
+ }
+
+ sock = &sockets[s];
+
+ if (!sock->conn) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
+ set_errno(EBADF);
+ return NULL;
+ }
+
+ return sock;
+}
+
+/**
+ * Same as get_socket but doesn't set errno
+ *
+ * @param s externally used socket index
+ * @return struct lwip_sock for the socket or NULL if not found
+ */
+static struct lwip_sock *
+tryget_socket(int s)
+{
+ if ((s < 0) || (s >= NUM_SOCKETS)) {
+ return NULL;
+ }
+ if (!sockets[s].conn) {
+ return NULL;
+ }
+ return &sockets[s];
+}
+
+/**
+ * Allocate a new socket for a given netconn.
+ *
+ * @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()
+ * @return the index of the new socket; -1 on error
+ */
+static int
+alloc_socket(struct netconn *newconn, int accepted)
+{
+ int i;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ /* allocate a new socket identifier */
+ for (i = 0; i < NUM_SOCKETS; ++i) {
+ /* Protect socket array */
+ SYS_ARCH_PROTECT(lev);
+ if (!sockets[i].conn) {
+ 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 = NULL;
+ sockets[i].lastoffset = 0;
+ 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 = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
+ sockets[i].errevent = 0;
+ sockets[i].err = 0;
+ sockets[i].select_waiting = 0;
+ return i;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+ }
+ return -1;
+}
+
+/** Free a socket. The socket's netconn must have been
+ * delete before!
+ *
+ * @param sock the socket to free
+ * @param is_tcp != 0 for TCP sockets, used to free lastdata
+ */
+static void
+free_socket(struct lwip_sock *sock, int is_tcp)
+{
+ void *lastdata;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ lastdata = sock->lastdata;
+ sock->lastdata = NULL;
+ sock->lastoffset = 0;
+ sock->err = 0;
+
+ /* Protect socket array */
+ SYS_ARCH_PROTECT(lev);
+ sock->conn = NULL;
+ SYS_ARCH_UNPROTECT(lev);
+ /* don't use 'sock' after this line, as another task might have allocated it */
+
+ if (lastdata != NULL) {
+ if (is_tcp) {
+ pbuf_free((struct pbuf *)lastdata);
+ } else {
+ netbuf_delete((struct netbuf *)lastdata);
+ }
+ }
+}
+
+/* Below this, the well-known socket functions are implemented.
+ * Use google.com or opengroup.org to get a good description :-)
+ *
+ * Exceptions are documented!
+ */
+
+int
+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct lwip_sock *sock, *nsock;
+ struct netconn *newconn;
+ ip_addr_t naddr;
+ u16_t port;
+ int newsock;
+ struct sockaddr_in sin;
+ err_t err;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
+ sock_set_errno(sock, EWOULDBLOCK);
+ 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));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+ LWIP_ASSERT("newconn != NULL", newconn != NULL);
+ /* Prevent automatic window updates, we do this on our own! */
+ netconn_set_noautorecved(newconn, 1);
+
+ /* 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));
+ netconn_delete(newconn);
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
+ * not be NULL if addr is valid.
+ */
+ if (NULL != addr) {
+ LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
+
+ if (*addrlen > sizeof(sin))
+ *addrlen = sizeof(sin);
+
+ MEMCPY(addr, &sin, *addrlen);
+ }
+
+ newsock = alloc_socket(newconn, 1);
+ if (newsock == -1) {
+ netconn_delete(newconn);
+ sock_set_errno(sock, ENFILE);
+ return -1;
+ }
+ LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
+ LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
+ nsock = &sockets[newsock];
+
+ /* 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);
+ nsock->rcvevent += (s16_t)(-1 - newconn->socket);
+ newconn->socket = newsock;
+ SYS_ARCH_UNPROTECT(lev);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
+ ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
+
+ sock_set_errno(sock, 0);
+ return newsock;
+}
+
+int
+lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
+{
+ struct lwip_sock *sock;
+ ip_addr_t local_addr;
+ u16_t local_port;
+ err_t err;
+ const struct sockaddr_in *name_in;
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ /* check size, familiy and alignment of 'name' */
+ LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
+ ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
+ sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
+ name_in = (const struct sockaddr_in *)(void*)name;
+
+ inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
+ local_port = name_in->sin_port;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
+
+ err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
+
+ 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));
+ return -1;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_close(int s)
+{
+ struct lwip_sock *sock;
+ int is_tcp = 0;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ if(sock->conn != NULL) {
+ is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
+ } else {
+ LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
+ }
+
+ netconn_delete(sock->conn);
+
+ free_socket(sock, is_tcp);
+ set_errno(0);
+ return 0;
+}
+
+int
+lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
+{
+ struct lwip_sock *sock;
+ err_t err;
+ const struct sockaddr_in *name_in;
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ /* check size, familiy and alignment of 'name' */
+ LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
+ ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
+ sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
+ name_in = (const struct sockaddr_in *)(void*)name;
+
+ if (name_in->sin_family == AF_UNSPEC) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
+ err = netconn_disconnect(sock->conn);
+ } else {
+ ip_addr_t remote_addr;
+ u16_t remote_port;
+
+ inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
+ remote_port = name_in->sin_port;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
+
+ err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+ }
+
+ 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));
+ return -1;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+/**
+ * Set a socket into listen mode.
+ * The socket may not have been used for another connection previously.
+ *
+ * @param s the socket to set to listening mode
+ * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
+ * @return 0 on success, non-zero on failure
+ */
+int
+lwip_listen(int s, int backlog)
+{
+ struct lwip_sock *sock;
+ err_t err;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ /* limit the "backlog" parameter to fit in an u8_t */
+ backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
+
+ err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
+
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_recvfrom(int s, void *mem, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen)
+{
+ struct lwip_sock *sock;
+ void *buf = NULL;
+ struct pbuf *p;
+ u16_t buflen, copylen;
+ int off = 0;
+ ip_addr_t *addr;
+ u16_t port;
+ u8_t done = 0;
+ err_t err;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ do {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
+ /* Check if there is data left from the last recv operation. */
+ if (sock->lastdata) {
+ buf = sock->lastdata;
+ } else {
+ /* If this is non-blocking call, then check first */
+ if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
+ (sock->rcvevent <= 0)) {
+ if (off > 0) {
+ /* update receive window */
+ netconn_recved(sock->conn, (u32_t)off);
+ /* already received data, return that */
+ sock_set_errno(sock, 0);
+ return off;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
+ sock_set_errno(sock, EWOULDBLOCK);
+ return -1;
+ }
+
+ /* No data was left from the previous operation, so we try to get
+ some from the network. */
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
+ } else {
+ err = netconn_recv(sock->conn, (struct netbuf **)&buf);
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
+ err, buf));
+
+ if (err != ERR_OK) {
+ if (off > 0) {
+ /* update receive window */
+ netconn_recved(sock->conn, (u32_t)off);
+ /* already received data, return that */
+ sock_set_errno(sock, 0);
+ return off;
+ }
+ /* We should really do some error checking here. */
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
+ s, lwip_strerr(err)));
+ sock_set_errno(sock, err_to_errno(err));
+ if (err == ERR_CLSD) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ LWIP_ASSERT("buf != NULL", buf != NULL);
+ sock->lastdata = buf;
+ }
+
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ p = (struct pbuf *)buf;
+ } else {
+ p = ((struct netbuf *)buf)->p;
+ }
+ buflen = p->tot_len;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
+ buflen, len, off, sock->lastoffset));
+
+ buflen -= sock->lastoffset;
+
+ if (len > buflen) {
+ copylen = buflen;
+ } else {
+ copylen = (u16_t)len;
+ }
+
+ /* copy the contents of the received buffer into
+ the supplied memory pointer mem */
+ pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
+
+ off += copylen;
+
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
+ len -= copylen;
+ if ( (len <= 0) ||
+ (p->flags & PBUF_FLAG_PUSH) ||
+ (sock->rcvevent <= 0) ||
+ ((flags & MSG_PEEK)!=0)) {
+ done = 1;
+ }
+ } else {
+ done = 1;
+ }
+
+ /* Check to see from where the data was.*/
+ if (done) {
+ ip_addr_t fromaddr;
+ if (from && fromlen) {
+ struct sockaddr_in sin;
+
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ addr = &fromaddr;
+ netconn_getaddr(sock->conn, addr, &port, 0);
+ } else {
+ addr = netbuf_fromaddr((struct netbuf *)buf);
+ port = netbuf_fromport((struct netbuf *)buf);
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ inet_addr_from_ipaddr(&sin.sin_addr, addr);
+
+ if (*fromlen > sizeof(sin)) {
+ *fromlen = sizeof(sin);
+ }
+
+ MEMCPY(from, &sin, *fromlen);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
+ } else {
+#if SOCKETS_DEBUG
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ addr = &fromaddr;
+ netconn_getaddr(sock->conn, addr, &port, 0);
+ } else {
+ addr = netbuf_fromaddr((struct netbuf *)buf);
+ port = netbuf_fromport((struct netbuf *)buf);
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
+#endif /* SOCKETS_DEBUG */
+ }
+ }
+
+ /* If we don't peek the incoming message... */
+ if ((flags & MSG_PEEK) == 0) {
+ /* If this is a TCP socket, check if there is data left in the
+ buffer. If so, it should be saved in the sock structure for next
+ time around. */
+ if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
+ sock->lastdata = buf;
+ sock->lastoffset += copylen;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
+ } else {
+ sock->lastdata = NULL;
+ sock->lastoffset = 0;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
+ if (netconn_type(sock->conn) == NETCONN_TCP) {
+ pbuf_free((struct pbuf *)buf);
+ } else {
+ netbuf_delete((struct netbuf *)buf);
+ }
+ }
+ }
+ } while (!done);
+
+ if (off > 0) {
+ /* update receive window */
+ netconn_recved(sock->conn, (u32_t)off);
+ }
+ sock_set_errno(sock, 0);
+ return off;
+}
+
+int
+lwip_read(int s, void *mem, size_t len)
+{
+ return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
+}
+
+int
+lwip_recv(int s, void *mem, size_t len, int flags)
+{
+ return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
+}
+
+int
+lwip_send(int s, const void *data, size_t size, int flags)
+{
+ struct lwip_sock *sock;
+ err_t err;
+ u8_t write_flags;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
+ s, data, size, flags));
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ if (sock->conn->type != NETCONN_TCP) {
+#if (LWIP_UDP || LWIP_RAW)
+ return lwip_sendto(s, data, size, flags, NULL, 0);
+#else /* (LWIP_UDP || LWIP_RAW) */
+ sock_set_errno(sock, err_to_errno(ERR_ARG));
+ return -1;
+#endif /* (LWIP_UDP || LWIP_RAW) */
+ }
+
+ if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
+ if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
+ /* too much data to ever send nonblocking! */
+ sock_set_errno(sock, EMSGSIZE);
+ return -1;
+ }
+ }
+
+ write_flags = NETCONN_COPY |
+ ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
+ ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
+ err = netconn_write(sock->conn, data, size, write_flags);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
+ sock_set_errno(sock, err_to_errno(err));
+ return (err == ERR_OK ? (int)size : -1);
+}
+
+int
+lwip_sendto(int s, const void *data, size_t size, int flags,
+ const struct sockaddr *to, socklen_t tolen)
+{
+ struct lwip_sock *sock;
+ err_t err;
+ u16_t short_size;
+ const struct sockaddr_in *to_in;
+ u16_t remote_port;
+#if !LWIP_TCPIP_CORE_LOCKING
+ struct netbuf buf;
+#endif
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ if (sock->conn->type == NETCONN_TCP) {
+#if LWIP_TCP
+ return lwip_send(s, data, size, flags);
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(flags);
+ sock_set_errno(sock, err_to_errno(ERR_ARG));
+ return -1;
+#endif /* LWIP_TCP */
+ }
+
+ /* @todo: split into multiple sendto's? */
+ LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
+ short_size = (u16_t)size;
+ LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
+ ((tolen == sizeof(struct sockaddr_in)) &&
+ ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
+ sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
+ to_in = (const struct sockaddr_in *)(void*)to;
+
+#if LWIP_TCPIP_CORE_LOCKING
+ /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
+ {
+ struct pbuf* p;
+ ip_addr_t *remote_addr;
+
+#if LWIP_NETIF_TX_SINGLE_PBUF
+ p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
+ if (p != NULL) {
+#if LWIP_CHECKSUM_ON_COPY
+ u16_t chksum = 0;
+ if (sock->conn->type != NETCONN_RAW) {
+ chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
+ } else
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ MEMCPY(p->payload, data, size);
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+ p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
+ if (p != NULL) {
+ p->payload = (void*)data;
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+
+ if (to_in != NULL) {
+ inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
+ remote_port = ntohs(to_in->sin_port);
+ } else {
+ remote_addr = &sock->conn->pcb.raw->remote_ip;
+ if (sock->conn->type == NETCONN_RAW) {
+ remote_port = 0;
+ } else {
+ remote_port = sock->conn->pcb.udp->remote_port;
+ }
+ }
+
+ LOCK_TCPIP_CORE();
+ if (sock->conn->type == NETCONN_RAW) {
+ err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
+ } else {
+#if LWIP_UDP
+#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
+ err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
+ remote_addr, remote_port, 1, chksum);
+#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
+ err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
+ remote_addr, remote_port);
+#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
+#else /* LWIP_UDP */
+ err = ERR_ARG;
+#endif /* LWIP_UDP */
+ }
+ UNLOCK_TCPIP_CORE();
+
+ pbuf_free(p);
+ } else {
+ err = ERR_MEM;
+ }
+ }
+#else /* LWIP_TCPIP_CORE_LOCKING */
+ /* initialize a buffer */
+ buf.p = buf.ptr = NULL;
+#if LWIP_CHECKSUM_ON_COPY
+ buf.flags = 0;
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ if (to) {
+ inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
+ remote_port = ntohs(to_in->sin_port);
+ netbuf_fromport(&buf) = remote_port;
+ } else {
+ remote_port = 0;
+ ip_addr_set_any(&buf.addr);
+ netbuf_fromport(&buf) = 0;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
+ s, data, short_size, flags));
+ ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
+
+ /* make the buffer point to the data that should be sent */
+#if LWIP_NETIF_TX_SINGLE_PBUF
+ /* Allocate a new netbuf and copy the data into it. */
+ if (netbuf_alloc(&buf, short_size) == NULL) {
+ err = ERR_MEM;
+ } else {
+#if LWIP_CHECKSUM_ON_COPY
+ if (sock->conn->type != NETCONN_RAW) {
+ u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
+ netbuf_set_chksum(&buf, chksum);
+ err = ERR_OK;
+ } else
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ {
+ err = netbuf_take(&buf, data, short_size);
+ }
+ }
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+ err = netbuf_ref(&buf, data, short_size);
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+ if (err == ERR_OK) {
+ /* send the data */
+ err = netconn_send(sock->conn, &buf);
+ }
+
+ /* deallocated the buffer */
+ netbuf_free(&buf);
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+ sock_set_errno(sock, err_to_errno(err));
+ return (err == ERR_OK ? short_size : -1);
+}
+
+int
+lwip_socket(int domain, int type, int protocol)
+{
+ struct netconn *conn;
+ int i;
+
+ LWIP_UNUSED_ARG(domain);
+
+ /* create a netconn */
+ switch (type) {
+ case SOCK_RAW:
+ conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ break;
+ case SOCK_DGRAM:
+ conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
+ NETCONN_UDPLITE : NETCONN_UDP, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ break;
+ case SOCK_STREAM:
+ conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ if (conn != NULL) {
+ /* Prevent automatic window updates, we do this on our own! */
+ netconn_set_noautorecved(conn, 1);
+ }
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
+ domain, type, protocol));
+ set_errno(EINVAL);
+ return -1;
+ }
+
+ if (!conn) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
+ set_errno(ENOBUFS);
+ return -1;
+ }
+
+ i = alloc_socket(conn, 0);
+
+ if (i == -1) {
+ netconn_delete(conn);
+ set_errno(ENFILE);
+ return -1;
+ }
+ conn->socket = i;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
+ set_errno(0);
+ return i;
+}
+
+int
+lwip_write(int s, const void *data, size_t size)
+{
+ return lwip_send(s, data, size, 0);
+}
+
+/**
+ * Go through the readset and writeset lists and see which socket of the sockets
+ * set in the sets has events. On return, readset, writeset and exceptset have
+ * the sockets enabled that had events.
+ *
+ * exceptset is not used for now!!!
+ *
+ * @param maxfdp1 the highest socket index in the sets
+ * @param readset_in: set of sockets to check for read events
+ * @param writeset_in: set of sockets to check for write events
+ * @param exceptset_in: set of sockets to check for error events
+ * @param readset_out: set of sockets that had read events
+ * @param writeset_out: set of sockets that had write events
+ * @param exceptset_out: set os sockets that had error events
+ * @return number of sockets that had events (read/write/exception) (>= 0)
+ */
+static int
+lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
+ fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
+{
+ int i, nready = 0;
+ fd_set lreadset, lwriteset, lexceptset;
+ struct lwip_sock *sock;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ FD_ZERO(&lreadset);
+ FD_ZERO(&lwriteset);
+ FD_ZERO(&lexceptset);
+
+ /* Go through each socket in each list to count number of sockets which
+ currently match */
+ for(i = 0; i < maxfdp1; i++) {
+ void* lastdata = NULL;
+ s16_t rcvevent = 0;
+ u16_t sendevent = 0;
+ u16_t errevent = 0;
+ /* First get the socket's status (protected)... */
+ SYS_ARCH_PROTECT(lev);
+ sock = tryget_socket(i);
+ if (sock != NULL) {
+ lastdata = sock->lastdata;
+ rcvevent = sock->rcvevent;
+ sendevent = sock->sendevent;
+ errevent = sock->errevent;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+ /* ... then examine it: */
+ /* See if netconn of this socket is ready for read */
+ if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
+ FD_SET(i, &lreadset);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
+ nready++;
+ }
+ /* See if netconn of this socket is ready for write */
+ if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
+ FD_SET(i, &lwriteset);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
+ nready++;
+ }
+ /* See if netconn of this socket had an error */
+ if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
+ FD_SET(i, &lexceptset);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
+ nready++;
+ }
+ }
+ /* copy local sets to the ones provided as arguments */
+ *readset_out = lreadset;
+ *writeset_out = lwriteset;
+ *exceptset_out = lexceptset;
+
+ LWIP_ASSERT("nready >= 0", nready >= 0);
+ return nready;
+}
+
+/**
+ * Processing exceptset is not yet implemented.
+ */
+int
+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
+ struct timeval *timeout)
+{
+ u32_t waitres = 0;
+ int nready;
+ fd_set lreadset, lwriteset, lexceptset;
+ u32_t msectimeout;
+ struct lwip_select_cb select_cb;
+ err_t err;
+ int i;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
+ maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
+ timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
+ timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
+
+ /* Go through each socket in each list to count number of sockets which
+ currently match */
+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
+
+ /* If we don't have any current events, then suspend if we are supposed to */
+ if (!nready) {
+ if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
+ /* This is OK as the local fdsets are empty and nready is zero,
+ or we would have returned earlier. */
+ goto return_copy_fdsets;
+ }
+
+ /* None ready: add our semaphore to list:
+ We don't actually need any dynamic memory. Our entry on the
+ list is only valid while we are in this function, so it's ok
+ to use local variables. */
+
+ select_cb.next = NULL;
+ select_cb.prev = NULL;
+ select_cb.readset = readset;
+ select_cb.writeset = writeset;
+ select_cb.exceptset = exceptset;
+ select_cb.sem_signalled = 0;
+ err = sys_sem_new(&select_cb.sem, 0);
+ if (err != ERR_OK) {
+ /* failed to create semaphore */
+ set_errno(ENOMEM);
+ return -1;
+ }
+
+ /* Protect the select_cb_list */
+ SYS_ARCH_PROTECT(lev);
+
+ /* Put this select_cb on top of list */
+ select_cb.next = select_cb_list;
+ if (select_cb_list != NULL) {
+ select_cb_list->prev = &select_cb;
+ }
+ select_cb_list = &select_cb;
+ /* Increasing this counter tells even_callback that the list has changed. */
+ select_cb_ctr++;
+
+ /* Now we can safely unprotect */
+ SYS_ARCH_UNPROTECT(lev);
+
+ /* Increase select_waiting for each socket we are interested in */
+ for(i = 0; i < maxfdp1; i++) {
+ if ((readset && FD_ISSET(i, readset)) ||
+ (writeset && FD_ISSET(i, writeset)) ||
+ (exceptset && FD_ISSET(i, exceptset))) {
+ struct lwip_sock *sock = tryget_socket(i);
+ LWIP_ASSERT("sock != NULL", sock != NULL);
+ SYS_ARCH_PROTECT(lev);
+ sock->select_waiting++;
+ LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
+ SYS_ARCH_UNPROTECT(lev);
+ }
+ }
+
+ /* Call lwip_selscan again: there could have been events between
+ the last scan (whithout us on the list) and putting us on the list! */
+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
+ if (!nready) {
+ /* Still none ready, just wait to be woken */
+ if (timeout == 0) {
+ /* Wait forever */
+ msectimeout = 0;
+ } else {
+ msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
+ if (msectimeout == 0) {
+ /* Wait 1ms at least (0 means wait forever) */
+ msectimeout = 1;
+ }
+ }
+
+ waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
+ }
+ /* Increase select_waiting for each socket we are interested in */
+ for(i = 0; i < maxfdp1; i++) {
+ if ((readset && FD_ISSET(i, readset)) ||
+ (writeset && FD_ISSET(i, writeset)) ||
+ (exceptset && FD_ISSET(i, exceptset))) {
+ struct lwip_sock *sock = tryget_socket(i);
+ LWIP_ASSERT("sock != NULL", sock != NULL);
+ SYS_ARCH_PROTECT(lev);
+ sock->select_waiting--;
+ LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
+ SYS_ARCH_UNPROTECT(lev);
+ }
+ }
+ /* Take us off the list */
+ SYS_ARCH_PROTECT(lev);
+ if (select_cb.next != NULL) {
+ select_cb.next->prev = select_cb.prev;
+ }
+ if (select_cb_list == &select_cb) {
+ LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
+ select_cb_list = select_cb.next;
+ } else {
+ LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
+ select_cb.prev->next = select_cb.next;
+ }
+ /* Increasing this counter tells even_callback that the list has changed. */
+ select_cb_ctr++;
+ SYS_ARCH_UNPROTECT(lev);
+
+ sys_sem_free(&select_cb.sem);
+ if (waitres == SYS_ARCH_TIMEOUT) {
+ /* Timeout */
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
+ /* This is OK as the local fdsets are empty and nready is zero,
+ or we would have returned earlier. */
+ goto return_copy_fdsets;
+ }
+
+ /* See what's set */
+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
+return_copy_fdsets:
+ set_errno(0);
+ if (readset) {
+ *readset = lreadset;
+ }
+ if (writeset) {
+ *writeset = lwriteset;
+ }
+ if (exceptset) {
+ *exceptset = lexceptset;
+ }
+
+
+ return nready;
+}
+
+/**
+ * Callback registered in the netconn layer for each socket-netconn.
+ * Processes recvevent (data available) and wakes up tasks waiting for select.
+ */
+static void
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
+{
+ int s;
+ struct lwip_sock *sock;
+ struct lwip_select_cb *scb;
+ int last_select_cb_ctr;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ LWIP_UNUSED_ARG(len);
+
+ /* Get socket */
+ if (conn) {
+ s = conn->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.
+ * Just count down (or up) if that's the case and we
+ * 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 (evt == NETCONN_EVT_RCVPLUS) {
+ conn->socket--;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+ return;
+ }
+ s = conn->socket;
+ SYS_ARCH_UNPROTECT(lev);
+ }
+
+ sock = get_socket(s);
+ if (!sock) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ SYS_ARCH_PROTECT(lev);
+ /* Set event as required */
+ switch (evt) {
+ case NETCONN_EVT_RCVPLUS:
+ sock->rcvevent++;
+ break;
+ case NETCONN_EVT_RCVMINUS:
+ sock->rcvevent--;
+ break;
+ case NETCONN_EVT_SENDPLUS:
+ sock->sendevent = 1;
+ break;
+ case NETCONN_EVT_SENDMINUS:
+ sock->sendevent = 0;
+ break;
+ case NETCONN_EVT_ERROR:
+ sock->errevent = 1;
+ break;
+ default:
+ LWIP_ASSERT("unknown event", 0);
+ break;
+ }
+
+ if (sock->select_waiting == 0) {
+ /* noone is waiting for this socket, no need to check select_cb_list */
+ SYS_ARCH_UNPROTECT(lev);
+ return;
+ }
+
+ /* Now decide if anyone is waiting for this socket */
+ /* NOTE: This code goes through the select_cb_list list multiple times
+ ONLY IF a select was actually waiting. We go through the list the number
+ of waiting select calls + 1. This list is expected to be small. */
+
+ /* At this point, SYS_ARCH is still protected! */
+again:
+ for (scb = select_cb_list; scb != NULL; scb = scb->next) {
+ if (scb->sem_signalled == 0) {
+ /* semaphore not signalled yet */
+ int do_signal = 0;
+ /* Test this select call for our socket */
+ if (sock->rcvevent > 0) {
+ if (scb->readset && FD_ISSET(s, scb->readset)) {
+ do_signal = 1;
+ }
+ }
+ if (sock->sendevent != 0) {
+ if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
+ do_signal = 1;
+ }
+ }
+ if (sock->errevent != 0) {
+ if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
+ do_signal = 1;
+ }
+ }
+ if (do_signal) {
+ scb->sem_signalled = 1;
+ /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
+ lead to the select thread taking itself off the list, invalidagin the semaphore. */
+ sys_sem_signal(&scb->sem);
+ }
+ }
+ /* unlock interrupts with each step */
+ last_select_cb_ctr = select_cb_ctr;
+ SYS_ARCH_UNPROTECT(lev);
+ /* this makes sure interrupt protection time is short */
+ SYS_ARCH_PROTECT(lev);
+ if (last_select_cb_ctr != select_cb_ctr) {
+ /* someone has changed select_cb_list, restart at the beginning */
+ goto again;
+ }
+ }
+ SYS_ARCH_UNPROTECT(lev);
+}
+
+/**
+ * Unimplemented: Close one end of a full-duplex connection.
+ * Currently, the full connection is closed.
+ */
+int
+lwip_shutdown(int s, int how)
+{
+ struct lwip_sock *sock;
+ err_t err;
+ u8_t shut_rx = 0, shut_tx = 0;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ if (sock->conn != NULL) {
+ if (netconn_type(sock->conn) != NETCONN_TCP) {
+ sock_set_errno(sock, EOPNOTSUPP);
+ return EOPNOTSUPP;
+ }
+ } else {
+ sock_set_errno(sock, ENOTCONN);
+ return ENOTCONN;
+ }
+
+ if (how == SHUT_RD) {
+ shut_rx = 1;
+ } else if (how == SHUT_WR) {
+ shut_tx = 1;
+ } else if(how == SHUT_RDWR) {
+ shut_rx = 1;
+ shut_tx = 1;
+ } else {
+ sock_set_errno(sock, EINVAL);
+ return EINVAL;
+ }
+ err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
+
+ sock_set_errno(sock, err_to_errno(err));
+ return (err == ERR_OK ? 0 : -1);
+}
+
+static int
+lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
+{
+ struct lwip_sock *sock;
+ struct sockaddr_in sin;
+ ip_addr_t naddr;
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+
+ /* get the IP address and port */
+ netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
+
+ sin.sin_port = htons(sin.sin_port);
+ inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
+
+ if (*namelen > sizeof(sin)) {
+ *namelen = sizeof(sin);
+ }
+
+ MEMCPY(name, &sin, *namelen);
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
+{
+ return lwip_getaddrname(s, name, namelen, 0);
+}
+
+int
+lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
+{
+ return lwip_getaddrname(s, name, namelen, 1);
+}
+
+int
+lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+ err_t err = ERR_OK;
+ struct lwip_sock *sock = get_socket(s);
+ struct lwip_setgetsockopt_data data;
+
+ if (!sock) {
+ return -1;
+ }
+
+ if ((NULL == optval) || (NULL == optlen)) {
+ sock_set_errno(sock, EFAULT);
+ return -1;
+ }
+
+ /* Do length and type checks for the various options first, to keep it readable. */
+ switch (level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch (optname) {
+
+ case SO_ACCEPTCONN:
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_ERROR:
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_CONTIMEO: */
+ /* UNIMPL case SO_SNDTIMEO: */
+#if LWIP_SO_RCVTIMEO
+ case SO_RCVTIMEO:
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ case SO_RCVBUF:
+#endif /* LWIP_SO_RCVBUF */
+ /* UNIMPL case SO_OOBINLINE: */
+ /* UNIMPL case SO_SNDBUF: */
+ /* UNIMPL case SO_RCVLOWAT: */
+ /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ case SO_TYPE:
+ /* UNIMPL case SO_USELOOPBACK: */
+ if (*optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+ break;
+
+ case SO_NO_CHECK:
+ if (*optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+#if LWIP_UDP
+ if ((sock->conn->type != NETCONN_UDP) ||
+ ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
+ /* this flag is only available for UDP, not for UDP lite */
+ err = EAFNOSUPPORT;
+ }
+#endif /* LWIP_UDP */
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch (optname) {
+ /* UNIMPL case IP_HDRINCL: */
+ /* UNIMPL case IP_RCVDSTADDR: */
+ /* UNIMPL case IP_RCVIF: */
+ case IP_TTL:
+ case IP_TOS:
+ if (*optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+ break;
+#if LWIP_IGMP
+ case IP_MULTICAST_TTL:
+ if (*optlen < sizeof(u8_t)) {
+ err = EINVAL;
+ }
+ break;
+ case IP_MULTICAST_IF:
+ if (*optlen < sizeof(struct in_addr)) {
+ err = EINVAL;
+ }
+ break;
+ case IP_MULTICAST_LOOP:
+ if (*optlen < sizeof(u8_t)) {
+ err = EINVAL;
+ }
+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+ err = EAFNOSUPPORT;
+ }
+ break;
+#endif /* LWIP_IGMP */
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+
+#if LWIP_TCP
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ if (*optlen < sizeof(int)) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no TCP socket, ignore any options. */
+ if (sock->conn->type != NETCONN_TCP)
+ return 0;
+
+ switch (optname) {
+ case TCP_NODELAY:
+ case TCP_KEEPALIVE:
+#if LWIP_TCP_KEEPALIVE
+ case TCP_KEEPIDLE:
+ case TCP_KEEPINTVL:
+ case TCP_KEEPCNT:
+#endif /* LWIP_TCP_KEEPALIVE */
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_TCP */
+#if LWIP_UDP && LWIP_UDPLITE
+/* Level: IPPROTO_UDPLITE */
+ case IPPROTO_UDPLITE:
+ if (*optlen < sizeof(int)) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no UDP lite socket, ignore any options. */
+ if (sock->conn->type != NETCONN_UDPLITE) {
+ return 0;
+ }
+
+ switch (optname) {
+ case UDPLITE_SEND_CSCOV:
+ case UDPLITE_RECV_CSCOV:
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_UDP && LWIP_UDPLITE*/
+/* UNDEFINED LEVEL */
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
+ s, level, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+
+
+ if (err != ERR_OK) {
+ sock_set_errno(sock, err);
+ return -1;
+ }
+
+ /* Now do the actual option processing */
+ data.sock = sock;
+#ifdef LWIP_DEBUG
+ data.s = s;
+#endif /* LWIP_DEBUG */
+ data.level = level;
+ data.optname = optname;
+ data.optval = optval;
+ data.optlen = optlen;
+ data.err = err;
+ tcpip_callback(lwip_getsockopt_internal, &data);
+ sys_arch_sem_wait(&sock->conn->op_completed, 0);
+ /* maybe lwip_getsockopt_internal has changed err */
+ err = data.err;
+
+ sock_set_errno(sock, err);
+ return err ? -1 : 0;
+}
+
+static void
+lwip_getsockopt_internal(void *arg)
+{
+ struct lwip_sock *sock;
+#ifdef LWIP_DEBUG
+ int s;
+#endif /* LWIP_DEBUG */
+ int level, optname;
+ void *optval;
+ struct lwip_setgetsockopt_data *data;
+
+ LWIP_ASSERT("arg != NULL", arg != NULL);
+
+ data = (struct lwip_setgetsockopt_data*)arg;
+ sock = data->sock;
+#ifdef LWIP_DEBUG
+ s = data->s;
+#endif /* LWIP_DEBUG */
+ level = data->level;
+ optname = data->optname;
+ optval = data->optval;
+
+ switch (level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch (optname) {
+
+ /* The option flags */
+ case SO_ACCEPTCONN:
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /*case SO_USELOOPBACK: UNIMPL */
+ *(int*)optval = sock->conn->pcb.ip->so_options & optname;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
+ s, optname, (*(int*)optval?"on":"off")));
+ break;
+
+ case SO_TYPE:
+ switch (NETCONNTYPE_GROUP(sock->conn->type)) {
+ case NETCONN_RAW:
+ *(int*)optval = SOCK_RAW;
+ break;
+ case NETCONN_TCP:
+ *(int*)optval = SOCK_STREAM;
+ break;
+ case NETCONN_UDP:
+ *(int*)optval = SOCK_DGRAM;
+ break;
+ default: /* unrecognized socket type */
+ *(int*)optval = sock->conn->type;
+ LWIP_DEBUGF(SOCKETS_DEBUG,
+ ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
+ s, *(int *)optval));
+ } /* switch (sock->conn->type) */
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
+ s, *(int *)optval));
+ break;
+
+ case SO_ERROR:
+ /* only overwrite ERR_OK or tempoary errors */
+ if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
+ sock_set_errno(sock, err_to_errno(sock->conn->last_err));
+ }
+ *(int *)optval = sock->err;
+ sock->err = 0;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
+ s, *(int *)optval));
+ break;
+
+#if LWIP_SO_RCVTIMEO
+ case SO_RCVTIMEO:
+ *(int *)optval = netconn_get_recvtimeout(sock->conn);
+ break;
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ case SO_RCVBUF:
+ *(int *)optval = netconn_get_recvbufsize(sock->conn);
+ break;
+#endif /* LWIP_SO_RCVBUF */
+#if LWIP_UDP
+ case SO_NO_CHECK:
+ *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
+ break;
+#endif /* LWIP_UDP*/
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch (optname) {
+ case IP_TTL:
+ *(int*)optval = sock->conn->pcb.ip->ttl;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
+ s, *(int *)optval));
+ break;
+ case IP_TOS:
+ *(int*)optval = sock->conn->pcb.ip->tos;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
+ s, *(int *)optval));
+ break;
+#if LWIP_IGMP
+ case IP_MULTICAST_TTL:
+ *(u8_t*)optval = sock->conn->pcb.ip->ttl;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
+ s, *(int *)optval));
+ break;
+ case IP_MULTICAST_IF:
+ inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
+ s, *(u32_t *)optval));
+ break;
+ case IP_MULTICAST_LOOP:
+ if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
+ *(u8_t*)optval = 1;
+ } else {
+ *(u8_t*)optval = 0;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
+ s, *(int *)optval));
+ break;
+#endif /* LWIP_IGMP */
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+
+#if LWIP_TCP
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ switch (optname) {
+ case TCP_NODELAY:
+ *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
+ s, (*(int*)optval)?"on":"off") );
+ break;
+ case TCP_KEEPALIVE:
+ *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
+ s, *(int *)optval));
+ break;
+
+#if LWIP_TCP_KEEPALIVE
+ case TCP_KEEPIDLE:
+ *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
+ s, *(int *)optval));
+ break;
+ case TCP_KEEPINTVL:
+ *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
+ s, *(int *)optval));
+ break;
+ case TCP_KEEPCNT:
+ *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
+ s, *(int *)optval));
+ break;
+#endif /* LWIP_TCP_KEEPALIVE */
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_TCP */
+#if LWIP_UDP && LWIP_UDPLITE
+ /* Level: IPPROTO_UDPLITE */
+ case IPPROTO_UDPLITE:
+ switch (optname) {
+ case UDPLITE_SEND_CSCOV:
+ *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
+ s, (*(int*)optval)) );
+ break;
+ case UDPLITE_RECV_CSCOV:
+ *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
+ s, (*(int*)optval)) );
+ break;
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_UDP */
+ default:
+ LWIP_ASSERT("unhandled level", 0);
+ break;
+ } /* switch (level) */
+ sys_sem_signal(&sock->conn->op_completed);
+}
+
+int
+lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+ struct lwip_sock *sock = get_socket(s);
+ err_t err = ERR_OK;
+ struct lwip_setgetsockopt_data data;
+
+ if (!sock) {
+ return -1;
+ }
+
+ if (NULL == optval) {
+ sock_set_errno(sock, EFAULT);
+ return -1;
+ }
+
+ /* Do length and type checks for the various options first, to keep it readable. */
+ switch (level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch (optname) {
+
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case case SO_CONTIMEO: */
+ /* UNIMPL case case SO_SNDTIMEO: */
+#if LWIP_SO_RCVTIMEO
+ case SO_RCVTIMEO:
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ case SO_RCVBUF:
+#endif /* LWIP_SO_RCVBUF */
+ /* UNIMPL case SO_OOBINLINE: */
+ /* UNIMPL case SO_SNDBUF: */
+ /* UNIMPL case SO_RCVLOWAT: */
+ /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /* UNIMPL case SO_USELOOPBACK: */
+ if (optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+ break;
+ case SO_NO_CHECK:
+ if (optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+#if LWIP_UDP
+ if ((sock->conn->type != NETCONN_UDP) ||
+ ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
+ /* this flag is only available for UDP, not for UDP lite */
+ err = EAFNOSUPPORT;
+ }
+#endif /* LWIP_UDP */
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch (optname) {
+ /* UNIMPL case IP_HDRINCL: */
+ /* UNIMPL case IP_RCVDSTADDR: */
+ /* UNIMPL case IP_RCVIF: */
+ case IP_TTL:
+ case IP_TOS:
+ if (optlen < sizeof(int)) {
+ err = EINVAL;
+ }
+ break;
+#if LWIP_IGMP
+ case IP_MULTICAST_TTL:
+ if (optlen < sizeof(u8_t)) {
+ err = EINVAL;
+ }
+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+ err = EAFNOSUPPORT;
+ }
+ break;
+ case IP_MULTICAST_IF:
+ if (optlen < sizeof(struct in_addr)) {
+ err = EINVAL;
+ }
+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+ err = EAFNOSUPPORT;
+ }
+ break;
+ case IP_MULTICAST_LOOP:
+ if (optlen < sizeof(u8_t)) {
+ err = EINVAL;
+ }
+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+ err = EAFNOSUPPORT;
+ }
+ break;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ if (optlen < sizeof(struct ip_mreq)) {
+ err = EINVAL;
+ }
+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+ err = EAFNOSUPPORT;
+ }
+ break;
+#endif /* LWIP_IGMP */
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+
+#if LWIP_TCP
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ if (optlen < sizeof(int)) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no TCP socket, ignore any options. */
+ if (sock->conn->type != NETCONN_TCP)
+ return 0;
+
+ switch (optname) {
+ case TCP_NODELAY:
+ case TCP_KEEPALIVE:
+#if LWIP_TCP_KEEPALIVE
+ case TCP_KEEPIDLE:
+ case TCP_KEEPINTVL:
+ case TCP_KEEPCNT:
+#endif /* LWIP_TCP_KEEPALIVE */
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_TCP */
+#if LWIP_UDP && LWIP_UDPLITE
+/* Level: IPPROTO_UDPLITE */
+ case IPPROTO_UDPLITE:
+ if (optlen < sizeof(int)) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no UDP lite socket, ignore any options. */
+ if (sock->conn->type != NETCONN_UDPLITE)
+ return 0;
+
+ switch (optname) {
+ case UDPLITE_SEND_CSCOV:
+ case UDPLITE_RECV_CSCOV:
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
+ s, optname));
+ err = ENOPROTOOPT;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_UDP && LWIP_UDPLITE */
+/* UNDEFINED LEVEL */
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
+ s, level, optname));
+ err = ENOPROTOOPT;
+ } /* switch (level) */
+
+
+ if (err != ERR_OK) {
+ sock_set_errno(sock, err);
+ return -1;
+ }
+
+
+ /* Now do the actual option processing */
+ data.sock = sock;
+#ifdef LWIP_DEBUG
+ data.s = s;
+#endif /* LWIP_DEBUG */
+ data.level = level;
+ data.optname = optname;
+ data.optval = (void*)optval;
+ data.optlen = &optlen;
+ data.err = err;
+ tcpip_callback(lwip_setsockopt_internal, &data);
+ sys_arch_sem_wait(&sock->conn->op_completed, 0);
+ /* maybe lwip_setsockopt_internal has changed err */
+ err = data.err;
+
+ sock_set_errno(sock, err);
+ return err ? -1 : 0;
+}
+
+static void
+lwip_setsockopt_internal(void *arg)
+{
+ struct lwip_sock *sock;
+#ifdef LWIP_DEBUG
+ int s;
+#endif /* LWIP_DEBUG */
+ int level, optname;
+ const void *optval;
+ struct lwip_setgetsockopt_data *data;
+
+ LWIP_ASSERT("arg != NULL", arg != NULL);
+
+ data = (struct lwip_setgetsockopt_data*)arg;
+ sock = data->sock;
+#ifdef LWIP_DEBUG
+ s = data->s;
+#endif /* LWIP_DEBUG */
+ level = data->level;
+ optname = data->optname;
+ optval = data->optval;
+
+ switch (level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch (optname) {
+
+ /* The option flags */
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /* UNIMPL case SO_USELOOPBACK: */
+ if (*(int*)optval) {
+ sock->conn->pcb.ip->so_options |= optname;
+ } else {
+ sock->conn->pcb.ip->so_options &= ~optname;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
+ s, optname, (*(int*)optval?"on":"off")));
+ break;
+#if LWIP_SO_RCVTIMEO
+ case SO_RCVTIMEO:
+ netconn_set_recvtimeout(sock->conn, *(int*)optval);
+ break;
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ case SO_RCVBUF:
+ netconn_set_recvbufsize(sock->conn, *(int*)optval);
+ break;
+#endif /* LWIP_SO_RCVBUF */
+#if LWIP_UDP
+ case SO_NO_CHECK:
+ if (*(int*)optval) {
+ udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
+ } else {
+ udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
+ }
+ break;
+#endif /* LWIP_UDP */
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch (optname) {
+ case IP_TTL:
+ sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
+ s, sock->conn->pcb.ip->ttl));
+ break;
+ case IP_TOS:
+ sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
+ s, sock->conn->pcb.ip->tos));
+ break;
+#if LWIP_IGMP
+ case IP_MULTICAST_TTL:
+ sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
+ break;
+ case IP_MULTICAST_IF:
+ inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
+ break;
+ case IP_MULTICAST_LOOP:
+ if (*(u8_t*)optval) {
+ udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
+ } else {
+ udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
+ }
+ break;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ {
+ /* If this is a TCP or a RAW socket, ignore these options. */
+ struct ip_mreq *imr = (struct ip_mreq *)optval;
+ ip_addr_t if_addr;
+ ip_addr_t multi_addr;
+ inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
+ inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
+ if(optname == IP_ADD_MEMBERSHIP){
+ data->err = igmp_joingroup(&if_addr, &multi_addr);
+ } else {
+ data->err = igmp_leavegroup(&if_addr, &multi_addr);
+ }
+ if(data->err != ERR_OK) {
+ data->err = EADDRNOTAVAIL;
+ }
+ }
+ break;
+#endif /* LWIP_IGMP */
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+
+#if LWIP_TCP
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ switch (optname) {
+ case TCP_NODELAY:
+ if (*(int*)optval) {
+ tcp_nagle_disable(sock->conn->pcb.tcp);
+ } else {
+ tcp_nagle_enable(sock->conn->pcb.tcp);
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
+ s, (*(int *)optval)?"on":"off") );
+ break;
+ case TCP_KEEPALIVE:
+ sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
+ s, sock->conn->pcb.tcp->keep_idle));
+ break;
+
+#if LWIP_TCP_KEEPALIVE
+ case TCP_KEEPIDLE:
+ sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
+ s, sock->conn->pcb.tcp->keep_idle));
+ break;
+ case TCP_KEEPINTVL:
+ sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
+ s, sock->conn->pcb.tcp->keep_intvl));
+ break;
+ case TCP_KEEPCNT:
+ sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
+ s, sock->conn->pcb.tcp->keep_cnt));
+ break;
+#endif /* LWIP_TCP_KEEPALIVE */
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_TCP*/
+#if LWIP_UDP && LWIP_UDPLITE
+ /* Level: IPPROTO_UDPLITE */
+ case IPPROTO_UDPLITE:
+ switch (optname) {
+ case UDPLITE_SEND_CSCOV:
+ if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
+ /* don't allow illegal values! */
+ sock->conn->pcb.udp->chksum_len_tx = 8;
+ } else {
+ sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
+ s, (*(int*)optval)) );
+ break;
+ case UDPLITE_RECV_CSCOV:
+ if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
+ /* don't allow illegal values! */
+ sock->conn->pcb.udp->chksum_len_rx = 8;
+ } else {
+ sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
+ s, (*(int*)optval)) );
+ break;
+ default:
+ LWIP_ASSERT("unhandled optname", 0);
+ break;
+ } /* switch (optname) */
+ break;
+#endif /* LWIP_UDP */
+ default:
+ LWIP_ASSERT("unhandled level", 0);
+ break;
+ } /* switch (level) */
+ sys_sem_signal(&sock->conn->op_completed);
+}
+
+int
+lwip_ioctl(int s, long cmd, void *argp)
+{
+ struct lwip_sock *sock = get_socket(s);
+ u8_t val;
+#if LWIP_SO_RCVBUF
+ u16_t buflen = 0;
+ s16_t recv_avail;
+#endif /* LWIP_SO_RCVBUF */
+
+ if (!sock) {
+ return -1;
+ }
+
+ switch (cmd) {
+#if LWIP_SO_RCVBUF
+ case FIONREAD:
+ if (!argp) {
+ sock_set_errno(sock, EINVAL);
+ return -1;
+ }
+
+ SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
+ if (recv_avail < 0) {
+ recv_avail = 0;
+ }
+ *((u16_t*)argp) = (u16_t)recv_avail;
+
+ /* Check if there is data left from the last recv operation. /maq 041215 */
+ if (sock->lastdata) {
+ struct pbuf *p = (struct pbuf *)sock->lastdata;
+ if (netconn_type(sock->conn) != NETCONN_TCP) {
+ p = ((struct netbuf *)p)->p;
+ }
+ buflen = p->tot_len;
+ buflen -= sock->lastoffset;
+
+ *((u16_t*)argp) += buflen;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
+ sock_set_errno(sock, 0);
+ return 0;
+#endif /* LWIP_SO_RCVBUF */
+
+ case FIONBIO:
+ val = 0;
+ if (argp && *(u32_t*)argp) {
+ val = 1;
+ }
+ netconn_set_nonblocking(sock->conn, val);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
+ sock_set_errno(sock, 0);
+ return 0;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
+ sock_set_errno(sock, ENOSYS); /* not yet implemented */
+ return -1;
+ } /* switch (cmd) */
+}
+
+/** A minimal implementation of fcntl.
+ * Currently only the commands F_GETFL and F_SETFL are implemented.
+ * Only the flag O_NONBLOCK is implemented.
+ */
+int
+lwip_fcntl(int s, int cmd, int val)
+{
+ struct lwip_sock *sock = get_socket(s);
+ int ret = -1;
+
+ if (!sock || !sock->conn) {
+ return -1;
+ }
+
+ switch (cmd) {
+ case F_GETFL:
+ ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
+ break;
+ case F_SETFL:
+ if ((val & ~O_NONBLOCK) == 0) {
+ /* only O_NONBLOCK, all other bits are zero */
+ netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
+ ret = 0;
+ }
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
+ break;
+ }
+ return ret;
+}
+
+#endif /* LWIP_SOCKET */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/tcpip.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/tcpip.c
new file mode 100644
index 0000000000..857e7d9bd6
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/api/tcpip.c
@@ -0,0 +1,460 @@
+/**
+ * @file
+ * Sequential API Main thread module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/sys.h"
+#include "lwip/memp.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+#include "lwip/init.h"
+#include "netif/etharp.h"
+#include "netif/ppp_oe.h"
+
+/* global variables */
+static tcpip_init_done_fn tcpip_init_done;
+static void *tcpip_init_done_arg;
+static sys_mbox_t mbox;
+
+#if LWIP_TCPIP_CORE_LOCKING
+/** The global semaphore to lock the stack. */
+sys_mutex_t lock_tcpip_core;
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
+
+/**
+ * The main lwIP thread. This thread has exclusive access to lwIP core functions
+ * (unless access to them is not locked). Other threads communicate with this
+ * thread using message boxes.
+ *
+ * It also starts all the timers to make sure they are running in the right
+ * thread context.
+ *
+ * @param arg unused argument
+ */
+static void
+tcpip_thread(void *arg)
+{
+ struct tcpip_msg *msg;
+ LWIP_UNUSED_ARG(arg);
+
+ if (tcpip_init_done != NULL) {
+ tcpip_init_done(tcpip_init_done_arg);
+ }
+
+ LOCK_TCPIP_CORE();
+ while (1) { /* MAIN Loop */
+ UNLOCK_TCPIP_CORE();
+ LWIP_TCPIP_THREAD_ALIVE();
+ /* wait for a message, timeouts are processed while waiting */
+ sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
+ LOCK_TCPIP_CORE();
+ switch (msg->type) {
+#if LWIP_NETCONN
+ case TCPIP_MSG_API:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
+ msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
+ break;
+#endif /* LWIP_NETCONN */
+
+#if !LWIP_TCPIP_CORE_LOCKING_INPUT
+ case TCPIP_MSG_INPKT:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
+#if LWIP_ETHERNET
+ if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
+ ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
+ } else
+#endif /* LWIP_ETHERNET */
+ {
+ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
+ }
+ memp_free(MEMP_TCPIP_MSG_INPKT, msg);
+ break;
+#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
+
+#if LWIP_NETIF_API
+ case TCPIP_MSG_NETIFAPI:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
+ msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
+ break;
+#endif /* LWIP_NETIF_API */
+
+ case TCPIP_MSG_CALLBACK:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
+ msg->msg.cb.function(msg->msg.cb.ctx);
+ memp_free(MEMP_TCPIP_MSG_API, msg);
+ break;
+
+#if LWIP_TCPIP_TIMEOUT
+ case TCPIP_MSG_TIMEOUT:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
+ sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
+ memp_free(MEMP_TCPIP_MSG_API, msg);
+ break;
+ case TCPIP_MSG_UNTIMEOUT:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
+ sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
+ memp_free(MEMP_TCPIP_MSG_API, msg);
+ break;
+#endif /* LWIP_TCPIP_TIMEOUT */
+
+ default:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
+ LWIP_ASSERT("tcpip_thread: invalid message", 0);
+ break;
+ }
+ }
+}
+
+/**
+ * Pass a received packet to tcpip_thread for input processing
+ *
+ * @param p the received packet, p->payload pointing to the Ethernet header or
+ * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
+ * NETIF_FLAG_ETHERNET flags)
+ * @param inp the network interface on which the packet was received
+ */
+err_t
+tcpip_input(struct pbuf *p, struct netif *inp)
+{
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ err_t ret;
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
+ LOCK_TCPIP_CORE();
+#if LWIP_ETHERNET
+ if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
+ ret = ethernet_input(p, inp);
+ } else
+#endif /* LWIP_ETHERNET */
+ {
+ ret = ip_input(p, inp);
+ }
+ UNLOCK_TCPIP_CORE();
+ return ret;
+#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
+ struct tcpip_msg *msg;
+
+ if (sys_mbox_valid(&mbox)) {
+ msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
+ if (msg == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_INPKT;
+ msg->msg.inp.p = p;
+ msg->msg.inp.netif = inp;
+ if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
+ memp_free(MEMP_TCPIP_MSG_INPKT, msg);
+ return ERR_MEM;
+ }
+ return ERR_OK;
+ }
+ return ERR_VAL;
+#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
+}
+
+/**
+ * Call a specific function in the thread context of
+ * tcpip_thread for easy access synchronization.
+ * A function called in that way may access lwIP core code
+ * without fearing concurrent access.
+ *
+ * @param f the function to call
+ * @param ctx parameter passed to f
+ * @param block 1 to block until the request is posted, 0 to non-blocking mode
+ * @return ERR_OK if the function was called, another err_t if not
+ */
+err_t
+tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
+{
+ struct tcpip_msg *msg;
+
+ if (sys_mbox_valid(&mbox)) {
+ msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+ if (msg == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_CALLBACK;
+ msg->msg.cb.function = function;
+ msg->msg.cb.ctx = ctx;
+ if (block) {
+ sys_mbox_post(&mbox, msg);
+ } else {
+ if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
+ memp_free(MEMP_TCPIP_MSG_API, msg);
+ return ERR_MEM;
+ }
+ }
+ return ERR_OK;
+ }
+ return ERR_VAL;
+}
+
+#if LWIP_TCPIP_TIMEOUT
+/**
+ * call sys_timeout in tcpip_thread
+ *
+ * @param msec time in milliseconds for timeout
+ * @param h function to be called on timeout
+ * @param arg argument to pass to timeout function h
+ * @return ERR_MEM on memory error, ERR_OK otherwise
+ */
+err_t
+tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
+{
+ struct tcpip_msg *msg;
+
+ if (sys_mbox_valid(&mbox)) {
+ msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+ if (msg == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_TIMEOUT;
+ msg->msg.tmo.msecs = msecs;
+ msg->msg.tmo.h = h;
+ msg->msg.tmo.arg = arg;
+ sys_mbox_post(&mbox, msg);
+ return ERR_OK;
+ }
+ return ERR_VAL;
+}
+
+/**
+ * call sys_untimeout in tcpip_thread
+ *
+ * @param msec time in milliseconds for timeout
+ * @param h function to be called on timeout
+ * @param arg argument to pass to timeout function h
+ * @return ERR_MEM on memory error, ERR_OK otherwise
+ */
+err_t
+tcpip_untimeout(sys_timeout_handler h, void *arg)
+{
+ struct tcpip_msg *msg;
+
+ if (sys_mbox_valid(&mbox)) {
+ msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+ if (msg == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_UNTIMEOUT;
+ msg->msg.tmo.h = h;
+ msg->msg.tmo.arg = arg;
+ sys_mbox_post(&mbox, msg);
+ return ERR_OK;
+ }
+ return ERR_VAL;
+}
+#endif /* LWIP_TCPIP_TIMEOUT */
+
+#if LWIP_NETCONN
+/**
+ * Call the lower part of a netconn_* function
+ * This function is then running in the thread context
+ * of tcpip_thread and has exclusive access to lwIP core code.
+ *
+ * @param apimsg a struct containing the function to call and its parameters
+ * @return ERR_OK if the function was called, another err_t if not
+ */
+err_t
+tcpip_apimsg(struct api_msg *apimsg)
+{
+ struct tcpip_msg msg;
+#ifdef LWIP_DEBUG
+ /* catch functions that don't set err */
+ apimsg->msg.err = ERR_VAL;
+#endif
+
+ if (sys_mbox_valid(&mbox)) {
+ msg.type = TCPIP_MSG_API;
+ msg.msg.apimsg = apimsg;
+ sys_mbox_post(&mbox, &msg);
+ sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
+ return apimsg->msg.err;
+ }
+ return ERR_VAL;
+}
+
+#if LWIP_TCPIP_CORE_LOCKING
+/**
+ * Call the lower part of a netconn_* function
+ * This function has exclusive access to lwIP core code by locking it
+ * before the function is called.
+ *
+ * @param apimsg a struct containing the function to call and its parameters
+ * @return ERR_OK (only for compatibility fo tcpip_apimsg())
+ */
+err_t
+tcpip_apimsg_lock(struct api_msg *apimsg)
+{
+#ifdef LWIP_DEBUG
+ /* catch functions that don't set err */
+ apimsg->msg.err = ERR_VAL;
+#endif
+
+ LOCK_TCPIP_CORE();
+ apimsg->function(&(apimsg->msg));
+ UNLOCK_TCPIP_CORE();
+ return apimsg->msg.err;
+
+}
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+#endif /* LWIP_NETCONN */
+
+#if LWIP_NETIF_API
+#if !LWIP_TCPIP_CORE_LOCKING
+/**
+ * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
+ * function.
+ *
+ * @param netifapimsg a struct containing the function to call and its parameters
+ * @return error code given back by the function that was called
+ */
+err_t
+tcpip_netifapi(struct netifapi_msg* netifapimsg)
+{
+ struct tcpip_msg msg;
+
+ if (sys_mbox_valid(&mbox)) {
+ err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
+ if (err != ERR_OK) {
+ netifapimsg->msg.err = err;
+ return err;
+ }
+
+ msg.type = TCPIP_MSG_NETIFAPI;
+ msg.msg.netifapimsg = netifapimsg;
+ sys_mbox_post(&mbox, &msg);
+ sys_sem_wait(&netifapimsg->msg.sem);
+ sys_sem_free(&netifapimsg->msg.sem);
+ return netifapimsg->msg.err;
+ }
+ return ERR_VAL;
+}
+#else /* !LWIP_TCPIP_CORE_LOCKING */
+/**
+ * Call the lower part of a netifapi_* function
+ * This function has exclusive access to lwIP core code by locking it
+ * before the function is called.
+ *
+ * @param netifapimsg a struct containing the function to call and its parameters
+ * @return ERR_OK (only for compatibility fo tcpip_netifapi())
+ */
+err_t
+tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
+{
+ LOCK_TCPIP_CORE();
+ netifapimsg->function(&(netifapimsg->msg));
+ UNLOCK_TCPIP_CORE();
+ return netifapimsg->msg.err;
+}
+#endif /* !LWIP_TCPIP_CORE_LOCKING */
+#endif /* LWIP_NETIF_API */
+
+/**
+ * Initialize this module:
+ * - initialize all sub modules
+ * - start the tcpip_thread
+ *
+ * @param initfunc a function to call when tcpip_thread is running and finished initializing
+ * @param arg argument to pass to initfunc
+ */
+void
+tcpip_init(tcpip_init_done_fn initfunc, void *arg)
+{
+ lwip_init();
+
+ tcpip_init_done = initfunc;
+ tcpip_init_done_arg = arg;
+ if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
+ LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
+ }
+#if LWIP_TCPIP_CORE_LOCKING
+ if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
+ LWIP_ASSERT("failed to create lock_tcpip_core", 0);
+ }
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
+ sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
+}
+
+/**
+ * Simple callback function used with tcpip_callback to free a pbuf
+ * (pbuf_free has a wrong signature for tcpip_callback)
+ *
+ * @param p The pbuf (chain) to be dereferenced.
+ */
+static void
+pbuf_free_int(void *p)
+{
+ struct pbuf *q = (struct pbuf *)p;
+ pbuf_free(q);
+}
+
+/**
+ * A simple wrapper function that allows you to free a pbuf from interrupt context.
+ *
+ * @param p The pbuf (chain) to be dereferenced.
+ * @return ERR_OK if callback could be enqueued, an err_t if not
+ */
+err_t
+pbuf_free_callback(struct pbuf *p)
+{
+ return tcpip_callback_with_block(pbuf_free_int, p, 0);
+}
+
+/**
+ * A simple wrapper function that allows you to free heap memory from
+ * interrupt context.
+ *
+ * @param m the heap memory to free
+ * @return ERR_OK if callback could be enqueued, an err_t if not
+ */
+err_t
+mem_free_callback(void *m)
+{
+ return tcpip_callback_with_block(mem_free, m, 0);
+}
+
+#endif /* !NO_SYS */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/def.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/def.c
new file mode 100644
index 0000000000..352b55241a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/def.c
@@ -0,0 +1,108 @@
+/**
+ * @file
+ * Common functions used throughout the stack.
+ *
+ */
+
+/*
+ * 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
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+
+/**
+ * These are reference implementations of the byte swapping functions.
+ * Again with the aim of being simple, correct and fully portable.
+ * Byte swapping is the second thing you would want to optimize. You will
+ * need to port it to your architecture and in your cc.h:
+ *
+ * #define LWIP_PLATFORM_BYTESWAP 1
+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>
+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>
+ *
+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.
+ */
+
+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
+
+/**
+ * Convert an u16_t from host- to network byte order.
+ *
+ * @param n u16_t in host byte order
+ * @return n in network byte order
+ */
+u16_t
+lwip_htons(u16_t n)
+{
+ return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
+}
+
+/**
+ * Convert an u16_t from network- to host byte order.
+ *
+ * @param n u16_t in network byte order
+ * @return n in host byte order
+ */
+u16_t
+lwip_ntohs(u16_t n)
+{
+ return lwip_htons(n);
+}
+
+/**
+ * Convert an u32_t from host- to network byte order.
+ *
+ * @param n u32_t in host byte order
+ * @return n in network byte order
+ */
+u32_t
+lwip_htonl(u32_t n)
+{
+ return ((n & 0xff) << 24) |
+ ((n & 0xff00) << 8) |
+ ((n & 0xff0000UL) >> 8) |
+ ((n & 0xff000000UL) >> 24);
+}
+
+/**
+ * Convert an u32_t from network- to host byte order.
+ *
+ * @param n u32_t in network byte order
+ * @return n in host byte order
+ */
+u32_t
+lwip_ntohl(u32_t n)
+{
+ return lwip_htonl(n);
+}
+
+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dhcp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dhcp.c
new file mode 100644
index 0000000000..03c0c62384
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dhcp.c
@@ -0,0 +1,1749 @@
+/**
+ * @file
+ * Dynamic Host Configuration Protocol client
+ *
+ */
+
+/*
+ *
+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * Copyright (c) 2001-2004 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.
+ *
+ * This file is a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+ *
+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
+ *
+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
+ * with RFC 2131 and RFC 2132.
+ *
+ * TODO:
+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
+ *
+ * Please coordinate changes and requests with Leon Woestenberg
+ * <leon.woestenberg@gmx.net>
+ *
+ * Integration with your code:
+ *
+ * In lwip/dhcp.h
+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
+ *
+ * Then have your application call dhcp_coarse_tmr() and
+ * dhcp_fine_tmr() on the defined intervals.
+ *
+ * dhcp_start(struct netif *netif);
+ * starts a DHCP client instance which configures the interface by
+ * obtaining an IP address lease and maintaining it.
+ *
+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
+ * to remove the DHCP client.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+#include "lwip/udp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/def.h"
+#include "lwip/sys.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/dns.h"
+#include "netif/etharp.h"
+
+#include <string.h>
+
+/** Default for DHCP_GLOBAL_XID is 0xABCD0000
+ * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
+ * #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
+ * #define DHCP_GLOBAL_XID rand()
+ */
+#ifdef DHCP_GLOBAL_XID_HEADER
+#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
+#endif
+
+/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
+ * MTU is checked to be big enough in dhcp_start */
+#define DHCP_MAX_MSG_LEN(netif) (netif->mtu)
+#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576
+/** Minimum length for reply before packet is parsed */
+#define DHCP_MIN_REPLY_LEN 44
+
+#define REBOOT_TRIES 2
+
+/** 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). */
+#define DHCP_OPTION_IDX_OVERLOAD 0
+#define DHCP_OPTION_IDX_MSG_TYPE 1
+#define DHCP_OPTION_IDX_SERVER_ID 2
+#define DHCP_OPTION_IDX_LEASE_TIME 3
+#define DHCP_OPTION_IDX_T1 4
+#define DHCP_OPTION_IDX_T2 5
+#define DHCP_OPTION_IDX_SUBNET_MASK 6
+#define DHCP_OPTION_IDX_ROUTER 7
+#define DHCP_OPTION_IDX_DNS_SERVER 8
+#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
+
+/** 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];
+/** 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];
+
+#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))
+
+
+/* DHCP client state machine functions */
+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
+static err_t dhcp_decline(struct netif *netif);
+#endif /* DHCP_DOES_ARP_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);
+
+/* receive, unfold, parse and free incoming messages */
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+
+/* set the DHCP timers */
+static void dhcp_timeout(struct netif *netif);
+static void dhcp_t1_timeout(struct netif *netif);
+static void dhcp_t2_timeout(struct netif *netif);
+
+/* build outgoing messages */
+/* create a DHCP message, fill in common headers */
+static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type);
+/* free a DHCP request */
+static void dhcp_delete_msg(struct dhcp *dhcp);
+/* add a DHCP option (type, then length in bytes) */
+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
+/* add option values */
+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
+/* always add the DHCP options trailer to end and pad */
+static void dhcp_option_trailer(struct dhcp *dhcp);
+
+/**
+ * Back-off the DHCP client (because of a received NAK response).
+ *
+ * Back-off the DHCP client because of a received NAK. Receiving a
+ * NAK means the client asked for something non-sensible, for
+ * example when it tries to renew a lease obtained on another network.
+ *
+ * We clear any existing set IP address and restart DHCP negotiation
+ * afresh (as per RFC2131 3.2.3).
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_nak(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
+ (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+ /* Set the interface down since the address must no longer be used, as per RFC2131 */
+ netif_set_down(netif);
+ /* remove IP address from interface */
+ netif_set_ipaddr(netif, IP_ADDR_ANY);
+ netif_set_gw(netif, IP_ADDR_ANY);
+ netif_set_netmask(netif, IP_ADDR_ANY);
+ /* Change to a defined state */
+ dhcp_set_state(dhcp, DHCP_BACKING_OFF);
+ /* We can immediately restart discovery */
+ dhcp_discover(netif);
+}
+
+#if DHCP_DOES_ARP_CHECK
+/**
+ * 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.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_check(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ 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_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"));
+ }
+ dhcp->tries++;
+ msecs = 500;
+ dhcp->request_timeout = (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));
+}
+#endif /* DHCP_DOES_ARP_CHECK */
+
+/**
+ * Remember the configuration offered by a DHCP server.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_offer(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
+ (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+ /* obtain the server address */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
+ ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
+ ip4_addr_get_u32(&dhcp->server_ip_addr)));
+ /* remember offered address */
+ ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n",
+ ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+ dhcp_select(netif);
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif));
+ }
+}
+
+/**
+ * Select a DHCP server offer out of all offers.
+ *
+ * Simply select the first offer received.
+ *
+ * @param netif the netif under DHCP control
+ * @return lwIP specific error (see error.h)
+ */
+static err_t
+dhcp_select(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result;
+ u16_t msecs;
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+ dhcp_set_state(dhcp, DHCP_REQUESTING);
+
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+ if (result == ERR_OK) {
+ dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+ /* MUST request the offered IP address */
+ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+ dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+ dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+ dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr)));
+
+ dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
+ dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
+ dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
+ dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
+ dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
+
+#if LWIP_NETIF_HOSTNAME
+ if (netif->hostname != NULL) {
+ const char *p = (const char*)netif->hostname;
+ u8_t namelen = (u8_t)strlen(p);
+ if (namelen > 0) {
+ LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+ dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+ while (*p) {
+ dhcp_option_byte(dhcp, *p++);
+ }
+ }
+ }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ dhcp_option_trailer(dhcp);
+ /* shrink the pbuf to the actual content length */
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ /* send broadcast to any DHCP server */
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
+ dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
+ return result;
+}
+
+/**
+ * The DHCP timer that checks for lease renewal/rebind timeouts.
+ */
+void
+dhcp_coarse_tmr()
+{
+ struct netif *netif = netif_list;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
+ /* iterate through all network interfaces */
+ while (netif != NULL) {
+ /* only act on DHCP configured interfaces */
+ if (netif->dhcp != NULL) {
+ /* timer is active (non zero), and triggers (zeroes) now? */
+ if (netif->dhcp->t2_timeout-- == 1) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
+ /* this clients' rebind timeout triggered */
+ dhcp_t2_timeout(netif);
+ /* timer is active (non zero), and triggers (zeroes) now */
+ } else if (netif->dhcp->t1_timeout-- == 1) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
+ /* this clients' renewal timeout triggered */
+ dhcp_t1_timeout(netif);
+ }
+ }
+ /* proceed to next netif */
+ netif = netif->next;
+ }
+}
+
+/**
+ * DHCP transaction timeout handling
+ *
+ * A DHCP server is expected to respond within a short period of time.
+ * This timer checks whether an outstanding DHCP request is timed out.
+ */
+void
+dhcp_fine_tmr()
+{
+ struct netif *netif = netif_list;
+ /* loop through netif's */
+ while (netif != NULL) {
+ /* only act on DHCP configured interfaces */
+ if (netif->dhcp != NULL) {
+ /* timer is active (non zero), and is about to trigger now */
+ if (netif->dhcp->request_timeout > 1) {
+ netif->dhcp->request_timeout--;
+ }
+ else if (netif->dhcp->request_timeout == 1) {
+ netif->dhcp->request_timeout--;
+ /* { netif->dhcp->request_timeout == 0 } */
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
+ /* this client's request timeout triggered */
+ dhcp_timeout(netif);
+ }
+ }
+ /* proceed to next network interface */
+ netif = netif->next;
+ }
+}
+
+/**
+ * A DHCP negotiation transaction, or ARP request, has timed out.
+ *
+ * The timer that was started with the DHCP or ARP request has
+ * timed out, indicating no response was received in time.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_timeout(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
+ /* back-off period has passed, or server selection timed out */
+ if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
+ dhcp_discover(netif);
+ /* receiving the requested lease timed out */
+ } else if (dhcp->state == DHCP_REQUESTING) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
+ if (dhcp->tries <= 5) {
+ dhcp_select(netif);
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
+ dhcp_release(netif);
+ dhcp_discover(netif);
+ }
+#if DHCP_DOES_ARP_CHECK
+ /* received no ARP reply for the offered address (which is good) */
+ } else if (dhcp->state == DHCP_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 */
+ }
+ /* did not get response to renew request? */
+ else if (dhcp->state == DHCP_RENEWING) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
+ /* just retry renewal */
+ /* note that the rebind timer will eventually time-out if renew does not work */
+ dhcp_renew(netif);
+ /* did not get response to rebind request? */
+ } else if (dhcp->state == DHCP_REBINDING) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
+ if (dhcp->tries <= 8) {
+ dhcp_rebind(netif);
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
+ dhcp_release(netif);
+ dhcp_discover(netif);
+ }
+ } else if (dhcp->state == DHCP_REBOOTING) {
+ if (dhcp->tries < REBOOT_TRIES) {
+ dhcp_reboot(netif);
+ } else {
+ dhcp_discover(netif);
+ }
+ }
+}
+
+/**
+ * The renewal period has timed out.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_t1_timeout(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
+ if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
+ (dhcp->state == DHCP_RENEWING)) {
+ /* just retry to renew - note that the rebind timer (t2) will
+ * eventually time-out if renew tries fail. */
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("dhcp_t1_timeout(): must renew\n"));
+ /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
+ DHCP_RENEWING, not DHCP_BOUND */
+ dhcp_renew(netif);
+ }
+}
+
+/**
+ * The rebind period has timed out.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_t2_timeout(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
+ if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
+ (dhcp->state == DHCP_RENEWING)) {
+ /* just retry to rebind */
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("dhcp_t2_timeout(): must rebind\n"));
+ /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
+ DHCP_REBINDING, not DHCP_BOUND */
+ dhcp_rebind(netif);
+ }
+}
+
+/**
+ * Handle a DHCP ACK packet
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_ack(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+#if LWIP_DNS
+ u8_t n;
+#endif /* LWIP_DNS */
+
+ /* clear options we might not get from the ACK */
+ ip_addr_set_zero(&dhcp->offered_sn_mask);
+ ip_addr_set_zero(&dhcp->offered_gw_addr);
+#if LWIP_DHCP_BOOTP_FILE
+ ip_addr_set_zero(&dhcp->offered_si_addr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+ /* lease time given? */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {
+ /* remember offered lease time */
+ dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);
+ }
+ /* renewal period given? */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {
+ /* remember given renewal period */
+ dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);
+ } else {
+ /* calculate safe periods for renewal */
+ dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
+ }
+
+ /* renewal period given? */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {
+ /* remember given rebind period */
+ dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);
+ } else {
+ /* calculate safe periods for rebinding */
+ dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
+ }
+
+ /* (y)our internet address */
+ ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
+
+#if LWIP_DHCP_BOOTP_FILE
+ /* copy boot server address,
+ boot file name copied in dhcp_parse_reply if not overloaded */
+ ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+ /* subnet mask given? */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
+ /* remember given subnet mask */
+ ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
+ dhcp->subnet_mask_given = 1;
+ } else {
+ dhcp->subnet_mask_given = 0;
+ }
+
+ /* gateway router */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
+ ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
+ }
+
+#if LWIP_DNS
+ /* DNS servers */
+ n = 0;
+ while((n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)) {
+ ip_addr_t dns_addr;
+ ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
+ dns_setserver(n, &dns_addr);
+ n++;
+ }
+#endif /* LWIP_DNS */
+}
+
+/** Set a statically allocated struct dhcp to work with.
+ * Using this prevents dhcp_start to allocate it using mem_malloc.
+ *
+ * @param netif the netif for which to set the struct dhcp
+ * @param dhcp (uninitialised) dhcp struct allocated by the application
+ */
+void
+dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
+{
+ LWIP_ASSERT("netif != NULL", netif != NULL);
+ LWIP_ASSERT("dhcp != NULL", dhcp != NULL);
+ LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL);
+
+ /* clear data structure */
+ memset(dhcp, 0, sizeof(struct dhcp));
+ /* dhcp_set_state(&dhcp, DHCP_OFF); */
+ netif->dhcp = dhcp;
+}
+
+/** Removes a struct dhcp from a netif.
+ *
+ * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
+ * struct dhcp since the memory is passed back to the heap.
+ *
+ * @param netif the netif from which to remove the struct dhcp
+ */
+void dhcp_cleanup(struct netif *netif)
+{
+ LWIP_ASSERT("netif != NULL", netif != NULL);
+
+ if (netif->dhcp != NULL) {
+ mem_free(netif->dhcp);
+ netif->dhcp = NULL;
+ }
+}
+
+/**
+ * Start DHCP negotiation for a network interface.
+ *
+ * If no DHCP client instance was attached to this interface,
+ * a new client is created first. If a DHCP client instance
+ * was already present, it restarts negotiation.
+ *
+ * @param netif The lwIP network interface
+ * @return lwIP error code
+ * - ERR_OK - No error
+ * - ERR_MEM - Out of memory
+ */
+err_t
+dhcp_start(struct netif *netif)
+{
+ struct dhcp *dhcp;
+ err_t result = ERR_OK;
+
+ LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
+ dhcp = netif->dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+ /* Remove the flag that says this netif is handled by DHCP,
+ it is set when we succeeded starting. */
+ netif->flags &= ~NETIF_FLAG_DHCP;
+
+ /* check hwtype of the netif */
+ if ((netif->flags & NETIF_FLAG_ETHARP) == 0) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n"));
+ return ERR_ARG;
+ }
+
+ /* check MTU of the netif */
+ if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
+ return ERR_MEM;
+ }
+
+ /* no DHCP client attached yet? */
+ if (dhcp == NULL) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
+ dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
+ if (dhcp == NULL) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
+ return ERR_MEM;
+ }
+ /* store this dhcp client in the netif */
+ netif->dhcp = dhcp;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
+ /* already has DHCP client attached */
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
+ if (dhcp->pcb != NULL) {
+ udp_remove(dhcp->pcb);
+ }
+ LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
+ LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL );
+ }
+
+ /* clear data structure */
+ memset(dhcp, 0, sizeof(struct dhcp));
+ /* dhcp_set_state(&dhcp, DHCP_OFF); */
+ /* allocate UDP PCB */
+ dhcp->pcb = udp_new();
+ if (dhcp->pcb == NULL) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
+ return ERR_MEM;
+ }
+ dhcp->pcb->so_options |= SOF_BROADCAST;
+ /* set up local and remote port for the pcb */
+ udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
+ udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
+ /* set up the recv callback and argument */
+ udp_recv(dhcp->pcb, dhcp_recv, netif);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
+ /* (re)start the DHCP negotiation */
+ result = dhcp_discover(netif);
+ if (result != ERR_OK) {
+ /* free resources allocated above */
+ dhcp_stop(netif);
+ return ERR_MEM;
+ }
+ /* Set the flag that says this netif is handled by DHCP. */
+ netif->flags |= NETIF_FLAG_DHCP;
+ return result;
+}
+
+/**
+ * Inform a DHCP server of our manual configuration.
+ *
+ * This informs DHCP servers of our fixed IP address configuration
+ * by sending an INFORM message. It does not involve DHCP address
+ * configuration, it is just here to be nice to the network.
+ *
+ * @param netif The lwIP network interface
+ */
+void
+dhcp_inform(struct netif *netif)
+{
+ struct dhcp dhcp;
+ err_t result = ERR_OK;
+ struct udp_pcb *pcb;
+
+ LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+
+ memset(&dhcp, 0, sizeof(struct dhcp));
+ dhcp_set_state(&dhcp, DHCP_INFORM);
+
+ if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) {
+ /* re-use existing pcb */
+ pcb = netif->dhcp->pcb;
+ } else {
+ pcb = udp_new();
+ if (pcb == NULL) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
+ return;
+ }
+ dhcp.pcb = pcb;
+ dhcp.pcb->so_options |= SOF_BROADCAST;
+ udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
+ }
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM);
+ if (result == ERR_OK) {
+ dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif));
+
+ dhcp_option_trailer(&dhcp);
+
+ pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len);
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
+ udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(&dhcp);
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
+ }
+
+ if (dhcp.pcb != NULL) {
+ /* otherwise, the existing pcb was used */
+ udp_remove(dhcp.pcb);
+ }
+}
+
+/** Handle a possible change in the network configuration.
+ *
+ * This enters the REBOOTING state to verify that the currently bound
+ * address is still valid.
+ */
+void
+dhcp_network_changed(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ if (!dhcp)
+ return;
+ switch (dhcp->state) {
+ case DHCP_REBINDING:
+ case DHCP_RENEWING:
+ case DHCP_BOUND:
+ case DHCP_REBOOTING:
+ netif_set_down(netif);
+ dhcp->tries = 0;
+ dhcp_reboot(netif);
+ break;
+ case DHCP_OFF:
+ /* stay off */
+ break;
+ default:
+ dhcp->tries = 0;
+#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 */
+ dhcp_discover(netif);
+ break;
+ }
+}
+
+#if DHCP_DOES_ARP_CHECK
+/**
+ * Match an ARP reply with the offered IP address.
+ *
+ * @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, ip_addr_t *addr)
+{
+ LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
+ /* is a DHCP client doing an ARP check? */
+ if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_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 (ip_addr_cmp(addr, &netif->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);
+ }
+ }
+}
+
+/**
+ * Decline an offered lease.
+ *
+ * Tell the DHCP server we do not accept the offered address.
+ * One reason to decline the lease is when we find out the address
+ * is already in use by another host (through ARP).
+ *
+ * @param netif the netif under DHCP control
+ */
+static err_t
+dhcp_decline(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result = ERR_OK;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
+ dhcp_set_state(dhcp, DHCP_BACKING_OFF);
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);
+ if (result == ERR_OK) {
+ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+ dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+ dhcp_option_trailer(dhcp);
+ /* resize pbuf to reflect true size of options */
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ /* per section 4.4.4, broadcast DECLINE messages */
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("dhcp_decline: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ msecs = 10*1000;
+ dhcp->request_timeout = (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 */
+
+
+/**
+ * Start the DHCP process, discover a DHCP server.
+ *
+ * @param netif the netif under DHCP control
+ */
+static err_t
+dhcp_discover(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result = ERR_OK;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
+ ip_addr_set_any(&dhcp->offered_ip_addr);
+ dhcp_set_state(dhcp, DHCP_SELECTING);
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER);
+ if (result == ERR_OK) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
+
+ dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+ dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
+ dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
+ dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
+ dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
+ dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
+
+ dhcp_option_trailer(dhcp);
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
+ dhcp_delete_msg(dhcp);
+ 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"));
+ }
+ 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 = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
+ dhcp->request_timeout = (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;
+}
+
+
+/**
+ * Bind the interface to the offered IP address.
+ *
+ * @param netif network interface to bind to the offered address
+ */
+static void
+dhcp_bind(struct netif *netif)
+{
+ u32_t timeout;
+ struct dhcp *dhcp;
+ ip_addr_t sn_mask, gw_addr;
+ LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
+ dhcp = netif->dhcp;
+ LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+
+ /* temporary DHCP lease? */
+ 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;
+ }
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
+ }
+ /* 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;
+ }
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
+ }
+
+ if (dhcp->subnet_mask_given) {
+ /* copy offered network mask */
+ ip_addr_copy(sn_mask, dhcp->offered_sn_mask);
+ } else {
+ /* subnet mask not given, choose a safe subnet mask given the network class */
+ u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
+ if (first_octet <= 127) {
+ ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
+ } else if (first_octet >= 192) {
+ ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
+ } else {
+ ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
+ }
+ }
+
+ ip_addr_copy(gw_addr, dhcp->offered_gw_addr);
+ /* gateway address not given? */
+ if (gw_addr.addr == IPADDR_ANY) {
+ /* copy network address */
+ ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
+ /* use first host address on network as gateway */
+ ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
+ }
+
+#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"\n",
+ ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+ netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n",
+ ip4_addr_get_u32(&sn_mask)));
+ netif_set_netmask(netif, &sn_mask);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n",
+ ip4_addr_get_u32(&gw_addr)));
+ netif_set_gw(netif, &gw_addr);
+ /* bring the interface up */
+ netif_set_up(netif);
+ /* netif is now bound to DHCP leased address */
+ dhcp_set_state(dhcp, DHCP_BOUND);
+}
+
+/**
+ * Renew an existing DHCP lease at the involved DHCP server.
+ *
+ * @param netif network interface which must renew its lease
+ */
+err_t
+dhcp_renew(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
+ dhcp_set_state(dhcp, DHCP_RENEWING);
+
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+ if (result == ERR_OK) {
+ dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+#if LWIP_NETIF_HOSTNAME
+ if (netif->hostname != NULL) {
+ const char *p = (const char*)netif->hostname;
+ u8_t namelen = (u8_t)strlen(p);
+ if (namelen > 0) {
+ LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+ dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+ while (*p) {
+ dhcp_option_byte(dhcp, *p++);
+ }
+ }
+ }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+#if 0
+ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+ dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
+#endif
+
+#if 0
+ dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+ dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
+#endif
+ /* append DHCP message trailer */
+ dhcp_option_trailer(dhcp);
+
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ /* back-off on retries, but to a maximum of 20 seconds */
+ msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
+ dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
+ return result;
+}
+
+/**
+ * Rebind with a DHCP server for an existing DHCP lease.
+ *
+ * @param netif network interface which must rebind with a DHCP server
+ */
+static err_t
+dhcp_rebind(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
+ dhcp_set_state(dhcp, DHCP_REBINDING);
+
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+ if (result == ERR_OK) {
+ dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+#if LWIP_NETIF_HOSTNAME
+ if (netif->hostname != NULL) {
+ const char *p = (const char*)netif->hostname;
+ u8_t namelen = (u8_t)strlen(p);
+ if (namelen > 0) {
+ LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+ dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+ while (*p) {
+ dhcp_option_byte(dhcp, *p++);
+ }
+ }
+ }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+#if 0
+ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+ dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
+
+ dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+ dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
+#endif
+
+ dhcp_option_trailer(dhcp);
+
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ /* broadcast to server */
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
+ dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
+ return result;
+}
+
+/**
+ * Enter REBOOTING state to verify an existing lease
+ *
+ * @param netif network interface which must reboot
+ */
+static err_t
+dhcp_reboot(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
+ dhcp_set_state(dhcp, DHCP_REBOOTING);
+
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+ if (result == ERR_OK) {
+ dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+ dhcp_option_short(dhcp, 576);
+
+ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+ dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+ dhcp_option_trailer(dhcp);
+
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ /* broadcast to server */
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
+ dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
+ return result;
+}
+
+
+/**
+ * Release a DHCP lease.
+ *
+ * @param netif network interface which must release its lease
+ */
+err_t
+dhcp_release(struct netif *netif)
+{
+ struct dhcp *dhcp = netif->dhcp;
+ err_t result;
+ u16_t msecs;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
+
+ /* idle DHCP client */
+ dhcp_set_state(dhcp, DHCP_OFF);
+ /* clean old DHCP offer */
+ ip_addr_set_zero(&dhcp->server_ip_addr);
+ ip_addr_set_zero(&dhcp->offered_ip_addr);
+ ip_addr_set_zero(&dhcp->offered_sn_mask);
+ ip_addr_set_zero(&dhcp->offered_gw_addr);
+#if LWIP_DHCP_BOOTP_FILE
+ ip_addr_set_zero(&dhcp->offered_si_addr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+ dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
+
+ /* create and initialize the DHCP message header */
+ result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);
+ if (result == ERR_OK) {
+ dhcp_option_trailer(dhcp);
+
+ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+ udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
+ dhcp_delete_msg(dhcp);
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
+ }
+ dhcp->tries++;
+ msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
+ dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
+ /* bring the interface down */
+ netif_set_down(netif);
+ /* remove IP address from interface */
+ netif_set_ipaddr(netif, IP_ADDR_ANY);
+ netif_set_gw(netif, IP_ADDR_ANY);
+ netif_set_netmask(netif, IP_ADDR_ANY);
+
+ return result;
+}
+
+/**
+ * Remove the DHCP client from the interface.
+ *
+ * @param netif The network interface to stop DHCP on
+ */
+void
+dhcp_stop(struct netif *netif)
+{
+ struct dhcp *dhcp;
+ LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
+ dhcp = netif->dhcp;
+ /* Remove the flag that says this netif is handled by DHCP. */
+ netif->flags &= ~NETIF_FLAG_DHCP;
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
+ /* netif is DHCP configured? */
+ if (dhcp != NULL) {
+#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 (dhcp->pcb != NULL) {
+ udp_remove(dhcp->pcb);
+ dhcp->pcb = NULL;
+ }
+ LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
+ dhcp_set_state(dhcp, DHCP_OFF);
+ }
+}
+
+/*
+ * Set the DHCP state of a DHCP client.
+ *
+ * If the state changed, reset the number of tries.
+ */
+static void
+dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
+{
+ if (new_state != dhcp->state) {
+ dhcp->state = new_state;
+ dhcp->tries = 0;
+ dhcp->request_timeout = 0;
+ }
+}
+
+/*
+ * Concatenate an option type and length field to the outgoing
+ * DHCP message.
+ *
+ */
+static void
+dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
+{
+ LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
+ dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
+ dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
+}
+/*
+ * Concatenate a single byte to the outgoing DHCP message.
+ *
+ */
+static void
+dhcp_option_byte(struct dhcp *dhcp, u8_t value)
+{
+ LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+ dhcp->msg_out->options[dhcp->options_out_len++] = value;
+}
+
+static void
+dhcp_option_short(struct dhcp *dhcp, u16_t value)
+{
+ LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);
+}
+
+static void
+dhcp_option_long(struct dhcp *dhcp, u32_t value)
+{
+ LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
+ dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
+}
+
+/**
+ * Extract the DHCP message and the DHCP options.
+ *
+ * Extract the DHCP message and the DHCP options, each into a contiguous
+ * piece of memory. As a DHCP message is variable sized by its options,
+ * and also allows overriding some fields for options, the easy approach
+ * is to first unfold the options into a conitguous piece of memory, and
+ * use that further on.
+ *
+ */
+static err_t
+dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)
+{
+ u8_t *options;
+ u16_t offset;
+ u16_t offset_max;
+ u16_t options_idx;
+ u16_t options_idx_max;
+ struct pbuf *q;
+ int parse_file_as_options = 0;
+ int parse_sname_as_options = 0;
+
+ /* clear received options */
+ dhcp_clear_all_options(dhcp);
+ /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
+ if (p->len < DHCP_SNAME_OFS) {
+ return ERR_BUF;
+ }
+ dhcp->msg_in = (struct dhcp_msg *)p->payload;
+#if LWIP_DHCP_BOOTP_FILE
+ /* clear boot file name */
+ dhcp->boot_file_name[0] = 0;
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+ /* parse options */
+
+ /* start with options field */
+ options_idx = DHCP_OPTIONS_OFS;
+ /* parse options to the end of the received packet */
+ options_idx_max = p->tot_len;
+again:
+ q = p;
+ while((q != NULL) && (options_idx >= q->len)) {
+ options_idx -= q->len;
+ options_idx_max -= q->len;
+ q = q->next;
+ }
+ if (q == NULL) {
+ return ERR_BUF;
+ }
+ offset = options_idx;
+ offset_max = options_idx_max;
+ options = (u8_t*)q->payload;
+ /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
+ while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) {
+ u8_t op = options[offset];
+ u8_t len;
+ u8_t decode_len = 0;
+ int decode_idx = -1;
+ u16_t val_offset = offset + 2;
+ /* len byte might be in the next pbuf */
+ if (offset + 1 < q->len) {
+ len = options[offset + 1];
+ } 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)); */
+ decode_len = len;
+ switch(op) {
+ /* case(DHCP_OPTION_END): handled above */
+ case(DHCP_OPTION_PAD):
+ /* special option: no len encoded */
+ decode_len = len = 0;
+ /* will be increased below */
+ offset--;
+ break;
+ case(DHCP_OPTION_SUBNET_MASK):
+ LWIP_ASSERT("len == 4", len == 4);
+ decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
+ break;
+ case(DHCP_OPTION_ROUTER):
+ decode_len = 4; /* only copy the first given router */
+ LWIP_ASSERT("len >= decode_len", len >= decode_len);
+ decode_idx = DHCP_OPTION_IDX_ROUTER;
+ break;
+ case(DHCP_OPTION_DNS_SERVER):
+ /* special case: there might be more than one server */
+ LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
+ /* limit number of DNS servers */
+ decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
+ LWIP_ASSERT("len >= decode_len", len >= decode_len);
+ decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
+ break;
+ case(DHCP_OPTION_LEASE_TIME):
+ LWIP_ASSERT("len == 4", len == 4);
+ decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
+ break;
+ case(DHCP_OPTION_OVERLOAD):
+ LWIP_ASSERT("len == 1", len == 1);
+ decode_idx = DHCP_OPTION_IDX_OVERLOAD;
+ break;
+ case(DHCP_OPTION_MESSAGE_TYPE):
+ LWIP_ASSERT("len == 1", len == 1);
+ decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
+ break;
+ case(DHCP_OPTION_SERVER_ID):
+ LWIP_ASSERT("len == 4", len == 4);
+ decode_idx = DHCP_OPTION_IDX_SERVER_ID;
+ break;
+ case(DHCP_OPTION_T1):
+ LWIP_ASSERT("len == 4", len == 4);
+ decode_idx = DHCP_OPTION_IDX_T1;
+ break;
+ case(DHCP_OPTION_T2):
+ LWIP_ASSERT("len == 4", len == 4);
+ decode_idx = DHCP_OPTION_IDX_T2;
+ break;
+ default:
+ decode_len = 0;
+ LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op));
+ break;
+ }
+ offset += len + 2;
+ if (decode_len > 0) {
+ u32_t value = 0;
+ u16_t copy_len;
+decode_next:
+ LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
+ LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
+ copy_len = LWIP_MIN(decode_len, 4);
+ pbuf_copy_partial(q, &value, copy_len, val_offset);
+ if (decode_len > 4) {
+ /* decode more than one u32_t */
+ LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
+ dhcp_got_option(dhcp, decode_idx);
+ dhcp_set_option_value(dhcp, decode_idx, htonl(value));
+ decode_len -= 4;
+ val_offset += 4;
+ decode_idx++;
+ goto decode_next;
+ } else if (decode_len == 4) {
+ value = ntohl(value);
+ } else {
+ LWIP_ASSERT("invalid decode_len", decode_len == 1);
+ value = ((u8_t*)&value)[0];
+ }
+ dhcp_got_option(dhcp, decode_idx);
+ dhcp_set_option_value(dhcp, decode_idx, value);
+ }
+ if (offset >= q->len) {
+ offset -= q->len;
+ offset_max -= q->len;
+ q = q->next;
+ options = (u8_t*)q->payload;
+ }
+ }
+ /* is this an overloaded message? */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
+ u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
+ dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
+ if (overload == DHCP_OVERLOAD_FILE) {
+ parse_file_as_options = 1;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
+ } else if (overload == DHCP_OVERLOAD_SNAME) {
+ parse_sname_as_options = 1;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
+ } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
+ parse_sname_as_options = 1;
+ parse_file_as_options = 1;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
+ } else {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
+ }
+#if LWIP_DHCP_BOOTP_FILE
+ if (!parse_file_as_options) {
+ /* only do this for ACK messages */
+ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
+ (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
+ /* copy bootp file name, don't care for sname (server hostname) */
+ pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);
+ /* make sure the string is really NULL-terminated */
+ dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
+ }
+#endif /* LWIP_DHCP_BOOTP_FILE */
+ }
+ if (parse_file_as_options) {
+ /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
+ parse_file_as_options = 0;
+ options_idx = DHCP_FILE_OFS;
+ options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
+ goto again;
+ } else if (parse_sname_as_options) {
+ parse_sname_as_options = 0;
+ options_idx = DHCP_SNAME_OFS;
+ options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
+ goto again;
+ }
+ return ERR_OK;
+}
+
+/**
+ * If an incoming DHCP message is in response to us, then trigger the state machine
+ */
+static void
+dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+ struct netif *netif = (struct netif *)arg;
+ struct dhcp *dhcp = netif->dhcp;
+ struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
+ u8_t msg_type;
+ u8_t i;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
+ ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port));
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
+ /* prevent warnings about unused arguments */
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_UNUSED_ARG(addr);
+ LWIP_UNUSED_ARG(port);
+
+ LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
+
+ if (p->len < DHCP_MIN_REPLY_LEN) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
+ goto free_pbuf_and_return;
+ }
+
+ if (reply_msg->op != DHCP_BOOTREPLY) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
+ goto free_pbuf_and_return;
+ }
+ /* iterate through hardware address and match against DHCP message */
+ for (i = 0; i < netif->hwaddr_len; i++) {
+ if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+ ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
+ (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
+ goto free_pbuf_and_return;
+ }
+ }
+ /* match transaction ID against what we expected */
+ if (ntohl(reply_msg->xid) != dhcp->xid) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+ ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
+ goto free_pbuf_and_return;
+ }
+ /* option fields could be unfold? */
+ if (dhcp_parse_reply(dhcp, p) != ERR_OK) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("problem unfolding DHCP message - too short on memory?\n"));
+ goto free_pbuf_and_return;
+ }
+
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
+ /* obtain pointer to DHCP message type */
+ if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
+ goto free_pbuf_and_return;
+ }
+
+ /* read DHCP message type */
+ msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
+ /* 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_REQUESTING) {
+ dhcp_handle_ack(netif);
+#if DHCP_DOES_ARP_CHECK
+ /* check if the acknowledged lease address is already in use */
+ dhcp_check(netif);
+#else
+ /* bind interface to the acknowledged lease address */
+ dhcp_bind(netif);
+#endif
+ }
+ /* already bound to the given lease address? */
+ else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
+ dhcp_bind(netif);
+ }
+ }
+ /* received a DHCP_NAK in appropriate state? */
+ else if ((msg_type == DHCP_NAK) &&
+ ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
+ (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
+ dhcp_handle_nak(netif);
+ }
+ /* received a DHCP_OFFER in DHCP_SELECTING state? */
+ else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
+ dhcp->request_timeout = 0;
+ /* remember offered lease */
+ dhcp_handle_offer(netif);
+ }
+free_pbuf_and_return:
+ dhcp->msg_in = NULL;
+ pbuf_free(p);
+}
+
+/**
+ * Create a DHCP request, fill in common headers
+ *
+ * @param netif the netif under DHCP control
+ * @param dhcp dhcp control struct
+ * @param message_type message type of the request
+ */
+static err_t
+dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
+{
+ u16_t i;
+#ifndef DHCP_GLOBAL_XID
+ /** default global transaction identifier starting value (easy to match
+ * with a packet analyser). We simply increment for each new request.
+ * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
+ * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
+ static u32_t xid = 0xABCD0000;
+#else
+ static u32_t xid;
+ static u8_t xid_initialised = 0;
+ if (!xid_initialised) {
+ xid = DHCP_GLOBAL_XID;
+ xid_initialised = !xid_initialised;
+ }
+#endif
+ LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;);
+ LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
+ LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL);
+ LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
+ dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
+ if (dhcp->p_out == NULL) {
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("dhcp_create_msg(): could not allocate pbuf\n"));
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
+ (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
+
+ /* reuse transaction identifier in retransmissions */
+ if (dhcp->tries == 0) {
+ xid++;
+ }
+ dhcp->xid = xid;
+ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
+ ("transaction id xid(%"X32_F")\n", xid));
+
+ dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
+
+ dhcp->msg_out->op = DHCP_BOOTREQUEST;
+ /* TODO: make link layer independent */
+ dhcp->msg_out->htype = DHCP_HTYPE_ETH;
+ dhcp->msg_out->hlen = netif->hwaddr_len;
+ dhcp->msg_out->hops = 0;
+ dhcp->msg_out->xid = htonl(dhcp->xid);
+ dhcp->msg_out->secs = 0;
+ /* we don't need the broadcast flag since we can receive unicast traffic
+ before being fully configured! */
+ dhcp->msg_out->flags = 0;
+ ip_addr_set_zero(&dhcp->msg_out->ciaddr);
+ /* set ciaddr to netif->ip_addr based on message_type and state */
+ if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) ||
+ ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */
+ ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) {
+ ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr);
+ }
+ ip_addr_set_zero(&dhcp->msg_out->yiaddr);
+ ip_addr_set_zero(&dhcp->msg_out->siaddr);
+ ip_addr_set_zero(&dhcp->msg_out->giaddr);
+ for (i = 0; i < netif->hwaddr_len; i++) {
+ /* copy netif hardware address */
+ dhcp->msg_out->chaddr[i] = netif->hwaddr[i];
+ }
+ for ( ; i < DHCP_CHADDR_LEN; i++) {
+ /* ... pad rest with zeroes */
+ dhcp->msg_out->chaddr[i] = 0;
+ }
+ for (i = 0; i < DHCP_SNAME_LEN; i++) {
+ dhcp->msg_out->sname[i] = 0;
+ }
+ for (i = 0; i < DHCP_FILE_LEN; i++) {
+ dhcp->msg_out->file[i] = 0;
+ }
+ dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
+ dhcp->options_out_len = 0;
+ /* fill options field with an incrementing array (for debugging purposes) */
+ for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
+ dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
+ }
+ /* Add option MESSAGE_TYPE */
+ dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
+ dhcp_option_byte(dhcp, message_type);
+ return ERR_OK;
+}
+
+/**
+ * Free previously allocated memory used to send a DHCP request.
+ *
+ * @param dhcp the dhcp struct to free the request from
+ */
+static void
+dhcp_delete_msg(struct dhcp *dhcp)
+{
+ LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;);
+ LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
+ LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
+ if (dhcp->p_out != NULL) {
+ pbuf_free(dhcp->p_out);
+ }
+ dhcp->p_out = NULL;
+ dhcp->msg_out = NULL;
+}
+
+/**
+ * Add a DHCP message trailer
+ *
+ * Adds the END option to the DHCP message, and if
+ * necessary, up to three padding bytes.
+ *
+ * @param dhcp DHCP state structure
+ */
+static void
+dhcp_option_trailer(struct dhcp *dhcp)
+{
+ LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
+ LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
+ LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+ dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
+ /* packet is too small, or not 4 byte aligned? */
+ while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
+ /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
+ LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+ /* add a fill/padding byte */
+ dhcp->msg_out->options[dhcp->options_out_len++] = 0;
+ }
+}
+
+#endif /* LWIP_DHCP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dns.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dns.c
new file mode 100644
index 0000000000..d63361226f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/dns.c
@@ -0,0 +1,970 @@
+/**
+ * @file
+ * DNS - host name to IP address resolver.
+ *
+ */
+
+/**
+
+ * This file implements a DNS host name to IP address resolver.
+
+ * Port to lwIP from uIP
+ * by Jim Pettinato April 2007
+
+ * uIP version Copyright (c) 2002-2003, Adam Dunkels.
+ * 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.
+ *
+ *
+ * DNS.C
+ *
+ * The lwIP DNS resolver functions are used to lookup a host name and
+ * map it to a numerical IP address. It maintains a list of resolved
+ * hostnames that can be queried with the dns_lookup() function.
+ * New hostnames can be resolved using the dns_query() function.
+ *
+ * The lwIP version of the resolver also adds a non-blocking version of
+ * gethostbyname() that will work with a raw API application. This function
+ * checks for an IP address string first and converts it if it is valid.
+ * gethostbyname() then does a dns_lookup() to see if the name is
+ * already in the table. If so, the IP is returned. If not, a query is
+ * issued and the function returns with a ERR_INPROGRESS status. The app
+ * using the dns client must then go into a waiting state.
+ *
+ * Once a hostname has been resolved (or found to be non-existent),
+ * the resolver code calls a specified callback function (which
+ * must be implemented by the module that uses the resolver).
+ */
+
+/*-----------------------------------------------------------------------------
+ * RFC 1035 - Domain names - implementation and specification
+ * RFC 2181 - Clarifications to the DNS Specification
+ *----------------------------------------------------------------------------*/
+
+/** @todo: define good default values (rfc compliance) */
+/** @todo: improve answer parsing, more checkings... */
+/** @todo: check RFC1035 - 7.3. Processing responses */
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/dns.h"
+
+#include <string.h>
+
+/** DNS server IP address */
+#ifndef DNS_SERVER_ADDRESS
+#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
+#endif
+
+/** DNS server port address */
+#ifndef DNS_SERVER_PORT
+#define DNS_SERVER_PORT 53
+#endif
+
+/** DNS maximum number of retries when asking for a name, before "timeout". */
+#ifndef DNS_MAX_RETRIES
+#define DNS_MAX_RETRIES 4
+#endif
+
+/** DNS resource record max. TTL (one week as default) */
+#ifndef DNS_MAX_TTL
+#define DNS_MAX_TTL 604800
+#endif
+
+/* DNS protocol flags */
+#define DNS_FLAG1_RESPONSE 0x80
+#define DNS_FLAG1_OPCODE_STATUS 0x10
+#define DNS_FLAG1_OPCODE_INVERSE 0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE 0x04
+#define DNS_FLAG1_TRUNC 0x02
+#define DNS_FLAG1_RD 0x01
+#define DNS_FLAG2_RA 0x80
+#define DNS_FLAG2_ERR_MASK 0x0f
+#define DNS_FLAG2_ERR_NONE 0x00
+#define DNS_FLAG2_ERR_NAME 0x03
+
+/* DNS protocol states */
+#define DNS_STATE_UNUSED 0
+#define DNS_STATE_NEW 1
+#define DNS_STATE_ASKING 2
+#define DNS_STATE_DONE 3
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** DNS message header */
+struct dns_hdr {
+ PACK_STRUCT_FIELD(u16_t id);
+ PACK_STRUCT_FIELD(u8_t flags1);
+ PACK_STRUCT_FIELD(u8_t flags2);
+ PACK_STRUCT_FIELD(u16_t numquestions);
+ PACK_STRUCT_FIELD(u16_t numanswers);
+ PACK_STRUCT_FIELD(u16_t numauthrr);
+ PACK_STRUCT_FIELD(u16_t numextrarr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+#define SIZEOF_DNS_HDR 12
+
+/** DNS query message structure.
+ No packing needed: only used locally on the stack. */
+struct dns_query {
+ /* DNS query record starts with either a domain name or a pointer
+ to a name already present somewhere in the packet. */
+ u16_t type;
+ u16_t cls;
+};
+#define SIZEOF_DNS_QUERY 4
+
+/** DNS answer message structure.
+ No packing needed: only used locally on the stack. */
+struct dns_answer {
+ /* DNS answer record starts with either a domain name or a pointer
+ to a name already present somewhere in the packet. */
+ u16_t type;
+ u16_t cls;
+ u32_t ttl;
+ u16_t len;
+};
+#define SIZEOF_DNS_ANSWER 10
+
+/** DNS table entry */
+struct dns_table_entry {
+ u8_t state;
+ u8_t numdns;
+ u8_t tmr;
+ u8_t retries;
+ u8_t seqno;
+ u8_t err;
+ u32_t ttl;
+ char name[DNS_MAX_NAME_LENGTH];
+ ip_addr_t ipaddr;
+ /* pointer to callback on DNS query done */
+ dns_found_callback found;
+ void *arg;
+};
+
+#if DNS_LOCAL_HOSTLIST
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Local host-list. For hostnames in this list, no
+ * external name resolution is performed */
+static struct local_hostlist_entry *local_hostlist_dynamic;
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
+#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
+#define DNS_LOCAL_HOSTLIST_STORAGE_POST
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
+DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
+ DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
+
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+static void dns_init_local();
+#endif /* DNS_LOCAL_HOSTLIST */
+
+
+/* forward declarations */
+static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+static void dns_check_entries(void);
+
+/*-----------------------------------------------------------------------------
+ * Globales
+ *----------------------------------------------------------------------------*/
+
+/* DNS variables */
+static struct udp_pcb *dns_pcb;
+static u8_t dns_seqno;
+static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
+static ip_addr_t dns_servers[DNS_MAX_SERVERS];
+/** Contiguous buffer for processing responses */
+static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
+static u8_t* dns_payload;
+
+/**
+ * Initialize the resolver: set up the UDP pcb and configure the default server
+ * (DNS_SERVER_ADDRESS).
+ */
+void
+dns_init()
+{
+ ip_addr_t dnsserver;
+
+ dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
+
+ /* initialize default DNS server address */
+ DNS_SERVER_ADDRESS(&dnsserver);
+
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
+
+ /* if dns client not yet initialized... */
+ if (dns_pcb == NULL) {
+ dns_pcb = udp_new();
+
+ if (dns_pcb != NULL) {
+ /* initialize DNS table not needed (initialized to zero since it is a
+ * global variable) */
+ LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
+ DNS_STATE_UNUSED == 0);
+
+ /* initialize DNS client */
+ udp_bind(dns_pcb, IP_ADDR_ANY, 0);
+ udp_recv(dns_pcb, dns_recv, NULL);
+
+ /* initialize default DNS primary server */
+ dns_setserver(0, &dnsserver);
+ }
+ }
+#if DNS_LOCAL_HOSTLIST
+ dns_init_local();
+#endif
+}
+
+/**
+ * Initialize one of the DNS servers.
+ *
+ * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
+ * @param dnsserver IP address of the DNS server to set
+ */
+void
+dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
+{
+ if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
+ (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
+ dns_servers[numdns] = (*dnsserver);
+ }
+}
+
+/**
+ * Obtain one of the currently configured DNS server.
+ *
+ * @param numdns the index of the DNS server
+ * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
+ * server has not been configured.
+ */
+ip_addr_t
+dns_getserver(u8_t numdns)
+{
+ if (numdns < DNS_MAX_SERVERS) {
+ return dns_servers[numdns];
+ } else {
+ return *IP_ADDR_ANY;
+ }
+}
+
+/**
+ * The DNS resolver client timer - handle retries and timeouts and should
+ * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
+ */
+void
+dns_tmr(void)
+{
+ if (dns_pcb != NULL) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
+ dns_check_entries();
+ }
+}
+
+#if DNS_LOCAL_HOSTLIST
+static void
+dns_init_local()
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
+ int i;
+ struct local_hostlist_entry *entry;
+ /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
+ struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
+ size_t namelen;
+ for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
+ struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
+ LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
+ namelen = strlen(init_entry->name);
+ LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+ entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+ LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
+ if (entry != NULL) {
+ entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+ MEMCPY((char*)entry->name, init_entry->name, namelen);
+ ((char*)entry->name)[namelen] = 0;
+ entry->addr = init_entry->addr;
+ entry->next = local_hostlist_dynamic;
+ local_hostlist_dynamic = entry;
+ }
+ }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
+}
+
+/**
+ * Scans the local host-list for a hostname.
+ *
+ * @param hostname Hostname to look for in the local host-list
+ * @return The first IP address for the hostname in the local host-list or
+ * IPADDR_NONE if not found.
+ */
+static u32_t
+dns_lookup_local(const char *hostname)
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+ struct local_hostlist_entry *entry = local_hostlist_dynamic;
+ while(entry != NULL) {
+ if(strcmp(entry->name, hostname) == 0) {
+ return ip4_addr_get_u32(&entry->addr);
+ }
+ entry = entry->next;
+ }
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+ int i;
+ for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
+ if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
+ return ip4_addr_get_u32(&local_hostlist_static[i].addr);
+ }
+ }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+ return IPADDR_NONE;
+}
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Remove all entries from the local host-list for a specific hostname
+ * and/or IP addess
+ *
+ * @param hostname hostname for which entries shall be removed from the local
+ * host-list
+ * @param addr address for which entries shall be removed from the local host-list
+ * @return the number of removed entries
+ */
+int
+dns_local_removehost(const char *hostname, const ip_addr_t *addr)
+{
+ int removed = 0;
+ struct local_hostlist_entry *entry = local_hostlist_dynamic;
+ struct local_hostlist_entry *last_entry = NULL;
+ while (entry != NULL) {
+ if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
+ ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
+ struct local_hostlist_entry *free_entry;
+ if (last_entry != NULL) {
+ last_entry->next = entry->next;
+ } else {
+ local_hostlist_dynamic = entry->next;
+ }
+ free_entry = entry;
+ entry = entry->next;
+ memp_free(MEMP_LOCALHOSTLIST, free_entry);
+ removed++;
+ } else {
+ last_entry = entry;
+ entry = entry->next;
+ }
+ }
+ return removed;
+}
+
+/**
+ * Add a hostname/IP address pair to the local host-list.
+ * Duplicates are not checked.
+ *
+ * @param hostname hostname of the new entry
+ * @param addr IP address of the new entry
+ * @return ERR_OK if succeeded or ERR_MEM on memory error
+ */
+err_t
+dns_local_addhost(const char *hostname, const ip_addr_t *addr)
+{
+ struct local_hostlist_entry *entry;
+ size_t namelen;
+ LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
+ namelen = strlen(hostname);
+ LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+ entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+ if (entry == NULL) {
+ return ERR_MEM;
+ }
+ entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+ MEMCPY((char*)entry->name, hostname, namelen);
+ ((char*)entry->name)[namelen] = 0;
+ ip_addr_copy(entry->addr, *addr);
+ entry->next = local_hostlist_dynamic;
+ local_hostlist_dynamic = entry;
+ return ERR_OK;
+}
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/**
+ * Look up a hostname in the array of known hostnames.
+ *
+ * @note This function only looks in the internal array of known
+ * hostnames, it does not send out a query for the hostname if none
+ * was found. The function dns_enqueue() can be used to send a query
+ * for a hostname.
+ *
+ * @param name the hostname to look up
+ * @return 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.
+ */
+static u32_t
+dns_lookup(const char *name)
+{
+ u8_t i;
+#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
+ u32_t addr;
+#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
+#if DNS_LOCAL_HOSTLIST
+ if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
+ return addr;
+ }
+#endif /* DNS_LOCAL_HOSTLIST */
+#ifdef DNS_LOOKUP_LOCAL_EXTERN
+ if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
+ return addr;
+ }
+#endif /* DNS_LOOKUP_LOCAL_EXTERN */
+
+ /* 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) &&
+ (strcmp(name, dns_table[i].name) == 0)) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
+ ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
+ LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+ return ip4_addr_get_u32(&dns_table[i].ipaddr);
+ }
+ }
+
+ return IPADDR_NONE;
+}
+
+#if DNS_DOES_NAME_CHECK
+/**
+ * Compare the "dotted" name "query" with the encoded name "response"
+ * to make sure an answer from the DNS server matches the current dns_table
+ * entry (otherwise, answers might arrive late for hostname not on the list
+ * any more).
+ *
+ * @param query hostname (not encoded) from the dns_table
+ * @param response encoded hostname in the DNS response
+ * @return 0: names equal; 1: names differ
+ */
+static u8_t
+dns_compare_name(unsigned char *query, unsigned char *response)
+{
+ unsigned char n;
+
+ do {
+ n = *response++;
+ /** @see RFC 1035 - 4.1.4. Message compression */
+ if ((n & 0xc0) == 0xc0) {
+ /* Compressed name */
+ break;
+ } else {
+ /* Not compressed name */
+ while (n > 0) {
+ if ((*query) != (*response)) {
+ return 1;
+ }
+ ++response;
+ ++query;
+ --n;
+ };
+ ++query;
+ }
+ } while (*response != 0);
+
+ return 0;
+}
+#endif /* DNS_DOES_NAME_CHECK */
+
+/**
+ * Walk through a compact encoded DNS name and return the end of the name.
+ *
+ * @param query encoded DNS name in the DNS server response
+ * @return end of the name
+ */
+static unsigned char *
+dns_parse_name(unsigned char *query)
+{
+ unsigned char n;
+
+ do {
+ n = *query++;
+ /** @see RFC 1035 - 4.1.4. Message compression */
+ if ((n & 0xc0) == 0xc0) {
+ /* Compressed name */
+ break;
+ } else {
+ /* Not compressed name */
+ while (n > 0) {
+ ++query;
+ --n;
+ };
+ }
+ } while (*query != 0);
+
+ return query + 1;
+}
+
+/**
+ * Send a DNS query packet.
+ *
+ * @param numdns index of the DNS server in the dns_servers table
+ * @param name hostname to query
+ * @param id index of the hostname in dns_table, used as transaction ID in the
+ * DNS query packet
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
+ */
+static err_t
+dns_send(u8_t numdns, const char* name, u8_t id)
+{
+ err_t err;
+ struct dns_hdr *hdr;
+ struct dns_query qry;
+ struct pbuf *p;
+ char *query, *nptr;
+ const char *pHostname;
+ u8_t n;
+
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
+ (u16_t)(numdns), name));
+ LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
+ LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
+
+ /* if here, we have either a new query or a retry on a previous query to process */
+ p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
+ SIZEOF_DNS_QUERY, PBUF_RAM);
+ if (p != NULL) {
+ LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
+ /* fill dns header */
+ hdr = (struct dns_hdr*)p->payload;
+ memset(hdr, 0, SIZEOF_DNS_HDR);
+ hdr->id = htons(id);
+ hdr->flags1 = DNS_FLAG1_RD;
+ hdr->numquestions = PP_HTONS(1);
+ query = (char*)hdr + SIZEOF_DNS_HDR;
+ pHostname = name;
+ --pHostname;
+
+ /* convert hostname into suitable query format. */
+ do {
+ ++pHostname;
+ nptr = query;
+ ++query;
+ for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+ *query = *pHostname;
+ ++query;
+ ++n;
+ }
+ *nptr = n;
+ } while(*pHostname != 0);
+ *query++='\0';
+
+ /* fill dns query */
+ qry.type = PP_HTONS(DNS_RRTYPE_A);
+ qry.cls = PP_HTONS(DNS_RRCLASS_IN);
+ SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
+
+ /* resize pbuf to the exact dns query */
+ pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
+
+ /* connect to the server for faster receiving */
+ udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
+ /* send dns packet */
+ err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
+
+ /* free pbuf */
+ pbuf_free(p);
+ } else {
+ err = ERR_MEM;
+ }
+
+ return err;
+}
+
+/**
+ * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
+ * Check an entry in the dns_table:
+ * - send out query for new entries
+ * - retry old pending entries on timeout (also with different servers)
+ * - remove completed entries from the table if their TTL has expired
+ *
+ * @param i index of the dns_table entry to check
+ */
+static void
+dns_check_entry(u8_t i)
+{
+ err_t err;
+ struct dns_table_entry *pEntry = &dns_table[i];
+
+ LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
+
+ switch(pEntry->state) {
+
+ case DNS_STATE_NEW: {
+ /* initialize new entry */
+ pEntry->state = DNS_STATE_ASKING;
+ pEntry->numdns = 0;
+ pEntry->tmr = 1;
+ pEntry->retries = 0;
+
+ /* send DNS packet for this entry */
+ err = dns_send(pEntry->numdns, pEntry->name, i);
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ ("dns_send returned error: %s\n", lwip_strerr(err)));
+ }
+ break;
+ }
+
+ case DNS_STATE_ASKING: {
+ if (--pEntry->tmr == 0) {
+ if (++pEntry->retries == DNS_MAX_RETRIES) {
+ if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
+ /* change of server */
+ pEntry->numdns++;
+ pEntry->tmr = 1;
+ pEntry->retries = 0;
+ break;
+ } else {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
+ /* call specified callback function if provided */
+ if (pEntry->found)
+ (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+ /* flush this entry */
+ pEntry->state = DNS_STATE_UNUSED;
+ pEntry->found = NULL;
+ break;
+ }
+ }
+
+ /* wait longer for the next retry */
+ pEntry->tmr = pEntry->retries;
+
+ /* send DNS packet for this entry */
+ err = dns_send(pEntry->numdns, pEntry->name, i);
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ ("dns_send returned error: %s\n", lwip_strerr(err)));
+ }
+ }
+ break;
+ }
+
+ case DNS_STATE_DONE: {
+ /* if the time to live is nul */
+ if (--pEntry->ttl == 0) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
+ /* flush this entry */
+ pEntry->state = DNS_STATE_UNUSED;
+ pEntry->found = NULL;
+ }
+ break;
+ }
+ case DNS_STATE_UNUSED:
+ /* nothing to do */
+ break;
+ default:
+ LWIP_ASSERT("unknown dns_table entry state:", 0);
+ break;
+ }
+}
+
+/**
+ * Call dns_check_entry for each entry in dns_table - check all entries.
+ */
+static void
+dns_check_entries(void)
+{
+ u8_t i;
+
+ for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+ dns_check_entry(i);
+ }
+}
+
+/**
+ * Receive input function for DNS response packets arriving for the dns UDP pcb.
+ *
+ * @params see udp.h
+ */
+static void
+dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+ u16_t i;
+ char *pHostname;
+ struct dns_hdr *hdr;
+ struct dns_answer ans;
+ struct dns_table_entry *pEntry;
+ u16_t nquestions, nanswers;
+
+ LWIP_UNUSED_ARG(arg);
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_UNUSED_ARG(addr);
+ LWIP_UNUSED_ARG(port);
+
+ /* is the dns message too big ? */
+ if (p->tot_len > DNS_MSG_SIZE) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
+ /* free pbuf and return */
+ goto memerr;
+ }
+
+ /* is the dns message big enough ? */
+ if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
+ /* free pbuf and return */
+ goto memerr;
+ }
+
+ /* copy dns payload inside static buffer for processing */
+ if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
+ /* The ID in the DNS header should be our entry into the name table. */
+ hdr = (struct dns_hdr*)dns_payload;
+ i = htons(hdr->id);
+ if (i < DNS_TABLE_SIZE) {
+ pEntry = &dns_table[i];
+ if(pEntry->state == DNS_STATE_ASKING) {
+ /* This entry is now completed. */
+ pEntry->state = DNS_STATE_DONE;
+ pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
+
+ /* We only care about the question(s) and the answers. The authrr
+ and the extrarr are simply discarded. */
+ nquestions = htons(hdr->numquestions);
+ nanswers = htons(hdr->numanswers);
+
+ /* Check for error. If so, call callback to inform. */
+ if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
+ /* call callback to indicate error, clean up memory and return */
+ goto responseerr;
+ }
+
+#if DNS_DOES_NAME_CHECK
+ /* Check if the name in the "question" part match with the name in the entry. */
+ if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
+ /* call callback to indicate error, clean up memory and return */
+ goto responseerr;
+ }
+#endif /* DNS_DOES_NAME_CHECK */
+
+ /* Skip the name in the "question" part */
+ pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
+
+ while (nanswers > 0) {
+ /* skip answer resource record's host name */
+ pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
+
+ /* Check for IP address type and Internet class. Others are discarded. */
+ SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
+ if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
+ (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
+ /* read the answer resource record's TTL, and maximize it if needed */
+ pEntry->ttl = ntohl(ans.ttl);
+ if (pEntry->ttl > DNS_MAX_TTL) {
+ pEntry->ttl = DNS_MAX_TTL;
+ }
+ /* read the IP address after answer resource record's header */
+ SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
+ ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
+ LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+ /* call specified callback function if provided */
+ if (pEntry->found) {
+ (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
+ }
+ /* deallocate memory and return */
+ goto memerr;
+ } else {
+ pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
+ }
+ --nanswers;
+ }
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
+ /* call callback to indicate error, clean up memory and return */
+ goto responseerr;
+ }
+ }
+ }
+
+ /* deallocate memory and return */
+ goto memerr;
+
+responseerr:
+ /* ERROR: call specified callback function with NULL as name to indicate an error */
+ if (pEntry->found) {
+ (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+ }
+ /* flush this entry */
+ pEntry->state = DNS_STATE_UNUSED;
+ pEntry->found = NULL;
+
+memerr:
+ /* free pbuf */
+ pbuf_free(p);
+ return;
+}
+
+/**
+ * Queues a new hostname to resolve and sends out a DNS query for that hostname
+ *
+ * @param name the hostname that is to be queried
+ * @param found a callback founction to be called on success, failure or timeout
+ * @param callback_arg argument to pass to the callback function
+ * @return @return a err_t return code.
+ */
+static err_t
+dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
+{
+ u8_t i;
+ u8_t lseq, lseqi;
+ struct dns_table_entry *pEntry = NULL;
+ size_t namelen;
+
+ /* search an unused entry, or the oldest one */
+ lseq = lseqi = 0;
+ for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+ pEntry = &dns_table[i];
+ /* is it an unused entry ? */
+ if (pEntry->state == DNS_STATE_UNUSED)
+ break;
+
+ /* check if this is the oldest completed entry */
+ if (pEntry->state == DNS_STATE_DONE) {
+ if ((dns_seqno - pEntry->seqno) > lseq) {
+ lseq = dns_seqno - pEntry->seqno;
+ lseqi = i;
+ }
+ }
+ }
+
+ /* if we don't have found an unused entry, use the oldest completed one */
+ if (i == DNS_TABLE_SIZE) {
+ if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
+ /* no entry can't be used now, table is full */
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
+ return ERR_MEM;
+ } else {
+ /* use the oldest completed one */
+ i = lseqi;
+ pEntry = &dns_table[i];
+ }
+ }
+
+ /* use this entry */
+ LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
+
+ /* fill the entry */
+ pEntry->state = DNS_STATE_NEW;
+ pEntry->seqno = dns_seqno++;
+ pEntry->found = found;
+ pEntry->arg = callback_arg;
+ namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
+ MEMCPY(pEntry->name, name, namelen);
+ pEntry->name[namelen] = 0;
+
+ /* force to send query without waiting timer */
+ dns_check_entry(i);
+
+ /* dns query is enqueued */
+ return ERR_INPROGRESS;
+}
+
+/**
+ * Resolve a hostname (string) into an IP address.
+ * NON-BLOCKING callback version for use with raw API!!!
+ *
+ * Returns immediately with one of err_t return codes:
+ * - ERR_OK if hostname is a valid IP address string or the host
+ * name is already in the local names table.
+ * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
+ * for resolution if no errors are present.
+ * - ERR_ARG: dns client not initialized or invalid hostname
+ *
+ * @param hostname the hostname that is to be queried
+ * @param addr pointer to a ip_addr_t where to store the address if it is already
+ * cached in the dns_table (only valid if ERR_OK is returned!)
+ * @param found a callback function to be called on success, failure or timeout (only if
+ * ERR_INPROGRESS is returned!)
+ * @param callback_arg argument to pass to the callback function
+ * @return a err_t return code.
+ */
+err_t
+dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
+ void *callback_arg)
+{
+ u32_t ipaddr;
+ /* not initialized or no valid server yet, or invalid addr pointer
+ * or invalid hostname or invalid hostname length */
+ if ((dns_pcb == NULL) || (addr == NULL) ||
+ (!hostname) || (!hostname[0]) ||
+ (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
+ return ERR_ARG;
+ }
+
+#if LWIP_HAVE_LOOPIF
+ if (strcmp(hostname, "localhost")==0) {
+ ip_addr_set_loopback(addr);
+ return ERR_OK;
+ }
+#endif /* LWIP_HAVE_LOOPIF */
+
+ /* host name already in octet notation? set ip addr and return ERR_OK */
+ ipaddr = ipaddr_addr(hostname);
+ if (ipaddr == IPADDR_NONE) {
+ /* already have this address cached? */
+ ipaddr = dns_lookup(hostname);
+ }
+ if (ipaddr != IPADDR_NONE) {
+ ip4_addr_set_u32(addr, ipaddr);
+ return ERR_OK;
+ }
+
+ /* queue query with specified callback */
+ return dns_enqueue(hostname, found, callback_arg);
+}
+
+#endif /* LWIP_DNS */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/init.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/init.c
new file mode 100644
index 0000000000..bf5c79da0d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/init.c
@@ -0,0 +1,306 @@
+/**
+ * @file
+ * Modules initialization
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/init.h"
+#include "lwip/stats.h"
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/sockets.h"
+#include "lwip/ip.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp_msg.h"
+#include "lwip/autoip.h"
+#include "lwip/igmp.h"
+#include "lwip/dns.h"
+#include "lwip/timers.h"
+#include "netif/etharp.h"
+
+/* Compile-time sanity checks for configuration errors.
+ * These can be done independently of LWIP_DEBUG, without penalty.
+ */
+#ifndef BYTE_ORDER
+ #error "BYTE_ORDER is not defined, you have to define it in your cc.h"
+#endif
+#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
+ #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
+#endif
+#if (!LWIP_ARP && ARP_QUEUEING)
+ #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_UDPLITE)
+ #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_SNMP)
+ #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_DHCP)
+ #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_IGMP)
+ #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_SNMP)
+ #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_DNS)
+ #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
+ #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
+#endif
+#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
+ #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
+ #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
+ #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_WND > 0xffff))
+ #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
+ #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
+ #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
+#endif
+#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"
+#endif
+#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
+ #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
+#endif
+#if (LWIP_NETIF_API && (NO_SYS==1))
+ #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
+#endif
+#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
+ #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
+#endif
+#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
+ #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
+#endif
+#if (!LWIP_NETCONN && LWIP_SOCKET)
+ #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
+#endif
+#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"
+#endif
+#if (!LWIP_ARP && LWIP_AUTOIP)
+ #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
+#endif
+#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
+ #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
+#endif
+#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
+ #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
+ #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
+#endif
+/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
+#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
+ #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate 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!"
+#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"
+#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"
+#endif
+#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
+ #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
+#endif
+#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
+ #error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
+#endif
+#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
+ #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
+#endif
+#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
+ #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_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
+#if LWIP_IGMP && !defined(LWIP_RAND)
+ #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
+#endif
+#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
+ #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
+#endif
+#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
+ #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
+#endif
+#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
+ #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
+#endif
+
+
+/* Compile-time checks for deprecated options.
+ */
+#ifdef MEMP_NUM_TCPIP_MSG
+ #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef MEMP_NUM_API_MSG
+ #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef TCP_REXMIT_DEBUG
+ #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef RAW_STATS
+ #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef ETHARP_QUEUE_FIRST
+ #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef ETHARP_ALWAYS_INSERT
+ #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
+#endif
+
+#ifdef LWIP_DEBUG
+static void
+lwip_sanity_check(void)
+{
+ /* Warnings */
+#if LWIP_NETCONN
+ if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
+#endif /* LWIP_NETCONN */
+#if LWIP_TCP
+ if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
+ if (TCP_SND_BUF < 2 * TCP_MSS)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
+ if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
+ if (TCP_SNDLOWAT >= TCP_SND_BUF)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
+ if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
+ if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
+ if (TCP_WND < TCP_MSS)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
+#endif /* LWIP_TCP */
+#if LWIP_SOCKET
+ /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
+ if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
+ if (SO_REUSEADDR != SOF_REUSEADDR)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
+ if (SO_KEEPALIVE != SOF_KEEPALIVE)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
+ if (SO_BROADCAST != SOF_BROADCAST)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
+ if (SO_LINGER != SOF_LINGER)
+ LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
+#endif /* LWIP_SOCKET */
+}
+#else /* LWIP_DEBUG */
+#define lwip_sanity_check()
+#endif /* LWIP_DEBUG */
+
+/**
+ * Perform Sanity check of user-configurable values, and initialize all modules.
+ */
+void
+lwip_init(void)
+{
+ /* Sanity check user-configurable values */
+ lwip_sanity_check();
+
+ /* Modules initialization */
+ stats_init();
+#if !NO_SYS
+ sys_init();
+#endif /* !NO_SYS */
+ mem_init();
+ memp_init();
+ pbuf_init();
+ netif_init();
+#if LWIP_SOCKET
+ lwip_socket_init();
+#endif /* LWIP_SOCKET */
+ ip_init();
+#if LWIP_ARP
+ etharp_init();
+#endif /* LWIP_ARP */
+#if LWIP_RAW
+ raw_init();
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+ udp_init();
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ tcp_init();
+#endif /* LWIP_TCP */
+#if LWIP_SNMP
+ snmp_init();
+#endif /* LWIP_SNMP */
+#if LWIP_AUTOIP
+ autoip_init();
+#endif /* LWIP_AUTOIP */
+#if LWIP_IGMP
+ igmp_init();
+#endif /* LWIP_IGMP */
+#if LWIP_DNS
+ dns_init();
+#endif /* LWIP_DNS */
+
+#if LWIP_TIMERS
+ sys_timeouts_init();
+#endif /* LWIP_TIMERS */
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/autoip.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/autoip.c
new file mode 100644
index 0000000000..92bb4591f1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/autoip.c
@@ -0,0 +1,536 @@
+/**
+ * @file
+ * AutoIP Automatic LinkLocal IP Configuration
+ *
+ */
+
+/*
+ *
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
+ * 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: Dominik Spies <kontakt@dspies.de>
+ *
+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
+ * with RFC 3927.
+ *
+ *
+ * Please coordinate changes and requests with Dominik Spies
+ * <kontakt@dspies.de>
+ */
+
+/*******************************************************************************
+ * USAGE:
+ *
+ * define LWIP_AUTOIP 1 in your lwipopts.h
+ *
+ * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
+ * - First, call autoip_init().
+ * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
+ * that should be defined in autoip.h.
+ * 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().
+ *
+ * With DHCP:
+ * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
+ * - Configure your DHCP Client.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/mem.h"
+#include "lwip/udp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/autoip.h"
+#include "netif/etharp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* 169.254.0.0 */
+#define AUTOIP_NET 0xA9FE0000
+/* 169.254.1.0 */
+#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
+/* 169.254.254.255 */
+#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
+
+
+/** 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?netif->autoip->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.
+ */
+#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
+#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
+ htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
+ ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
+#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
+
+/* static functions */
+static void autoip_handle_arp_conflict(struct netif *netif);
+
+/* creates a pseudo random LL IP-Address for a network interface */
+static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
+
+/* sends an ARP probe */
+static err_t autoip_arp_probe(struct netif *netif);
+
+/* sends an ARP announce */
+static err_t autoip_arp_announce(struct netif *netif);
+
+/* configure interface for use with current LL IP-Address */
+static err_t autoip_bind(struct netif *netif);
+
+/* start sending probes for llipaddr */
+static void autoip_start_probing(struct netif *netif);
+
+/**
+ * Initialize this module
+ */
+void
+autoip_init(void)
+{
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
+}
+
+/** Set a statically allocated struct autoip to work with.
+ * Using this prevents autoip_start to allocate it using mem_malloc.
+ *
+ * @param netif the netif for which to set the struct autoip
+ * @param dhcp (uninitialised) dhcp struct allocated by the application
+ */
+void
+autoip_set_struct(struct netif *netif, struct autoip *autoip)
+{
+ LWIP_ASSERT("netif != NULL", netif != NULL);
+ LWIP_ASSERT("autoip != NULL", autoip != NULL);
+ LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
+
+ /* clear data structure */
+ memset(autoip, 0, sizeof(struct autoip));
+ /* autoip->state = AUTOIP_STATE_OFF; */
+ netif->autoip = autoip;
+}
+
+/** Restart AutoIP client and check the next address (conflict detected)
+ *
+ * @param netif The netif under AutoIP control
+ */
+static void
+autoip_restart(struct netif *netif)
+{
+ netif->autoip->tried_llipaddr++;
+ autoip_start(netif);
+}
+
+/**
+ * Handle a IP address conflict after an ARP conflict detection
+ */
+static void
+autoip_handle_arp_conflict(struct netif *netif)
+{
+ /* Somehow detect if we are defending or retreating */
+ unsigned char defend = 1; /* tbd */
+
+ if(defend) {
+ if(netif->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"));
+
+ /* TODO: close all TCP sessions */
+ 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);
+ netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+ }
+ } else {
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
+ /* TODO: close all TCP sessions */
+ autoip_restart(netif);
+ }
+}
+
+/**
+ * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
+ *
+ * @param netif network interface on which create the IP-Address
+ * @param ipaddr ip address to initialize
+ */
+static void
+autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
+{
+ /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
+ * compliant to RFC 3927 Section 2.1
+ * We have 254 * 256 possibilities */
+
+ u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
+ addr += netif->autoip->tried_llipaddr;
+ addr = AUTOIP_NET | (addr & 0xffff);
+ /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
+
+ if (addr < AUTOIP_RANGE_START) {
+ addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+ }
+ if (addr > AUTOIP_RANGE_END) {
+ addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+ }
+ LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
+ (addr <= AUTOIP_RANGE_END));
+ ip4_addr_set_u32(ipaddr, htonl(addr));
+
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(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)
+{
+ return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+ (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
+ &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * 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_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+ (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
+ &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * Configure interface for use with current LL IP-Address
+ *
+ * @param netif network interface to configure with current LL IP-Address
+ */
+static err_t
+autoip_bind(struct netif *netif)
+{
+ struct autoip *autoip = netif->autoip;
+ ip_addr_t sn_mask, gw_addr;
+
+ 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,
+ ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
+ ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
+
+ IP4_ADDR(&sn_mask, 255, 255, 0, 0);
+ IP4_ADDR(&gw_addr, 0, 0, 0, 0);
+
+ netif_set_ipaddr(netif, &autoip->llipaddr);
+ netif_set_netmask(netif, &sn_mask);
+ netif_set_gw(netif, &gw_addr);
+
+ /* bring the interface up */
+ netif_set_up(netif);
+
+ return ERR_OK;
+}
+
+/**
+ * Start AutoIP client
+ *
+ * @param netif network interface on which start the AutoIP client
+ */
+err_t
+autoip_start(struct netif *netif)
+{
+ struct autoip *autoip = netif->autoip;
+ err_t result = ERR_OK;
+
+ if(netif_is_up(netif)) {
+ netif_set_down(netif);
+ }
+
+ /* Set IP-Address, Netmask and Gateway to 0 to make sure that
+ * ARP Packets are formed correctly
+ */
+ ip_addr_set_zero(&netif->ip_addr);
+ ip_addr_set_zero(&netif->netmask);
+ ip_addr_set_zero(&netif->gw);
+
+ 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,
+ ("autoip_start(): starting new AUTOIP client\n"));
+ autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
+ if(autoip == NULL) {
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+ ("autoip_start(): could not allocate autoip\n"));
+ return ERR_MEM;
+ }
+ memset(autoip, 0, sizeof(struct autoip));
+ /* store this AutoIP client in the netif */
+ netif->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;
+ ip_addr_set_zero(&autoip->llipaddr);
+ autoip->lastconflict = 0;
+ }
+
+ autoip_create_addr(netif, &(autoip->llipaddr));
+ autoip_start_probing(netif);
+
+ return result;
+}
+
+static void
+autoip_start_probing(struct netif *netif)
+{
+ struct autoip *autoip = netif->autoip;
+
+ 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(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+ ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+
+ /* time to wait to first probe, this is randomly
+ * choosen 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
+ * accquiring 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;
+ }
+}
+
+/**
+ * Handle a possible change in the network configuration.
+ *
+ * If there is an AutoIP address configured, take the interface down
+ * and begin probing with the same address.
+ */
+void
+autoip_network_changed(struct netif *netif)
+{
+ if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
+ netif_set_down(netif);
+ autoip_start_probing(netif);
+ }
+}
+
+/**
+ * Stop AutoIP client
+ *
+ * @param netif network interface on which stop the AutoIP client
+ */
+err_t
+autoip_stop(struct netif *netif)
+{
+ netif->autoip->state = AUTOIP_STATE_OFF;
+ netif_set_down(netif);
+ return ERR_OK;
+}
+
+/**
+ * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
+ */
+void
+autoip_tmr()
+{
+ struct netif *netif = netif_list;
+ /* loop through netif's */
+ while (netif != NULL) {
+ /* only act on AutoIP configured interfaces */
+ if (netif->autoip != NULL) {
+ if(netif->autoip->lastconflict > 0) {
+ netif->autoip->lastconflict--;
+ }
+
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+ ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
+ (u16_t)(netif->autoip->state), netif->autoip->ttw));
+
+ switch(netif->autoip->state) {
+ case AUTOIP_STATE_PROBING:
+ if(netif->autoip->ttw > 0) {
+ netif->autoip->ttw--;
+ } else {
+ if(netif->autoip->sent_num >= PROBE_NUM) {
+ netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
+ netif->autoip->sent_num = 0;
+ netif->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(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+ ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+ } else {
+ autoip_arp_probe(netif);
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+ ("autoip_tmr() PROBING Sent Probe\n"));
+ netif->autoip->sent_num++;
+ /* calculate time to wait to next probe */
+ netif->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(netif->autoip->ttw > 0) {
+ netif->autoip->ttw--;
+ } else {
+ if(netif->autoip->sent_num == 0) {
+ /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
+ * Now we can bind to an IP address and use it.
+ *
+ * autoip_bind calls netif_set_up. This triggers a gratuitous ARP
+ * which counts as an announcement.
+ */
+ autoip_bind(netif);
+ } else {
+ autoip_arp_announce(netif);
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+ ("autoip_tmr() ANNOUNCING Sent Announce\n"));
+ }
+ netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+ netif->autoip->sent_num++;
+
+ if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
+ netif->autoip->state = AUTOIP_STATE_BOUND;
+ netif->autoip->sent_num = 0;
+ netif->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(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+ ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+ }
+ }
+ break;
+ }
+ }
+ /* proceed to next network interface */
+ netif = netif->next;
+ }
+}
+
+/**
+ * Handles every incoming ARP Packet, called by etharp_arp_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)
+{
+ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
+ if ((netif->autoip != NULL) && (netif->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
+ */
+ ip_addr_t sipaddr, dipaddr;
+ struct eth_addr netifaddr;
+ ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
+
+ /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
+ * structure packing (not using structure copy which breaks strict-aliasing rules).
+ */
+ IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
+ IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
+
+ if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
+ ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
+ (netif->autoip->sent_num == 0))) {
+ /* 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 ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
+ (ip_addr_cmp(&dipaddr, &netif->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 (ip_addr_cmp(&sipaddr, &netif->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);
+ }
+ }
+ }
+}
+
+#endif /* LWIP_AUTOIP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/icmp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/icmp.c
new file mode 100644
index 0000000000..32902a522c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/icmp.c
@@ -0,0 +1,335 @@
+/**
+ * @file
+ * ICMP - Internet Control Message Protocol
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+/* Some ICMP messages should be passed to the transport protocols. This
+ is not implemented. */
+
+#include "lwip/opt.h"
+
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/icmp.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+
+#include <string.h>
+
+/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
+ * used to modify and send a response packet (and to 1 if this is not the case,
+ * e.g. when link header is stripped of when receiving) */
+#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+
+/* The amount of data from the original packet to return in a dest-unreachable */
+#define ICMP_DEST_UNREACH_DATASIZE 8
+
+static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
+
+/**
+ * Processes ICMP input packets, called from ip_input().
+ *
+ * Currently only processes icmp echo requests and sends
+ * out the echo response.
+ *
+ * @param p the icmp echo request packet, p->payload pointing to the ip header
+ * @param inp the netif on which this packet was received
+ */
+void
+icmp_input(struct pbuf *p, struct netif *inp)
+{
+ u8_t type;
+#ifdef LWIP_DEBUG
+ u8_t code;
+#endif /* LWIP_DEBUG */
+ struct icmp_echo_hdr *iecho;
+ struct ip_hdr *iphdr;
+ s16_t hlen;
+
+ ICMP_STATS_INC(icmp.recv);
+ snmp_inc_icmpinmsgs();
+
+
+ iphdr = (struct ip_hdr *)p->payload;
+ hlen = IPH_HL(iphdr) * 4;
+ if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
+ goto lenerr;
+ }
+
+ type = *((u8_t *)p->payload);
+#ifdef LWIP_DEBUG
+ code = *(((u8_t *)p->payload)+1);
+#endif /* LWIP_DEBUG */
+ switch (type) {
+ case ICMP_ER:
+ /* This is OK, echo reply might have been parsed by a raw PCB
+ (as obviously, an echo request has been sent, too). */
+ break;
+ case ICMP_ECHO:
+#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
+ {
+ int accepted = 1;
+#if !LWIP_MULTICAST_PING
+ /* multicast destination address? */
+ if (ip_addr_ismulticast(&current_iphdr_dest)) {
+ accepted = 0;
+ }
+#endif /* LWIP_MULTICAST_PING */
+#if !LWIP_BROADCAST_PING
+ /* broadcast destination address? */
+ if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+ accepted = 0;
+ }
+#endif /* LWIP_BROADCAST_PING */
+ /* broadcast or multicast destination address not acceptd? */
+ if (!accepted) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
+ ICMP_STATS_INC(icmp.err);
+ pbuf_free(p);
+ return;
+ }
+ }
+#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
+ if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
+ goto lenerr;
+ }
+ if (inet_chksum_pbuf(p) != 0) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
+ pbuf_free(p);
+ ICMP_STATS_INC(icmp.chkerr);
+ snmp_inc_icmpinerrors();
+ return;
+ }
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+ if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+ /* p is not big enough to contain link headers
+ * allocate a new one and copy p into it
+ */
+ struct pbuf *r;
+ /* switch p->payload to ip header */
+ if (pbuf_header(p, hlen)) {
+ LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
+ goto memerr;
+ }
+ /* allocate new packet buffer with space for link headers */
+ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+ if (r == NULL) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
+ goto memerr;
+ }
+ LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
+ (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
+ /* copy the whole packet including ip header */
+ if (pbuf_copy(r, p) != ERR_OK) {
+ LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
+ goto memerr;
+ }
+ iphdr = (struct ip_hdr *)r->payload;
+ /* switch r->payload back to icmp header */
+ if (pbuf_header(r, -hlen)) {
+ LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+ goto memerr;
+ }
+ /* free the original p */
+ pbuf_free(p);
+ /* we now have an identical copy of p that has room for link headers */
+ p = r;
+ } else {
+ /* restore p->payload to point to icmp header */
+ if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+ LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+ goto memerr;
+ }
+ }
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+ /* At this point, all checks are OK. */
+ /* We generate an answer by switching the dest and src ip addresses,
+ * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
+ iecho = (struct icmp_echo_hdr *)p->payload;
+ ip_addr_copy(iphdr->src, *ip_current_dest_addr());
+ ip_addr_copy(iphdr->dest, *ip_current_src_addr());
+ ICMPH_TYPE_SET(iecho, ICMP_ER);
+ /* adjust the checksum */
+ if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
+ iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
+ } else {
+ iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
+ }
+
+ /* Set the correct TTL and recalculate the header checksum. */
+ IPH_TTL_SET(iphdr, ICMP_TTL);
+ IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+#endif /* CHECKSUM_GEN_IP */
+
+ ICMP_STATS_INC(icmp.xmit);
+ /* increase number of messages attempted to send */
+ snmp_inc_icmpoutmsgs();
+ /* increase number of echo replies attempted to send */
+ snmp_inc_icmpoutechoreps();
+
+ if(pbuf_header(p, hlen)) {
+ LWIP_ASSERT("Can't move over header in packet", 0);
+ } else {
+ err_t ret;
+ /* send an ICMP packet, src addr is the dest addr of the curren packet */
+ ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
+ ICMP_TTL, 0, IP_PROTO_ICMP, inp);
+ if (ret != ERR_OK) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
+ }
+ }
+ break;
+ default:
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
+ (s16_t)type, (s16_t)code));
+ ICMP_STATS_INC(icmp.proterr);
+ ICMP_STATS_INC(icmp.drop);
+ }
+ pbuf_free(p);
+ return;
+lenerr:
+ pbuf_free(p);
+ ICMP_STATS_INC(icmp.lenerr);
+ snmp_inc_icmpinerrors();
+ return;
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+memerr:
+ pbuf_free(p);
+ ICMP_STATS_INC(icmp.err);
+ snmp_inc_icmpinerrors();
+ return;
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+}
+
+/**
+ * Send an icmp 'destination unreachable' packet, called from ip_input() if
+ * the transport layer protocol is unknown and from udp_input() if the local
+ * port is not bound.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ * p->payload pointing to the IP header
+ * @param t type of the 'unreachable' packet
+ */
+void
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
+{
+ icmp_send_response(p, ICMP_DUR, t);
+}
+
+#if IP_FORWARD || IP_REASSEMBLY
+/**
+ * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
+ *
+ * @param p the input packet for which the 'time exceeded' should be sent,
+ * p->payload pointing to the IP header
+ * @param t type of the 'time exceeded' packet
+ */
+void
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
+{
+ icmp_send_response(p, ICMP_TE, t);
+}
+
+#endif /* IP_FORWARD || IP_REASSEMBLY */
+
+/**
+ * Send an icmp packet in response to an incoming packet.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ * p->payload pointing to the IP header
+ * @param type Type of the ICMP header
+ * @param code Code of the ICMP header
+ */
+static void
+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;
+ ip_addr_t iphdr_src;
+
+ /* ICMP header + IP header + 8 bytes of data */
+ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
+ PBUF_RAM);
+ if (q == NULL) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
+ return;
+ }
+ LWIP_ASSERT("check that first pbuf can hold icmp message",
+ (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
+
+ iphdr = (struct ip_hdr *)p->payload;
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
+ ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
+ LWIP_DEBUGF(ICMP_DEBUG, (" to "));
+ ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
+ LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
+
+ icmphdr = (struct icmp_echo_hdr *)q->payload;
+ icmphdr->type = type;
+ icmphdr->code = code;
+ icmphdr->id = 0;
+ icmphdr->seqno = 0;
+
+ /* copy fields from original packet */
+ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
+ IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
+
+ /* calculate checksum */
+ icmphdr->chksum = 0;
+ icmphdr->chksum = inet_chksum(icmphdr, q->len);
+ ICMP_STATS_INC(icmp.xmit);
+ /* increase number of messages attempted to send */
+ snmp_inc_icmpoutmsgs();
+ /* increase number of destination unreachable messages attempted to send */
+ snmp_inc_icmpouttimeexcds();
+ ip_addr_copy(iphdr_src, iphdr->src);
+ ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
+ pbuf_free(q);
+}
+
+#endif /* LWIP_ICMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/igmp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/igmp.c
new file mode 100644
index 0000000000..45bb5d95c2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/igmp.c
@@ -0,0 +1,805 @@
+/**
+ * @file
+ * IGMP - Internet Group Management Protocol
+ *
+ */
+
+/*
+ * Copyright (c) 2002 CITEL Technologies 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 CITEL Technologies Ltd 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 CITEL TECHNOLOGIES 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 CITEL TECHNOLOGIES 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 a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+*/
+
+/*-------------------------------------------------------------
+Note 1)
+Although the rfc requires V1 AND V2 capability
+we will only support v2 since now V1 is very old (August 1989)
+V1 can be added if required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 2)
+A query for a specific group address (as opposed to ALLHOSTS)
+has now been implemented as I am unsure if it is required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 3)
+The router alert rfc 2113 is implemented in outgoing packets
+but not checked rigorously incoming
+-------------------------------------------------------------
+Steve Reynolds
+------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * RFC 988 - Host extensions for IP multicasting - V0
+ * RFC 1054 - Host extensions for IP multicasting -
+ * RFC 1112 - Host extensions for IP multicasting - V1
+ * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
+ * RFC 3376 - Internet Group Management Protocol, Version 3 - V3
+ * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
+ * RFC 2113 - IP Router Alert Option -
+ *----------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/igmp.h"
+#include "lwip/debug.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+
+#include "string.h"
+
+/*
+ * IGMP constants
+ */
+#define IGMP_TTL 1
+#define IGMP_MINLEN 8
+#define ROUTER_ALERT 0x9404U
+#define ROUTER_ALERTLEN 4
+
+/*
+ * IGMP message types, including version number.
+ */
+#define IGMP_MEMB_QUERY 0x11 /* Membership query */
+#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
+#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
+#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
+
+/* Group membership states */
+#define IGMP_GROUP_NON_MEMBER 0
+#define IGMP_GROUP_DELAYING_MEMBER 1
+#define IGMP_GROUP_IDLE_MEMBER 2
+
+/**
+ * IGMP packet format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct igmp_msg {
+ PACK_STRUCT_FIELD(u8_t igmp_msgtype);
+ PACK_STRUCT_FIELD(u8_t igmp_maxresp);
+ PACK_STRUCT_FIELD(u16_t igmp_checksum);
+ PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+
+static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
+static err_t igmp_remove_group(struct igmp_group *group);
+static void igmp_timeout( struct igmp_group *group);
+static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
+static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
+static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
+static void igmp_send(struct igmp_group *group, u8_t type);
+
+
+static struct igmp_group* igmp_group_list;
+static ip_addr_t allsystems;
+static ip_addr_t allrouters;
+
+
+/**
+ * Initialize the IGMP module
+ */
+void
+igmp_init(void)
+{
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
+
+ IP4_ADDR(&allsystems, 224, 0, 0, 1);
+ IP4_ADDR(&allrouters, 224, 0, 0, 2);
+}
+
+#ifdef LWIP_DEBUG
+/**
+ * Dump global IGMP groups list
+ */
+void
+igmp_dump_group_list()
+{
+ struct igmp_group *group = igmp_group_list;
+
+ while (group != NULL) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
+ ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+ LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+ group = group->next;
+ }
+ LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+}
+#else
+#define igmp_dump_group_list()
+#endif /* LWIP_DEBUG */
+
+/**
+ * Start IGMP processing on interface
+ *
+ * @param netif network interface on which start IGMP processing
+ */
+err_t
+igmp_start(struct netif *netif)
+{
+ struct igmp_group* group;
+
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
+
+ group = igmp_lookup_group(netif, &allsystems);
+
+ if (group != NULL) {
+ group->group_state = IGMP_GROUP_IDLE_MEMBER;
+ group->use++;
+
+ /* Allow the igmp messages at the MAC level */
+ if (netif->igmp_mac_filter != NULL) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
+ ip_addr_debug_print(IGMP_DEBUG, &allsystems);
+ LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+ netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
+ }
+
+ return ERR_OK;
+ }
+
+ return ERR_MEM;
+}
+
+/**
+ * Stop IGMP processing on interface
+ *
+ * @param netif network interface on which stop IGMP processing
+ */
+err_t
+igmp_stop(struct netif *netif)
+{
+ struct igmp_group *group = igmp_group_list;
+ struct igmp_group *prev = NULL;
+ struct igmp_group *next;
+
+ /* look for groups joined on this interface further down the list */
+ while (group != NULL) {
+ next = group->next;
+ /* is it a group joined on this interface? */
+ if (group->netif == netif) {
+ /* is it the first group of the list? */
+ if (group == igmp_group_list) {
+ igmp_group_list = next;
+ }
+ /* is there a "previous" group defined? */
+ if (prev != NULL) {
+ prev->next = next;
+ }
+ /* disable the group at the MAC level */
+ if (netif->igmp_mac_filter != NULL) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
+ ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+ LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+ netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
+ }
+ /* free group */
+ memp_free(MEMP_IGMP_GROUP, group);
+ } else {
+ /* change the "previous" */
+ prev = group;
+ }
+ /* move to "next" */
+ group = next;
+ }
+ return ERR_OK;
+}
+
+/**
+ * Report IGMP memberships for this interface
+ *
+ * @param netif network interface on which report IGMP memberships
+ */
+void
+igmp_report_groups(struct netif *netif)
+{
+ struct igmp_group *group = igmp_group_list;
+
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
+
+ while (group != NULL) {
+ if (group->netif == netif) {
+ igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+ }
+ group = group->next;
+ }
+}
+
+/**
+ * Search for a group in the global igmp_group_list
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search for
+ * @return a struct igmp_group* if the group has been found,
+ * NULL if the group wasn't found.
+ */
+struct igmp_group *
+igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
+{
+ struct igmp_group *group = igmp_group_list;
+
+ while (group != NULL) {
+ if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
+ return group;
+ }
+ group = group->next;
+ }
+
+ /* to be clearer, we return NULL here instead of
+ * 'group' (which is also NULL at this point).
+ */
+ return NULL;
+}
+
+/**
+ * Search for a specific igmp group and create a new one if not found-
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search
+ * @return a struct igmp_group*,
+ * NULL on memory error.
+ */
+struct igmp_group *
+igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
+{
+ struct igmp_group *group = igmp_group_list;
+
+ /* Search if the group already exists */
+ group = igmp_lookfor_group(ifp, addr);
+ if (group != NULL) {
+ /* Group already exists. */
+ return group;
+ }
+
+ /* Group doesn't exist yet, create a new one */
+ group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
+ if (group != NULL) {
+ group->netif = ifp;
+ ip_addr_set(&(group->group_address), addr);
+ group->timer = 0; /* Not running */
+ group->group_state = IGMP_GROUP_NON_MEMBER;
+ group->last_reporter_flag = 0;
+ group->use = 0;
+ group->next = igmp_group_list;
+
+ igmp_group_list = group;
+ }
+
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
+ ip_addr_debug_print(IGMP_DEBUG, addr);
+ LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
+
+ return group;
+}
+
+/**
+ * Remove a group in the global igmp_group_list
+ *
+ * @param group the group to remove from the global igmp_group_list
+ * @return ERR_OK if group was removed from the list, an err_t otherwise
+ */
+static err_t
+igmp_remove_group(struct igmp_group *group)
+{
+ err_t err = ERR_OK;
+
+ /* Is it the first group? */
+ if (igmp_group_list == group) {
+ igmp_group_list = group->next;
+ } else {
+ /* look for group further down the list */
+ struct igmp_group *tmpGroup;
+ for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
+ if (tmpGroup->next == group) {
+ tmpGroup->next = group->next;
+ break;
+ }
+ }
+ /* Group not found in the global igmp_group_list */
+ if (tmpGroup == NULL)
+ err = ERR_ARG;
+ }
+ /* free group */
+ memp_free(MEMP_IGMP_GROUP, group);
+
+ return err;
+}
+
+/**
+ * Called from ip_input() if a new IGMP packet is received.
+ *
+ * @param p received igmp packet, p->payload pointing to the ip header
+ * @param inp network interface on which the packet was received
+ * @param dest destination ip address of the igmp packet
+ */
+void
+igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
+{
+ struct ip_hdr * iphdr;
+ struct igmp_msg* igmp;
+ struct igmp_group* group;
+ struct igmp_group* groupref;
+
+ IGMP_STATS_INC(igmp.recv);
+
+ /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
+ iphdr = (struct ip_hdr *)p->payload;
+ if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
+ pbuf_free(p);
+ IGMP_STATS_INC(igmp.lenerr);
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
+ return;
+ }
+
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
+ ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
+ LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
+ ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
+ LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
+
+ /* Now calculate and check the checksum */
+ igmp = (struct igmp_msg *)p->payload;
+ if (inet_chksum(igmp, p->len)) {
+ pbuf_free(p);
+ IGMP_STATS_INC(igmp.chkerr);
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
+ return;
+ }
+
+ /* Packet is ok so find an existing group */
+ group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
+
+ /* If group can be found or create... */
+ if (!group) {
+ pbuf_free(p);
+ IGMP_STATS_INC(igmp.drop);
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
+ return;
+ }
+
+ /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
+ switch (igmp->igmp_msgtype) {
+ case IGMP_MEMB_QUERY: {
+ /* IGMP_MEMB_QUERY to the "all systems" address ? */
+ if ((ip_addr_cmp(dest, &allsystems)) && ip_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)));
+
+ if (igmp->igmp_maxresp == 0) {
+ IGMP_STATS_INC(igmp.rx_v1);
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
+ igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
+ } else {
+ IGMP_STATS_INC(igmp.rx_general);
+ }
+
+ groupref = igmp_group_list;
+ while (groupref) {
+ /* Do not send messages on the all systems group address! */
+ if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
+ igmp_delaying_member(groupref, igmp->igmp_maxresp);
+ }
+ groupref = groupref->next;
+ }
+ } else {
+ /* IGMP_MEMB_QUERY to a specific group ? */
+ if (!ip_addr_isany(&igmp->igmp_group_address)) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
+ ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
+ if (ip_addr_cmp(dest, &allsystems)) {
+ ip_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 */
+ ip_addr_copy(groupaddr, igmp->igmp_group_address);
+ group = igmp_lookfor_group(inp, &groupaddr);
+ } else {
+ LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+ }
+
+ if (group != NULL) {
+ IGMP_STATS_INC(igmp.rx_group);
+ igmp_delaying_member(group, igmp->igmp_maxresp);
+ } else {
+ IGMP_STATS_INC(igmp.drop);
+ }
+ } else {
+ IGMP_STATS_INC(igmp.proterr);
+ }
+ }
+ break;
+ }
+ case IGMP_V2_MEMB_REPORT: {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
+ IGMP_STATS_INC(igmp.rx_report);
+ if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+ /* This is on a specific group we have already looked up */
+ group->timer = 0; /* stopped */
+ group->group_state = IGMP_GROUP_IDLE_MEMBER;
+ group->last_reporter_flag = 0;
+ }
+ break;
+ }
+ default: {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
+ igmp->igmp_msgtype, group->group_state, &group, group->netif));
+ IGMP_STATS_INC(igmp.proterr);
+ break;
+ }
+ }
+
+ pbuf_free(p);
+ return;
+}
+
+/**
+ * Join a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should join a new group
+ * @param groupaddr the ip address of the group which to join
+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+ err_t err = ERR_VAL; /* no matching interface */
+ struct igmp_group *group;
+ struct netif *netif;
+
+ /* make sure it is multicast address */
+ LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+ LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+ /* loop through netif's */
+ netif = netif_list;
+ while (netif != NULL) {
+ /* Should we join this interface ? */
+ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+ /* find group or create a new one if not found */
+ group = igmp_lookup_group(netif, groupaddr);
+
+ if (group != NULL) {
+ /* This should create a new group, check the state to make sure */
+ if (group->group_state != IGMP_GROUP_NON_MEMBER) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
+ } else {
+ /* OK - it was new group */
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
+ ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+ LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+ /* If first use of the group, allow the group at the MAC level */
+ if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
+ ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+ LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+ netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
+ }
+
+ IGMP_STATS_INC(igmp.tx_join);
+ igmp_send(group, IGMP_V2_MEMB_REPORT);
+
+ igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+
+ /* Need to work out where this timer comes from */
+ group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+ }
+ /* Increment group use */
+ group->use++;
+ /* Join on this interface */
+ err = ERR_OK;
+ } else {
+ /* Return an error even if some network interfaces are joined */
+ /** @todo undo any other netif already joined */
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
+ return ERR_MEM;
+ }
+ }
+ /* proceed to next network interface */
+ netif = netif->next;
+ }
+
+ return err;
+}
+
+/**
+ * Leave a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should leave a group
+ * @param groupaddr the ip address of the group which to leave
+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+ err_t err = ERR_VAL; /* no matching interface */
+ struct igmp_group *group;
+ struct netif *netif;
+
+ /* make sure it is multicast address */
+ LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+ LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+ /* loop through netif's */
+ netif = netif_list;
+ while (netif != NULL) {
+ /* Should we leave this interface ? */
+ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+ /* find group */
+ group = igmp_lookfor_group(netif, groupaddr);
+
+ if (group != NULL) {
+ /* Only send a leave if the flag is set according to the state diagram */
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
+ ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+ LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+ /* If there is no other use of the group */
+ if (group->use <= 1) {
+ /* If we are the last reporter for this group */
+ if (group->last_reporter_flag) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
+ IGMP_STATS_INC(igmp.tx_leave);
+ igmp_send(group, IGMP_LEAVE_GROUP);
+ }
+
+ /* Disable the group at the MAC level */
+ if (netif->igmp_mac_filter != NULL) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
+ ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+ LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+ netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
+ }
+
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
+ ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+ LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+ /* Free the group */
+ igmp_remove_group(group);
+ } else {
+ /* Decrement group use */
+ group->use--;
+ }
+ /* Leave on this interface */
+ err = ERR_OK;
+ } else {
+ /* It's not a fatal error on "leavegroup" */
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
+ }
+ }
+ /* proceed to next network interface */
+ netif = netif->next;
+ }
+
+ return err;
+}
+
+/**
+ * The igmp timer function (both for NO_SYS=1 and =0)
+ * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
+ */
+void
+igmp_tmr(void)
+{
+ struct igmp_group *group = igmp_group_list;
+
+ while (group != NULL) {
+ if (group->timer > 0) {
+ group->timer--;
+ if (group->timer == 0) {
+ igmp_timeout(group);
+ }
+ }
+ group = group->next;
+ }
+}
+
+/**
+ * Called if a timeout for one group is reached.
+ * Sends a report for this group.
+ *
+ * @param group an igmp_group for which a timeout is reached
+ */
+static void
+igmp_timeout(struct igmp_group *group)
+{
+ /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
+ if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
+ ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
+ LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+
+ IGMP_STATS_INC(igmp.tx_report);
+ igmp_send(group, IGMP_V2_MEMB_REPORT);
+ }
+}
+
+/**
+ * Start a timer for an igmp group
+ *
+ * @param group the igmp_group for which to start a timer
+ * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
+ * every call to igmp_tmr())
+ */
+static void
+igmp_start_timer(struct igmp_group *group, u8_t max_time)
+{
+ /* ensure the input value is > 0 */
+ if (max_time == 0) {
+ max_time = 1;
+ }
+ /* ensure the random value is > 0 */
+ group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
+}
+
+/**
+ * Delaying membership report for a group if necessary
+ *
+ * @param group the igmp_group for which "delaying" membership report
+ * @param maxresp query delay
+ */
+static void
+igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
+{
+ if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
+ ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
+ ((group->timer == 0) || (maxresp < group->timer)))) {
+ igmp_start_timer(group, maxresp);
+ group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+ }
+}
+
+
+/**
+ * Sends an IP packet on a network interface. This function constructs the IP header
+ * and calculates the IP header checksum. If the source IP address is NULL,
+ * the IP address of the outgoing network interface is filled in as source address.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an IP
+ header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ * IP address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ * ERR_BUF if p doesn't have enough space for IP/LINK headers
+ * returns errors returned by netif->output
+ */
+static err_t
+igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
+{
+ /* This is the "router alert" option */
+ u16_t ra[2];
+ ra[0] = PP_HTONS(ROUTER_ALERT);
+ ra[1] = 0x0000; /* Router shall examine packet */
+ IGMP_STATS_INC(igmp.xmit);
+ return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
+}
+
+/**
+ * Send an igmp packet to a specific group.
+ *
+ * @param group the group to which to send the packet
+ * @param type the type of igmp packet to send
+ */
+static void
+igmp_send(struct igmp_group *group, u8_t type)
+{
+ struct pbuf* p = NULL;
+ struct igmp_msg* igmp = NULL;
+ ip_addr_t src = *IP_ADDR_ANY;
+ ip_addr_t* dest = NULL;
+
+ /* IP header + "router alert" option + IGMP header */
+ p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
+
+ if (p) {
+ igmp = (struct igmp_msg *)p->payload;
+ LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
+ (p->len >= sizeof(struct igmp_msg)));
+ ip_addr_copy(src, group->netif->ip_addr);
+
+ if (type == IGMP_V2_MEMB_REPORT) {
+ dest = &(group->group_address);
+ ip_addr_copy(igmp->igmp_group_address, group->group_address);
+ group->last_reporter_flag = 1; /* Remember we were the last to report */
+ } else {
+ if (type == IGMP_LEAVE_GROUP) {
+ dest = &allrouters;
+ ip_addr_copy(igmp->igmp_group_address, group->group_address);
+ }
+ }
+
+ if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
+ igmp->igmp_msgtype = type;
+ igmp->igmp_maxresp = 0;
+ igmp->igmp_checksum = 0;
+ igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
+
+ igmp_ip_output_if(p, &src, dest, group->netif);
+ }
+
+ pbuf_free(p);
+ } else {
+ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
+ IGMP_STATS_INC(igmp.memerr);
+ }
+}
+
+#endif /* LWIP_IGMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet.c
new file mode 100644
index 0000000000..e283a57660
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet.c
@@ -0,0 +1,42 @@
+/**
+ * @file
+ * Functions common to all TCP/IPv4 modules, such as the byte order functions.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet.h"
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet_chksum.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet_chksum.c
new file mode 100644
index 0000000000..960252f64f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/inet_chksum.c
@@ -0,0 +1,450 @@
+/**
+ * @file
+ * Incluse internet checksum functions.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet_chksum.h"
+#include "lwip/def.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* These are some reference implementations of the checksum algorithm, with the
+ * aim of being simple, correct and fully portable. Checksumming is the
+ * first thing you would want to optimize for your platform. If you create
+ * your own version, link it in and in your cc.h put:
+ *
+ * #define LWIP_CHKSUM <your_checksum_routine>
+ *
+ * Or you can select from the implementations below by defining
+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
+ */
+
+#ifndef LWIP_CHKSUM
+# define LWIP_CHKSUM lwip_standard_chksum
+# ifndef LWIP_CHKSUM_ALGORITHM
+# define LWIP_CHKSUM_ALGORITHM 2
+# endif
+#endif
+/* If none set: */
+#ifndef LWIP_CHKSUM_ALGORITHM
+# define LWIP_CHKSUM_ALGORITHM 0
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
+/**
+ * lwip checksum
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum)
+ *
+ * @note accumulator size limits summable length to 64k
+ * @note host endianess is irrelevant (p3 RFC1071)
+ */
+static u16_t
+lwip_standard_chksum(void *dataptr, u16_t len)
+{
+ u32_t acc;
+ u16_t src;
+ u8_t *octetptr;
+
+ acc = 0;
+ /* dataptr may be at odd or even addresses */
+ octetptr = (u8_t*)dataptr;
+ while (len > 1) {
+ /* declare first octet as most significant
+ thus assume network order, ignoring host order */
+ src = (*octetptr) << 8;
+ octetptr++;
+ /* declare second octet as least significant */
+ src |= (*octetptr);
+ octetptr++;
+ acc += src;
+ len -= 2;
+ }
+ if (len > 0) {
+ /* accumulate remaining octet */
+ src = (*octetptr) << 8;
+ acc += src;
+ }
+ /* add deferred carry bits */
+ acc = (acc >> 16) + (acc & 0x0000ffffUL);
+ if ((acc & 0xffff0000UL) != 0) {
+ acc = (acc >> 16) + (acc & 0x0000ffffUL);
+ }
+ /* This maybe a little confusing: reorder sum using htons()
+ instead of ntohs() since it has a little less call overhead.
+ The caller must invert bits for Internet sum ! */
+ return htons((u16_t)acc);
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
+/*
+ * Curt McDowell
+ * Broadcom Corp.
+ * csm@broadcom.com
+ *
+ * IP checksum two bytes at a time with support for
+ * unaligned buffer.
+ * Works for len up to and including 0x20000.
+ * by Curt McDowell, Broadcom Corp. 12/08/2005
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum)
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+ u8_t *pb = (u8_t *)dataptr;
+ u16_t *ps, t = 0;
+ u32_t sum = 0;
+ int odd = ((mem_ptr_t)pb & 1);
+
+ /* Get aligned to u16_t */
+ if (odd && len > 0) {
+ ((u8_t *)&t)[1] = *pb++;
+ len--;
+ }
+
+ /* Add the bulk of the data */
+ ps = (u16_t *)(void *)pb;
+ while (len > 1) {
+ sum += *ps++;
+ len -= 2;
+ }
+
+ /* Consume left-over byte, if any */
+ if (len > 0) {
+ ((u8_t *)&t)[0] = *(u8_t *)ps;
+ }
+
+ /* Add end bytes */
+ sum += t;
+
+ /* Fold 32-bit sum to 16 bits
+ calling this twice is propably faster than if statements... */
+ sum = FOLD_U32T(sum);
+ sum = FOLD_U32T(sum);
+
+ /* Swap if alignment was odd */
+ if (odd) {
+ sum = SWAP_BYTES_IN_WORD(sum);
+ }
+
+ return (u16_t)sum;
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
+/**
+ * An optimized checksum routine. Basically, it uses loop-unrolling on
+ * the checksum loop, treating the head and tail bytes specially, whereas
+ * the inner loop acts on 8 bytes at a time.
+ *
+ * @arg start of buffer to be checksummed. May be an odd byte address.
+ * @len number of bytes in the buffer to be checksummed.
+ * @return host order (!) lwip checksum (non-inverted Internet sum)
+ *
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+ u8_t *pb = (u8_t *)dataptr;
+ u16_t *ps, t = 0;
+ u32_t *pl;
+ u32_t sum = 0, tmp;
+ /* starts at odd byte address? */
+ int odd = ((mem_ptr_t)pb & 1);
+
+ if (odd && len > 0) {
+ ((u8_t *)&t)[1] = *pb++;
+ len--;
+ }
+
+ ps = (u16_t *)pb;
+
+ if (((mem_ptr_t)ps & 3) && len > 1) {
+ sum += *ps++;
+ len -= 2;
+ }
+
+ pl = (u32_t *)ps;
+
+ while (len > 7) {
+ tmp = sum + *pl++; /* ping */
+ if (tmp < sum) {
+ tmp++; /* add back carry */
+ }
+
+ sum = tmp + *pl++; /* pong */
+ if (sum < tmp) {
+ sum++; /* add back carry */
+ }
+
+ len -= 8;
+ }
+
+ /* make room in upper bits */
+ sum = FOLD_U32T(sum);
+
+ ps = (u16_t *)pl;
+
+ /* 16-bit aligned word remaining? */
+ while (len > 1) {
+ sum += *ps++;
+ len -= 2;
+ }
+
+ /* dangling tail byte remaining? */
+ if (len > 0) { /* include odd byte */
+ ((u8_t *)&t)[0] = *(u8_t *)ps;
+ }
+
+ sum += t; /* add end bytes */
+
+ /* Fold 32-bit sum to 16 bits
+ calling this twice is propably faster than if statements... */
+ sum = FOLD_U32T(sum);
+ sum = FOLD_U32T(sum);
+
+ if (odd) {
+ sum = SWAP_BYTES_IN_WORD(sum);
+ }
+
+ return (u16_t)sum;
+}
+#endif
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo(struct pbuf *p,
+ ip_addr_t *src, ip_addr_t *dest,
+ u8_t proto, u16_t proto_len)
+{
+ u32_t acc;
+ u32_t addr;
+ struct pbuf *q;
+ u8_t swapped;
+
+ acc = 0;
+ swapped = 0;
+ /* iterate through all pbuf in chain */
+ for(q = p; q != NULL; q = q->next) {
+ LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+ (void *)q, (void *)q->next));
+ acc += LWIP_CHKSUM(q->payload, q->len);
+ /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+ /* just executing this next line is probably faster that the if statement needed
+ to check whether we really need to execute it, and does no harm */
+ acc = FOLD_U32T(acc);
+ if (q->len % 2 != 0) {
+ swapped = 1 - swapped;
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+ }
+
+ if (swapped) {
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ addr = ip4_addr_get_u32(src);
+ acc += (addr & 0xffffUL);
+ acc += ((addr >> 16) & 0xffffUL);
+ addr = ip4_addr_get_u32(dest);
+ acc += (addr & 0xffffUL);
+ acc += ((addr >> 16) & 0xffffUL);
+ acc += (u32_t)htons((u16_t)proto);
+ acc += (u32_t)htons(proto_len);
+
+ /* Fold 32-bit sum to 16 bits
+ calling this twice is propably faster than if statements... */
+ acc = FOLD_U32T(acc);
+ acc = FOLD_U32T(acc);
+ LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+ return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo_partial(struct pbuf *p,
+ ip_addr_t *src, ip_addr_t *dest,
+ u8_t proto, u16_t proto_len, u16_t chksum_len)
+{
+ u32_t acc;
+ u32_t addr;
+ struct pbuf *q;
+ u8_t swapped;
+ u16_t chklen;
+
+ acc = 0;
+ swapped = 0;
+ /* iterate through all pbuf in chain */
+ for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
+ LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+ (void *)q, (void *)q->next));
+ chklen = q->len;
+ if (chklen > chksum_len) {
+ chklen = chksum_len;
+ }
+ acc += LWIP_CHKSUM(q->payload, chklen);
+ chksum_len -= chklen;
+ LWIP_ASSERT("delete me", chksum_len < 0x7fff);
+ /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+ /* fold the upper bit down */
+ acc = FOLD_U32T(acc);
+ if (q->len % 2 != 0) {
+ swapped = 1 - swapped;
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+ }
+
+ if (swapped) {
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ addr = ip4_addr_get_u32(src);
+ acc += (addr & 0xffffUL);
+ acc += ((addr >> 16) & 0xffffUL);
+ addr = ip4_addr_get_u32(dest);
+ acc += (addr & 0xffffUL);
+ acc += ((addr >> 16) & 0xffffUL);
+ acc += (u32_t)htons((u16_t)proto);
+ acc += (u32_t)htons(proto_len);
+
+ /* Fold 32-bit sum to 16 bits
+ calling this twice is propably faster than if statements... */
+ acc = FOLD_U32T(acc);
+ acc = FOLD_U32T(acc);
+ LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+ return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum:
+ *
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP
+ * and ICMP.
+ *
+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
+ * @param len length of the buffer to calculate the checksum
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+
+u16_t
+inet_chksum(void *dataptr, u16_t len)
+{
+ return ~LWIP_CHKSUM(dataptr, len);
+}
+
+/**
+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
+ * inet_chksum only pbufs are used).
+ *
+ * @param p pbuf chain over that the checksum should be calculated
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pbuf(struct pbuf *p)
+{
+ u32_t acc;
+ struct pbuf *q;
+ u8_t swapped;
+
+ acc = 0;
+ swapped = 0;
+ for(q = p; q != NULL; q = q->next) {
+ acc += LWIP_CHKSUM(q->payload, q->len);
+ acc = FOLD_U32T(acc);
+ if (q->len % 2 != 0) {
+ swapped = 1 - swapped;
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ }
+
+ if (swapped) {
+ acc = SWAP_BYTES_IN_WORD(acc);
+ }
+ return (u16_t)~(acc & 0xffffUL);
+}
+
+/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
+ * like MEMCPY but generates a checksum at the same time. Since this is a
+ * performance-sensitive function, you might want to create your own version
+ * in assembly targeted at your hardware by defining it in lwipopts.h:
+ * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
+ */
+
+#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
+/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
+ * For architectures with big caches, data might still be in cache when
+ * generating the checksum after copying.
+ */
+u16_t
+lwip_chksum_copy(void *dst, const void *src, u16_t len)
+{
+ MEMCPY(dst, src, len);
+ return LWIP_CHKSUM(dst, len);
+}
+#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip.c
new file mode 100644
index 0000000000..56843273d1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip.c
@@ -0,0 +1,857 @@
+/**
+ * @file
+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
+ *
+ * @see ip_frag.c
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip_frag.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/igmp.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** Set this to 0 in the rare case of wanting to call an extra function to
+ * generate the IP checksum (in contrast to calculating it on-the-fly). */
+#ifndef LWIP_INLINE_IP_CHKSUM
+#define LWIP_INLINE_IP_CHKSUM 1
+#endif
+#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
+#define CHECKSUM_GEN_IP_INLINE 1
+#else
+#define CHECKSUM_GEN_IP_INLINE 0
+#endif
+
+#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
+
+/** Some defines for DHCP to let link-layer-addressed packets through while the
+ * netif is down.
+ * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
+ * to return 1 if the port is accepted and 0 if the port is not accepted.
+ */
+#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
+/* accept DHCP client port and custom port */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
+ || (LWIP_IP_ACCEPT_UDP_PORT(port)))
+#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept custom port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
+#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept DHCP client port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
+#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+
+#else /* LWIP_DHCP */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
+#endif /* LWIP_DHCP */
+
+/**
+ * The interface that provided the packet for the current callback
+ * invocation.
+ */
+struct netif *current_netif;
+
+/**
+ * Header of the input packet currently being processed.
+ */
+const struct ip_hdr *current_header;
+/** Source IP address of current_header */
+ip_addr_t current_iphdr_src;
+/** Destination IP address of current_header */
+ip_addr_t current_iphdr_dest;
+
+/** The IP header ID of the next outgoing IP packet */
+static u16_t ip_id;
+
+/**
+ * Finds the appropriate network interface for a given IP address. It
+ * searches the list of network interfaces linearly. A match is found
+ * if the masked IP address of the network interface equals the masked
+ * IP address given to the function.
+ *
+ * @param dest the destination IP address for which to find the route
+ * @return the netif on which to send to reach dest
+ */
+struct netif *
+ip_route(ip_addr_t *dest)
+{
+ struct netif *netif;
+
+ /* iterate through netifs */
+ for(netif = netif_list; netif != NULL; netif = netif->next) {
+ /* network mask matches? */
+ if (netif_is_up(netif)) {
+ if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
+ /* return netif on which to forward IP packet */
+ return netif;
+ }
+ }
+ }
+ if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: 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);
+ snmp_inc_ipoutnoroutes();
+ return NULL;
+ }
+ /* no matching netif found, use default netif */
+ return netif_default;
+}
+
+#if IP_FORWARD
+/**
+ * Forwards an IP packet. It finds an appropriate route for the
+ * packet, decrements the TTL value of the packet, adjusts the
+ * checksum and outputs the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ */
+static void
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
+{
+ struct netif *netif;
+
+ PERF_START;
+
+ /* RFC3927 2.7: do not forward link-local addresses */
+ if (ip_addr_islinklocal(&current_iphdr_dest)) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+ ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+ goto return_noroute;
+ }
+
+ /* Find network interface where to forward this IP packet to. */
+ netif = ip_route(&current_iphdr_dest);
+ if (netif == NULL) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
+ ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+ ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+ goto return_noroute;
+ }
+ /* Do not forward packets onto the same network interface on which
+ * they arrived. */
+ if (netif == inp) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
+ goto return_noroute;
+ }
+
+ /* decrement TTL */
+ IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
+ /* send ICMP if TTL == 0 */
+ if (IPH_TTL(iphdr) == 0) {
+ snmp_inc_ipinhdrerrors();
+#if LWIP_ICMP
+ /* Don't send ICMP messages in response to ICMP messages */
+ if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
+ icmp_time_exceeded(p, ICMP_TE_TTL);
+ }
+#endif /* LWIP_ICMP */
+ return;
+ }
+
+ /* Incrementally update the IP checksum. */
+ if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
+ IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
+ } else {
+ IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
+ }
+
+ LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+ ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+
+ IP_STATS_INC(ip.fw);
+ IP_STATS_INC(ip.xmit);
+ snmp_inc_ipforwdatagrams();
+
+ PERF_STOP("ip_forward");
+ /* transmit pbuf on chosen interface */
+ netif->output(netif, p, &current_iphdr_dest);
+ return;
+return_noroute:
+ snmp_inc_ipoutnoroutes();
+}
+#endif /* IP_FORWARD */
+
+/**
+ * This function is called by the network interface device driver when
+ * an IP packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip_forward). The IP checksum is always checked.
+ *
+ * Finally, the packet is sent to the upper layer protocol input function.
+ *
+ * @param p the received IP packet (p->payload points to IP header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ * processed, but currently always returns ERR_OK)
+ */
+err_t
+ip_input(struct pbuf *p, struct netif *inp)
+{
+ struct ip_hdr *iphdr;
+ struct netif *netif;
+ u16_t iphdr_hlen;
+ u16_t iphdr_len;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+ int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+ IP_STATS_INC(ip.recv);
+ snmp_inc_ipinreceives();
+
+ /* identify the IP header */
+ iphdr = (struct ip_hdr *)p->payload;
+ if (IPH_V(iphdr) != 4) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
+ ip_debug_print(p);
+ pbuf_free(p);
+ IP_STATS_INC(ip.err);
+ IP_STATS_INC(ip.drop);
+ snmp_inc_ipinhdrerrors();
+ return ERR_OK;
+ }
+
+ /* obtain IP header length in number of 32-bit words */
+ iphdr_hlen = IPH_HL(iphdr);
+ /* calculate IP header length in bytes */
+ iphdr_hlen *= 4;
+ /* obtain ip length in bytes */
+ iphdr_len = ntohs(IPH_LEN(iphdr));
+
+ /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+ if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
+ if (iphdr_hlen > p->len) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+ iphdr_hlen, p->len));
+ }
+ if (iphdr_len > p->tot_len) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+ iphdr_len, p->tot_len));
+ }
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP_STATS_INC(ip.lenerr);
+ IP_STATS_INC(ip.drop);
+ snmp_inc_ipindiscards();
+ return ERR_OK;
+ }
+
+ /* verify checksum */
+#if CHECKSUM_CHECK_IP
+ if (inet_chksum(iphdr, iphdr_hlen) != 0) {
+
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
+ ip_debug_print(p);
+ pbuf_free(p);
+ IP_STATS_INC(ip.chkerr);
+ IP_STATS_INC(ip.drop);
+ snmp_inc_ipinhdrerrors();
+ return ERR_OK;
+ }
+#endif
+
+ /* Trim pbuf. This should have been done at the netif layer,
+ * but we'll do it anyway just to be sure that its done. */
+ pbuf_realloc(p, iphdr_len);
+
+ /* copy IP addresses to aligned ip_addr_t */
+ ip_addr_copy(current_iphdr_dest, iphdr->dest);
+ ip_addr_copy(current_iphdr_src, iphdr->src);
+
+ /* match packet against an interface, i.e. is this packet for us? */
+#if LWIP_IGMP
+ if (ip_addr_ismulticast(&current_iphdr_dest)) {
+ if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
+ netif = inp;
+ } else {
+ netif = NULL;
+ }
+ } else
+#endif /* LWIP_IGMP */
+ {
+ /* start trying with inp. if that's not acceptable, start walking the
+ list of configured netifs.
+ 'first' is used as a boolean to mark whether we started walking the list */
+ int first = 1;
+ netif = inp;
+ do {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
+ ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
+ ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
+ ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
+ ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
+
+ /* interface is up and configured? */
+ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
+ /* unicast to this interface address? */
+ if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
+ /* or broadcast on this interface network address? */
+ ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
+ netif->name[0], netif->name[1]));
+ /* break out of for loop */
+ break;
+ }
+#if LWIP_AUTOIP
+ /* connections to link-local addresses must persist after changing
+ the netif's address (RFC3927 ch. 1.9) */
+ if ((netif->autoip != NULL) &&
+ ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
+ netif->name[0], netif->name[1]));
+ /* break out of for loop */
+ break;
+ }
+#endif /* LWIP_AUTOIP */
+ }
+ if (first) {
+ first = 0;
+ netif = netif_list;
+ } else {
+ netif = netif->next;
+ }
+ if (netif == inp) {
+ netif = netif->next;
+ }
+ } while(netif != NULL);
+ }
+
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+ /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
+ * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
+ * According to RFC 1542 section 3.1.1, referred by RFC 2131).
+ *
+ * If you want to accept private broadcast communication while a netif is down,
+ * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
+ *
+ * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
+ */
+ if (netif == NULL) {
+ /* remote port is DHCP server? */
+ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+ struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
+ ntohs(udphdr->dest)));
+ if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
+ netif = inp;
+ check_ip_src = 0;
+ }
+ }
+ }
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+ /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+ /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
+ if (check_ip_src && current_iphdr_src.addr != IPADDR_ANY)
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+ { if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
+ (ip_addr_ismulticast(&current_iphdr_src))) {
+ /* packet source is not valid */
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP_STATS_INC(ip.drop);
+ snmp_inc_ipinaddrerrors();
+ snmp_inc_ipindiscards();
+ return ERR_OK;
+ }
+ }
+
+ /* packet not for us? */
+ if (netif == NULL) {
+ /* packet not for us, route or discard */
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
+#if IP_FORWARD
+ /* non-broadcast packet? */
+ if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+ /* try to forward IP packet on (other) interfaces */
+ ip_forward(p, iphdr, inp);
+ } else
+#endif /* IP_FORWARD */
+ {
+ snmp_inc_ipinaddrerrors();
+ snmp_inc_ipindiscards();
+ }
+ pbuf_free(p);
+ return ERR_OK;
+ }
+ /* packet consists of multiple fragments? */
+ if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */
+ LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
+ ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
+ /* reassemble the packet*/
+ p = ip_reass(p);
+ /* packet not fully reassembled yet? */
+ if (p == NULL) {
+ return ERR_OK;
+ }
+ iphdr = (struct ip_hdr *)p->payload;
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
+ pbuf_free(p);
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
+ ntohs(IPH_OFFSET(iphdr))));
+ IP_STATS_INC(ip.opterr);
+ IP_STATS_INC(ip.drop);
+ /* unsupported protocol feature */
+ snmp_inc_ipinunknownprotos();
+ return ERR_OK;
+#endif /* IP_REASSEMBLY */
+ }
+
+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
+
+#if LWIP_IGMP
+ /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
+ if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
+#else
+ if (iphdr_hlen > IP_HLEN) {
+#endif /* LWIP_IGMP */
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
+ pbuf_free(p);
+ IP_STATS_INC(ip.opterr);
+ IP_STATS_INC(ip.drop);
+ /* unsupported protocol feature */
+ snmp_inc_ipinunknownprotos();
+ return ERR_OK;
+ }
+#endif /* IP_OPTIONS_ALLOWED == 0 */
+
+ /* send to upper layers */
+ LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
+ ip_debug_print(p);
+ LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+ current_netif = inp;
+ current_header = iphdr;
+
+#if LWIP_RAW
+ /* raw input did not eat the packet? */
+ if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+ {
+
+ switch (IPH_PROTO(iphdr)) {
+#if LWIP_UDP
+ case IP_PROTO_UDP:
+#if LWIP_UDPLITE
+ case IP_PROTO_UDPLITE:
+#endif /* LWIP_UDPLITE */
+ snmp_inc_ipindelivers();
+ udp_input(p, inp);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case IP_PROTO_TCP:
+ snmp_inc_ipindelivers();
+ tcp_input(p, inp);
+ break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP
+ case IP_PROTO_ICMP:
+ snmp_inc_ipindelivers();
+ icmp_input(p, inp);
+ break;
+#endif /* LWIP_ICMP */
+#if LWIP_IGMP
+ case IP_PROTO_IGMP:
+ igmp_input(p, inp, &current_iphdr_dest);
+ break;
+#endif /* LWIP_IGMP */
+ default:
+#if LWIP_ICMP
+ /* send ICMP destination protocol unreachable unless is was a broadcast */
+ if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
+ !ip_addr_ismulticast(&current_iphdr_dest)) {
+ p->payload = iphdr;
+ icmp_dest_unreach(p, ICMP_DUR_PROTO);
+ }
+#endif /* LWIP_ICMP */
+ pbuf_free(p);
+
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
+
+ IP_STATS_INC(ip.proterr);
+ IP_STATS_INC(ip.drop);
+ snmp_inc_ipinunknownprotos();
+ }
+ }
+
+ current_netif = NULL;
+ current_header = NULL;
+ ip_addr_set_any(&current_iphdr_src);
+ ip_addr_set_any(&current_iphdr_dest);
+
+ return ERR_OK;
+}
+
+/**
+ * Sends an IP packet on a network interface. This function constructs
+ * the IP header and calculates the IP header checksum. If the source
+ * IP address is NULL, the IP address of the outgoing network
+ * interface is filled in as source address.
+ * If the destination IP address is IP_HDRINCL, p is assumed to already
+ * include an IP header and p->payload points to it instead of the data.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an IP
+ header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ * IP address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ * ERR_BUF if p doesn't have enough space for IP/LINK headers
+ * returns errors returned by netif->output
+ *
+ * @note ip_id: RFC791 "some host may be able to simply use
+ * unique identifiers independent of destination"
+ */
+err_t
+ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos,
+ u8_t proto, struct netif *netif)
+{
+#if IP_OPTIONS_SEND
+ return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
+}
+
+/**
+ * Same as ip_output_if() but with the possibility to include IP options:
+ *
+ * @ param ip_options pointer to the IP options, copied into the IP header
+ * @ param optlen length of ip_options
+ */
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+ u16_t optlen)
+{
+#endif /* IP_OPTIONS_SEND */
+ struct ip_hdr *iphdr;
+ ip_addr_t dest_addr;
+#if CHECKSUM_GEN_IP_INLINE
+ u32_t chk_sum = 0;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ snmp_inc_ipoutrequests();
+
+ /* Should the IP header be generated or is it already included in p? */
+ if (dest != IP_HDRINCL) {
+ u16_t ip_hlen = IP_HLEN;
+#if IP_OPTIONS_SEND
+ u16_t optlen_aligned = 0;
+ if (optlen != 0) {
+#if CHECKSUM_GEN_IP_INLINE
+ int i;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ /* round up to a multiple of 4 */
+ optlen_aligned = ((optlen + 3) & ~3);
+ ip_hlen += optlen_aligned;
+ /* First write in the IP options */
+ if (pbuf_header(p, optlen_aligned)) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
+ IP_STATS_INC(ip.err);
+ snmp_inc_ipoutdiscards();
+ return ERR_BUF;
+ }
+ MEMCPY(p->payload, ip_options, optlen);
+ if (optlen < optlen_aligned) {
+ /* zero the remaining bytes */
+ memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
+ }
+#if CHECKSUM_GEN_IP_INLINE
+ for (i = 0; i < optlen_aligned/2; i++) {
+ chk_sum += ((u16_t*)p->payload)[i];
+ }
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ }
+#endif /* IP_OPTIONS_SEND */
+ /* generate IP header */
+ if (pbuf_header(p, IP_HLEN)) {
+ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
+
+ IP_STATS_INC(ip.err);
+ snmp_inc_ipoutdiscards();
+ return ERR_BUF;
+ }
+
+ iphdr = (struct ip_hdr *)p->payload;
+ LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
+ (p->len >= sizeof(struct ip_hdr)));
+
+ IPH_TTL_SET(iphdr, ttl);
+ IPH_PROTO_SET(iphdr, proto);
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += LWIP_MAKE_U16(proto, ttl);
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+ /* dest cannot be NULL here */
+ ip_addr_copy(iphdr->dest, *dest);
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
+ chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+ IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += iphdr->_v_hl_tos;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ IPH_LEN_SET(iphdr, htons(p->tot_len));
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += iphdr->_len;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ IPH_OFFSET_SET(iphdr, 0);
+ IPH_ID_SET(iphdr, htons(ip_id));
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += iphdr->_id;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ ++ip_id;
+
+ if (ip_addr_isany(src)) {
+ ip_addr_copy(iphdr->src, netif->ip_addr);
+ } else {
+ /* src cannot be NULL here */
+ ip_addr_copy(iphdr->src, *src);
+ }
+
+#if CHECKSUM_GEN_IP_INLINE
+ chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
+ chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
+ chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
+ chk_sum = (chk_sum >> 16) + chk_sum;
+ chk_sum = ~chk_sum;
+ iphdr->_chksum = chk_sum; /* network order */
+#else /* CHECKSUM_GEN_IP_INLINE */
+ IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
+#endif
+#endif /* CHECKSUM_GEN_IP_INLINE */
+ } else {
+ /* IP header already included in p */
+ iphdr = (struct ip_hdr *)p->payload;
+ ip_addr_copy(dest_addr, iphdr->dest);
+ dest = &dest_addr;
+ }
+
+ IP_STATS_INC(ip.xmit);
+
+ LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+ ip_debug_print(p);
+
+#if ENABLE_LOOPBACK
+ if (ip_addr_cmp(dest, &netif->ip_addr)) {
+ /* Packet to self, enqueue it for loopback */
+ LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
+ return netif_loop_output(netif, p, dest);
+ }
+#if LWIP_IGMP
+ if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
+ netif_loop_output(netif, p, dest);
+ }
+#endif /* LWIP_IGMP */
+#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 ip_frag(p, netif, dest);
+ }
+#endif /* IP_FRAG */
+
+ LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+ return netif->output(netif, p, dest);
+}
+
+/**
+ * Simple interface to ip_output_if. It finds the outgoing network
+ * interface and calls upon ip_output_if to do the actual work.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an IP
+ header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ * IP address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ *
+ * @return ERR_RTE if no route is found
+ * see ip_output_if() for more return values
+ */
+err_t
+ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto)
+{
+ struct netif *netif;
+
+ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ if ((netif = ip_route(dest)) == NULL) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_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);
+ return ERR_RTE;
+ }
+
+ return ip_output_if(p, src, dest, ttl, tos, proto, netif);
+}
+
+#if LWIP_NETIF_HWADDRHINT
+/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ * before calling ip_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an IP
+ header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ * IP address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ * calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ * see ip_output_if() for more return values
+ */
+err_t
+ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+{
+ struct netif *netif;
+ err_t err;
+
+ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ if ((netif = ip_route(dest)) == NULL) {
+ LWIP_DEBUGF(IP_DEBUG, ("ip_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);
+ return ERR_RTE;
+ }
+
+ netif->addr_hint = addr_hint;
+ err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
+ netif->addr_hint = NULL;
+
+ return err;
+}
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+#if IP_DEBUG
+/* Print an IP header by using LWIP_DEBUGF
+ * @param p an IP packet, p->payload pointing to the IP header
+ */
+void
+ip_debug_print(struct pbuf *p)
+{
+ struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+ u8_t *payload;
+
+ payload = (u8_t *)iphdr + IP_HLEN;
+
+ LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
+ IPH_V(iphdr),
+ IPH_HL(iphdr),
+ IPH_TOS(iphdr),
+ ntohs(IPH_LEN(iphdr))));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
+ ntohs(IPH_ID(iphdr)),
+ ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
+ ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
+ ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
+ ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
+ IPH_TTL(iphdr),
+ IPH_PROTO(iphdr),
+ ntohs(IPH_CHKSUM(iphdr))));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
+ ip4_addr1_16(&iphdr->src),
+ ip4_addr2_16(&iphdr->src),
+ ip4_addr3_16(&iphdr->src),
+ ip4_addr4_16(&iphdr->src)));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
+ ip4_addr1_16(&iphdr->dest),
+ ip4_addr2_16(&iphdr->dest),
+ ip4_addr3_16(&iphdr->dest),
+ ip4_addr4_16(&iphdr->dest)));
+ LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+}
+#endif /* IP_DEBUG */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_addr.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_addr.c
new file mode 100644
index 0000000000..8f633ff231
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_addr.c
@@ -0,0 +1,312 @@
+/**
+ * @file
+ * This is the IPv4 address tools implementation.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
+const ip_addr_t ip_addr_any = { IPADDR_ANY };
+const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
+
+/**
+ * Determine if an address is a broadcast address on a network interface
+ *
+ * @param addr address to be checked
+ * @param netif the network interface against which the address is checked
+ * @return returns non-zero if the address is a broadcast address
+ */
+u8_t
+ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
+{
+ ip_addr_t ipaddr;
+ ip4_addr_set_u32(&ipaddr, addr);
+
+ /* all ones (broadcast) or all zeroes (old skool broadcast) */
+ if ((~addr == IPADDR_ANY) ||
+ (addr == IPADDR_ANY)) {
+ return 1;
+ /* no broadcast support on this network interface? */
+ } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
+ /* the given address cannot be a broadcast address
+ * nor can we check against any broadcast addresses */
+ return 0;
+ /* address matches network interface address exactly? => no broadcast */
+ } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
+ return 0;
+ /* on the same (sub) network... */
+ } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
+ /* ...and host identifier bits are all ones? =>... */
+ && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
+ (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
+ /* => network broadcast address */
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/** Checks if a netmask is valid (starting with ones, then only zeros)
+ *
+ * @param netmask the IPv4 netmask to check (in network byte order!)
+ * @return 1 if the netmask is valid, 0 if it is not
+ */
+u8_t
+ip4_addr_netmask_valid(u32_t netmask)
+{
+ u32_t mask;
+ u32_t nm_hostorder = lwip_htonl(netmask);
+
+ /* first, check for the first zero */
+ for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
+ if ((nm_hostorder & mask) == 0) {
+ break;
+ }
+ }
+ /* then check that there is no one */
+ for (; mask != 0; mask >>= 1) {
+ if ((nm_hostorder & mask) != 0) {
+ /* there is a one after the first zero -> invalid */
+ return 0;
+ }
+ }
+ /* no one after the first zero -> valid */
+ return 1;
+}
+
+/* Here for now until needed in other places in lwIP */
+#ifndef isprint
+#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c) in_range(c, 0x20, 0x7f)
+#define isdigit(c) in_range(c, '0', '9')
+#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c) in_range(c, 'a', 'z')
+#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+/**
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @return ip address in network order
+ */
+u32_t
+ipaddr_addr(const char *cp)
+{
+ ip_addr_t val;
+
+ if (ipaddr_aton(cp, &val)) {
+ return ip4_addr_get_u32(&val);
+ }
+ return (IPADDR_NONE);
+}
+
+/**
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @param addr pointer to which to save the ip address in network order
+ * @return 1 if cp could be converted to addr, 0 on failure
+ */
+int
+ipaddr_aton(const char *cp, ip_addr_t *addr)
+{
+ u32_t val;
+ u8_t base;
+ char c;
+ u32_t parts[4];
+ u32_t *pp = parts;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, 1-9=decimal.
+ */
+ if (!isdigit(c))
+ return (0);
+ val = 0;
+ base = 10;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X') {
+ base = 16;
+ c = *++cp;
+ } else
+ base = 8;
+ }
+ for (;;) {
+ if (isdigit(c)) {
+ val = (val * base) + (int)(c - '0');
+ c = *++cp;
+ } else if (base == 16 && isxdigit(c)) {
+ val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
+ c = *++cp;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3) {
+ return (0);
+ }
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && !isspace(c)) {
+ return (0);
+ }
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ switch (pp - parts + 1) {
+
+ case 0:
+ return (0); /* initial nondigit */
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffffUL) {
+ return (0);
+ }
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff) {
+ return (0);
+ }
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff) {
+ return (0);
+ }
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ default:
+ LWIP_ASSERT("unhandled", 0);
+ break;
+ }
+ if (addr) {
+ ip4_addr_set_u32(addr, htonl(val));
+ }
+ return (1);
+}
+
+/**
+ * Convert numeric IP address into decimal dotted ASCII representation.
+ * returns ptr to static buffer; not reentrant!
+ *
+ * @param addr ip address in network order to convert
+ * @return pointer to a global static (!) buffer that holds the ASCII
+ * represenation of addr
+ */
+char *
+ipaddr_ntoa(const ip_addr_t *addr)
+{
+ static char str[16];
+ return ipaddr_ntoa_r(addr, str, 16);
+}
+
+/**
+ * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
+ *
+ * @param addr ip address in network order to convert
+ * @param buf target buffer where the string is stored
+ * @param buflen length of buf
+ * @return either pointer to buf which now holds the ASCII
+ * representation of addr or NULL if buf was too small
+ */
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
+{
+ u32_t s_addr;
+ char inv[3];
+ char *rp;
+ u8_t *ap;
+ u8_t rem;
+ u8_t n;
+ u8_t i;
+ int len = 0;
+
+ s_addr = ip4_addr_get_u32(addr);
+
+ rp = buf;
+ ap = (u8_t *)&s_addr;
+ for(n = 0; n < 4; n++) {
+ i = 0;
+ do {
+ rem = *ap % (u8_t)10;
+ *ap /= (u8_t)10;
+ inv[i++] = '0' + rem;
+ } while(*ap);
+ while(i--) {
+ if (len++ >= buflen) {
+ return NULL;
+ }
+ *rp++ = inv[i];
+ }
+ if (len++ >= buflen) {
+ return NULL;
+ }
+ *rp++ = '.';
+ ap++;
+ }
+ *--rp = 0;
+ return buf;
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_frag.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_frag.c
new file mode 100644
index 0000000000..8d184345df
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/ipv4/ip_frag.c
@@ -0,0 +1,863 @@
+/**
+ * @file
+ * This is the IPv4 packet segmentation and reassembly implementation.
+ *
+ */
+
+/*
+ * 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: Jani Monoses <jani@iv.ro>
+ * Simon Goldschmidt
+ * original reassembly code by Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_frag.h"
+#include "lwip/def.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/snmp.h"
+#include "lwip/stats.h"
+#include "lwip/icmp.h"
+
+#include <string.h>
+
+#if IP_REASSEMBLY
+/**
+ * The IP reassembly code currently has the following limitations:
+ * - IP header options are not supported
+ * - fragments must not overlap (e.g. due to different routes),
+ * currently, overlapping or duplicate fragments are thrown away
+ * if IP_REASS_CHECK_OVERLAP=1 (the default)!
+ *
+ * @todo: work with IP header options
+ */
+
+/** Setting this to 0, you can turn off checking the fragments for overlapping
+ * regions. The code gets a little smaller. Only use this if you know that
+ * overlapping won't occur on your network! */
+#ifndef IP_REASS_CHECK_OVERLAP
+#define IP_REASS_CHECK_OVERLAP 1
+#endif /* IP_REASS_CHECK_OVERLAP */
+
+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
+ * is set to 1, so one datagram can be reassembled at a time, only. */
+#ifndef IP_REASS_FREE_OLDEST
+#define IP_REASS_FREE_OLDEST 1
+#endif /* IP_REASS_FREE_OLDEST */
+
+#define IP_REASS_FLAG_LASTFRAG 0x01
+
+/** This is a helper struct which holds the starting
+ * offset and the ending offset of this fragment to
+ * easily chain the fragments.
+ * It has the same packing requirements as the IP header, since it replaces
+ * the IP header in memory in incoming fragments (after copying it) to keep
+ * track of the various fragments. (-> If the IP header doesn't need packing,
+ * this struct doesn't need packing, too.)
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_reass_helper {
+ PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
+ PACK_STRUCT_FIELD(u16_t start);
+ PACK_STRUCT_FIELD(u16_t end);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
+ (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
+ ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
+ IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
+
+/* global variables */
+static struct ip_reassdata *reassdatagrams;
+static u16_t ip_reass_pbufcount;
+
+/* function prototypes */
+static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+
+/**
+ * Reassembly timer base function
+ * for both NO_SYS == 0 and 1 (!).
+ *
+ * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
+ */
+void
+ip_reass_tmr(void)
+{
+ struct ip_reassdata *r, *prev = NULL;
+
+ r = reassdatagrams;
+ while (r != NULL) {
+ /* Decrement the timer. Once it reaches 0,
+ * clean up the incomplete fragment assembly */
+ if (r->timer > 0) {
+ r->timer--;
+ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
+ prev = r;
+ r = r->next;
+ } else {
+ /* reassembly timed out */
+ struct ip_reassdata *tmp;
+ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
+ tmp = r;
+ /* get the next pointer before freeing */
+ r = r->next;
+ /* free the helper struct and all enqueued pbufs */
+ ip_reass_free_complete_datagram(tmp, prev);
+ }
+ }
+}
+
+/**
+ * Free a datagram (struct ip_reassdata) and all its pbufs.
+ * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
+ * SNMP counters and sends an ICMP time exceeded packet.
+ *
+ * @param ipr datagram to free
+ * @param prev the previous datagram in the linked list
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+ u16_t pbufs_freed = 0;
+ u8_t clen;
+ struct pbuf *p;
+ struct ip_reass_helper *iprh;
+
+ LWIP_ASSERT("prev != ipr", prev != ipr);
+ if (prev != NULL) {
+ LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
+ }
+
+ snmp_inc_ipreasmfails();
+#if LWIP_ICMP
+ iprh = (struct ip_reass_helper *)ipr->p->payload;
+ if (iprh->start == 0) {
+ /* The first fragment was received, send ICMP time exceeded. */
+ /* First, de-queue the first pbuf from r->p. */
+ p = ipr->p;
+ ipr->p = iprh->next_pbuf;
+ /* Then, copy the original header into it. */
+ SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
+ icmp_time_exceeded(p, ICMP_TE_FRAG);
+ clen = pbuf_clen(p);
+ LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+ pbufs_freed += clen;
+ pbuf_free(p);
+ }
+#endif /* LWIP_ICMP */
+
+ /* First, free all received pbufs. The individual pbufs need to be released
+ separately as they have not yet been chained */
+ p = ipr->p;
+ while (p != NULL) {
+ struct pbuf *pcur;
+ iprh = (struct ip_reass_helper *)p->payload;
+ pcur = p;
+ /* get the next pointer before freeing */
+ p = iprh->next_pbuf;
+ clen = pbuf_clen(pcur);
+ LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+ pbufs_freed += clen;
+ pbuf_free(pcur);
+ }
+ /* Then, unchain the struct ip_reassdata from the list and free it. */
+ ip_reass_dequeue_datagram(ipr, prev);
+ LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
+ ip_reass_pbufcount -= pbufs_freed;
+
+ return pbufs_freed;
+}
+
+#if IP_REASS_FREE_OLDEST
+/**
+ * Free the oldest datagram to make room for enqueueing new fragments.
+ * The datagram 'fraghdr' belongs to is not freed!
+ *
+ * @param fraghdr IP header of the current fragment
+ * @param pbufs_needed number of pbufs needed to enqueue
+ * (used for freeing other datagrams if not enough space)
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
+{
+ /* @todo Can't we simply remove the last datagram in the
+ * linked list behind reassdatagrams?
+ */
+ struct ip_reassdata *r, *oldest, *prev;
+ int pbufs_freed = 0, pbufs_freed_current;
+ int other_datagrams;
+
+ /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
+ * but don't free the datagram that 'fraghdr' belongs to! */
+ do {
+ oldest = NULL;
+ prev = NULL;
+ other_datagrams = 0;
+ r = reassdatagrams;
+ while (r != NULL) {
+ if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
+ /* Not the same datagram as fraghdr */
+ other_datagrams++;
+ if (oldest == NULL) {
+ oldest = r;
+ } else if (r->timer <= oldest->timer) {
+ /* older than the previous oldest */
+ oldest = r;
+ }
+ }
+ if (r->next != NULL) {
+ prev = r;
+ }
+ r = r->next;
+ }
+ if (oldest != NULL) {
+ pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
+ pbufs_freed += pbufs_freed_current;
+ }
+ } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
+ return pbufs_freed;
+}
+#endif /* IP_REASS_FREE_OLDEST */
+
+/**
+ * Enqueues a new fragment into the fragment queue
+ * @param fraghdr points to the new fragments IP hdr
+ * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
+ * @return A pointer to the queue location into which the fragment was enqueued
+ */
+static struct ip_reassdata*
+ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
+{
+ struct ip_reassdata* ipr;
+ /* No matching previous fragment found, allocate a new reassdata struct */
+ ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+ if (ipr == NULL) {
+#if IP_REASS_FREE_OLDEST
+ if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
+ ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+ }
+ if (ipr == NULL)
+#endif /* IP_REASS_FREE_OLDEST */
+ {
+ IPFRAG_STATS_INC(ip_frag.memerr);
+ LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
+ return NULL;
+ }
+ }
+ memset(ipr, 0, sizeof(struct ip_reassdata));
+ ipr->timer = IP_REASS_MAXAGE;
+
+ /* enqueue the new structure to the front of the list */
+ ipr->next = reassdatagrams;
+ reassdatagrams = ipr;
+ /* copy the ip header for later tests and input */
+ /* @todo: no ip options supported? */
+ SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
+ return ipr;
+}
+
+/**
+ * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
+ * @param ipr points to the queue entry to dequeue
+ */
+static void
+ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+
+ /* dequeue the reass struct */
+ if (reassdatagrams == ipr) {
+ /* it was the first in the list */
+ reassdatagrams = ipr->next;
+ } else {
+ /* it wasn't the first, so it must have a valid 'prev' */
+ LWIP_ASSERT("sanity check linked list", prev != NULL);
+ prev->next = ipr->next;
+ }
+
+ /* now we can free the ip_reass struct */
+ memp_free(MEMP_REASSDATA, ipr);
+}
+
+/**
+ * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
+ * will grow over time as new pbufs are rx.
+ * Also checks that the datagram passes basic continuity checks (if the last
+ * fragment was received at least once).
+ * @param root_p points to the 'root' pbuf for the current datagram being assembled.
+ * @param new_p points to the pbuf for the current fragment
+ * @return 0 if invalid, >0 otherwise
+ */
+static int
+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
+{
+ struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
+ struct pbuf *q;
+ u16_t offset,len;
+ struct ip_hdr *fraghdr;
+ int valid = 1;
+
+ /* Extract length and fragment offset from current fragment */
+ fraghdr = (struct ip_hdr*)new_p->payload;
+ len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+ offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+
+ /* overwrite the fragment's ip header from the pbuf with our helper struct,
+ * and setup the embedded helper structure. */
+ /* make sure the struct ip_reass_helper fits into the IP header */
+ LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
+ sizeof(struct ip_reass_helper) <= IP_HLEN);
+ iprh = (struct ip_reass_helper*)new_p->payload;
+ iprh->next_pbuf = NULL;
+ iprh->start = offset;
+ iprh->end = offset + len;
+
+ /* Iterate through until we either get to the end of the list (append),
+ * or we find on with a larger offset (insert). */
+ for (q = ipr->p; q != NULL;) {
+ iprh_tmp = (struct ip_reass_helper*)q->payload;
+ if (iprh->start < iprh_tmp->start) {
+ /* the new pbuf should be inserted before this */
+ iprh->next_pbuf = q;
+ if (iprh_prev != NULL) {
+ /* not the fragment with the lowest offset */
+#if IP_REASS_CHECK_OVERLAP
+ if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
+ /* fragment overlaps with previous or following, throw away */
+ goto freepbuf;
+ }
+#endif /* IP_REASS_CHECK_OVERLAP */
+ iprh_prev->next_pbuf = new_p;
+ } else {
+ /* fragment with the lowest offset */
+ ipr->p = new_p;
+ }
+ break;
+ } else if(iprh->start == iprh_tmp->start) {
+ /* received the same datagram twice: no need to keep the datagram */
+ goto freepbuf;
+#if IP_REASS_CHECK_OVERLAP
+ } else if(iprh->start < iprh_tmp->end) {
+ /* overlap: no need to keep the new datagram */
+ goto freepbuf;
+#endif /* IP_REASS_CHECK_OVERLAP */
+ } else {
+ /* Check if the fragments received so far have no wholes. */
+ if (iprh_prev != NULL) {
+ if (iprh_prev->end != iprh_tmp->start) {
+ /* There is a fragment missing between the current
+ * and the previous fragment */
+ valid = 0;
+ }
+ }
+ }
+ q = iprh_tmp->next_pbuf;
+ iprh_prev = iprh_tmp;
+ }
+
+ /* If q is NULL, then we made it to the end of the list. Determine what to do now */
+ if (q == NULL) {
+ if (iprh_prev != NULL) {
+ /* this is (for now), the fragment with the highest offset:
+ * chain it to the last fragment */
+#if IP_REASS_CHECK_OVERLAP
+ LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
+#endif /* IP_REASS_CHECK_OVERLAP */
+ iprh_prev->next_pbuf = new_p;
+ if (iprh_prev->end != iprh->start) {
+ valid = 0;
+ }
+ } else {
+#if IP_REASS_CHECK_OVERLAP
+ LWIP_ASSERT("no previous fragment, this must be the first fragment!",
+ ipr->p == NULL);
+#endif /* IP_REASS_CHECK_OVERLAP */
+ /* this is the first fragment we ever received for this ip datagram */
+ ipr->p = new_p;
+ }
+ }
+
+ /* At this point, the validation part begins: */
+ /* If we already received the last fragment */
+ if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
+ /* and had no wholes so far */
+ if (valid) {
+ /* then check if the rest of the fragments is here */
+ /* Check if the queue starts with the first datagram */
+ if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
+ valid = 0;
+ } else {
+ /* and check that there are no wholes after this datagram */
+ iprh_prev = iprh;
+ q = iprh->next_pbuf;
+ while (q != NULL) {
+ iprh = (struct ip_reass_helper*)q->payload;
+ if (iprh_prev->end != iprh->start) {
+ valid = 0;
+ break;
+ }
+ iprh_prev = iprh;
+ q = iprh->next_pbuf;
+ }
+ /* if still valid, all fragments are received
+ * (because to the MF==0 already arrived */
+ if (valid) {
+ LWIP_ASSERT("sanity check", ipr->p != NULL);
+ LWIP_ASSERT("sanity check",
+ ((struct ip_reass_helper*)ipr->p->payload) != iprh);
+ LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
+ iprh->next_pbuf == NULL);
+ LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
+ iprh->end == ipr->datagram_len);
+ }
+ }
+ }
+ /* If valid is 0 here, there are some fragments missing in the middle
+ * (since MF == 0 has already arrived). Such datagrams simply time out if
+ * no more fragments are received... */
+ return valid;
+ }
+ /* If we come here, not all fragments were received, yet! */
+ return 0; /* not yet valid! */
+#if IP_REASS_CHECK_OVERLAP
+freepbuf:
+ ip_reass_pbufcount -= pbuf_clen(new_p);
+ pbuf_free(new_p);
+ return 0;
+#endif /* IP_REASS_CHECK_OVERLAP */
+}
+
+/**
+ * Reassembles incoming IP fragments into an IP datagram.
+ *
+ * @param p points to a pbuf chain of the fragment
+ * @return NULL if reassembly is incomplete, ? otherwise
+ */
+struct pbuf *
+ip_reass(struct pbuf *p)
+{
+ struct pbuf *r;
+ struct ip_hdr *fraghdr;
+ struct ip_reassdata *ipr;
+ struct ip_reass_helper *iprh;
+ u16_t offset, len;
+ u8_t clen;
+ struct ip_reassdata *ipr_prev = NULL;
+
+ IPFRAG_STATS_INC(ip_frag.recv);
+ snmp_inc_ipreasmreqds();
+
+ fraghdr = (struct ip_hdr*)p->payload;
+
+ if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
+ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
+ IPFRAG_STATS_INC(ip_frag.err);
+ goto nullreturn;
+ }
+
+ offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+ len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+
+ /* Check if we are allowed to enqueue more datagrams. */
+ clen = pbuf_clen(p);
+ if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
+#if IP_REASS_FREE_OLDEST
+ if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
+ ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
+#endif /* IP_REASS_FREE_OLDEST */
+ {
+ /* No datagram could be freed and still too many pbufs enqueued */
+ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
+ ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
+ IPFRAG_STATS_INC(ip_frag.memerr);
+ /* @todo: send ICMP time exceeded here? */
+ /* drop this pbuf */
+ goto nullreturn;
+ }
+ }
+
+ /* Look for the datagram the fragment belongs to in the current datagram queue,
+ * remembering the previous in the queue for later dequeueing. */
+ for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
+ /* Check if the incoming fragment matches the one currently present
+ in the reassembly buffer. If so, we proceed with copying the
+ fragment into the buffer. */
+ if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
+ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
+ ntohs(IPH_ID(fraghdr))));
+ IPFRAG_STATS_INC(ip_frag.cachehit);
+ break;
+ }
+ ipr_prev = ipr;
+ }
+
+ if (ipr == NULL) {
+ /* Enqueue a new datagram into the datagram queue */
+ ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
+ /* Bail if unable to enqueue */
+ if(ipr == NULL) {
+ goto nullreturn;
+ }
+ } else {
+ if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
+ ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
+ /* ipr->iphdr is not the header from the first fragment, but fraghdr is
+ * -> copy fraghdr into ipr->iphdr since we want to have the header
+ * of the first fragment (for ICMP time exceeded and later, for copying
+ * all options, if supported)*/
+ SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
+ }
+ }
+ /* Track the current number of pbufs current 'in-flight', in order to limit
+ the number of fragments that may be enqueued at any one time */
+ ip_reass_pbufcount += clen;
+
+ /* At this point, we have either created a new entry or pointing
+ * to an existing one */
+
+ /* check for 'no more fragments', and update queue entry*/
+ if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
+ ipr->flags |= IP_REASS_FLAG_LASTFRAG;
+ ipr->datagram_len = offset + len;
+ LWIP_DEBUGF(IP_REASS_DEBUG,
+ ("ip_reass: last fragment seen, total len %"S16_F"\n",
+ ipr->datagram_len));
+ }
+ /* find the right place to insert this pbuf */
+ /* @todo: trim pbufs if fragments are overlapping */
+ if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
+ /* the totally last fragment (flag more fragments = 0) was received at least
+ * once AND all fragments are received */
+ ipr->datagram_len += IP_HLEN;
+
+ /* save the second pbuf before copying the header over the pointer */
+ r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
+
+ /* copy the original ip header back to the first pbuf */
+ fraghdr = (struct ip_hdr*)(ipr->p->payload);
+ SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
+ IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
+ IPH_OFFSET_SET(fraghdr, 0);
+ IPH_CHKSUM_SET(fraghdr, 0);
+ /* @todo: do we need to set calculate the correct checksum? */
+ IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
+
+ p = ipr->p;
+
+ /* chain together the pbufs contained within the reass_data list. */
+ while(r != NULL) {
+ iprh = (struct ip_reass_helper*)r->payload;
+
+ /* hide the ip header for every succeding fragment */
+ pbuf_header(r, -IP_HLEN);
+ pbuf_cat(p, r);
+ r = iprh->next_pbuf;
+ }
+ /* release the sources allocate for the fragment queue entry */
+ ip_reass_dequeue_datagram(ipr, ipr_prev);
+
+ /* and adjust the number of pbufs currently queued for reassembly. */
+ ip_reass_pbufcount -= pbuf_clen(p);
+
+ /* Return the pbuf chain */
+ return p;
+ }
+ /* the datagram is not (yet?) reassembled completely */
+ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
+ return NULL;
+
+nullreturn:
+ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
+ IPFRAG_STATS_INC(ip_frag.drop);
+ pbuf_free(p);
+ return NULL;
+}
+#endif /* IP_REASSEMBLY */
+
+#if IP_FRAG
+#if IP_FRAG_USES_STATIC_BUF
+static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
+#else /* IP_FRAG_USES_STATIC_BUF */
+
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+/** Allocate a new struct pbuf_custom_ref */
+static struct pbuf_custom_ref*
+ip_frag_alloc_pbuf_custom_ref(void)
+{
+ return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
+}
+
+/** Free a struct pbuf_custom_ref */
+static void
+ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
+{
+ LWIP_ASSERT("p != NULL", p != NULL);
+ memp_free(MEMP_FRAG_PBUF, p);
+}
+
+/** Free-callback function to free a 'struct pbuf_custom_ref', called by
+ * pbuf_free. */
+static void
+ipfrag_free_pbuf_custom(struct pbuf *p)
+{
+ struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
+ LWIP_ASSERT("pcr != NULL", pcr != NULL);
+ LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
+ if (pcr->original != NULL) {
+ pbuf_free(pcr->original);
+ }
+ ip_frag_free_pbuf_custom_ref(pcr);
+}
+#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+/**
+ * Fragment an IP datagram if too large for the netif.
+ *
+ * Chop the datagram in MTU sized chunks and send them in order
+ * by using a fixed size static memory buffer (PBUF_REF) or
+ * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
+ *
+ * @param p ip packet to send
+ * @param netif the netif on which to send
+ * @param dest destination ip address to which to send
+ *
+ * @return ERR_OK if sent successfully, err_t otherwise
+ */
+err_t
+ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
+{
+ struct pbuf *rambuf;
+#if IP_FRAG_USES_STATIC_BUF
+ struct pbuf *header;
+#else
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+ struct pbuf *newpbuf;
+#endif
+ struct ip_hdr *original_iphdr;
+#endif
+ struct ip_hdr *iphdr;
+ u16_t nfb;
+ u16_t left, cop;
+ u16_t mtu = netif->mtu;
+ u16_t ofo, omf;
+ u16_t last;
+ u16_t poff = IP_HLEN;
+ u16_t tmp;
+#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+ u16_t newpbuflen = 0;
+ u16_t left_to_copy;
+#endif
+
+ /* Get a RAM based MTU sized pbuf */
+#if IP_FRAG_USES_STATIC_BUF
+ /* When using a static buffer, we use a PBUF_REF, which we will
+ * use to reference the packet (without link header).
+ * Layer and length is irrelevant.
+ */
+ rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
+ if (rambuf == NULL) {
+ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
+ return ERR_MEM;
+ }
+ rambuf->tot_len = rambuf->len = mtu;
+ rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
+
+ /* Copy the IP header in it */
+ iphdr = (struct ip_hdr *)rambuf->payload;
+ SMEMCPY(iphdr, p->payload, IP_HLEN);
+#else /* IP_FRAG_USES_STATIC_BUF */
+ original_iphdr = (struct ip_hdr *)p->payload;
+ iphdr = original_iphdr;
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+ /* Save original offset */
+ tmp = ntohs(IPH_OFFSET(iphdr));
+ ofo = tmp & IP_OFFMASK;
+ omf = tmp & IP_MF;
+
+ left = p->tot_len - IP_HLEN;
+
+ nfb = (mtu - IP_HLEN) / 8;
+
+ while (left) {
+ last = (left <= mtu - IP_HLEN);
+
+ /* Set new offset and MF flag */
+ tmp = omf | (IP_OFFMASK & (ofo));
+ if (!last) {
+ tmp = tmp | IP_MF;
+ }
+
+ /* Fill this fragment */
+ cop = last ? left : nfb * 8;
+
+#if IP_FRAG_USES_STATIC_BUF
+ poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
+#else /* IP_FRAG_USES_STATIC_BUF */
+#if LWIP_NETIF_TX_SINGLE_PBUF
+ rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
+ if (rambuf == NULL) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("this needs a pbuf in one piece!",
+ (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
+ poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
+ /* make room for the IP header */
+ if(pbuf_header(rambuf, IP_HLEN)) {
+ pbuf_free(rambuf);
+ return ERR_MEM;
+ }
+ /* fill in the IP header */
+ SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+ iphdr = rambuf->payload;
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+ /* When not using a static buffer, create a chain of pbufs.
+ * The first will be a PBUF_RAM holding the link and IP header.
+ * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
+ * but limited to the size of an mtu.
+ */
+ rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
+ if (rambuf == NULL) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("this needs a pbuf in one piece!",
+ (p->len >= (IP_HLEN)));
+ SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+ iphdr = (struct ip_hdr *)rambuf->payload;
+
+ /* Can just adjust p directly for needed offset. */
+ p->payload = (u8_t *)p->payload + poff;
+ p->len -= poff;
+
+ left_to_copy = cop;
+ while (left_to_copy) {
+ struct pbuf_custom_ref *pcr;
+ newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
+ /* Is this pbuf already empty? */
+ if (!newpbuflen) {
+ p = p->next;
+ continue;
+ }
+ pcr = ip_frag_alloc_pbuf_custom_ref();
+ if (pcr == NULL) {
+ pbuf_free(rambuf);
+ return ERR_MEM;
+ }
+ /* Mirror this pbuf, although we might not need all of it. */
+ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
+ if (newpbuf == NULL) {
+ ip_frag_free_pbuf_custom_ref(pcr);
+ pbuf_free(rambuf);
+ return ERR_MEM;
+ }
+ pbuf_ref(p);
+ pcr->original = p;
+ pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
+
+ /* 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.
+ */
+ pbuf_cat(rambuf, newpbuf);
+ left_to_copy -= newpbuflen;
+ if (left_to_copy) {
+ p = p->next;
+ }
+ }
+ poff = newpbuflen;
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+ /* Correct header */
+ IPH_OFFSET_SET(iphdr, htons(tmp));
+ IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
+ IPH_CHKSUM_SET(iphdr, 0);
+ IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+
+#if IP_FRAG_USES_STATIC_BUF
+ if (last) {
+ pbuf_realloc(rambuf, left + IP_HLEN);
+ }
+
+ /* This part is ugly: we alloc a RAM based pbuf for
+ * the link level header for each chunk and then
+ * free it.A PBUF_ROM style pbuf for which pbuf_header
+ * worked would make things simpler.
+ */
+ header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
+ if (header != NULL) {
+ pbuf_chain(header, rambuf);
+ netif->output(netif, header, dest);
+ IPFRAG_STATS_INC(ip_frag.xmit);
+ snmp_inc_ipfragcreates();
+ pbuf_free(header);
+ } else {
+ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
+ pbuf_free(rambuf);
+ return ERR_MEM;
+ }
+#else /* IP_FRAG_USES_STATIC_BUF */
+ /* No need for separate header pbuf - we allowed room for it in rambuf
+ * when allocated.
+ */
+ netif->output(netif, rambuf, dest);
+ IPFRAG_STATS_INC(ip_frag.xmit);
+
+ /* Unfortunately we can't reuse rambuf - the hardware may still be
+ * using the buffer. Instead we free it (and the ensuing chain) and
+ * recreate it next time round the loop. If we're lucky the hardware
+ * will have already sent the packet, the free will really free, and
+ * there will be zero memory penalty.
+ */
+
+ pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+ left -= cop;
+ ofo += nfb;
+ }
+#if IP_FRAG_USES_STATIC_BUF
+ pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+ snmp_inc_ipfragoks();
+ return ERR_OK;
+}
+#endif /* IP_FRAG */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/mem.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/mem.c
new file mode 100644
index 0000000000..7ebe304138
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/mem.c
@@ -0,0 +1,657 @@
+/**
+ * @file
+ * Dynamic memory manager
+ *
+ * This is a lightweight replacement for the standard C library malloc().
+ *
+ * If you want to use the standard C library malloc() instead, define
+ * MEM_LIBC_MALLOC to 1 in your lwipopts.h
+ *
+ * To let mem_malloc() use pools (prevents fragmentation and is much faster than
+ * a heap but might waste some memory), define MEM_USE_POOLS to 1, define
+ * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
+ * of pools like this (more pools can be added between _START and _END):
+ *
+ * Define three pools with sizes 256, 512, and 1512 bytes
+ * LWIP_MALLOC_MEMPOOL_START
+ * LWIP_MALLOC_MEMPOOL(20, 256)
+ * LWIP_MALLOC_MEMPOOL(10, 512)
+ * LWIP_MALLOC_MEMPOOL(5, 1512)
+ * LWIP_MALLOC_MEMPOOL_END
+ */
+
+/*
+ * 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 <adam@sics.se>
+ * Simon Goldschmidt
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/err.h"
+
+#include <string.h>
+
+#if MEM_USE_POOLS
+/* lwIP head implemented with different sized pools */
+
+/**
+ * Allocate memory: determine the smallest pool that is big enough
+ * to contain an element of 'size' and get an element from that pool.
+ *
+ * @param size the size in bytes of the memory needed
+ * @return a pointer to the allocated memory or NULL if the pool is empty
+ */
+void *
+mem_malloc(mem_size_t size)
+{
+ struct memp_malloc_helper *element;
+ memp_t poolnr;
+ mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
+
+ for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
+#if MEM_USE_POOLS_TRY_BIGGER_POOL
+again:
+#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
+ /* is this pool big enough to hold an element of the required size
+ plus a struct memp_malloc_helper that saves the pool this element came from? */
+ if (required_size <= memp_sizes[poolnr]) {
+ break;
+ }
+ }
+ if (poolnr > MEMP_POOL_LAST) {
+ LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
+ return NULL;
+ }
+ element = (struct memp_malloc_helper*)memp_malloc(poolnr);
+ if (element == NULL) {
+ /* No need to DEBUGF or ASSERT: This error is already
+ taken care of in memp.c */
+#if MEM_USE_POOLS_TRY_BIGGER_POOL
+ /** Try a bigger pool if this one is empty! */
+ if (poolnr < MEMP_POOL_LAST) {
+ poolnr++;
+ goto again;
+ }
+#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
+ return NULL;
+ }
+
+ /* save the pool number this element came from */
+ element->poolnr = poolnr;
+ /* and return a pointer to the memory directly after the struct memp_malloc_helper */
+ element++;
+
+ return element;
+}
+
+/**
+ * Free memory previously allocated by mem_malloc. Loads the pool number
+ * and calls memp_free with that pool number to put the element back into
+ * its pool
+ *
+ * @param rmem the memory element to free
+ */
+void
+mem_free(void *rmem)
+{
+ struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
+
+ LWIP_ASSERT("rmem != NULL", (rmem != NULL));
+ LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
+
+ /* get the original struct memp_malloc_helper */
+ hmem--;
+
+ LWIP_ASSERT("hmem != NULL", (hmem != NULL));
+ LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
+ LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
+
+ /* and put it in the pool we saved earlier */
+ memp_free(hmem->poolnr, hmem);
+}
+
+#else /* MEM_USE_POOLS */
+/* lwIP replacement for your libc malloc() */
+
+/**
+ * The heap is made up as a list of structs of this type.
+ * This does not have to be aligned since for getting its size,
+ * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
+ */
+struct mem {
+ /** index (-> ram[next]) of the next struct */
+ mem_size_t next;
+ /** index (-> ram[prev]) of the previous struct */
+ mem_size_t prev;
+ /** 1: this area is used; 0: this area is unused */
+ u8_t used;
+};
+
+/** All allocated blocks will be MIN_SIZE bytes big, at least!
+ * MIN_SIZE can be overridden to suit your needs. Smaller values save space,
+ * larger values could prevent too small blocks to fragment the RAM too much. */
+#ifndef MIN_SIZE
+#define MIN_SIZE 12
+#endif /* MIN_SIZE */
+/* some alignment macros: we define them here for better source code layout */
+#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
+#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
+#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
+
+/** If you want to relocate the heap to external memory, simply define
+ * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
+ * If so, make sure the memory at that location is big enough (see below on
+ * how that space is calculated). */
+#ifndef LWIP_RAM_HEAP_POINTER
+
+#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+# if defined (__ICCARM__)
+# define ETHMEM_SECTION
+# elif defined(TOOLCHAIN_GCC_CR)
+# define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
+# else
+# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
+# endif
+#elif defined(TARGET_LPC1768)
+# define ETHMEM_SECTION __attribute((section("AHBSRAM0")))
+#else
+# define ETHMEM_SECTION
+#endif
+
+/** the heap. we need one struct mem at the end and some room for alignment */
+u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] ETHMEM_SECTION;
+#define LWIP_RAM_HEAP_POINTER ram_heap
+#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;
+/** the last entry, always unused! */
+static struct mem *ram_end;
+/** pointer to the lowest free block, this is used for faster search */
+static struct mem *lfree;
+
+/** concurrent access protection */
+static sys_mutex_t mem_mutex;
+
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+
+static volatile u8_t mem_free_count;
+
+/* Allow mem_free from other (e.g. interrupt) context */
+#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
+#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
+#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
+#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
+
+#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+/* Protect the heap only by using a semaphore */
+#define LWIP_MEM_FREE_DECL_PROTECT()
+#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
+#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
+/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
+#define LWIP_MEM_ALLOC_DECL_PROTECT()
+#define LWIP_MEM_ALLOC_PROTECT()
+#define LWIP_MEM_ALLOC_UNPROTECT()
+
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+
+/**
+ * "Plug holes" by combining adjacent empty struct mems.
+ * After this function is through, there should not exist
+ * one empty struct mem pointing to another empty struct mem.
+ *
+ * @param mem this points to a struct mem which just has been freed
+ * @internal this function is only called by mem_free() and mem_trim()
+ *
+ * This assumes access to the heap is protected by the calling function
+ * already.
+ */
+static void
+plug_holes(struct mem *mem)
+{
+ struct mem *nmem;
+ struct mem *pmem;
+
+ LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
+ LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
+ LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
+
+ /* plug hole forward */
+ LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
+
+ nmem = (struct mem *)(void *)&ram[mem->next];
+ if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
+ /* if mem->next is unused and not end of ram, combine mem and mem->next */
+ if (lfree == nmem) {
+ lfree = mem;
+ }
+ mem->next = nmem->next;
+ ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
+ }
+
+ /* plug hole backward */
+ pmem = (struct mem *)(void *)&ram[mem->prev];
+ if (pmem != mem && pmem->used == 0) {
+ /* if mem->prev is unused, combine mem and mem->prev */
+ if (lfree == mem) {
+ lfree = pmem;
+ }
+ pmem->next = mem->next;
+ ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
+ }
+}
+
+/**
+ * Zero the heap and initialize start, end and lowest-free
+ */
+void
+mem_init(void)
+{
+ struct mem *mem;
+
+ LWIP_ASSERT("Sanity check alignment",
+ (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
+
+ /* align the heap */
+ ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
+ /* initialize the start of the heap */
+ mem = (struct mem *)(void *)ram;
+ mem->next = MEM_SIZE_ALIGNED;
+ mem->prev = 0;
+ mem->used = 0;
+ /* initialize the end of the heap */
+ ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
+ ram_end->used = 1;
+ ram_end->next = MEM_SIZE_ALIGNED;
+ ram_end->prev = MEM_SIZE_ALIGNED;
+
+ /* initialize the lowest-free pointer to the start of the heap */
+ lfree = (struct mem *)(void *)ram;
+
+ MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
+
+ if(sys_mutex_new(&mem_mutex) != ERR_OK) {
+ LWIP_ASSERT("failed to create mem_mutex", 0);
+ }
+}
+
+/**
+ * Put a struct mem back on the heap
+ *
+ * @param rmem is the data portion of a struct mem as returned by a previous
+ * call to mem_malloc()
+ */
+void
+mem_free(void *rmem)
+{
+ struct mem *mem;
+ LWIP_MEM_FREE_DECL_PROTECT();
+
+ if (rmem == NULL) {
+ LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
+ return;
+ }
+ LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
+
+ LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
+ (u8_t *)rmem < (u8_t *)ram_end);
+
+ if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+ SYS_ARCH_DECL_PROTECT(lev);
+ LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
+ /* protect mem stats from concurrent access */
+ SYS_ARCH_PROTECT(lev);
+ MEM_STATS_INC(illegal);
+ SYS_ARCH_UNPROTECT(lev);
+ return;
+ }
+ /* protect the heap from concurrent access */
+ LWIP_MEM_FREE_PROTECT();
+ /* Get the corresponding struct mem ... */
+ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
+ /* ... which has to be in a used state ... */
+ LWIP_ASSERT("mem_free: mem->used", mem->used);
+ /* ... and is now unused. */
+ mem->used = 0;
+
+ if (mem < lfree) {
+ /* the newly freed struct is now the lowest */
+ lfree = mem;
+ }
+
+ MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
+
+ /* finally, see if prev or next are free also */
+ plug_holes(mem);
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ mem_free_count = 1;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+ LWIP_MEM_FREE_UNPROTECT();
+}
+
+/**
+ * Shrink memory returned by mem_malloc().
+ *
+ * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
+ * @param newsize 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
+ * or NULL if newsize is > old size, in which case rmem is NOT touched
+ * or freed!
+ */
+void *
+mem_trim(void *rmem, mem_size_t newsize)
+{
+ mem_size_t size;
+ mem_size_t ptr, ptr2;
+ struct mem *mem, *mem2;
+ /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
+ LWIP_MEM_FREE_DECL_PROTECT();
+
+ /* Expand the size of the allocated memory region so that we can
+ adjust for alignment. */
+ newsize = LWIP_MEM_ALIGN_SIZE(newsize);
+
+ if(newsize < MIN_SIZE_ALIGNED) {
+ /* every data block must be at least MIN_SIZE_ALIGNED long */
+ newsize = MIN_SIZE_ALIGNED;
+ }
+
+ if (newsize > MEM_SIZE_ALIGNED) {
+ return NULL;
+ }
+
+ LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
+ (u8_t *)rmem < (u8_t *)ram_end);
+
+ if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+ SYS_ARCH_DECL_PROTECT(lev);
+ LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
+ /* protect mem stats from concurrent access */
+ SYS_ARCH_PROTECT(lev);
+ MEM_STATS_INC(illegal);
+ SYS_ARCH_UNPROTECT(lev);
+ return rmem;
+ }
+ /* Get the corresponding struct mem ... */
+ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
+ /* ... and its offset pointer */
+ ptr = (mem_size_t)((u8_t *)mem - ram);
+
+ size = mem->next - ptr - SIZEOF_STRUCT_MEM;
+ LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
+ if (newsize > size) {
+ /* not supported */
+ return NULL;
+ }
+ if (newsize == size) {
+ /* No change in size, simply return */
+ return rmem;
+ }
+
+ /* protect the heap from concurrent access */
+ LWIP_MEM_FREE_PROTECT();
+
+ mem2 = (struct mem *)(void *)&ram[mem->next];
+ if(mem2->used == 0) {
+ /* The next struct is unused, we can simply move it at little */
+ mem_size_t next;
+ /* remember the old next pointer */
+ next = mem2->next;
+ /* create new struct mem which is moved directly after the shrinked mem */
+ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
+ if (lfree == mem2) {
+ lfree = (struct mem *)(void *)&ram[ptr2];
+ }
+ mem2 = (struct mem *)(void *)&ram[ptr2];
+ mem2->used = 0;
+ /* restore the next pointer */
+ mem2->next = next;
+ /* link it back to mem */
+ mem2->prev = ptr;
+ /* link mem to it */
+ mem->next = ptr2;
+ /* last thing to restore linked list: as we have moved mem2,
+ * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
+ * the end of the heap */
+ if (mem2->next != MEM_SIZE_ALIGNED) {
+ ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+ }
+ MEM_STATS_DEC_USED(used, (size - newsize));
+ /* no need to plug holes, we've already done that */
+ } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
+ /* Next struct is used but there's room for another struct mem with
+ * at least MIN_SIZE_ALIGNED of data.
+ * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
+ * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
+ * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
+ * region that couldn't hold data, but when mem->next gets freed,
+ * the 2 regions would be combined, resulting in more free memory */
+ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
+ mem2 = (struct mem *)(void *)&ram[ptr2];
+ if (mem2 < lfree) {
+ lfree = mem2;
+ }
+ mem2->used = 0;
+ mem2->next = mem->next;
+ mem2->prev = ptr;
+ mem->next = ptr2;
+ if (mem2->next != MEM_SIZE_ALIGNED) {
+ ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+ }
+ MEM_STATS_DEC_USED(used, (size - newsize));
+ /* the original mem->next is used, so no need to plug holes! */
+ }
+ /* 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.
+ -> the remaining space stays unused since it is too small
+ } */
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ mem_free_count = 1;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+ LWIP_MEM_FREE_UNPROTECT();
+ return rmem;
+}
+
+/**
+ * Adam's mem_malloc() plus solution for bug #17922
+ * Allocate a block of memory with a minimum of 'size' bytes.
+ *
+ * @param size is the minimum size of the requested block in bytes.
+ * @return pointer to allocated memory or NULL if no free memory was found.
+ *
+ * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
+ */
+void *
+mem_malloc(mem_size_t size)
+{
+ mem_size_t ptr, ptr2;
+ struct mem *mem, *mem2;
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ u8_t local_mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+ LWIP_MEM_ALLOC_DECL_PROTECT();
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ /* Expand the size of the allocated memory region so that we can
+ adjust for alignment. */
+ size = LWIP_MEM_ALIGN_SIZE(size);
+
+ if(size < MIN_SIZE_ALIGNED) {
+ /* every data block must be at least MIN_SIZE_ALIGNED long */
+ size = MIN_SIZE_ALIGNED;
+ }
+
+ if (size > MEM_SIZE_ALIGNED) {
+ return NULL;
+ }
+
+ /* protect the heap from concurrent access */
+ sys_mutex_lock(&mem_mutex);
+ LWIP_MEM_ALLOC_PROTECT();
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ /* run as long as a mem_free disturbed mem_malloc */
+ do {
+ local_mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+ /* Scan through the heap searching for a free block that is big enough,
+ * beginning with the lowest free block.
+ */
+ for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
+ ptr = ((struct mem *)(void *)&ram[ptr])->next) {
+ mem = (struct mem *)(void *)&ram[ptr];
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ mem_free_count = 0;
+ LWIP_MEM_ALLOC_UNPROTECT();
+ /* allow mem_free to run */
+ LWIP_MEM_ALLOC_PROTECT();
+ if (mem_free_count != 0) {
+ local_mem_free_count = mem_free_count;
+ }
+ mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+ if ((!mem->used) &&
+ (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
+ /* mem is not used and at least perfect fit is possible:
+ * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
+
+ if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
+ /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
+ * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
+ * -> split large block, create empty remainder,
+ * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
+ * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
+ * struct mem would fit in but no data between mem2 and mem2->next
+ * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
+ * region that couldn't hold data, but when mem->next gets freed,
+ * the 2 regions would be combined, resulting in more free memory
+ */
+ ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
+ /* create mem2 struct */
+ mem2 = (struct mem *)(void *)&ram[ptr2];
+ mem2->used = 0;
+ mem2->next = mem->next;
+ mem2->prev = ptr;
+ /* and insert it between mem and mem->next */
+ mem->next = ptr2;
+ mem->used = 1;
+
+ if (mem2->next != MEM_SIZE_ALIGNED) {
+ ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+ }
+ MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
+ } else {
+ /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
+ * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
+ * take care of this).
+ * -> near fit or excact fit: do not split, no mem2 creation
+ * also can't move mem->next directly behind mem, since mem->next
+ * will always be used at this point!
+ */
+ mem->used = 1;
+ MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
+ }
+
+ if (mem == lfree) {
+ /* Find next free block after mem and update lowest free pointer */
+ while (lfree->used && lfree != ram_end) {
+ LWIP_MEM_ALLOC_UNPROTECT();
+ /* prevent high interrupt latency... */
+ LWIP_MEM_ALLOC_PROTECT();
+ lfree = (struct mem *)(void *)&ram[lfree->next];
+ }
+ LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
+ }
+ LWIP_MEM_ALLOC_UNPROTECT();
+ sys_mutex_unlock(&mem_mutex);
+ LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
+ (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
+ LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
+ ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
+ LWIP_ASSERT("mem_malloc: sanity check alignment",
+ (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
+
+ return (u8_t *)mem + SIZEOF_STRUCT_MEM;
+ }
+ }
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+ /* if we got interrupted by a mem_free, try again */
+ } while(local_mem_free_count != 0);
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+ LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
+ MEM_STATS_INC(err);
+ LWIP_MEM_ALLOC_UNPROTECT();
+ sys_mutex_unlock(&mem_mutex);
+ return NULL;
+}
+
+#endif /* MEM_USE_POOLS */
+/**
+ * Contiguously allocates enough space for count objects that are size bytes
+ * of memory each and returns a pointer to the allocated memory.
+ *
+ * The allocated memory is filled with bytes of value zero.
+ *
+ * @param count number of objects to allocate
+ * @param size size of the objects to allocate
+ * @return pointer to allocated memory / NULL pointer if there is an error
+ */
+void *mem_calloc(mem_size_t count, mem_size_t size)
+{
+ void *p;
+
+ /* allocate 'count' objects of size 'size' */
+ p = mem_malloc(count * size);
+ if (p) {
+ /* zero the memory */
+ memset(p, 0, count * size);
+ }
+ return p;
+}
+
+#endif /* !MEM_LIBC_MALLOC */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/memp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/memp.c
new file mode 100644
index 0000000000..19bc5579db
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/memp.c
@@ -0,0 +1,475 @@
+/**
+ * @file
+ * Dynamic pool memory manager
+ *
+ * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
+ * packet buffers, ...). All these pools are managed here.
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/udp.h"
+#include "lwip/raw.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/igmp.h"
+#include "lwip/api.h"
+#include "lwip/api_msg.h"
+#include "lwip/tcpip.h"
+#include "lwip/sys.h"
+#include "lwip/timers.h"
+#include "lwip/stats.h"
+#include "netif/etharp.h"
+#include "lwip/ip_frag.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/snmp_msg.h"
+#include "lwip/dns.h"
+#include "netif/ppp_oe.h"
+
+#include <string.h>
+
+#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+struct memp {
+ struct memp *next;
+#if MEMP_OVERFLOW_CHECK
+ const char *file;
+ int line;
+#endif /* MEMP_OVERFLOW_CHECK */
+};
+
+#if MEMP_OVERFLOW_CHECK
+/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
+ * and at the end of each element, initialize them as 0xcd and check
+ * them later. */
+/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
+ * every single element in each pool is checked!
+ * This is VERY SLOW but also very helpful. */
+/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
+ * lwipopts.h to change the amount reserved for checking. */
+#ifndef MEMP_SANITY_REGION_BEFORE
+#define MEMP_SANITY_REGION_BEFORE 16
+#endif /* MEMP_SANITY_REGION_BEFORE*/
+#if MEMP_SANITY_REGION_BEFORE > 0
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
+#else
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
+#endif /* MEMP_SANITY_REGION_BEFORE*/
+#ifndef MEMP_SANITY_REGION_AFTER
+#define MEMP_SANITY_REGION_AFTER 16
+#endif /* MEMP_SANITY_REGION_AFTER*/
+#if MEMP_SANITY_REGION_AFTER > 0
+#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
+#else
+#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
+#endif /* MEMP_SANITY_REGION_AFTER*/
+
+/* MEMP_SIZE: save space for struct memp and for sanity check */
+#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
+
+#else /* MEMP_OVERFLOW_CHECK */
+
+/* No sanity checks
+ * We don't need to preserve the struct memp while not allocated, so we
+ * can save a little space and set MEMP_SIZE to 0.
+ */
+#define MEMP_SIZE 0
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
+
+#endif /* MEMP_OVERFLOW_CHECK */
+
+/** This array holds the first free element of each pool.
+ * Elements form a linked list. */
+static struct memp *memp_tab[MEMP_MAX];
+
+#else /* MEMP_MEM_MALLOC */
+
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
+
+#endif /* MEMP_MEM_MALLOC */
+
+/** This array holds the element sizes of each pool. */
+#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
+static
+#endif
+const u16_t memp_sizes[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
+#include "lwip/memp_std.h"
+};
+
+#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+/** This array holds the number of elements in each pool. */
+static const u16_t memp_num[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc) (num),
+#include "lwip/memp_std.h"
+};
+
+/** This array holds a textual description of each pool. */
+#ifdef LWIP_DEBUG
+static const char *memp_desc[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc) (desc),
+#include "lwip/memp_std.h"
+};
+#endif /* LWIP_DEBUG */
+
+#if MEMP_SEPARATE_POOLS
+
+/** This creates each memory pool. These are named memp_memory_XXX_base (where
+ * XXX is the name of the pool defined in memp_std.h).
+ * To relocate a pool, declare it as extern in cc.h. Example for GCC:
+ * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
+ */
+#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
+ [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
+#include "lwip/memp_std.h"
+
+/** This array holds the base of each memory pool. */
+static u8_t *const memp_bases[] = {
+#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
+#include "lwip/memp_std.h"
+};
+
+#else /* MEMP_SEPARATE_POOLS */
+
+#if defined(TARGET_LPC1768)
+# define ETHMEM_SECTION __attribute((section("AHBSRAM1")))
+#else
+# define ETHMEM_SECTION
+#endif
+
+/** This is the actual memory used by the pools (all pools in one big block). */
+static u8_t memp_memory[MEM_ALIGNMENT - 1
+#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
+#include "lwip/memp_std.h"
+] ETHMEM_SECTION;
+
+#endif /* MEMP_SEPARATE_POOLS */
+
+#if MEMP_SANITY_CHECK
+/**
+ * Check that memp-lists don't form a circle
+ */
+static int
+memp_sanity(void)
+{
+ s16_t i, c;
+ struct memp *m, *n;
+
+ for (i = 0; i < MEMP_MAX; i++) {
+ for (m = memp_tab[i]; m != NULL; m = m->next) {
+ c = 1;
+ for (n = memp_tab[i]; n != NULL; n = n->next) {
+ if (n == m && --c < 0) {
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+}
+#endif /* MEMP_SANITY_CHECK*/
+#if MEMP_OVERFLOW_CHECK
+#if defined(LWIP_DEBUG) && MEMP_STATS
+static const char * memp_overflow_names[] = {
+#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
+#include "lwip/memp_std.h"
+ };
+#endif
+
+/**
+ * Check if a memp element was victim of an overflow
+ * (e.g. the restricted area after it has been altered)
+ *
+ * @param p the memp element to check
+ * @param memp_type the pool p comes from
+ */
+static void
+memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
+{
+ u16_t k;
+ u8_t *m;
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
+ m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
+ for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
+ if (m[k] != 0xcd) {
+ char errstr[128] = "detected memp overflow in pool ";
+ char digit[] = "0";
+ if(memp_type >= 10) {
+ digit[0] = '0' + (memp_type/10);
+ strcat(errstr, digit);
+ }
+ digit[0] = '0' + (memp_type%10);
+ strcat(errstr, digit);
+#if defined(LWIP_DEBUG) && MEMP_STATS
+ strcat(errstr, memp_overflow_names[memp_type]);
+#endif
+ LWIP_ASSERT(errstr, 0);
+ }
+ }
+#endif
+}
+
+/**
+ * Check if a memp element was victim of an underflow
+ * (e.g. the restricted area before it has been altered)
+ *
+ * @param p the memp element to check
+ * @param memp_type the pool p comes from
+ */
+static void
+memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
+{
+ u16_t k;
+ u8_t *m;
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
+ m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
+ for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
+ if (m[k] != 0xcd) {
+ char errstr[128] = "detected memp underflow in pool ";
+ char digit[] = "0";
+ if(memp_type >= 10) {
+ digit[0] = '0' + (memp_type/10);
+ strcat(errstr, digit);
+ }
+ digit[0] = '0' + (memp_type%10);
+ strcat(errstr, digit);
+#if defined(LWIP_DEBUG) && MEMP_STATS
+ strcat(errstr, memp_overflow_names[memp_type]);
+#endif
+ LWIP_ASSERT(errstr, 0);
+ }
+ }
+#endif
+}
+
+/**
+ * Do an overflow check for all elements in every pool.
+ *
+ * @see memp_overflow_check_element for a description of the check
+ */
+static void
+memp_overflow_check_all(void)
+{
+ u16_t i, j;
+ struct memp *p;
+
+ p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+ for (i = 0; i < MEMP_MAX; ++i) {
+ p = p;
+ for (j = 0; j < memp_num[i]; ++j) {
+ memp_overflow_check_element_overflow(p, i);
+ p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+ }
+ }
+ p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+ for (i = 0; i < MEMP_MAX; ++i) {
+ p = p;
+ for (j = 0; j < memp_num[i]; ++j) {
+ memp_overflow_check_element_underflow(p, i);
+ p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+ }
+ }
+}
+
+/**
+ * Initialize the restricted areas of all memp elements in every pool.
+ */
+static void
+memp_overflow_init(void)
+{
+ u16_t i, j;
+ struct memp *p;
+ u8_t *m;
+
+ p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+ for (i = 0; i < MEMP_MAX; ++i) {
+ p = p;
+ for (j = 0; j < memp_num[i]; ++j) {
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
+ m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
+ memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
+#endif
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
+ m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
+ memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
+#endif
+ p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+ }
+ }
+}
+#endif /* MEMP_OVERFLOW_CHECK */
+
+/**
+ * Initialize this module.
+ *
+ * Carves out memp_memory into linked lists for each pool-type.
+ */
+void
+memp_init(void)
+{
+ struct memp *memp;
+ u16_t i, j;
+
+ for (i = 0; i < MEMP_MAX; ++i) {
+ MEMP_STATS_AVAIL(used, i, 0);
+ MEMP_STATS_AVAIL(max, i, 0);
+ MEMP_STATS_AVAIL(err, i, 0);
+ MEMP_STATS_AVAIL(avail, i, memp_num[i]);
+ }
+
+#if !MEMP_SEPARATE_POOLS
+ memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+#endif /* !MEMP_SEPARATE_POOLS */
+ /* for every pool: */
+ for (i = 0; i < MEMP_MAX; ++i) {
+ memp_tab[i] = NULL;
+#if MEMP_SEPARATE_POOLS
+ memp = (struct memp*)memp_bases[i];
+#endif /* MEMP_SEPARATE_POOLS */
+ /* create a linked list of memp elements */
+ for (j = 0; j < memp_num[i]; ++j) {
+ memp->next = memp_tab[i];
+ memp_tab[i] = memp;
+ memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
+#if MEMP_OVERFLOW_CHECK
+ + MEMP_SANITY_REGION_AFTER_ALIGNED
+#endif
+ );
+ }
+ }
+#if MEMP_OVERFLOW_CHECK
+ memp_overflow_init();
+ /* check everything a first time to see if it worked */
+ memp_overflow_check_all();
+#endif /* MEMP_OVERFLOW_CHECK */
+}
+
+/**
+ * Get an element from a specific pool.
+ *
+ * @param type the pool to get an element from
+ *
+ * the debug version has two more parameters:
+ * @param file file name calling this function
+ * @param line number of line where this function is called
+ *
+ * @return a pointer to the allocated memory or a NULL pointer on error
+ */
+void *
+#if !MEMP_OVERFLOW_CHECK
+memp_malloc(memp_t type)
+#else
+memp_malloc_fn(memp_t type, const char* file, const int line)
+#endif
+{
+ struct memp *memp;
+ SYS_ARCH_DECL_PROTECT(old_level);
+
+ LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
+
+ SYS_ARCH_PROTECT(old_level);
+#if MEMP_OVERFLOW_CHECK >= 2
+ memp_overflow_check_all();
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */
+
+ memp = memp_tab[type];
+
+ if (memp != NULL) {
+ memp_tab[type] = memp->next;
+#if MEMP_OVERFLOW_CHECK
+ memp->next = NULL;
+ memp->file = file;
+ memp->line = line;
+#endif /* MEMP_OVERFLOW_CHECK */
+ MEMP_STATS_INC_USED(used, type);
+ LWIP_ASSERT("memp_malloc: memp properly aligned",
+ ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
+ memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
+ } else {
+ LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
+ MEMP_STATS_INC(err, type);
+ }
+
+ SYS_ARCH_UNPROTECT(old_level);
+
+ return memp;
+}
+
+/**
+ * Put an element back into its pool.
+ *
+ * @param type the pool where to put mem
+ * @param mem the memp element to free
+ */
+void
+memp_free(memp_t type, void *mem)
+{
+ struct memp *memp;
+ SYS_ARCH_DECL_PROTECT(old_level);
+
+ if (mem == NULL) {
+ return;
+ }
+ LWIP_ASSERT("memp_free: mem properly aligned",
+ ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
+
+ memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
+
+ SYS_ARCH_PROTECT(old_level);
+#if MEMP_OVERFLOW_CHECK
+#if MEMP_OVERFLOW_CHECK >= 2
+ memp_overflow_check_all();
+#else
+ memp_overflow_check_element_overflow(memp, type);
+ memp_overflow_check_element_underflow(memp, type);
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */
+#endif /* MEMP_OVERFLOW_CHECK */
+
+ MEMP_STATS_DEC(used, type);
+
+ memp->next = memp_tab[type];
+ memp_tab[type] = memp;
+
+#if MEMP_SANITY_CHECK
+ LWIP_ASSERT("memp sanity", memp_sanity());
+#endif /* MEMP_SANITY_CHECK */
+
+ SYS_ARCH_UNPROTECT(old_level);
+}
+
+#endif /* MEMP_MEM_MALLOC */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/netif.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/netif.c
new file mode 100644
index 0000000000..b3a5e16337
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/netif.c
@@ -0,0 +1,758 @@
+/**
+ * @file
+ * lwIP network interface abstraction
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/igmp.h"
+#include "netif/etharp.h"
+#include "lwip/stats.h"
+#if ENABLE_LOOPBACK
+#include "lwip/sys.h"
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING
+#include "lwip/tcpip.h"
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
+
+#if LWIP_AUTOIP
+#include "lwip/autoip.h"
+#endif /* LWIP_AUTOIP */
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#endif /* LWIP_DHCP */
+
+#if LWIP_NETIF_STATUS_CALLBACK
+#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
+#else
+#define NETIF_STATUS_CALLBACK(n)
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+
+#if LWIP_NETIF_LINK_CALLBACK
+#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
+#else
+#define NETIF_LINK_CALLBACK(n)
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+struct netif *netif_list;
+struct netif *netif_default;
+
+#if LWIP_HAVE_LOOPIF
+static struct netif loop_netif;
+
+/**
+ * Initialize a lwip network interface structure for a loopback interface
+ *
+ * @param netif the lwip network interface structure for this loopif
+ * @return ERR_OK if the loopif is initialized
+ * ERR_MEM if private data couldn't be allocated
+ */
+static err_t
+netif_loopif_init(struct netif *netif)
+{
+ /* initialize the snmp variables and counters inside the struct netif
+ * ifSpeed: no assumption can be made!
+ */
+ NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
+
+ netif->name[0] = 'l';
+ netif->name[1] = 'o';
+ netif->output = netif_loop_output;
+ return ERR_OK;
+}
+#endif /* LWIP_HAVE_LOOPIF */
+
+void
+netif_init(void)
+{
+#if LWIP_HAVE_LOOPIF
+ ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
+ IP4_ADDR(&loop_gw, 127,0,0,1);
+ IP4_ADDR(&loop_ipaddr, 127,0,0,1);
+ IP4_ADDR(&loop_netmask, 255,0,0,0);
+
+#if NO_SYS
+ netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
+#else /* NO_SYS */
+ netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
+#endif /* NO_SYS */
+ netif_set_up(&loop_netif);
+
+#endif /* LWIP_HAVE_LOOPIF */
+}
+
+/**
+ * Add a network interface to the list of lwIP netifs.
+ *
+ * @param netif a pre-allocated netif structure
+ * @param ipaddr IP address for the new netif
+ * @param netmask network mask for the new netif
+ * @param gw default gateway IP address for the new netif
+ * @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.
+ *
+ * @return netif, or NULL if failed.
+ */
+struct netif *
+netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+ ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
+{
+ static u8_t netifnum = 0;
+
+ LWIP_ASSERT("No init function given", init != NULL);
+
+ /* reset new interface configuration state */
+ ip_addr_set_zero(&netif->ip_addr);
+ ip_addr_set_zero(&netif->netmask);
+ ip_addr_set_zero(&netif->gw);
+ netif->flags = 0;
+#if LWIP_DHCP
+ /* netif not under DHCP control by default */
+ netif->dhcp = NULL;
+#endif /* LWIP_DHCP */
+#if LWIP_AUTOIP
+ /* netif not under AutoIP control by default */
+ netif->autoip = NULL;
+#endif /* LWIP_AUTOIP */
+#if LWIP_NETIF_STATUS_CALLBACK
+ netif->status_callback = NULL;
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+#if LWIP_NETIF_LINK_CALLBACK
+ netif->link_callback = NULL;
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+#if LWIP_IGMP
+ netif->igmp_mac_filter = NULL;
+#endif /* LWIP_IGMP */
+#if ENABLE_LOOPBACK
+ netif->loop_first = NULL;
+ netif->loop_last = NULL;
+#endif /* ENABLE_LOOPBACK */
+
+ /* remember netif specific state information data */
+ netif->state = state;
+ netif->num = netifnum++;
+ netif->input = input;
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
+ netif->loop_cnt_current = 0;
+#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
+
+ netif_set_addr(netif, ipaddr, netmask, gw);
+
+ /* call user specified initialization function for netif */
+ if (init(netif) != ERR_OK) {
+ return NULL;
+ }
+
+ /* add this netif to the list */
+ netif->next = netif_list;
+ netif_list = netif;
+ snmp_inc_iflist();
+
+#if LWIP_IGMP
+ /* start IGMP processing */
+ if (netif->flags & NETIF_FLAG_IGMP) {
+ igmp_start(netif);
+ }
+#endif /* LWIP_IGMP */
+
+ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
+ netif->name[0], netif->name[1]));
+ ip_addr_debug_print(NETIF_DEBUG, ipaddr);
+ LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
+ ip_addr_debug_print(NETIF_DEBUG, netmask);
+ LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
+ ip_addr_debug_print(NETIF_DEBUG, gw);
+ LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
+ return netif;
+}
+
+/**
+ * Change IP address configuration for a network interface (including netmask
+ * and default gateway).
+ *
+ * @param netif the network interface to change
+ * @param ipaddr the new IP address
+ * @param netmask the new netmask
+ * @param gw the new default gateway
+ */
+void
+netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+ ip_addr_t *gw)
+{
+ netif_set_ipaddr(netif, ipaddr);
+ netif_set_netmask(netif, netmask);
+ netif_set_gw(netif, gw);
+}
+
+/**
+ * Remove a network interface from the list of lwIP netifs.
+ *
+ * @param netif the network interface to remove
+ */
+void
+netif_remove(struct netif *netif)
+{
+ if (netif == NULL) {
+ return;
+ }
+
+#if LWIP_IGMP
+ /* stop IGMP processing */
+ if (netif->flags & NETIF_FLAG_IGMP) {
+ igmp_stop(netif);
+ }
+#endif /* LWIP_IGMP */
+ if (netif_is_up(netif)) {
+ /* set netif down before removing (call callback function) */
+ netif_set_down(netif);
+ }
+
+ snmp_delete_ipaddridx_tree(netif);
+
+ /* is it the first netif? */
+ if (netif_list == netif) {
+ netif_list = netif->next;
+ } else {
+ /* look for netif further down the list */
+ struct netif * tmpNetif;
+ for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
+ if (tmpNetif->next == netif) {
+ tmpNetif->next = netif->next;
+ break;
+ }
+ }
+ if (tmpNetif == NULL)
+ return; /* we didn't find any netif today */
+ }
+ snmp_dec_iflist();
+ /* this netif is default? */
+ if (netif_default == netif) {
+ /* reset default netif */
+ netif_set_default(NULL);
+ }
+ LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
+}
+
+/**
+ * Find a network interface by searching for its name
+ *
+ * @param name the name of the netif (like netif->name) plus concatenated number
+ * in ascii representation (e.g. 'en0')
+ */
+struct netif *
+netif_find(char *name)
+{
+ struct netif *netif;
+ u8_t num;
+
+ if (name == NULL) {
+ return NULL;
+ }
+
+ num = name[2] - '0';
+
+ for(netif = netif_list; netif != NULL; netif = netif->next) {
+ if (num == netif->num &&
+ name[0] == netif->name[0] &&
+ name[1] == netif->name[1]) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
+ return netif;
+ }
+ }
+ LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
+ return NULL;
+}
+
+/**
+ * Change the IP address of a network interface
+ *
+ * @param netif the network interface to change
+ * @param ipaddr the new IP address
+ *
+ * @note call netif_set_addr() if you also want to change netmask and
+ * default gateway
+ */
+void
+netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
+{
+ /* Protect against dereferencing NULL pointers by
+ treating like ANY, as does ip_addr_set() */
+ if (!ipaddr) {
+ ipaddr = IP_ADDR_ANY;
+ }
+
+ /* TODO: Handling of obsolete pcbs */
+ /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
+#if LWIP_TCP
+ struct tcp_pcb *pcb;
+ struct tcp_pcb_listen *lpcb;
+
+ /* address is actually being changed? */
+ if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
+ /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
+ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
+ pcb = tcp_active_pcbs;
+ while (pcb != NULL) {
+ /* PCB bound to current local interface address? */
+ if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
+#if LWIP_AUTOIP
+ /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
+ && !ip_addr_islinklocal(&(pcb->local_ip))
+#endif /* LWIP_AUTOIP */
+ ) {
+ /* 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));
+ tcp_abort(pcb);
+ pcb = next;
+ } else {
+ pcb = pcb->next;
+ }
+ }
+ for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+ /* PCB bound to current local interface address? */
+ if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
+ (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
+ /* The PCB is listening to the old ipaddr and
+ * is set to listen to the new one instead */
+ ip_addr_set(&(lpcb->local_ip), ipaddr);
+ }
+ }
+ }
+#endif
+ snmp_delete_ipaddridx_tree(netif);
+ snmp_delete_iprteidx_tree(0,netif);
+ /* set new IP address to netif */
+ ip_addr_set(&(netif->ip_addr), ipaddr);
+ snmp_insert_ipaddridx_tree(netif);
+ snmp_insert_iprteidx_tree(0,netif);
+
+ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ netif->name[0], netif->name[1],
+ ip4_addr1_16(&netif->ip_addr),
+ ip4_addr2_16(&netif->ip_addr),
+ ip4_addr3_16(&netif->ip_addr),
+ ip4_addr4_16(&netif->ip_addr)));
+}
+
+/**
+ * Change the default gateway for a network interface
+ *
+ * @param netif the network interface to change
+ * @param gw the new default gateway
+ *
+ * @note call netif_set_addr() if you also want to change ip address and netmask
+ */
+void
+netif_set_gw(struct netif *netif, ip_addr_t *gw)
+{
+ ip_addr_set(&(netif->gw), gw);
+ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ netif->name[0], netif->name[1],
+ ip4_addr1_16(&netif->gw),
+ ip4_addr2_16(&netif->gw),
+ ip4_addr3_16(&netif->gw),
+ ip4_addr4_16(&netif->gw)));
+}
+
+/**
+ * Change the netmask of a network interface
+ *
+ * @param netif the network interface to change
+ * @param netmask the new netmask
+ *
+ * @note call netif_set_addr() if you also want to change ip address and
+ * default gateway
+ */
+void
+netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
+{
+ snmp_delete_iprteidx_tree(0, netif);
+ /* set new netmask to netif */
+ ip_addr_set(&(netif->netmask), netmask);
+ snmp_insert_iprteidx_tree(0, netif);
+ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ netif->name[0], netif->name[1],
+ ip4_addr1_16(&netif->netmask),
+ ip4_addr2_16(&netif->netmask),
+ ip4_addr3_16(&netif->netmask),
+ ip4_addr4_16(&netif->netmask)));
+}
+
+/**
+ * Set a network interface as the default network interface
+ * (used to output all packets for which no specific route is found)
+ *
+ * @param netif the default network interface
+ */
+void
+netif_set_default(struct netif *netif)
+{
+ if (netif == NULL) {
+ /* remove default route */
+ snmp_delete_iprteidx_tree(1, netif);
+ } else {
+ /* install default route */
+ snmp_insert_iprteidx_tree(1, netif);
+ }
+ netif_default = netif;
+ LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
+ netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
+}
+
+/**
+ * Bring an interface up, available for processing
+ * traffic.
+ *
+ * @note: Enabling DHCP on a down interface will make it come
+ * up once configured.
+ *
+ * @see dhcp_start()
+ */
+void netif_set_up(struct netif *netif)
+{
+ if (!(netif->flags & NETIF_FLAG_UP)) {
+ netif->flags |= NETIF_FLAG_UP;
+
+#if LWIP_SNMP
+ snmp_get_sysuptime(&netif->ts);
+#endif /* LWIP_SNMP */
+
+ NETIF_STATUS_CALLBACK(netif);
+
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+#if LWIP_ARP
+ /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
+ if (netif->flags & (NETIF_FLAG_ETHARP)) {
+ etharp_gratuitous(netif);
+ }
+#endif /* LWIP_ARP */
+
+#if LWIP_IGMP
+ /* resend IGMP memberships */
+ if (netif->flags & NETIF_FLAG_IGMP) {
+ igmp_report_groups( netif);
+ }
+#endif /* LWIP_IGMP */
+ }
+ }
+}
+
+/**
+ * Bring an interface down, disabling any traffic processing.
+ *
+ * @note: Enabling DHCP on a down interface will make it come
+ * up once configured.
+ *
+ * @see dhcp_start()
+ */
+void netif_set_down(struct netif *netif)
+{
+ if (netif->flags & NETIF_FLAG_UP) {
+ netif->flags &= ~NETIF_FLAG_UP;
+#if LWIP_SNMP
+ snmp_get_sysuptime(&netif->ts);
+#endif
+
+ NETIF_STATUS_CALLBACK(netif);
+ }
+}
+
+#if LWIP_NETIF_STATUS_CALLBACK
+/**
+ * Set callback to be called when interface is brought up/down
+ */
+void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
+{
+ if (netif) {
+ netif->status_callback = status_callback;
+ }
+}
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+
+/**
+ * Called by a driver when its link goes up
+ */
+void netif_set_link_up(struct netif *netif )
+{
+ if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
+ netif->flags |= NETIF_FLAG_LINK_UP;
+
+#if LWIP_DHCP
+ if (netif->dhcp) {
+ dhcp_network_changed(netif);
+ }
+#endif /* LWIP_DHCP */
+
+#if LWIP_AUTOIP
+ if (netif->autoip) {
+ autoip_network_changed(netif);
+ }
+#endif /* LWIP_AUTOIP */
+
+ if (netif->flags & NETIF_FLAG_UP) {
+#if LWIP_ARP
+ /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
+ if (netif->flags & NETIF_FLAG_ETHARP) {
+ etharp_gratuitous(netif);
+ }
+#endif /* LWIP_ARP */
+
+#if LWIP_IGMP
+ /* resend IGMP memberships */
+ if (netif->flags & NETIF_FLAG_IGMP) {
+ igmp_report_groups( netif);
+ }
+#endif /* LWIP_IGMP */
+ }
+ NETIF_LINK_CALLBACK(netif);
+ }
+}
+
+/**
+ * Called by a driver when its link goes down
+ */
+void netif_set_link_down(struct netif *netif )
+{
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+ netif->flags &= ~NETIF_FLAG_LINK_UP;
+ NETIF_LINK_CALLBACK(netif);
+ }
+}
+
+#if LWIP_NETIF_LINK_CALLBACK
+/**
+ * Set callback to be called when link is brought up/down
+ */
+void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
+{
+ if (netif) {
+ netif->link_callback = link_callback;
+ }
+}
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#if ENABLE_LOOPBACK
+/**
+ * Send an IP packet to be received on the same netif (loopif-like).
+ * The pbuf is simply copied and handed back to netif->input.
+ * In multithreaded mode, this is done directly since netif->input must put
+ * the packet on a queue.
+ * In callback mode, the packet is put on an internal queue and is fed to
+ * netif->input by netif_poll().
+ *
+ * @param netif the lwip network interface structure
+ * @param p the (IP) packet to 'send'
+ * @param ipaddr the ip address to send the packet to (not used)
+ * @return ERR_OK if the packet has been sent
+ * ERR_MEM if the pbuf used to copy the packet couldn't be allocated
+ */
+err_t
+netif_loop_output(struct netif *netif, struct pbuf *p,
+ ip_addr_t *ipaddr)
+{
+ struct pbuf *r;
+ err_t err;
+ struct pbuf *last;
+#if LWIP_LOOPBACK_MAX_PBUFS
+ u8_t clen = 0;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+ /* If we have a loopif, SNMP counters are adjusted for it,
+ * if not they are adjusted for 'netif'. */
+#if LWIP_SNMP
+#if LWIP_HAVE_LOOPIF
+ struct netif *stats_if = &loop_netif;
+#else /* LWIP_HAVE_LOOPIF */
+ struct netif *stats_if = netif;
+#endif /* LWIP_HAVE_LOOPIF */
+#endif /* LWIP_SNMP */
+ SYS_ARCH_DECL_PROTECT(lev);
+ LWIP_UNUSED_ARG(ipaddr);
+
+ /* Allocate a new pbuf */
+ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+ if (r == NULL) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(stats_if);
+ return ERR_MEM;
+ }
+#if LWIP_LOOPBACK_MAX_PBUFS
+ clen = pbuf_clen(r);
+ /* check for overflow or too many pbuf on queue */
+ if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
+ ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
+ pbuf_free(r);
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(stats_if);
+ return ERR_MEM;
+ }
+ netif->loop_cnt_current += clen;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+
+ /* Copy the whole pbuf queue p into the single pbuf r */
+ if ((err = pbuf_copy(r, p)) != ERR_OK) {
+ pbuf_free(r);
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(stats_if);
+ return err;
+ }
+
+ /* Put the packet on a linked list which gets emptied through calling
+ netif_poll(). */
+
+ /* let last point to the last pbuf in chain r */
+ for (last = r; last->next != NULL; last = last->next);
+
+ SYS_ARCH_PROTECT(lev);
+ if(netif->loop_first != NULL) {
+ LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
+ netif->loop_last->next = r;
+ netif->loop_last = last;
+ } else {
+ netif->loop_first = r;
+ netif->loop_last = last;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+
+ LINK_STATS_INC(link.xmit);
+ snmp_add_ifoutoctets(stats_if, p->tot_len);
+ snmp_inc_ifoutucastpkts(stats_if);
+
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING
+ /* For multithreading environment, schedule a call to netif_poll */
+ tcpip_callback((tcpip_callback_fn)netif_poll, netif);
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+
+ return ERR_OK;
+}
+
+/**
+ * Call netif_poll() in the main loop of your application. This is to prevent
+ * reentering non-reentrant functions like tcp_input(). Packets passed to
+ * netif_loop_output() are put on a list that is passed to netif->input() by
+ * netif_poll().
+ */
+void
+netif_poll(struct netif *netif)
+{
+ struct pbuf *in;
+ /* If we have a loopif, SNMP counters are adjusted for it,
+ * if not they are adjusted for 'netif'. */
+#if LWIP_SNMP
+#if LWIP_HAVE_LOOPIF
+ struct netif *stats_if = &loop_netif;
+#else /* LWIP_HAVE_LOOPIF */
+ struct netif *stats_if = netif;
+#endif /* LWIP_HAVE_LOOPIF */
+#endif /* LWIP_SNMP */
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ do {
+ /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
+ SYS_ARCH_PROTECT(lev);
+ in = netif->loop_first;
+ if (in != NULL) {
+ struct pbuf *in_end = in;
+#if LWIP_LOOPBACK_MAX_PBUFS
+ u8_t clen = pbuf_clen(in);
+ /* adjust the number of pbufs on queue */
+ LWIP_ASSERT("netif->loop_cnt_current underflow",
+ ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
+ netif->loop_cnt_current -= clen;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+ while (in_end->len != in_end->tot_len) {
+ LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
+ in_end = in_end->next;
+ }
+ /* 'in_end' now points to the last pbuf from 'in' */
+ if (in_end == netif->loop_last) {
+ /* this was the last pbuf in the list */
+ netif->loop_first = netif->loop_last = NULL;
+ } else {
+ /* pop the pbuf off the list */
+ netif->loop_first = in_end->next;
+ LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
+ }
+ /* De-queue the pbuf from its successors on the 'loop_' list. */
+ in_end->next = NULL;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+
+ if (in != NULL) {
+ LINK_STATS_INC(link.recv);
+ snmp_add_ifinoctets(stats_if, in->tot_len);
+ snmp_inc_ifinucastpkts(stats_if);
+ /* loopback packets are always IP packets! */
+ if (ip_input(in, netif) != ERR_OK) {
+ pbuf_free(in);
+ }
+ /* Don't reference the packet any more! */
+ in = NULL;
+ }
+ /* go on while there is a packet on the list */
+ } while (netif->loop_first != NULL);
+}
+
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+/**
+ * Calls netif_poll() for every netif on the netif_list.
+ */
+void
+netif_poll_all(void)
+{
+ struct netif *netif = netif_list;
+ /* loop through netifs */
+ while (netif != NULL) {
+ netif_poll(netif);
+ /* proceed to next network interface */
+ netif = netif->next;
+ }
+}
+#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/pbuf.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/pbuf.c
new file mode 100644
index 0000000000..cd37c79723
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/pbuf.c
@@ -0,0 +1,1158 @@
+/**
+ * @file
+ * Packet buffer management
+ *
+ * Packets are built from the pbuf data structure. It supports dynamic
+ * memory allocation for packet contents or can reference externally
+ * managed packet contents both in RAM and ROM. Quick allocation for
+ * incoming packets is provided through pools with fixed sized pbufs.
+ *
+ * A packet may span over multiple pbufs, chained as a singly linked
+ * list. This is called a "pbuf chain".
+ *
+ * Multiple packets may be queued, also using this singly linked list.
+ * This is called a "packet queue".
+ *
+ * So, a packet queue consists of one or more pbuf chains, each of
+ * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
+ * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
+ *
+ * The differences between a pbuf chain and a packet queue are very
+ * precise but subtle.
+ *
+ * The last pbuf of a packet has a ->tot_len field that equals the
+ * ->len field. It can be found by traversing the list. If the last
+ * pbuf of a packet has a ->next field other than NULL, more packets
+ * are on the queue.
+ *
+ * Therefore, looping through a pbuf of a single packet, has an
+ * loop end condition (tot_len == p->len), NOT (next == NULL).
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/stats.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "arch/perf.h"
+#if TCP_QUEUE_OOSEQ
+#include "lwip/tcp_impl.h"
+#endif
+#if LWIP_CHECKSUM_ON_COPY
+#include "lwip/inet_chksum.h"
+#endif
+
+#include <string.h>
+
+#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
+/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
+ aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
+#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
+
+#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
+#define PBUF_POOL_IS_EMPTY()
+#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
+/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
+#ifndef PBUF_POOL_FREE_OOSEQ
+#define PBUF_POOL_FREE_OOSEQ 1
+#endif /* PBUF_POOL_FREE_OOSEQ */
+
+#if PBUF_POOL_FREE_OOSEQ
+#include "lwip/tcpip.h"
+#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
+static u8_t pbuf_free_ooseq_queued;
+/**
+ * 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
+ * if we're running out.
+ *
+ * This must be done in the correct thread context therefore this function
+ * can only be used with NO_SYS=0 and through tcpip_callback.
+ */
+static void
+pbuf_free_ooseq(void* arg)
+{
+ struct tcp_pcb* pcb;
+ SYS_ARCH_DECL_PROTECT(old_level);
+ LWIP_UNUSED_ARG(arg);
+
+ SYS_ARCH_PROTECT(old_level);
+ pbuf_free_ooseq_queued = 0;
+ SYS_ARCH_UNPROTECT(old_level);
+
+ for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
+ if (NULL != pcb->ooseq) {
+ /** Free the ooseq pbufs of one PCB only */
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
+ tcp_segs_free(pcb->ooseq);
+ pcb->ooseq = NULL;
+ return;
+ }
+ }
+}
+
+/** Queue a call to pbuf_free_ooseq if not already queued. */
+static void
+pbuf_pool_is_empty(void)
+{
+ u8_t queued;
+ SYS_ARCH_DECL_PROTECT(old_level);
+
+ SYS_ARCH_PROTECT(old_level);
+ queued = pbuf_free_ooseq_queued;
+ pbuf_free_ooseq_queued = 1;
+ SYS_ARCH_UNPROTECT(old_level);
+
+ if(!queued) {
+ /* queue a call to pbuf_free_ooseq if not already queued */
+ if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
+ SYS_ARCH_PROTECT(old_level);
+ pbuf_free_ooseq_queued = 0;
+ SYS_ARCH_UNPROTECT(old_level);
+ }
+ }
+}
+#endif /* PBUF_POOL_FREE_OOSEQ */
+#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
+
+/**
+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
+ *
+ * The actual memory allocated for the pbuf is determined by the
+ * layer at which the pbuf is allocated and the requested size
+ * (from the size parameter).
+ *
+ * @param layer flag to define header size
+ * @param length size of the pbuf's payload
+ * @param type this parameter decides how and where the pbuf
+ * should be allocated as follows:
+ *
+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large
+ * chunk. This includes protocol headers as well.
+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
+ * protocol headers. Additional headers must be prepended
+ * by allocating another pbuf and chain in to the front of
+ * the ROM pbuf. It is assumed that the memory used is really
+ * similar to ROM in that it is immutable and will not be
+ * changed. Memory which is dynamic should generally not
+ * be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
+ * protocol headers. It is assumed that the pbuf is only
+ * being used in a single thread. If the pbuf gets queued,
+ * then pbuf_take should be called to copy the buffer.
+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
+ * the pbuf pool that is allocated during pbuf_init().
+ *
+ * @return the allocated pbuf. If multiple pbufs where allocated, this
+ * is the first pbuf of a pbuf chain.
+ */
+struct pbuf *
+pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
+{
+ struct pbuf *p, *q, *r;
+ u16_t offset;
+ s32_t rem_len; /* remaining length */
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
+
+ /* determine header offset */
+ offset = 0;
+ switch (layer) {
+ case PBUF_TRANSPORT:
+ /* add room for transport (often TCP) layer header */
+ offset += PBUF_TRANSPORT_HLEN;
+ /* FALLTHROUGH */
+ case PBUF_IP:
+ /* add room for IP layer header */
+ offset += PBUF_IP_HLEN;
+ /* FALLTHROUGH */
+ case PBUF_LINK:
+ /* add room for link layer header */
+ offset += PBUF_LINK_HLEN;
+ break;
+ case PBUF_RAW:
+ break;
+ default:
+ LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
+ return NULL;
+ }
+
+ switch (type) {
+ case PBUF_POOL:
+ /* allocate head of pbuf chain into p */
+ p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
+ if (p == NULL) {
+ PBUF_POOL_IS_EMPTY();
+ return NULL;
+ }
+ p->type = type;
+ p->next = NULL;
+
+ /* make the payload pointer point 'offset' bytes into pbuf data memory */
+ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
+ LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
+ ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
+ /* the total length of the pbuf chain is the requested size */
+ p->tot_len = length;
+ /* set the length of the first pbuf in the chain */
+ p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
+ LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
+ ((u8_t*)p->payload + p->len <=
+ (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
+ LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
+ (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
+ /* set reference count (needed here in case we fail) */
+ p->ref = 1;
+
+ /* now allocate the tail of the pbuf chain */
+
+ /* remember first pbuf for linkage in next iteration */
+ r = p;
+ /* remaining length to be allocated */
+ rem_len = length - p->len;
+ /* any remaining pbufs to be allocated? */
+ while (rem_len > 0) {
+ q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
+ if (q == NULL) {
+ PBUF_POOL_IS_EMPTY();
+ /* free chain so far allocated */
+ pbuf_free(p);
+ /* bail out unsuccesfully */
+ return NULL;
+ }
+ q->type = type;
+ q->flags = 0;
+ q->next = NULL;
+ /* make previous pbuf point to this pbuf */
+ r->next = q;
+ /* set total length of this pbuf and next in chain */
+ LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
+ q->tot_len = (u16_t)rem_len;
+ /* this pbuf length is pool size, unless smaller sized tail */
+ q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
+ q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
+ LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
+ ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
+ LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
+ ((u8_t*)p->payload + p->len <=
+ (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
+ q->ref = 1;
+ /* calculate remaining length to be allocated */
+ rem_len -= q->len;
+ /* remember this pbuf for linkage in next iteration */
+ r = q;
+ }
+ /* end of chain */
+ /*r->next = NULL;*/
+
+ break;
+ case PBUF_RAM:
+ /* If pbuf is to be allocated in RAM, allocate memory for it. */
+ p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
+ if (p == NULL) {
+ return NULL;
+ }
+ /* Set up internal structure of the pbuf. */
+ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
+ p->len = p->tot_len = length;
+ p->next = NULL;
+ p->type = type;
+
+ LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
+ ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
+ break;
+ /* pbuf references existing (non-volatile static constant) ROM payload? */
+ case PBUF_ROM:
+ /* pbuf references existing (externally allocated) RAM payload? */
+ case PBUF_REF:
+ /* only allocate memory for the pbuf structure */
+ p = (struct pbuf *)memp_malloc(MEMP_PBUF);
+ if (p == NULL) {
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
+ (type == PBUF_ROM) ? "ROM" : "REF"));
+ return NULL;
+ }
+ /* caller must set this field properly, afterwards */
+ p->payload = NULL;
+ p->len = p->tot_len = length;
+ p->next = NULL;
+ p->type = type;
+ break;
+ default:
+ LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
+ return NULL;
+ }
+ /* set reference count */
+ p->ref = 1;
+ /* set flags */
+ p->flags = 0;
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
+ return p;
+}
+
+#if LWIP_SUPPORT_CUSTOM_PBUF
+/** Initialize a custom pbuf (already allocated).
+ *
+ * @param layer flag to define header size
+ * @param length size of the pbuf's payload
+ * @param type type of the pbuf (only used to treat the pbuf accordingly, as
+ * this function allocates no memory)
+ * @param p pointer to the custom pbuf to initialize (already allocated)
+ * @param payload_mem pointer to the buffer that is used for payload and headers,
+ * must be at least big enough to hold 'length' plus the header size,
+ * may be NULL if set later
+ * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
+ * big enough to hold 'length' plus the header size
+ */
+struct pbuf*
+pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
+ void *payload_mem, u16_t payload_mem_len)
+{
+ u16_t offset;
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
+
+ /* determine header offset */
+ offset = 0;
+ switch (l) {
+ case PBUF_TRANSPORT:
+ /* add room for transport (often TCP) layer header */
+ offset += PBUF_TRANSPORT_HLEN;
+ /* FALLTHROUGH */
+ case PBUF_IP:
+ /* add room for IP layer header */
+ offset += PBUF_IP_HLEN;
+ /* FALLTHROUGH */
+ case PBUF_LINK:
+ /* add room for link layer header */
+ offset += PBUF_LINK_HLEN;
+ break;
+ case PBUF_RAW:
+ break;
+ default:
+ LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
+ return NULL;
+ }
+
+ if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
+ return NULL;
+ }
+
+ p->pbuf.next = NULL;
+ if (payload_mem != NULL) {
+ p->pbuf.payload = (void *)((u8_t *)payload_mem + offset);
+ } else {
+ p->pbuf.payload = NULL;
+ }
+ p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
+ p->pbuf.len = p->pbuf.tot_len = length;
+ p->pbuf.type = type;
+ p->pbuf.ref = 1;
+ return &p->pbuf;
+}
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+
+/**
+ * Shrink a pbuf chain to a desired length.
+ *
+ * @param p pbuf to shrink.
+ * @param new_len desired new length of pbuf chain
+ *
+ * Depending on the desired length, the first few pbufs in a chain might
+ * be skipped and left unchanged. The new last pbuf in the chain will be
+ * resized, and any remaining pbufs will be freed.
+ *
+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
+ * @note May not be called on a packet queue.
+ *
+ * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
+ */
+void
+pbuf_realloc(struct pbuf *p, u16_t new_len)
+{
+ struct pbuf *q;
+ u16_t rem_len; /* remaining length */
+ s32_t grow;
+
+ LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
+ LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
+ p->type == PBUF_ROM ||
+ p->type == PBUF_RAM ||
+ p->type == PBUF_REF);
+
+ /* desired length larger than current length? */
+ if (new_len >= p->tot_len) {
+ /* enlarging not yet supported */
+ return;
+ }
+
+ /* the pbuf chain grows by (new_len - p->tot_len) bytes
+ * (which may be negative in case of shrinking) */
+ grow = new_len - p->tot_len;
+
+ /* first, step over any pbufs that should remain in the chain */
+ rem_len = new_len;
+ q = p;
+ /* should this pbuf be kept? */
+ while (rem_len > q->len) {
+ /* decrease remaining length by pbuf length */
+ rem_len -= q->len;
+ /* decrease total length indicator */
+ LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
+ q->tot_len += (u16_t)grow;
+ /* proceed to next pbuf in chain */
+ q = q->next;
+ LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
+ }
+ /* we have now reached the new last pbuf (in q) */
+ /* rem_len == desired length for pbuf q */
+
+ /* shrink allocated memory for PBUF_RAM */
+ /* (other types merely adjust their length fields */
+ if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
+ /* reallocate and adjust the length of the pbuf that will be split */
+ q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
+ LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
+ }
+ /* adjust length fields for new last pbuf */
+ q->len = rem_len;
+ q->tot_len = q->len;
+
+ /* any remaining pbufs in chain? */
+ if (q->next != NULL) {
+ /* free remaining pbufs in chain */
+ pbuf_free(q->next);
+ }
+ /* q is last packet in chain */
+ q->next = NULL;
+
+}
+
+/**
+ * Adjusts the payload pointer to hide or reveal headers in the payload.
+ *
+ * Adjusts the ->payload pointer so that space for a header
+ * (dis)appears in the pbuf payload.
+ *
+ * The ->payload, ->tot_len and ->len fields are adjusted.
+ *
+ * @param p pbuf to change the header size.
+ * @param header_size_increment Number of bytes to increment header size which
+ * increases the size of the pbuf. New space is on the front.
+ * (Using a negative value decreases the header size.)
+ * If hdr_size_inc is 0, this function does nothing and returns succesful.
+ *
+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
+ * the call will fail. A check is made that the increase in header size does
+ * not move the payload pointer in front of the start of the buffer.
+ * @return non-zero on failure, zero on success.
+ *
+ */
+u8_t
+pbuf_header(struct pbuf *p, s16_t header_size_increment)
+{
+ u16_t type;
+ void *payload;
+ u16_t increment_magnitude;
+
+ LWIP_ASSERT("p != NULL", p != NULL);
+ if ((header_size_increment == 0) || (p == NULL)) {
+ return 0;
+ }
+
+ if (header_size_increment < 0){
+ increment_magnitude = -header_size_increment;
+ /* Check that we aren't going to move off the end of the pbuf */
+ LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
+ } else {
+ increment_magnitude = header_size_increment;
+#if 0
+ /* Can't assert these as some callers speculatively call
+ pbuf_header() to see if it's OK. Will return 1 below instead. */
+ /* Check that we've got the correct type of pbuf to work with */
+ LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
+ p->type == PBUF_RAM || p->type == PBUF_POOL);
+ /* Check that we aren't going to move off the beginning of the pbuf */
+ LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
+ (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
+#endif
+ }
+
+ type = p->type;
+ /* remember current payload pointer */
+ payload = p->payload;
+
+ /* pbuf types containing payloads? */
+ if (type == PBUF_RAM || type == PBUF_POOL) {
+ /* set new payload pointer */
+ p->payload = (u8_t *)p->payload - header_size_increment;
+ /* boundary check fails? */
+ if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
+ LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
+ (void *)p->payload, (void *)(p + 1)));
+ /* restore old payload pointer */
+ p->payload = payload;
+ /* bail out unsuccesfully */
+ return 1;
+ }
+ /* pbuf types refering to external payloads? */
+ } else if (type == PBUF_REF || type == PBUF_ROM) {
+ /* hide a header in the payload? */
+ if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
+ /* increase payload pointer */
+ p->payload = (u8_t *)p->payload - header_size_increment;
+ } else {
+ /* cannot expand payload to front (yet!)
+ * bail out unsuccesfully */
+ return 1;
+ }
+ } else {
+ /* Unknown type */
+ LWIP_ASSERT("bad pbuf type", 0);
+ return 1;
+ }
+ /* modify pbuf length fields */
+ p->len += header_size_increment;
+ p->tot_len += header_size_increment;
+
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
+ (void *)payload, (void *)p->payload, header_size_increment));
+
+ return 0;
+}
+
+/**
+ * Dereference a pbuf chain or queue and deallocate any no-longer-used
+ * pbufs at the head of this chain or queue.
+ *
+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is
+ * deallocated.
+ *
+ * For a pbuf chain, this is repeated for each pbuf in the chain,
+ * up to the first pbuf which has a non-zero reference count after
+ * decrementing. So, when all reference counts are one, the whole
+ * chain is free'd.
+ *
+ * @param p The pbuf (chain) to be dereferenced.
+ *
+ * @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).
+ *
+ * @internal examples:
+ *
+ * Assuming existing chains a->b->c with the following reference
+ * counts, calling pbuf_free(a) results in:
+ *
+ * 1->2->3 becomes ...1->3
+ * 3->3->3 becomes 2->3->3
+ * 1->1->2 becomes ......1
+ * 2->1->1 becomes 1->1->1
+ * 1->1->1 becomes .......
+ *
+ */
+u8_t
+pbuf_free(struct pbuf *p)
+{
+ u16_t type;
+ struct pbuf *q;
+ u8_t count;
+
+ if (p == NULL) {
+ LWIP_ASSERT("p != NULL", p != NULL);
+ /* if assertions are disabled, proceed with debug output */
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("pbuf_free(p == NULL) was called.\n"));
+ return 0;
+ }
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
+
+ PERF_START;
+
+ LWIP_ASSERT("pbuf_free: sane type",
+ p->type == PBUF_RAM || p->type == PBUF_ROM ||
+ p->type == PBUF_REF || p->type == PBUF_POOL);
+
+ count = 0;
+ /* de-allocate all consecutive pbufs from the head of the chain that
+ * obtain a zero reference count after decrementing*/
+ while (p != NULL) {
+ u16_t ref;
+ SYS_ARCH_DECL_PROTECT(old_level);
+ /* Since decrementing ref cannot be guaranteed to be a single machine operation
+ * we must protect it. We put the new ref into a local variable to prevent
+ * further protection. */
+ SYS_ARCH_PROTECT(old_level);
+ /* all pbufs in a chain are referenced at least once */
+ LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
+ /* decrease reference count (number of pointers to pbuf) */
+ ref = --(p->ref);
+ SYS_ARCH_UNPROTECT(old_level);
+ /* this pbuf is no longer referenced to? */
+ if (ref == 0) {
+ /* remember next pbuf in chain for next iteration */
+ q = p->next;
+ LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
+ type = p->type;
+#if LWIP_SUPPORT_CUSTOM_PBUF
+ /* is this a custom pbuf? */
+ if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
+ 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);
+ } else
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+ {
+ /* is this a pbuf from the pool? */
+ if (type == PBUF_POOL) {
+ memp_free(MEMP_PBUF_POOL, p);
+ /* is this a ROM or RAM referencing pbuf? */
+ } else if (type == PBUF_ROM || type == PBUF_REF) {
+ memp_free(MEMP_PBUF, p);
+ /* type == PBUF_RAM */
+ } else {
+ mem_free(p);
+ }
+ }
+ count++;
+ /* proceed to next pbuf */
+ p = q;
+ /* p->ref > 0, this pbuf is still referenced to */
+ /* (and so the remaining pbufs in chain as well) */
+ } else {
+ LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
+ /* stop walking through the chain */
+ p = NULL;
+ }
+ }
+ PERF_STOP("pbuf_free");
+ /* return number of de-allocated pbufs */
+ return count;
+}
+
+/**
+ * Count number of pbufs in a chain
+ *
+ * @param p first pbuf of chain
+ * @return the number of pbufs in a chain
+ */
+
+u8_t
+pbuf_clen(struct pbuf *p)
+{
+ u8_t len;
+
+ len = 0;
+ while (p != NULL) {
+ ++len;
+ p = p->next;
+ }
+ return len;
+}
+
+/**
+ * Increment the reference count of the pbuf.
+ *
+ * @param p pbuf to increase reference counter of
+ *
+ */
+void
+pbuf_ref(struct pbuf *p)
+{
+ SYS_ARCH_DECL_PROTECT(old_level);
+ /* pbuf given? */
+ if (p != NULL) {
+ SYS_ARCH_PROTECT(old_level);
+ ++(p->ref);
+ SYS_ARCH_UNPROTECT(old_level);
+ }
+}
+
+/**
+ * Concatenate two pbufs (each may be a pbuf chain) and take over
+ * the caller's reference of the tail pbuf.
+ *
+ * @note The caller MAY NOT reference the tail pbuf afterwards.
+ * Use pbuf_chain() for that purpose.
+ *
+ * @see pbuf_chain()
+ */
+
+void
+pbuf_cat(struct pbuf *h, struct pbuf *t)
+{
+ struct pbuf *p;
+
+ LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
+ ((h != NULL) && (t != NULL)), return;);
+
+ /* 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 += 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 += 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,
+ * so netto there is no change to the reference count of t.
+ */
+}
+
+/**
+ * Chain two pbufs (or pbuf chains) together.
+ *
+ * The caller MUST call pbuf_free(t) once it has stopped
+ * using it. Use pbuf_cat() instead if you no longer use t.
+ *
+ * @param h head pbuf (chain)
+ * @param t tail pbuf (chain)
+ * @note The pbufs MUST belong to the same packet.
+ * @note MAY NOT be called on a packet queue.
+ *
+ * The ->tot_len fields of all pbufs of the head chain are adjusted.
+ * The ->next field of the last pbuf of the head chain is adjusted.
+ * The ->ref field of the first pbuf of the tail chain is adjusted.
+ *
+ */
+void
+pbuf_chain(struct pbuf *h, struct pbuf *t)
+{
+ pbuf_cat(h, t);
+ /* t is now referenced by h */
+ pbuf_ref(t);
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
+}
+
+/**
+ * Dechains the first pbuf from its succeeding pbufs in the chain.
+ *
+ * Makes p->tot_len field equal to p->len.
+ * @param p pbuf to dechain
+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.
+ * @note May not be called on a packet queue.
+ */
+struct pbuf *
+pbuf_dechain(struct pbuf *p)
+{
+ struct pbuf *q;
+ u8_t tail_gone = 1;
+ /* tail */
+ q = p->next;
+ /* pbuf has successor in chain? */
+ if (q != NULL) {
+ /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+ LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
+ /* enforce invariant if assertion is disabled */
+ q->tot_len = p->tot_len - p->len;
+ /* decouple pbuf from remainder */
+ p->next = NULL;
+ /* total length of pbuf p is its own length only */
+ p->tot_len = p->len;
+ /* q is no longer referenced by p, free it */
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
+ tail_gone = pbuf_free(q);
+ if (tail_gone > 0) {
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
+ ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
+ }
+ /* return remaining tail or NULL if deallocated */
+ }
+ /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+ LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
+ return ((tail_gone > 0) ? NULL : q);
+}
+
+/**
+ *
+ * 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);
+ *
+ * @note Only one packet is copied, no packet queue!
+ *
+ * @param p_to pbuf destination of the copy
+ * @param p_from pbuf source of the copy
+ *
+ * @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_t
+pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
+{
+ u16_t offset_to=0, offset_from=0, len;
+
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
+ (void*)p_to, (void*)p_from));
+
+ /* is the target big enough to hold the source? */
+ LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
+ (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
+
+ /* iterate through pbuf chain */
+ do
+ {
+ LWIP_ASSERT("p_to != NULL", p_to != NULL);
+ /* 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 = p_from->len - offset_from;
+ } else {
+ /* current p_from does not fit into current p_to */
+ len = p_to->len - offset_to;
+ }
+ MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
+ offset_to += len;
+ offset_from += len;
+ LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
+ if (offset_to == p_to->len) {
+ /* on to next p_to (if any) */
+ offset_to = 0;
+ p_to = p_to->next;
+ }
+ LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
+ if (offset_from >= p_from->len) {
+ /* on to next p_from (if any) */
+ offset_from = 0;
+ p_from = p_from->next;
+ }
+
+ if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
+ /* don't copy more than one packet! */
+ LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
+ (p_from->next == NULL), return ERR_VAL;);
+ }
+ if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
+ /* don't copy more than one packet! */
+ LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
+ (p_to->next == NULL), return ERR_VAL;);
+ }
+ } while (p_from);
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
+ return ERR_OK;
+}
+
+/**
+ * Copy (part of) the contents of a packet buffer
+ * to an application supplied buffer.
+ *
+ * @param buf the pbuf from which to copy data
+ * @param dataptr 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 offset offset into the packet buffer from where to begin copying len bytes
+ * @return the number of bytes copied, or 0 on failure
+ */
+u16_t
+pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
+{
+ struct pbuf *p;
+ u16_t left;
+ u16_t buf_copy_len;
+ u16_t copied_total = 0;
+
+ LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
+ LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
+
+ left = 0;
+
+ if((buf == NULL) || (dataptr == NULL)) {
+ return 0;
+ }
+
+ /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
+ for(p = buf; len != 0 && p != NULL; p = p->next) {
+ if ((offset != 0) && (offset >= p->len)) {
+ /* don't copy from this buffer -> on to the next */
+ offset -= p->len;
+ } else {
+ /* copy from this buffer. maybe only partially. */
+ buf_copy_len = p->len - offset;
+ if (buf_copy_len > len)
+ buf_copy_len = len;
+ /* copy the necessary parts of the buffer */
+ MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
+ copied_total += buf_copy_len;
+ left += buf_copy_len;
+ len -= buf_copy_len;
+ offset = 0;
+ }
+ }
+ return copied_total;
+}
+
+/**
+ * Copy application supplied data into a pbuf.
+ * This function can only be used to copy the equivalent of buf->tot_len data.
+ *
+ * @param buf pbuf to fill with data
+ * @param dataptr application supplied data buffer
+ * @param len length of the application supplied data buffer
+ *
+ * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
+ */
+err_t
+pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
+{
+ struct pbuf *p;
+ u16_t buf_copy_len;
+ u16_t total_copy_len = len;
+ u16_t copied_total = 0;
+
+ LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
+ LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
+
+ if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
+ return ERR_ARG;
+ }
+
+ /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
+ for(p = buf; total_copy_len != 0; p = p->next) {
+ LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
+ buf_copy_len = total_copy_len;
+ if (buf_copy_len > p->len) {
+ /* this pbuf cannot hold all remaining data */
+ buf_copy_len = p->len;
+ }
+ /* copy the necessary parts of the buffer */
+ MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
+ total_copy_len -= buf_copy_len;
+ copied_total += buf_copy_len;
+ }
+ LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
+ return ERR_OK;
+}
+
+/**
+ * Creates a single pbuf out of a queue of pbufs.
+ *
+ * @remark: Either the source pbuf 'p' is freed by this function or the original
+ * pbuf 'p' is returned, therefore the caller has to check the result!
+ *
+ * @param p the source pbuf
+ * @param layer pbuf_layer of the new pbuf
+ *
+ * @return a new, single pbuf (p->next is NULL)
+ * or the old pbuf if allocation fails
+ */
+struct pbuf*
+pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
+{
+ struct pbuf *q;
+ err_t err;
+ if (p->next == NULL) {
+ return p;
+ }
+ q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
+ if (q == NULL) {
+ /* @todo: what do we do now? */
+ return p;
+ }
+ err = pbuf_copy(q, p);
+ LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
+ /* next line references err variable even if LWIP_ASSERT is ignored. */
+ (void)err;
+ pbuf_free(p);
+ return q;
+}
+
+#if LWIP_CHECKSUM_ON_COPY
+/**
+ * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
+ * the checksum while copying
+ *
+ * @param p the pbuf to copy data into
+ * @param start_offset offset of p->payload where to copy the data to
+ * @param dataptr data to copy into the pbuf
+ * @param len length of data to copy into the pbuf
+ * @param chksum pointer to the checksum which is updated
+ * @return ERR_OK if successful, another error if the data does not fit
+ * within the (first) pbuf (no pbuf queues!)
+ */
+err_t
+pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
+ u16_t len, u16_t *chksum)
+{
+ u32_t acc;
+ u16_t copy_chksum;
+ char *dst_ptr;
+ LWIP_ASSERT("p != NULL", p != NULL);
+ LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
+ LWIP_ASSERT("chksum != NULL", chksum != NULL);
+ LWIP_ASSERT("len != 0", len != 0);
+
+ if ((start_offset >= p->len) || (start_offset + len > p->len)) {
+ return ERR_ARG;
+ }
+
+ dst_ptr = ((char*)p->payload) + start_offset;
+ copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
+ if ((start_offset & 1) != 0) {
+ copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
+ }
+ acc = *chksum;
+ acc += copy_chksum;
+ *chksum = FOLD_U32T(acc);
+ return ERR_OK;
+}
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+ /** Get one byte from the specified position in a pbuf
+ * WARNING: returns zero for offset >= p->tot_len
+ *
+ * @param p pbuf to parse
+ * @param offset offset into p of the byte to return
+ * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
+ */
+u8_t
+pbuf_get_at(struct pbuf* p, u16_t offset)
+{
+ u16_t copy_from = offset;
+ struct pbuf* q = p;
+
+ /* get the correct pbuf */
+ while ((q != NULL) && (q->len <= copy_from)) {
+ copy_from -= q->len;
+ q = q->next;
+ }
+ /* return requested data if pbuf is OK */
+ if ((q != NULL) && (q->len > copy_from)) {
+ return ((u8_t*)q->payload)[copy_from];
+ }
+ return 0;
+}
+
+/** Compare pbuf contents at specified offset with memory s2, both of length n
+ *
+ * @param p pbuf to compare
+ * @param offset offset into p at wich to start comparing
+ * @param s2 buffer to compare
+ * @param n length of buffer to compare
+ * @return zero if equal, nonzero otherwise
+ * (0xffff if p is too short, diffoffset+1 otherwise)
+ */
+u16_t
+pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
+{
+ u16_t start = offset;
+ struct pbuf* q = p;
+
+ /* get the correct pbuf */
+ while ((q != NULL) && (q->len <= start)) {
+ start -= q->len;
+ q = q->next;
+ }
+ /* return requested data if pbuf is OK */
+ if ((q != NULL) && (q->len > start)) {
+ u16_t i;
+ for(i = 0; i < n; i++) {
+ u8_t a = pbuf_get_at(q, start + i);
+ u8_t b = ((u8_t*)s2)[i];
+ if (a != b) {
+ return i+1;
+ }
+ }
+ return 0;
+ }
+ return 0xffff;
+}
+
+/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
+ * start_offset.
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ * return value 'not found'
+ * @param mem search for the contents of this buffer
+ * @param mem_len length of 'mem'
+ * @param start_offset offset into p at which to start searching
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
+{
+ u16_t i;
+ u16_t max = p->tot_len - mem_len;
+ if (p->tot_len >= mem_len + start_offset) {
+ for(i = start_offset; i <= max; ) {
+ u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
+ if (plus == 0) {
+ return i;
+ } else {
+ i += plus;
+ }
+ }
+ }
+ return 0xFFFF;
+}
+
+/** Find occurrence of substr with length substr_len in pbuf p, start at offset
+ * start_offset
+ * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
+ * the pbuf/source string!
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ * return value 'not found'
+ * @param substr string to search for in p, maximum length is 0xFFFE
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_strstr(struct pbuf* p, const char* substr)
+{
+ size_t substr_len;
+ if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
+ return 0xFFFF;
+ }
+ substr_len = strlen(substr);
+ if (substr_len >= 0xFFFF) {
+ return 0xFFFF;
+ }
+ return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
+}
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/raw.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/raw.c
new file mode 100644
index 0000000000..9fcb100316
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/raw.c
@@ -0,0 +1,354 @@
+/**
+ * @file
+ * Implementation of raw protocol PCBs for low-level handling of
+ * different types of protocols besides (or overriding) those
+ * already available in lwIP.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/memp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/raw.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** The list of RAW PCBs */
+static struct raw_pcb *raw_pcbs;
+
+/**
+ * Determine if in incoming IP packet is covered by a RAW PCB
+ * and if so, pass it to a user-provided receive callback function.
+ *
+ * Given an incoming IP datagram (as a chain of pbufs) this function
+ * finds a corresponding RAW PCB and calls the corresponding receive
+ * callback function.
+ *
+ * @param p pbuf to be demultiplexed to a RAW PCB.
+ * @param inp network interface on which the datagram was received.
+ * @return - 1 if the packet has been eaten by a RAW PCB receive
+ * callback function. The caller MAY NOT not reference the
+ * packet any longer, and MAY NOT call pbuf_free().
+ * @return - 0 if packet is not eaten (pbuf is still referenced by the
+ * caller).
+ *
+ */
+u8_t
+raw_input(struct pbuf *p, struct netif *inp)
+{
+ struct raw_pcb *pcb, *prev;
+ struct ip_hdr *iphdr;
+ s16_t proto;
+ u8_t eaten = 0;
+
+ LWIP_UNUSED_ARG(inp);
+
+ iphdr = (struct ip_hdr *)p->payload;
+ proto = IPH_PROTO(iphdr);
+
+ prev = NULL;
+ pcb = raw_pcbs;
+ /* loop through all raw pcbs until the packet is eaten by one */
+ /* this allows multiple pcbs to match against the packet by design */
+ while ((eaten == 0) && (pcb != NULL)) {
+ if ((pcb->protocol == proto) &&
+ (ip_addr_isany(&pcb->local_ip) ||
+ ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
+#if IP_SOF_BROADCAST_RECV
+ /* broadcast filter? */
+ if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
+#endif /* IP_SOF_BROADCAST_RECV */
+ {
+ /* receive callback function available? */
+ if (pcb->recv != NULL) {
+ /* the receive callback function did not eat the packet? */
+ if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
+ /* receive function ate the packet */
+ p = NULL;
+ eaten = 1;
+ if (prev != NULL) {
+ /* move the pcb to the front of raw_pcbs so that is
+ found faster next time */
+ prev->next = pcb->next;
+ pcb->next = raw_pcbs;
+ raw_pcbs = pcb;
+ }
+ }
+ }
+ /* no receive callback function was set for this raw PCB */
+ }
+ /* drop the packet */
+ }
+ prev = pcb;
+ pcb = pcb->next;
+ }
+ return eaten;
+}
+
+/**
+ * Bind a RAW PCB.
+ *
+ * @param pcb RAW PCB to be bound with a local address ipaddr.
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
+ * bind to all local interfaces.
+ *
+ * @return lwIP error code.
+ * - ERR_OK. Successful. No error occured.
+ * - ERR_USE. The specified IP address is already bound to by
+ * another RAW PCB.
+ *
+ * @see raw_disconnect()
+ */
+err_t
+raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+{
+ ip_addr_set(&pcb->local_ip, ipaddr);
+ return ERR_OK;
+}
+
+/**
+ * Connect an RAW PCB. This function is required by upper layers
+ * of lwip. Using the raw api you could use raw_sendto() instead
+ *
+ * This will associate the RAW PCB with the remote address.
+ *
+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.
+ * @param ipaddr remote IP address to connect with.
+ *
+ * @return lwIP error code
+ *
+ * @see raw_disconnect() and raw_sendto()
+ */
+err_t
+raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+{
+ ip_addr_set(&pcb->remote_ip, ipaddr);
+ return ERR_OK;
+}
+
+
+/**
+ * Set the callback function for received packets that match the
+ * raw PCB's protocol and binding.
+ *
+ * The callback function MUST either
+ * - eat the packet by calling pbuf_free() and returning non-zero. The
+ * packet will not be passed to other raw PCBs or other protocol layers.
+ * - not free the packet, and return zero. The packet will be matched
+ * against further PCBs and/or forwarded to another protocol layers.
+ *
+ * @return non-zero if the packet was free()d, zero if the packet remains
+ * available for others.
+ */
+void
+raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
+{
+ /* remember recv() callback and user data */
+ pcb->recv = recv;
+ pcb->recv_arg = recv_arg;
+}
+
+/**
+ * Send the raw IP packet to the given address. Note that actually you cannot
+ * modify the IP headers (this is inconsistent with the receive callback where
+ * you actually get the IP headers), you can only specify the IP payload here.
+ * It requires some more changes in lwIP. (there will be a raw_send() function
+ * then.)
+ *
+ * @param pcb the raw pcb which to send
+ * @param p the IP payload to send
+ * @param ipaddr the destination address of the IP packet
+ *
+ */
+err_t
+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
+{
+ err_t err;
+ struct netif *netif;
+ ip_addr_t *src_ip;
+ struct pbuf *q; /* q will be sent down the stack */
+
+ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
+
+ /* not enough space to add an IP header to first pbuf in given p chain? */
+ if (pbuf_header(p, IP_HLEN)) {
+ /* allocate header in new pbuf */
+ q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
+ /* new header pbuf could not be allocated? */
+ if (q == NULL) {
+ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
+ return ERR_MEM;
+ }
+ if (p->tot_len != 0) {
+ /* chain header q in front of given pbuf p */
+ pbuf_chain(q, p);
+ }
+ /* { first pbuf q points to header pbuf } */
+ LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
+ } else {
+ /* first pbuf q equals given pbuf */
+ q = p;
+ if(pbuf_header(q, -IP_HLEN)) {
+ LWIP_ASSERT("Can't restore header we just removed!", 0);
+ return ERR_MEM;
+ }
+ }
+
+ if ((netif = ip_route(ipaddr)) == NULL) {
+ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+ /* free any temporary header pbuf allocated by pbuf_header() */
+ if (q != p) {
+ pbuf_free(q);
+ }
+ return ERR_RTE;
+ }
+
+#if IP_SOF_BROADCAST
+ /* broadcast filter? */
+ if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
+ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+ /* free any temporary header pbuf allocated by pbuf_header() */
+ if (q != p) {
+ pbuf_free(q);
+ }
+ return ERR_VAL;
+ }
+#endif /* IP_SOF_BROADCAST */
+
+ if (ip_addr_isany(&pcb->local_ip)) {
+ /* use outgoing network interface IP address as source address */
+ src_ip = &(netif->ip_addr);
+ } else {
+ /* use RAW PCB local IP address as source address */
+ src_ip = &(pcb->local_ip);
+ }
+
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = &(pcb->addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+ /* did we chain a header earlier? */
+ if (q != p) {
+ /* free the header */
+ pbuf_free(q);
+ }
+ return err;
+}
+
+/**
+ * Send the raw IP packet to the address given by raw_connect()
+ *
+ * @param pcb the raw pcb which to send
+ * @param p the IP payload to send
+ *
+ */
+err_t
+raw_send(struct raw_pcb *pcb, struct pbuf *p)
+{
+ return raw_sendto(pcb, p, &pcb->remote_ip);
+}
+
+/**
+ * Remove an RAW PCB.
+ *
+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of
+ * RAW PCB's and the data structure is freed from memory.
+ *
+ * @see raw_new()
+ */
+void
+raw_remove(struct raw_pcb *pcb)
+{
+ struct raw_pcb *pcb2;
+ /* pcb to be removed is first in list? */
+ if (raw_pcbs == pcb) {
+ /* make list start at 2nd pcb */
+ raw_pcbs = raw_pcbs->next;
+ /* pcb not 1st in list */
+ } else {
+ for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
+ /* find pcb in raw_pcbs list */
+ if (pcb2->next != NULL && pcb2->next == pcb) {
+ /* remove pcb from list */
+ pcb2->next = pcb->next;
+ }
+ }
+ }
+ memp_free(MEMP_RAW_PCB, pcb);
+}
+
+/**
+ * Create a RAW PCB.
+ *
+ * @return The RAW PCB which was created. NULL if the PCB data structure
+ * could not be allocated.
+ *
+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
+ *
+ * @see raw_remove()
+ */
+struct raw_pcb *
+raw_new(u8_t proto)
+{
+ struct raw_pcb *pcb;
+
+ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
+
+ pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
+ /* could allocate RAW PCB? */
+ if (pcb != NULL) {
+ /* initialize PCB to all zeroes */
+ memset(pcb, 0, sizeof(struct raw_pcb));
+ pcb->protocol = proto;
+ pcb->ttl = RAW_TTL;
+ pcb->next = raw_pcbs;
+ raw_pcbs = pcb;
+ }
+ return pcb;
+}
+
+#endif /* LWIP_RAW */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_dec.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_dec.c
new file mode 100644
index 0000000000..1d5658207a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_dec.c
@@ -0,0 +1,657 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding
+ *
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp_asn1.h"
+
+/**
+ * Retrieves type field from incoming pbuf chain.
+ *
+ * @param p points to a pbuf holding an ASN1 coded type field
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
+ * @param type return ASN1 type
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+ *type = *msg_ptr;
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Decodes length field from incoming pbuf chain into host length.
+ *
+ * @param p points to a pbuf holding an ASN1 coded length
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
+ * @param octets_used returns number of octets used by the length code
+ * @param length return host order length, upto 64k
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ if (*msg_ptr < 0x80)
+ {
+ /* primitive definite length format */
+ *octets_used = 1;
+ *length = *msg_ptr;
+ return ERR_OK;
+ }
+ else if (*msg_ptr == 0x80)
+ {
+ /* constructed indefinite length format, termination with two zero octets */
+ u8_t zeros;
+ u8_t i;
+
+ *length = 0;
+ zeros = 0;
+ while (zeros != 2)
+ {
+ i = 2;
+ while (i > 0)
+ {
+ i--;
+ (*length) += 1;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ if (*msg_ptr == 0)
+ {
+ zeros++;
+ if (zeros == 2)
+ {
+ /* stop while (i > 0) */
+ i = 0;
+ }
+ }
+ else
+ {
+ zeros = 0;
+ }
+ }
+ }
+ *octets_used = 1;
+ return ERR_OK;
+ }
+ else if (*msg_ptr == 0x81)
+ {
+ /* constructed definite length format, one octet */
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ *length = *msg_ptr;
+ *octets_used = 2;
+ return ERR_OK;
+ }
+ else if (*msg_ptr == 0x82)
+ {
+ u8_t i;
+
+ /* constructed definite length format, two octets */
+ i = 2;
+ while (i > 0)
+ {
+ i--;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ if (i == 0)
+ {
+ /* least significant length octet */
+ *length |= *msg_ptr;
+ }
+ else
+ {
+ /* most significant length octet */
+ *length = (*msg_ptr) << 8;
+ }
+ }
+ *octets_used = 3;
+ return ERR_OK;
+ }
+ else
+ {
+ /* constructed definite length format 3..127 octets, this is too big (>64k) */
+ /** @todo: do we need to accept inefficient codings with many leading zero's? */
+ *octets_used = 1 + ((*msg_ptr) & 0x7f);
+ return ERR_ARG;
+ }
+ }
+ p = p->next;
+ }
+
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded integer
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
+ * @param len length of the coded integer field
+ * @param value return host order integer
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ *
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
+ */
+err_t
+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+ if ((len > 0) && (len < 6))
+ {
+ /* start from zero */
+ *value = 0;
+ if (*msg_ptr & 0x80)
+ {
+ /* negative, expecting zero sign bit! */
+ return ERR_ARG;
+ }
+ else
+ {
+ /* positive */
+ if ((len > 1) && (*msg_ptr == 0))
+ {
+ /* skip leading "sign byte" octet 0x00 */
+ len--;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ }
+ /* OR octets with value */
+ while (len > 1)
+ {
+ len--;
+ *value |= *msg_ptr;
+ *value <<= 8;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ *value |= *msg_ptr;
+ return ERR_OK;
+ }
+ else
+ {
+ return ERR_ARG;
+ }
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Decodes integer into s32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded integer
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
+ * @param len length of the coded integer field
+ * @param value return host order integer
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ *
+ * @note ASN coded integers are _always_ signed!
+ */
+err_t
+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u8_t *lsb_ptr = (u8_t*)value;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
+#endif
+ u8_t sign;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+ if ((len > 0) && (len < 5))
+ {
+ if (*msg_ptr & 0x80)
+ {
+ /* negative, start from -1 */
+ *value = -1;
+ sign = 1;
+ }
+ else
+ {
+ /* positive, start from 0 */
+ *value = 0;
+ sign = 0;
+ }
+ /* OR/AND octets with value */
+ while (len > 1)
+ {
+ len--;
+ if (sign)
+ {
+ *lsb_ptr &= *msg_ptr;
+ *value <<= 8;
+ *lsb_ptr |= 255;
+ }
+ else
+ {
+ *lsb_ptr |= *msg_ptr;
+ *value <<= 8;
+ }
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ if (sign)
+ {
+ *lsb_ptr &= *msg_ptr;
+ }
+ else
+ {
+ *lsb_ptr |= *msg_ptr;
+ }
+ return ERR_OK;
+ }
+ else
+ {
+ return ERR_ARG;
+ }
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Decodes object identifier from incoming message into array of s32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded object identifier
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
+ * @param len length of the coded object identifier
+ * @param oid return object identifier struct
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+ s32_t *oid_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ oid->len = 0;
+ oid_ptr = &oid->id[0];
+ if (len > 0)
+ {
+ /* first compressed octet */
+ if (*msg_ptr == 0x2B)
+ {
+ /* (most) common case 1.3 (iso.org) */
+ *oid_ptr = 1;
+ oid_ptr++;
+ *oid_ptr = 3;
+ oid_ptr++;
+ }
+ else if (*msg_ptr < 40)
+ {
+ *oid_ptr = 0;
+ oid_ptr++;
+ *oid_ptr = *msg_ptr;
+ oid_ptr++;
+ }
+ else if (*msg_ptr < 80)
+ {
+ *oid_ptr = 1;
+ oid_ptr++;
+ *oid_ptr = (*msg_ptr) - 40;
+ oid_ptr++;
+ }
+ else
+ {
+ *oid_ptr = 2;
+ oid_ptr++;
+ *oid_ptr = (*msg_ptr) - 80;
+ oid_ptr++;
+ }
+ oid->len = 2;
+ }
+ else
+ {
+ /* accepting zero length identifiers e.g. for
+ getnext operation. uncommon but valid */
+ return ERR_OK;
+ }
+ len--;
+ if (len > 0)
+ {
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
+ {
+ /* sub-identifier uses multiple octets */
+ if (*msg_ptr & 0x80)
+ {
+ s32_t sub_id = 0;
+
+ while ((*msg_ptr & 0x80) && (len > 1))
+ {
+ len--;
+ sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ if (!(*msg_ptr & 0x80) && (len > 0))
+ {
+ /* last octet sub-identifier */
+ len--;
+ sub_id = (sub_id << 7) + *msg_ptr;
+ *oid_ptr = sub_id;
+ }
+ }
+ else
+ {
+ /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
+ len--;
+ *oid_ptr = *msg_ptr;
+ }
+ if (len > 0)
+ {
+ /* remaining oid bytes available ... */
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ oid_ptr++;
+ oid->len++;
+ }
+ if (len == 0)
+ {
+ /* len == 0, end of oid */
+ return ERR_OK;
+ }
+ else
+ {
+ /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
+ return ERR_ARG;
+ }
+
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
+ * from incoming message into array.
+ *
+ * @param p points to a pbuf holding an ASN1 coded raw data
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)
+ * @param raw_len length of the raw return value
+ * @param raw return raw bytes
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ if (len > 0)
+ {
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+ if (raw_len >= len)
+ {
+ while (len > 1)
+ {
+ /* copy len - 1 octets */
+ len--;
+ *raw = *msg_ptr;
+ raw++;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ /* copy last octet */
+ *raw = *msg_ptr;
+ return ERR_OK;
+ }
+ else
+ {
+ /* raw_len < len, not enough dst space */
+ return ERR_ARG;
+ }
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+ }
+ else
+ {
+ /* len == 0, empty string */
+ return ERR_OK;
+ }
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_enc.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_enc.c
new file mode 100644
index 0000000000..64dfc5f6ea
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/asn1_enc.c
@@ -0,0 +1,611 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding
+ *
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp_asn1.h"
+
+/**
+ * Returns octet count for length.
+ *
+ * @param length
+ * @param octets_needed points to the return value
+ */
+void
+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
+{
+ if (length < 0x80U)
+ {
+ *octets_needed = 1;
+ }
+ else if (length < 0x100U)
+ {
+ *octets_needed = 2;
+ }
+ else
+ {
+ *octets_needed = 3;
+ }
+}
+
+/**
+ * Returns octet count for an u32_t.
+ *
+ * @param value
+ * @param octets_needed points to the return value
+ *
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
+ */
+void
+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
+{
+ if (value < 0x80UL)
+ {
+ *octets_needed = 1;
+ }
+ else if (value < 0x8000UL)
+ {
+ *octets_needed = 2;
+ }
+ else if (value < 0x800000UL)
+ {
+ *octets_needed = 3;
+ }
+ else if (value < 0x80000000UL)
+ {
+ *octets_needed = 4;
+ }
+ else
+ {
+ *octets_needed = 5;
+ }
+}
+
+/**
+ * Returns octet count for an s32_t.
+ *
+ * @param value
+ * @param octets_needed points to the return value
+ *
+ * @note ASN coded integers are _always_ signed.
+ */
+void
+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
+{
+ if (value < 0)
+ {
+ value = ~value;
+ }
+ if (value < 0x80L)
+ {
+ *octets_needed = 1;
+ }
+ else if (value < 0x8000L)
+ {
+ *octets_needed = 2;
+ }
+ else if (value < 0x800000L)
+ {
+ *octets_needed = 3;
+ }
+ else
+ {
+ *octets_needed = 4;
+ }
+}
+
+/**
+ * Returns octet count for an object identifier.
+ *
+ * @param ident_len object identifier array length
+ * @param ident points to object identifier array
+ * @param octets_needed points to the return value
+ */
+void
+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
+{
+ s32_t sub_id;
+ u8_t cnt;
+
+ cnt = 0;
+ if (ident_len > 1)
+ {
+ /* compressed prefix in one octet */
+ cnt++;
+ ident_len -= 2;
+ ident += 2;
+ }
+ while(ident_len > 0)
+ {
+ ident_len--;
+ sub_id = *ident;
+
+ sub_id >>= 7;
+ cnt++;
+ while(sub_id > 0)
+ {
+ sub_id >>= 7;
+ cnt++;
+ }
+ ident++;
+ }
+ *octets_needed = cnt;
+}
+
+/**
+ * Encodes ASN type field into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param type input ASN1 type
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+ *msg_ptr = type;
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Encodes host order length field into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode length into
+ * @param ofs points to the offset within the pbuf chain
+ * @param length is the host order length to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ if (length < 0x80)
+ {
+ *msg_ptr = (u8_t)length;
+ return ERR_OK;
+ }
+ else if (length < 0x100)
+ {
+ *msg_ptr = 0x81;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ *msg_ptr = (u8_t)length;
+ return ERR_OK;
+ }
+ else
+ {
+ u8_t i;
+
+ /* length >= 0x100 && length <= 0xFFFF */
+ *msg_ptr = 0x82;
+ i = 2;
+ while (i > 0)
+ {
+ i--;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ if (i == 0)
+ {
+ /* least significant length octet */
+ *msg_ptr = (u8_t)length;
+ }
+ else
+ {
+ /* most significant length octet */
+ *msg_ptr = (u8_t)(length >> 8);
+ }
+ }
+ return ERR_OK;
+ }
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
+ * @param value is the host order u32_t value to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ *
+ * @see snmp_asn1_enc_u32t_cnt()
+ */
+err_t
+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ if (octets_needed == 5)
+ {
+ /* not enough bits in 'value' add leading 0x00 */
+ octets_needed--;
+ *msg_ptr = 0x00;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ while (octets_needed > 1)
+ {
+ octets_needed--;
+ *msg_ptr = (u8_t)(value >> (octets_needed << 3));
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ /* (only) one least significant octet */
+ *msg_ptr = (u8_t)value;
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Encodes s32_t integer into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
+ * @param value is the host order s32_t value to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ *
+ * @see snmp_asn1_enc_s32t_cnt()
+ */
+err_t
+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ while (octets_needed > 1)
+ {
+ octets_needed--;
+ *msg_ptr = (u8_t)(value >> (octets_needed << 3));
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ /* (only) one least significant octet */
+ *msg_ptr = (u8_t)value;
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Encodes object identifier into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode oid into
+ * @param ofs points to the offset within the pbuf chain
+ * @param ident_len object identifier array length
+ * @param ident points to object identifier array
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ if (ident_len > 1)
+ {
+ if ((ident[0] == 1) && (ident[1] == 3))
+ {
+ /* compressed (most common) prefix .iso.org */
+ *msg_ptr = 0x2b;
+ }
+ else
+ {
+ /* calculate prefix */
+ *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
+ }
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ ident_len -= 2;
+ ident += 2;
+ }
+ else
+ {
+/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
+ /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
+ return ERR_ARG;
+ }
+ while (ident_len > 0)
+ {
+ s32_t sub_id;
+ u8_t shift, tail;
+
+ ident_len--;
+ sub_id = *ident;
+ tail = 0;
+ shift = 28;
+ while(shift > 0)
+ {
+ u8_t code;
+
+ code = (u8_t)(sub_id >> shift);
+ if ((code != 0) || (tail != 0))
+ {
+ tail = 1;
+ *msg_ptr = code | 0x80;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ shift -= 7;
+ }
+ *msg_ptr = (u8_t)sub_id & 0x7F;
+ if (ident_len > 0)
+ {
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ /* proceed to next sub-identifier */
+ ident++;
+ }
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+/**
+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode raw data into
+ * @param ofs points to the offset within the pbuf chain
+ * @param raw_len raw data length
+ * @param raw points raw data
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw)
+{
+ u16_t plen, base;
+ u8_t *msg_ptr;
+
+ plen = 0;
+ while (p != NULL)
+ {
+ base = plen;
+ plen += p->len;
+ if (ofs < plen)
+ {
+ msg_ptr = (u8_t*)p->payload;
+ msg_ptr += ofs - base;
+
+ while (raw_len > 1)
+ {
+ /* copy raw_len - 1 octets */
+ raw_len--;
+ *msg_ptr = *raw;
+ raw++;
+ ofs += 1;
+ if (ofs >= plen)
+ {
+ /* next octet in next pbuf */
+ p = p->next;
+ if (p == NULL) { return ERR_ARG; }
+ msg_ptr = (u8_t*)p->payload;
+ plen += p->len;
+ }
+ else
+ {
+ /* next octet in same pbuf */
+ msg_ptr++;
+ }
+ }
+ if (raw_len > 0)
+ {
+ /* copy last or single octet */
+ *msg_ptr = *raw;
+ }
+ return ERR_OK;
+ }
+ p = p->next;
+ }
+ /* p == NULL, ofs >= plen */
+ return ERR_ARG;
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib2.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib2.c
new file mode 100644
index 0000000000..29decd306f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib2.c
@@ -0,0 +1,4146 @@
+/**
+ * @file
+ * Management Information Base II (RFC1213) objects and functions.
+ *
+ * @note the object identifiers for this MIB-2 and private MIB tree
+ * must be kept in sorted ascending order. This to ensure correct getnext operation.
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp.h"
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+#include "lwip/ip_frag.h"
+#include "lwip/mem.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/udp.h"
+#include "lwip/snmp_asn1.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/sys.h"
+#include "netif/etharp.h"
+
+/**
+ * IANA assigned enterprise ID for lwIP is 26381
+ * @see http://www.iana.org/assignments/enterprise-numbers
+ *
+ * @note this enterprise ID is assigned to the lwIP project,
+ * all object identifiers living under this ID are assigned
+ * by the lwIP maintainers (contact Christiaan Simons)!
+ * @note don't change this define, use snmp_set_sysobjid()
+ *
+ * If you need to create your own private MIB you'll need
+ * to apply for your own enterprise ID with IANA:
+ * http://www.iana.org/numbers.html
+ */
+#define SNMP_ENTERPRISE_ID 26381
+#define SNMP_SYSOBJID_LEN 7
+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}
+
+#ifndef SNMP_SYSSERVICES
+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))
+#endif
+
+#ifndef SNMP_GET_SYSUPTIME
+#define SNMP_GET_SYSUPTIME(sysuptime)
+#endif
+
+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void system_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);
+static void system_set_value(struct obj_def *od, u16_t len, void *value);
+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);
+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);
+#if !SNMP_SAFE_REQUESTS
+static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value);
+static void ifentry_set_value (struct obj_def *od, u16_t len, void *value);
+#endif /* SNMP_SAFE_REQUESTS */
+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);
+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);
+#if LWIP_TCP
+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);
+#ifdef THIS_SEEMS_UNUSED
+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);
+#endif
+#endif
+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void udp_get_value(struct obj_def *od, u16_t len, void *value);
+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);
+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);
+
+
+/* snmp .1.3.6.1.2.1.11 */
+const mib_scalar_node snmp_scalar = {
+ &snmp_get_object_def,
+ &snmp_get_value,
+ &snmp_set_test,
+ &snmp_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t snmp_ids[28] = {
+ 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30
+};
+struct mib_node* const snmp_nodes[28] = {
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+ (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar
+};
+const struct mib_array_node snmp = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 28,
+ snmp_ids,
+ snmp_nodes
+};
+
+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
+
+/* udp .1.3.6.1.2.1.7 */
+/** index root node for udpTable */
+struct mib_list_rootnode udp_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t udpentry_ids[2] = { 1, 2 };
+struct mib_node* const udpentry_nodes[2] = {
+ (struct mib_node*)&udp_root, (struct mib_node*)&udp_root,
+};
+const struct mib_array_node udpentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 2,
+ udpentry_ids,
+ udpentry_nodes
+};
+
+s32_t udptable_id = 1;
+struct mib_node* udptable_node = (struct mib_node*)&udpentry;
+struct mib_ram_array_node udptable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &udptable_id,
+ &udptable_node
+};
+
+const mib_scalar_node udp_scalar = {
+ &udp_get_object_def,
+ &udp_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const udp_nodes[5] = {
+ (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar,
+ (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar,
+ (struct mib_node*)&udptable
+};
+const struct mib_array_node udp = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 5,
+ udp_ids,
+ udp_nodes
+};
+
+/* tcp .1.3.6.1.2.1.6 */
+#if LWIP_TCP
+/* only if the TCP protocol is available may implement this group */
+/** index root node for tcpConnTable */
+struct mib_list_rootnode tcpconntree_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const tcpconnentry_nodes[5] = {
+ (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root,
+ (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root,
+ (struct mib_node*)&tcpconntree_root
+};
+const struct mib_array_node tcpconnentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 5,
+ tcpconnentry_ids,
+ tcpconnentry_nodes
+};
+
+s32_t tcpconntable_id = 1;
+struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry;
+struct mib_ram_array_node tcpconntable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+/** @todo update maxlength when inserting / deleting from table
+ 0 when table is empty, 1 when more than one entry */
+ 0,
+ &tcpconntable_id,
+ &tcpconntable_node
+};
+
+const mib_scalar_node tcp_scalar = {
+ &tcp_get_object_def,
+ &tcp_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+struct mib_node* const tcp_nodes[15] = {
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar,
+ (struct mib_node*)&tcp_scalar
+};
+const struct mib_array_node tcp = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 15,
+ tcp_ids,
+ tcp_nodes
+};
+#endif
+
+/* icmp .1.3.6.1.2.1.5 */
+const mib_scalar_node icmp_scalar = {
+ &icmp_get_object_def,
+ &icmp_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
+struct mib_node* const icmp_nodes[26] = {
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+ (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar
+};
+const struct mib_array_node icmp = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 26,
+ icmp_ids,
+ icmp_nodes
+};
+
+/** index root node for ipNetToMediaTable */
+struct mib_list_rootnode ipntomtree_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };
+struct mib_node* const ipntomentry_nodes[4] = {
+ (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root,
+ (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root
+};
+const struct mib_array_node ipntomentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 4,
+ ipntomentry_ids,
+ ipntomentry_nodes
+};
+
+s32_t ipntomtable_id = 1;
+struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry;
+struct mib_ram_array_node ipntomtable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &ipntomtable_id,
+ &ipntomtable_node
+};
+
+/** index root node for ipRouteTable */
+struct mib_list_rootnode iprtetree_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
+struct mib_node* const iprteentry_nodes[13] = {
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+ (struct mib_node*)&iprtetree_root
+};
+const struct mib_array_node iprteentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 13,
+ iprteentry_ids,
+ iprteentry_nodes
+};
+
+s32_t iprtetable_id = 1;
+struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry;
+struct mib_ram_array_node iprtetable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &iprtetable_id,
+ &iprtetable_node
+};
+
+/** index root node for ipAddrTable */
+struct mib_list_rootnode ipaddrtree_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const ipaddrentry_nodes[5] = {
+ (struct mib_node*)&ipaddrtree_root,
+ (struct mib_node*)&ipaddrtree_root,
+ (struct mib_node*)&ipaddrtree_root,
+ (struct mib_node*)&ipaddrtree_root,
+ (struct mib_node*)&ipaddrtree_root
+};
+const struct mib_array_node ipaddrentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 5,
+ ipaddrentry_ids,
+ ipaddrentry_nodes
+};
+
+s32_t ipaddrtable_id = 1;
+struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry;
+struct mib_ram_array_node ipaddrtable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &ipaddrtable_id,
+ &ipaddrtable_node
+};
+
+/* ip .1.3.6.1.2.1.4 */
+const mib_scalar_node ip_scalar = {
+ &ip_get_object_def,
+ &ip_get_value,
+ &ip_set_test,
+ &noleafs_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+struct mib_node* const ip_nodes[23] = {
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+ (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable,
+ (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable,
+ (struct mib_node*)&ip_scalar
+};
+const struct mib_array_node mib2_ip = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 23,
+ ip_ids,
+ ip_nodes
+};
+
+/** index root node for atTable */
+struct mib_list_rootnode arptree_root = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t atentry_ids[3] = { 1, 2, 3 };
+struct mib_node* const atentry_nodes[3] = {
+ (struct mib_node*)&arptree_root,
+ (struct mib_node*)&arptree_root,
+ (struct mib_node*)&arptree_root
+};
+const struct mib_array_node atentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 3,
+ atentry_ids,
+ atentry_nodes
+};
+
+const s32_t attable_id = 1;
+struct mib_node* const attable_node = (struct mib_node*)&atentry;
+const struct mib_array_node attable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 1,
+ &attable_id,
+ &attable_node
+};
+
+/* at .1.3.6.1.2.1.3 */
+s32_t at_id = 1;
+struct mib_node* mib2_at_node = (struct mib_node*)&attable;
+struct mib_ram_array_node at = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &at_id,
+ &mib2_at_node
+};
+
+/** index root node for ifTable */
+struct mib_list_rootnode iflist_root = {
+ &ifentry_get_object_def,
+ &ifentry_get_value,
+#if SNMP_SAFE_REQUESTS
+ &noleafs_set_test,
+ &noleafs_set_value,
+#else /* SNMP_SAFE_REQUESTS */
+ &ifentry_set_test,
+ &ifentry_set_value,
+#endif /* SNMP_SAFE_REQUESTS */
+ MIB_NODE_LR,
+ 0,
+ NULL,
+ NULL,
+ 0
+};
+const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 };
+struct mib_node* const ifentry_nodes[22] = {
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+ (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root
+};
+const struct mib_array_node ifentry = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 22,
+ ifentry_ids,
+ ifentry_nodes
+};
+
+s32_t iftable_id = 1;
+struct mib_node* iftable_node = (struct mib_node*)&ifentry;
+struct mib_ram_array_node iftable = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_RA,
+ 0,
+ &iftable_id,
+ &iftable_node
+};
+
+/* interfaces .1.3.6.1.2.1.2 */
+const mib_scalar_node interfaces_scalar = {
+ &interfaces_get_object_def,
+ &interfaces_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t interfaces_ids[2] = { 1, 2 };
+struct mib_node* const interfaces_nodes[2] = {
+ (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable
+};
+const struct mib_array_node interfaces = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 2,
+ interfaces_ids,
+ interfaces_nodes
+};
+
+
+/* 0 1 2 3 4 5 6 */
+/* system .1.3.6.1.2.1.1 */
+const mib_scalar_node sys_tem_scalar = {
+ &system_get_object_def,
+ &system_get_value,
+ &system_set_test,
+ &system_set_value,
+ MIB_NODE_SC,
+ 0
+};
+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };
+struct mib_node* const sys_tem_nodes[7] = {
+ (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+ (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+ (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+ (struct mib_node*)&sys_tem_scalar
+};
+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */
+const struct mib_array_node sys_tem = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 7,
+ sys_tem_ids,
+ sys_tem_nodes
+};
+
+/* mib-2 .1.3.6.1.2.1 */
+#if LWIP_TCP
+#define MIB2_GROUPS 8
+#else
+#define MIB2_GROUPS 7
+#endif
+const s32_t mib2_ids[MIB2_GROUPS] =
+{
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+#if LWIP_TCP
+ 6,
+#endif
+ 7,
+ 11
+};
+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {
+ (struct mib_node*)&sys_tem,
+ (struct mib_node*)&interfaces,
+ (struct mib_node*)&at,
+ (struct mib_node*)&mib2_ip,
+ (struct mib_node*)&icmp,
+#if LWIP_TCP
+ (struct mib_node*)&tcp,
+#endif
+ (struct mib_node*)&udp,
+ (struct mib_node*)&snmp
+};
+
+const struct mib_array_node mib2 = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ MIB2_GROUPS,
+ mib2_ids,
+ mib2_nodes
+};
+
+/* mgmt .1.3.6.1.2 */
+const s32_t mgmt_ids[1] = { 1 };
+struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 };
+const struct mib_array_node mgmt = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 1,
+ mgmt_ids,
+ mgmt_nodes
+};
+
+/* internet .1.3.6.1 */
+#if SNMP_PRIVATE_MIB
+/* When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB. */
+s32_t internet_ids[2] = { 2, 4 };
+struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private };
+const struct mib_array_node internet = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 2,
+ internet_ids,
+ internet_nodes
+};
+#else
+const s32_t internet_ids[1] = { 2 };
+struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt };
+const struct mib_array_node internet = {
+ &noleafs_get_object_def,
+ &noleafs_get_value,
+ &noleafs_set_test,
+ &noleafs_set_value,
+ MIB_NODE_AR,
+ 1,
+ internet_ids,
+ internet_nodes
+};
+#endif
+
+/** mib-2.system.sysObjectID */
+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};
+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */
+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};
+/** mib-2.system.sysServices */
+static const s32_t sysservices = SNMP_SYSSERVICES;
+
+/** mib-2.system.sysDescr */
+static const u8_t sysdescr_len_default = 4;
+static const u8_t sysdescr_default[] = "lwIP";
+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;
+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];
+/** mib-2.system.sysContact */
+static const u8_t syscontact_len_default = 0;
+static const u8_t syscontact_default[] = "";
+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;
+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];
+/** mib-2.system.sysName */
+static const u8_t sysname_len_default = 8;
+static const u8_t sysname_default[] = "FQDN-unk";
+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;
+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];
+/** mib-2.system.sysLocation */
+static const u8_t syslocation_len_default = 0;
+static const u8_t syslocation_default[] = "";
+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;
+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];
+/** mib-2.snmp.snmpEnableAuthenTraps */
+static const u8_t snmpenableauthentraps_default = 2; /* disabled */
+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;
+
+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */
+static const struct snmp_obj_id ifspecific = {2, {0, 0}};
+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */
+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};
+
+
+
+/* mib-2.system counter(s) */
+static u32_t sysuptime = 0;
+
+/* mib-2.ip counter(s) */
+static u32_t ipinreceives = 0,
+ ipinhdrerrors = 0,
+ ipinaddrerrors = 0,
+ ipforwdatagrams = 0,
+ ipinunknownprotos = 0,
+ ipindiscards = 0,
+ ipindelivers = 0,
+ ipoutrequests = 0,
+ ipoutdiscards = 0,
+ ipoutnoroutes = 0,
+ ipreasmreqds = 0,
+ ipreasmoks = 0,
+ ipreasmfails = 0,
+ ipfragoks = 0,
+ ipfragfails = 0,
+ ipfragcreates = 0,
+ iproutingdiscards = 0;
+/* mib-2.icmp counter(s) */
+static u32_t icmpinmsgs = 0,
+ icmpinerrors = 0,
+ icmpindestunreachs = 0,
+ icmpintimeexcds = 0,
+ icmpinparmprobs = 0,
+ icmpinsrcquenchs = 0,
+ icmpinredirects = 0,
+ icmpinechos = 0,
+ icmpinechoreps = 0,
+ icmpintimestamps = 0,
+ icmpintimestampreps = 0,
+ icmpinaddrmasks = 0,
+ icmpinaddrmaskreps = 0,
+ icmpoutmsgs = 0,
+ icmpouterrors = 0,
+ icmpoutdestunreachs = 0,
+ icmpouttimeexcds = 0,
+ icmpoutparmprobs = 0,
+ icmpoutsrcquenchs = 0,
+ icmpoutredirects = 0,
+ icmpoutechos = 0,
+ icmpoutechoreps = 0,
+ icmpouttimestamps = 0,
+ icmpouttimestampreps = 0,
+ icmpoutaddrmasks = 0,
+ icmpoutaddrmaskreps = 0;
+/* mib-2.tcp counter(s) */
+static u32_t tcpactiveopens = 0,
+ tcppassiveopens = 0,
+ tcpattemptfails = 0,
+ tcpestabresets = 0,
+ tcpinsegs = 0,
+ tcpoutsegs = 0,
+ tcpretranssegs = 0,
+ tcpinerrs = 0,
+ tcpoutrsts = 0;
+/* mib-2.udp counter(s) */
+static u32_t udpindatagrams = 0,
+ udpnoports = 0,
+ udpinerrors = 0,
+ udpoutdatagrams = 0;
+/* mib-2.snmp counter(s) */
+static u32_t snmpinpkts = 0,
+ snmpoutpkts = 0,
+ snmpinbadversions = 0,
+ snmpinbadcommunitynames = 0,
+ snmpinbadcommunityuses = 0,
+ snmpinasnparseerrs = 0,
+ snmpintoobigs = 0,
+ snmpinnosuchnames = 0,
+ snmpinbadvalues = 0,
+ snmpinreadonlys = 0,
+ snmpingenerrs = 0,
+ snmpintotalreqvars = 0,
+ snmpintotalsetvars = 0,
+ snmpingetrequests = 0,
+ snmpingetnexts = 0,
+ snmpinsetrequests = 0,
+ snmpingetresponses = 0,
+ snmpintraps = 0,
+ snmpouttoobigs = 0,
+ snmpoutnosuchnames = 0,
+ snmpoutbadvalues = 0,
+ snmpoutgenerrs = 0,
+ snmpoutgetrequests = 0,
+ snmpoutgetnexts = 0,
+ snmpoutsetrequests = 0,
+ snmpoutgetresponses = 0,
+ snmpouttraps = 0;
+
+
+
+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */
+/**
+ * Copy octet string.
+ *
+ * @param dst points to destination
+ * @param src points to source
+ * @param n number of octets to copy.
+ */
+static void ocstrncpy(u8_t *dst, u8_t *src, u16_t n)
+{
+ u16_t i = n;
+ while (i > 0) {
+ i--;
+ *dst++ = *src++;
+ }
+}
+
+/**
+ * Copy object identifier (s32_t) array.
+ *
+ * @param dst points to destination
+ * @param src points to source
+ * @param n number of sub identifiers to copy.
+ */
+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)
+{
+ u8_t i = n;
+ while(i > 0) {
+ i--;
+ *dst++ = *src++;
+ }
+}
+
+/**
+ * Initializes sysDescr pointers.
+ *
+ * @param str if non-NULL then copy str pointer
+ * @param len points to string length, excluding zero terminator
+ */
+void snmp_set_sysdesr(u8_t *str, u8_t *len)
+{
+ if (str != NULL)
+ {
+ sysdescr_ptr = str;
+ sysdescr_len_ptr = len;
+ }
+}
+
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)
+{
+ *oid = &sysobjid;
+}
+
+/**
+ * Initializes sysObjectID value.
+ *
+ * @param oid points to stuct snmp_obj_id to copy
+ */
+void snmp_set_sysobjid(struct snmp_obj_id *oid)
+{
+ sysobjid = *oid;
+}
+
+/**
+ * Must be called at regular 10 msec interval from a timer interrupt
+ * or signal handler depending on your runtime environment.
+ */
+void snmp_inc_sysuptime(void)
+{
+ sysuptime++;
+}
+
+void snmp_add_sysuptime(u32_t value)
+{
+ sysuptime+=value;
+}
+
+void snmp_get_sysuptime(u32_t *value)
+{
+ SNMP_GET_SYSUPTIME(sysuptime);
+ *value = sysuptime;
+}
+
+/**
+ * Initializes sysContact pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)
+{
+ if (ocstr != NULL)
+ {
+ syscontact_ptr = ocstr;
+ syscontact_len_ptr = ocstrlen;
+ }
+}
+
+/**
+ * Initializes sysName pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)
+{
+ if (ocstr != NULL)
+ {
+ sysname_ptr = ocstr;
+ sysname_len_ptr = ocstrlen;
+ }
+}
+
+/**
+ * Initializes sysLocation pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)
+{
+ if (ocstr != NULL)
+ {
+ syslocation_ptr = ocstr;
+ syslocation_len_ptr = ocstrlen;
+ }
+}
+
+
+void snmp_add_ifinoctets(struct netif *ni, u32_t value)
+{
+ ni->ifinoctets += value;
+}
+
+void snmp_inc_ifinucastpkts(struct netif *ni)
+{
+ (ni->ifinucastpkts)++;
+}
+
+void snmp_inc_ifinnucastpkts(struct netif *ni)
+{
+ (ni->ifinnucastpkts)++;
+}
+
+void snmp_inc_ifindiscards(struct netif *ni)
+{
+ (ni->ifindiscards)++;
+}
+
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)
+{
+ ni->ifoutoctets += value;
+}
+
+void snmp_inc_ifoutucastpkts(struct netif *ni)
+{
+ (ni->ifoutucastpkts)++;
+}
+
+void snmp_inc_ifoutnucastpkts(struct netif *ni)
+{
+ (ni->ifoutnucastpkts)++;
+}
+
+void snmp_inc_ifoutdiscards(struct netif *ni)
+{
+ (ni->ifoutdiscards)++;
+}
+
+void snmp_inc_iflist(void)
+{
+ struct mib_list_node *if_node = NULL;
+
+ snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);
+ /* enable getnext traversal on filled table */
+ iftable.maxlength = 1;
+}
+
+void snmp_dec_iflist(void)
+{
+ snmp_mib_node_delete(&iflist_root, iflist_root.tail);
+ /* disable getnext traversal on empty table */
+ if(iflist_root.count == 0) iftable.maxlength = 0;
+}
+
+/**
+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)
+ * into arp table index trees (both atTable and ipNetToMediaTable).
+ */
+void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip)
+{
+ struct mib_list_rootnode *at_rn;
+ struct mib_list_node *at_node;
+ s32_t arpidx[5];
+ u8_t level, tree;
+
+ LWIP_ASSERT("ni != NULL", ni != NULL);
+ snmp_netiftoifindex(ni, &arpidx[0]);
+ snmp_iptooid(ip, &arpidx[1]);
+
+ for (tree = 0; tree < 2; tree++)
+ {
+ if (tree == 0)
+ {
+ at_rn = &arptree_root;
+ }
+ else
+ {
+ at_rn = &ipntomtree_root;
+ }
+ for (level = 0; level < 5; level++)
+ {
+ at_node = NULL;
+ snmp_mib_node_insert(at_rn, arpidx[level], &at_node);
+ if ((level != 4) && (at_node != NULL))
+ {
+ if (at_node->nptr == NULL)
+ {
+ at_rn = snmp_mib_lrn_alloc();
+ at_node->nptr = (struct mib_node*)at_rn;
+ if (at_rn != NULL)
+ {
+ if (level == 3)
+ {
+ if (tree == 0)
+ {
+ at_rn->get_object_def = atentry_get_object_def;
+ at_rn->get_value = atentry_get_value;
+ }
+ else
+ {
+ at_rn->get_object_def = ip_ntomentry_get_object_def;
+ at_rn->get_value = ip_ntomentry_get_value;
+ }
+ at_rn->set_test = noleafs_set_test;
+ at_rn->set_value = noleafs_set_value;
+ }
+ }
+ else
+ {
+ /* at_rn == NULL, malloc failure */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));
+ break;
+ }
+ }
+ else
+ {
+ at_rn = (struct mib_list_rootnode*)at_node->nptr;
+ }
+ }
+ }
+ }
+ /* enable getnext traversal on filled tables */
+ at.maxlength = 1;
+ ipntomtable.maxlength = 1;
+}
+
+/**
+ * Removes ARP table indexes (.xIfIndex.xNetAddress)
+ * from arp table index trees.
+ */
+void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip)
+{
+ struct mib_list_rootnode *at_rn, *next, *del_rn[5];
+ struct mib_list_node *at_n, *del_n[5];
+ s32_t arpidx[5];
+ u8_t fc, tree, level, del_cnt;
+
+ snmp_netiftoifindex(ni, &arpidx[0]);
+ snmp_iptooid(ip, &arpidx[1]);
+
+ for (tree = 0; tree < 2; tree++)
+ {
+ /* mark nodes for deletion */
+ if (tree == 0)
+ {
+ at_rn = &arptree_root;
+ }
+ else
+ {
+ at_rn = &ipntomtree_root;
+ }
+ level = 0;
+ del_cnt = 0;
+ while ((level < 5) && (at_rn != NULL))
+ {
+ fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);
+ if (fc == 0)
+ {
+ /* arpidx[level] does not exist */
+ del_cnt = 0;
+ at_rn = NULL;
+ }
+ else if (fc == 1)
+ {
+ del_rn[del_cnt] = at_rn;
+ del_n[del_cnt] = at_n;
+ del_cnt++;
+ at_rn = (struct mib_list_rootnode*)(at_n->nptr);
+ }
+ else if (fc == 2)
+ {
+ /* reset delete (2 or more childs) */
+ del_cnt = 0;
+ at_rn = (struct mib_list_rootnode*)(at_n->nptr);
+ }
+ level++;
+ }
+ /* delete marked index nodes */
+ while (del_cnt > 0)
+ {
+ del_cnt--;
+
+ at_rn = del_rn[del_cnt];
+ at_n = del_n[del_cnt];
+
+ next = snmp_mib_node_delete(at_rn, at_n);
+ if (next != NULL)
+ {
+ LWIP_ASSERT("next_count == 0",next->count == 0);
+ snmp_mib_lrn_free(next);
+ }
+ }
+ }
+ /* disable getnext traversal on empty tables */
+ if(arptree_root.count == 0) at.maxlength = 0;
+ if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;
+}
+
+void snmp_inc_ipinreceives(void)
+{
+ ipinreceives++;
+}
+
+void snmp_inc_ipinhdrerrors(void)
+{
+ ipinhdrerrors++;
+}
+
+void snmp_inc_ipinaddrerrors(void)
+{
+ ipinaddrerrors++;
+}
+
+void snmp_inc_ipforwdatagrams(void)
+{
+ ipforwdatagrams++;
+}
+
+void snmp_inc_ipinunknownprotos(void)
+{
+ ipinunknownprotos++;
+}
+
+void snmp_inc_ipindiscards(void)
+{
+ ipindiscards++;
+}
+
+void snmp_inc_ipindelivers(void)
+{
+ ipindelivers++;
+}
+
+void snmp_inc_ipoutrequests(void)
+{
+ ipoutrequests++;
+}
+
+void snmp_inc_ipoutdiscards(void)
+{
+ ipoutdiscards++;
+}
+
+void snmp_inc_ipoutnoroutes(void)
+{
+ ipoutnoroutes++;
+}
+
+void snmp_inc_ipreasmreqds(void)
+{
+ ipreasmreqds++;
+}
+
+void snmp_inc_ipreasmoks(void)
+{
+ ipreasmoks++;
+}
+
+void snmp_inc_ipreasmfails(void)
+{
+ ipreasmfails++;
+}
+
+void snmp_inc_ipfragoks(void)
+{
+ ipfragoks++;
+}
+
+void snmp_inc_ipfragfails(void)
+{
+ ipfragfails++;
+}
+
+void snmp_inc_ipfragcreates(void)
+{
+ ipfragcreates++;
+}
+
+void snmp_inc_iproutingdiscards(void)
+{
+ iproutingdiscards++;
+}
+
+/**
+ * Inserts ipAddrTable indexes (.ipAdEntAddr)
+ * into index tree.
+ */
+void snmp_insert_ipaddridx_tree(struct netif *ni)
+{
+ struct mib_list_rootnode *ipa_rn;
+ struct mib_list_node *ipa_node;
+ s32_t ipaddridx[4];
+ u8_t level;
+
+ LWIP_ASSERT("ni != NULL", ni != NULL);
+ snmp_iptooid(&ni->ip_addr, &ipaddridx[0]);
+
+ level = 0;
+ ipa_rn = &ipaddrtree_root;
+ while (level < 4)
+ {
+ ipa_node = NULL;
+ snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);
+ if ((level != 3) && (ipa_node != NULL))
+ {
+ if (ipa_node->nptr == NULL)
+ {
+ ipa_rn = snmp_mib_lrn_alloc();
+ ipa_node->nptr = (struct mib_node*)ipa_rn;
+ if (ipa_rn != NULL)
+ {
+ if (level == 2)
+ {
+ ipa_rn->get_object_def = ip_addrentry_get_object_def;
+ ipa_rn->get_value = ip_addrentry_get_value;
+ ipa_rn->set_test = noleafs_set_test;
+ ipa_rn->set_value = noleafs_set_value;
+ }
+ }
+ else
+ {
+ /* ipa_rn == NULL, malloc failure */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));
+ break;
+ }
+ }
+ else
+ {
+ ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;
+ }
+ }
+ level++;
+ }
+ /* enable getnext traversal on filled table */
+ ipaddrtable.maxlength = 1;
+}
+
+/**
+ * Removes ipAddrTable indexes (.ipAdEntAddr)
+ * from index tree.
+ */
+void snmp_delete_ipaddridx_tree(struct netif *ni)
+{
+ struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];
+ struct mib_list_node *ipa_n, *del_n[4];
+ s32_t ipaddridx[4];
+ u8_t fc, level, del_cnt;
+
+ LWIP_ASSERT("ni != NULL", ni != NULL);
+ snmp_iptooid(&ni->ip_addr, &ipaddridx[0]);
+
+ /* mark nodes for deletion */
+ level = 0;
+ del_cnt = 0;
+ ipa_rn = &ipaddrtree_root;
+ while ((level < 4) && (ipa_rn != NULL))
+ {
+ fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);
+ if (fc == 0)
+ {
+ /* ipaddridx[level] does not exist */
+ del_cnt = 0;
+ ipa_rn = NULL;
+ }
+ else if (fc == 1)
+ {
+ del_rn[del_cnt] = ipa_rn;
+ del_n[del_cnt] = ipa_n;
+ del_cnt++;
+ ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
+ }
+ else if (fc == 2)
+ {
+ /* reset delete (2 or more childs) */
+ del_cnt = 0;
+ ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
+ }
+ level++;
+ }
+ /* delete marked index nodes */
+ while (del_cnt > 0)
+ {
+ del_cnt--;
+
+ ipa_rn = del_rn[del_cnt];
+ ipa_n = del_n[del_cnt];
+
+ next = snmp_mib_node_delete(ipa_rn, ipa_n);
+ if (next != NULL)
+ {
+ LWIP_ASSERT("next_count == 0",next->count == 0);
+ snmp_mib_lrn_free(next);
+ }
+ }
+ /* disable getnext traversal on empty table */
+ if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;
+}
+
+/**
+ * Inserts ipRouteTable indexes (.ipRouteDest)
+ * into index tree.
+ *
+ * @param dflt non-zero for the default rte, zero for network rte
+ * @param ni points to network interface for this rte
+ *
+ * @todo record sysuptime for _this_ route when it is installed
+ * (needed for ipRouteAge) in the netif.
+ */
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)
+{
+ u8_t insert = 0;
+ ip_addr_t dst;
+
+ if (dflt != 0)
+ {
+ /* the default route 0.0.0.0 */
+ ip_addr_set_any(&dst);
+ insert = 1;
+ }
+ else
+ {
+ /* route to the network address */
+ ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask);
+ /* exclude 0.0.0.0 network (reserved for default rte) */
+ if (!ip_addr_isany(&dst)) {
+ insert = 1;
+ }
+ }
+ if (insert)
+ {
+ struct mib_list_rootnode *iprte_rn;
+ struct mib_list_node *iprte_node;
+ s32_t iprteidx[4];
+ u8_t level;
+
+ snmp_iptooid(&dst, &iprteidx[0]);
+ level = 0;
+ iprte_rn = &iprtetree_root;
+ while (level < 4)
+ {
+ iprte_node = NULL;
+ snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);
+ if ((level != 3) && (iprte_node != NULL))
+ {
+ if (iprte_node->nptr == NULL)
+ {
+ iprte_rn = snmp_mib_lrn_alloc();
+ iprte_node->nptr = (struct mib_node*)iprte_rn;
+ if (iprte_rn != NULL)
+ {
+ if (level == 2)
+ {
+ iprte_rn->get_object_def = ip_rteentry_get_object_def;
+ iprte_rn->get_value = ip_rteentry_get_value;
+ iprte_rn->set_test = noleafs_set_test;
+ iprte_rn->set_value = noleafs_set_value;
+ }
+ }
+ else
+ {
+ /* iprte_rn == NULL, malloc failure */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));
+ break;
+ }
+ }
+ else
+ {
+ iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;
+ }
+ }
+ level++;
+ }
+ }
+ /* enable getnext traversal on filled table */
+ iprtetable.maxlength = 1;
+}
+
+/**
+ * Removes ipRouteTable indexes (.ipRouteDest)
+ * from index tree.
+ *
+ * @param dflt non-zero for the default rte, zero for network rte
+ * @param ni points to network interface for this rte or NULL
+ * for default route to be removed.
+ */
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)
+{
+ u8_t del = 0;
+ ip_addr_t dst;
+
+ if (dflt != 0)
+ {
+ /* the default route 0.0.0.0 */
+ ip_addr_set_any(&dst);
+ del = 1;
+ }
+ else
+ {
+ /* route to the network address */
+ ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask);
+ /* exclude 0.0.0.0 network (reserved for default rte) */
+ if (!ip_addr_isany(&dst)) {
+ del = 1;
+ }
+ }
+ if (del)
+ {
+ struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];
+ struct mib_list_node *iprte_n, *del_n[4];
+ s32_t iprteidx[4];
+ u8_t fc, level, del_cnt;
+
+ snmp_iptooid(&dst, &iprteidx[0]);
+ /* mark nodes for deletion */
+ level = 0;
+ del_cnt = 0;
+ iprte_rn = &iprtetree_root;
+ while ((level < 4) && (iprte_rn != NULL))
+ {
+ fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);
+ if (fc == 0)
+ {
+ /* iprteidx[level] does not exist */
+ del_cnt = 0;
+ iprte_rn = NULL;
+ }
+ else if (fc == 1)
+ {
+ del_rn[del_cnt] = iprte_rn;
+ del_n[del_cnt] = iprte_n;
+ del_cnt++;
+ iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
+ }
+ else if (fc == 2)
+ {
+ /* reset delete (2 or more childs) */
+ del_cnt = 0;
+ iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
+ }
+ level++;
+ }
+ /* delete marked index nodes */
+ while (del_cnt > 0)
+ {
+ del_cnt--;
+
+ iprte_rn = del_rn[del_cnt];
+ iprte_n = del_n[del_cnt];
+
+ next = snmp_mib_node_delete(iprte_rn, iprte_n);
+ if (next != NULL)
+ {
+ LWIP_ASSERT("next_count == 0",next->count == 0);
+ snmp_mib_lrn_free(next);
+ }
+ }
+ }
+ /* disable getnext traversal on empty table */
+ if (iprtetree_root.count == 0) iprtetable.maxlength = 0;
+}
+
+
+void snmp_inc_icmpinmsgs(void)
+{
+ icmpinmsgs++;
+}
+
+void snmp_inc_icmpinerrors(void)
+{
+ icmpinerrors++;
+}
+
+void snmp_inc_icmpindestunreachs(void)
+{
+ icmpindestunreachs++;
+}
+
+void snmp_inc_icmpintimeexcds(void)
+{
+ icmpintimeexcds++;
+}
+
+void snmp_inc_icmpinparmprobs(void)
+{
+ icmpinparmprobs++;
+}
+
+void snmp_inc_icmpinsrcquenchs(void)
+{
+ icmpinsrcquenchs++;
+}
+
+void snmp_inc_icmpinredirects(void)
+{
+ icmpinredirects++;
+}
+
+void snmp_inc_icmpinechos(void)
+{
+ icmpinechos++;
+}
+
+void snmp_inc_icmpinechoreps(void)
+{
+ icmpinechoreps++;
+}
+
+void snmp_inc_icmpintimestamps(void)
+{
+ icmpintimestamps++;
+}
+
+void snmp_inc_icmpintimestampreps(void)
+{
+ icmpintimestampreps++;
+}
+
+void snmp_inc_icmpinaddrmasks(void)
+{
+ icmpinaddrmasks++;
+}
+
+void snmp_inc_icmpinaddrmaskreps(void)
+{
+ icmpinaddrmaskreps++;
+}
+
+void snmp_inc_icmpoutmsgs(void)
+{
+ icmpoutmsgs++;
+}
+
+void snmp_inc_icmpouterrors(void)
+{
+ icmpouterrors++;
+}
+
+void snmp_inc_icmpoutdestunreachs(void)
+{
+ icmpoutdestunreachs++;
+}
+
+void snmp_inc_icmpouttimeexcds(void)
+{
+ icmpouttimeexcds++;
+}
+
+void snmp_inc_icmpoutparmprobs(void)
+{
+ icmpoutparmprobs++;
+}
+
+void snmp_inc_icmpoutsrcquenchs(void)
+{
+ icmpoutsrcquenchs++;
+}
+
+void snmp_inc_icmpoutredirects(void)
+{
+ icmpoutredirects++;
+}
+
+void snmp_inc_icmpoutechos(void)
+{
+ icmpoutechos++;
+}
+
+void snmp_inc_icmpoutechoreps(void)
+{
+ icmpoutechoreps++;
+}
+
+void snmp_inc_icmpouttimestamps(void)
+{
+ icmpouttimestamps++;
+}
+
+void snmp_inc_icmpouttimestampreps(void)
+{
+ icmpouttimestampreps++;
+}
+
+void snmp_inc_icmpoutaddrmasks(void)
+{
+ icmpoutaddrmasks++;
+}
+
+void snmp_inc_icmpoutaddrmaskreps(void)
+{
+ icmpoutaddrmaskreps++;
+}
+
+void snmp_inc_tcpactiveopens(void)
+{
+ tcpactiveopens++;
+}
+
+void snmp_inc_tcppassiveopens(void)
+{
+ tcppassiveopens++;
+}
+
+void snmp_inc_tcpattemptfails(void)
+{
+ tcpattemptfails++;
+}
+
+void snmp_inc_tcpestabresets(void)
+{
+ tcpestabresets++;
+}
+
+void snmp_inc_tcpinsegs(void)
+{
+ tcpinsegs++;
+}
+
+void snmp_inc_tcpoutsegs(void)
+{
+ tcpoutsegs++;
+}
+
+void snmp_inc_tcpretranssegs(void)
+{
+ tcpretranssegs++;
+}
+
+void snmp_inc_tcpinerrs(void)
+{
+ tcpinerrs++;
+}
+
+void snmp_inc_tcpoutrsts(void)
+{
+ tcpoutrsts++;
+}
+
+void snmp_inc_udpindatagrams(void)
+{
+ udpindatagrams++;
+}
+
+void snmp_inc_udpnoports(void)
+{
+ udpnoports++;
+}
+
+void snmp_inc_udpinerrors(void)
+{
+ udpinerrors++;
+}
+
+void snmp_inc_udpoutdatagrams(void)
+{
+ udpoutdatagrams++;
+}
+
+/**
+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)
+ * into index tree.
+ */
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)
+{
+ struct mib_list_rootnode *udp_rn;
+ struct mib_list_node *udp_node;
+ s32_t udpidx[5];
+ u8_t level;
+
+ LWIP_ASSERT("pcb != NULL", pcb != NULL);
+ snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+ udpidx[4] = pcb->local_port;
+
+ udp_rn = &udp_root;
+ for (level = 0; level < 5; level++)
+ {
+ udp_node = NULL;
+ snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);
+ if ((level != 4) && (udp_node != NULL))
+ {
+ if (udp_node->nptr == NULL)
+ {
+ udp_rn = snmp_mib_lrn_alloc();
+ udp_node->nptr = (struct mib_node*)udp_rn;
+ if (udp_rn != NULL)
+ {
+ if (level == 3)
+ {
+ udp_rn->get_object_def = udpentry_get_object_def;
+ udp_rn->get_value = udpentry_get_value;
+ udp_rn->set_test = noleafs_set_test;
+ udp_rn->set_value = noleafs_set_value;
+ }
+ }
+ else
+ {
+ /* udp_rn == NULL, malloc failure */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));
+ break;
+ }
+ }
+ else
+ {
+ udp_rn = (struct mib_list_rootnode*)udp_node->nptr;
+ }
+ }
+ }
+ udptable.maxlength = 1;
+}
+
+/**
+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)
+ * from index tree.
+ */
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
+{
+ struct udp_pcb *npcb;
+ struct mib_list_rootnode *udp_rn, *next, *del_rn[5];
+ struct mib_list_node *udp_n, *del_n[5];
+ s32_t udpidx[5];
+ u8_t bindings, fc, level, del_cnt;
+
+ LWIP_ASSERT("pcb != NULL", pcb != NULL);
+ snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+ udpidx[4] = pcb->local_port;
+
+ /* count PCBs for a given binding
+ (e.g. when reusing ports or for temp output PCBs) */
+ bindings = 0;
+ npcb = udp_pcbs;
+ while ((npcb != NULL))
+ {
+ if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) &&
+ (npcb->local_port == udpidx[4]))
+ {
+ bindings++;
+ }
+ npcb = npcb->next;
+ }
+ if (bindings == 1)
+ {
+ /* selectively remove */
+ /* mark nodes for deletion */
+ level = 0;
+ del_cnt = 0;
+ udp_rn = &udp_root;
+ while ((level < 5) && (udp_rn != NULL))
+ {
+ fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);
+ if (fc == 0)
+ {
+ /* udpidx[level] does not exist */
+ del_cnt = 0;
+ udp_rn = NULL;
+ }
+ else if (fc == 1)
+ {
+ del_rn[del_cnt] = udp_rn;
+ del_n[del_cnt] = udp_n;
+ del_cnt++;
+ udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
+ }
+ else if (fc == 2)
+ {
+ /* reset delete (2 or more childs) */
+ del_cnt = 0;
+ udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
+ }
+ level++;
+ }
+ /* delete marked index nodes */
+ while (del_cnt > 0)
+ {
+ del_cnt--;
+
+ udp_rn = del_rn[del_cnt];
+ udp_n = del_n[del_cnt];
+
+ next = snmp_mib_node_delete(udp_rn, udp_n);
+ if (next != NULL)
+ {
+ LWIP_ASSERT("next_count == 0",next->count == 0);
+ snmp_mib_lrn_free(next);
+ }
+ }
+ }
+ /* disable getnext traversal on empty table */
+ if (udp_root.count == 0) udptable.maxlength = 0;
+}
+
+
+void snmp_inc_snmpinpkts(void)
+{
+ snmpinpkts++;
+}
+
+void snmp_inc_snmpoutpkts(void)
+{
+ snmpoutpkts++;
+}
+
+void snmp_inc_snmpinbadversions(void)
+{
+ snmpinbadversions++;
+}
+
+void snmp_inc_snmpinbadcommunitynames(void)
+{
+ snmpinbadcommunitynames++;
+}
+
+void snmp_inc_snmpinbadcommunityuses(void)
+{
+ snmpinbadcommunityuses++;
+}
+
+void snmp_inc_snmpinasnparseerrs(void)
+{
+ snmpinasnparseerrs++;
+}
+
+void snmp_inc_snmpintoobigs(void)
+{
+ snmpintoobigs++;
+}
+
+void snmp_inc_snmpinnosuchnames(void)
+{
+ snmpinnosuchnames++;
+}
+
+void snmp_inc_snmpinbadvalues(void)
+{
+ snmpinbadvalues++;
+}
+
+void snmp_inc_snmpinreadonlys(void)
+{
+ snmpinreadonlys++;
+}
+
+void snmp_inc_snmpingenerrs(void)
+{
+ snmpingenerrs++;
+}
+
+void snmp_add_snmpintotalreqvars(u8_t value)
+{
+ snmpintotalreqvars += value;
+}
+
+void snmp_add_snmpintotalsetvars(u8_t value)
+{
+ snmpintotalsetvars += value;
+}
+
+void snmp_inc_snmpingetrequests(void)
+{
+ snmpingetrequests++;
+}
+
+void snmp_inc_snmpingetnexts(void)
+{
+ snmpingetnexts++;
+}
+
+void snmp_inc_snmpinsetrequests(void)
+{
+ snmpinsetrequests++;
+}
+
+void snmp_inc_snmpingetresponses(void)
+{
+ snmpingetresponses++;
+}
+
+void snmp_inc_snmpintraps(void)
+{
+ snmpintraps++;
+}
+
+void snmp_inc_snmpouttoobigs(void)
+{
+ snmpouttoobigs++;
+}
+
+void snmp_inc_snmpoutnosuchnames(void)
+{
+ snmpoutnosuchnames++;
+}
+
+void snmp_inc_snmpoutbadvalues(void)
+{
+ snmpoutbadvalues++;
+}
+
+void snmp_inc_snmpoutgenerrs(void)
+{
+ snmpoutgenerrs++;
+}
+
+void snmp_inc_snmpoutgetrequests(void)
+{
+ snmpoutgetrequests++;
+}
+
+void snmp_inc_snmpoutgetnexts(void)
+{
+ snmpoutgetnexts++;
+}
+
+void snmp_inc_snmpoutsetrequests(void)
+{
+ snmpoutsetrequests++;
+}
+
+void snmp_inc_snmpoutgetresponses(void)
+{
+ snmpoutgetresponses++;
+}
+
+void snmp_inc_snmpouttraps(void)
+{
+ snmpouttraps++;
+}
+
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)
+{
+ *oid = &snmpgrp_id;
+}
+
+void snmp_set_snmpenableauthentraps(u8_t *value)
+{
+ if (value != NULL)
+ {
+ snmpenableauthentraps_ptr = value;
+ }
+}
+
+void snmp_get_snmpenableauthentraps(u8_t *value)
+{
+ *value = *snmpenableauthentraps_ptr;
+}
+
+void
+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ LWIP_UNUSED_ARG(ident_len);
+ LWIP_UNUSED_ARG(ident);
+ od->instance = MIB_OBJECT_NONE;
+}
+
+void
+noleafs_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ LWIP_UNUSED_ARG(od);
+ LWIP_UNUSED_ARG(len);
+ LWIP_UNUSED_ARG(value);
+}
+
+u8_t
+noleafs_set_test(struct obj_def *od, u16_t len, void *value)
+{
+ LWIP_UNUSED_ARG(od);
+ LWIP_UNUSED_ARG(len);
+ LWIP_UNUSED_ARG(value);
+ /* can't set */
+ return 0;
+}
+
+void
+noleafs_set_value(struct obj_def *od, u16_t len, void *value)
+{
+ LWIP_UNUSED_ARG(od);
+ LWIP_UNUSED_ARG(len);
+ LWIP_UNUSED_ARG(value);
+}
+
+
+/**
+ * Returns systems object definitions.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param od points to object definition.
+ */
+static void
+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ u8_t id;
+
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));
+ switch (id)
+ {
+ case 1: /* sysDescr */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = *sysdescr_len_ptr;
+ break;
+ case 2: /* sysObjectID */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+ od->v_len = sysobjid.len * sizeof(s32_t);
+ break;
+ case 3: /* sysUpTime */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 4: /* sysContact */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = *syscontact_len_ptr;
+ break;
+ case 5: /* sysName */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = *sysname_len_ptr;
+ break;
+ case 6: /* sysLocation */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = *syslocation_len_ptr;
+ break;
+ case 7: /* sysServices */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+/**
+ * Returns system object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+system_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* sysDescr */
+ ocstrncpy((u8_t*)value, sysdescr_ptr, len);
+ break;
+ case 2: /* sysObjectID */
+ objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t)));
+ break;
+ case 3: /* sysUpTime */
+ {
+ snmp_get_sysuptime((u32_t*)value);
+ }
+ break;
+ case 4: /* sysContact */
+ ocstrncpy((u8_t*)value, syscontact_ptr, len);
+ break;
+ case 5: /* sysName */
+ ocstrncpy((u8_t*)value, sysname_ptr, len);
+ break;
+ case 6: /* sysLocation */
+ ocstrncpy((u8_t*)value, syslocation_ptr, len);
+ break;
+ case 7: /* sysServices */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = sysservices;
+ }
+ break;
+ };
+}
+
+static u8_t
+system_set_test(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id, set_ok;
+
+ LWIP_UNUSED_ARG(value);
+ set_ok = 0;
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 4: /* sysContact */
+ if ((syscontact_ptr != syscontact_default) &&
+ (len <= 255))
+ {
+ set_ok = 1;
+ }
+ break;
+ case 5: /* sysName */
+ if ((sysname_ptr != sysname_default) &&
+ (len <= 255))
+ {
+ set_ok = 1;
+ }
+ break;
+ case 6: /* sysLocation */
+ if ((syslocation_ptr != syslocation_default) &&
+ (len <= 255))
+ {
+ set_ok = 1;
+ }
+ break;
+ };
+ return set_ok;
+}
+
+static void
+system_set_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+
+ LWIP_ASSERT("invalid len", len <= 0xff);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 4: /* sysContact */
+ ocstrncpy(syscontact_ptr, (u8_t*)value, len);
+ *syscontact_len_ptr = (u8_t)len;
+ break;
+ case 5: /* sysName */
+ ocstrncpy(sysname_ptr, (u8_t*)value, len);
+ *sysname_len_ptr = (u8_t)len;
+ break;
+ case 6: /* sysLocation */
+ ocstrncpy(syslocation_ptr, (u8_t*)value, len);
+ *syslocation_len_ptr = (u8_t)len;
+ break;
+ };
+}
+
+/**
+ * Returns interfaces.ifnumber object definition.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.index
+ * @param od points to object definition.
+ */
+static void
+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+/**
+ * Returns interfaces.ifnumber object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+interfaces_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ LWIP_UNUSED_ARG(len);
+ if (od->id_inst_ptr[0] == 1)
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = iflist_root.count;
+ }
+}
+
+/**
+ * Returns ifentry object definitions.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.index
+ * @param od points to object definition.
+ */
+static void
+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ u8_t id;
+
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));
+ switch (id)
+ {
+ case 1: /* ifIndex */
+ case 3: /* ifType */
+ case 4: /* ifMtu */
+ case 8: /* ifOperStatus */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 2: /* ifDescr */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ /** @todo this should be some sort of sizeof(struct netif.name) */
+ od->v_len = 2;
+ break;
+ case 5: /* ifSpeed */
+ case 21: /* ifOutQLen */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 6: /* ifPhysAddress */
+ {
+ struct netif *netif;
+
+ snmp_ifindextonetif(ident[1], &netif);
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = netif->hwaddr_len;
+ }
+ break;
+ case 7: /* ifAdminStatus */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 9: /* ifLastChange */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 10: /* ifInOctets */
+ case 11: /* ifInUcastPkts */
+ case 12: /* ifInNUcastPkts */
+ case 13: /* ifInDiscarts */
+ case 14: /* ifInErrors */
+ case 15: /* ifInUnkownProtos */
+ case 16: /* ifOutOctets */
+ case 17: /* ifOutUcastPkts */
+ case 18: /* ifOutNUcastPkts */
+ case 19: /* ifOutDiscarts */
+ case 20: /* ifOutErrors */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 22: /* ifSpecific */
+ /** @note returning zeroDotZero (0.0) no media specific MIB support */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+ od->v_len = ifspecific.len * sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+/**
+ * Returns ifentry object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+ifentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ struct netif *netif;
+ u8_t id;
+
+ snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* ifIndex */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = od->id_inst_ptr[1];
+ }
+ break;
+ case 2: /* ifDescr */
+ ocstrncpy((u8_t*)value, (u8_t*)netif->name, len);
+ break;
+ case 3: /* ifType */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = netif->link_type;
+ }
+ break;
+ case 4: /* ifMtu */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = netif->mtu;
+ }
+ break;
+ case 5: /* ifSpeed */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->link_speed;
+ }
+ break;
+ case 6: /* ifPhysAddress */
+ ocstrncpy((u8_t*)value, netif->hwaddr, len);
+ break;
+ case 7: /* ifAdminStatus */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ if (netif_is_up(netif))
+ {
+ if (netif_is_link_up(netif))
+ {
+ *sint_ptr = 1; /* up */
+ }
+ else
+ {
+ *sint_ptr = 7; /* lowerLayerDown */
+ }
+ }
+ else
+ {
+ *sint_ptr = 2; /* down */
+ }
+ }
+ break;
+ case 8: /* ifOperStatus */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ if (netif_is_up(netif))
+ {
+ *sint_ptr = 1;
+ }
+ else
+ {
+ *sint_ptr = 2;
+ }
+ }
+ break;
+ case 9: /* ifLastChange */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ts;
+ }
+ break;
+ case 10: /* ifInOctets */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifinoctets;
+ }
+ break;
+ case 11: /* ifInUcastPkts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifinucastpkts;
+ }
+ break;
+ case 12: /* ifInNUcastPkts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifinnucastpkts;
+ }
+ break;
+ case 13: /* ifInDiscarts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifindiscards;
+ }
+ break;
+ case 14: /* ifInErrors */
+ case 15: /* ifInUnkownProtos */
+ /** @todo add these counters! */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = 0;
+ }
+ break;
+ case 16: /* ifOutOctets */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifoutoctets;
+ }
+ break;
+ case 17: /* ifOutUcastPkts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifoutucastpkts;
+ }
+ break;
+ case 18: /* ifOutNUcastPkts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifoutnucastpkts;
+ }
+ break;
+ case 19: /* ifOutDiscarts */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = netif->ifoutdiscards;
+ }
+ break;
+ case 20: /* ifOutErrors */
+ /** @todo add this counter! */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = 0;
+ }
+ break;
+ case 21: /* ifOutQLen */
+ /** @todo figure out if this must be 0 (no queue) or 1? */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = 0;
+ }
+ break;
+ case 22: /* ifSpecific */
+ objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t)));
+ break;
+ };
+}
+
+#if !SNMP_SAFE_REQUESTS
+static u8_t
+ifentry_set_test(struct obj_def *od, u16_t len, void *value)
+{
+ struct netif *netif;
+ u8_t id, set_ok;
+ LWIP_UNUSED_ARG(len);
+
+ set_ok = 0;
+ snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 7: /* ifAdminStatus */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ if (*sint_ptr == 1 || *sint_ptr == 2)
+ set_ok = 1;
+ }
+ break;
+ }
+ return set_ok;
+}
+
+static void
+ifentry_set_value(struct obj_def *od, u16_t len, void *value)
+{
+ struct netif *netif;
+ u8_t id;
+ LWIP_UNUSED_ARG(len);
+
+ snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 7: /* ifAdminStatus */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ if (*sint_ptr == 1)
+ {
+ netif_set_up(netif);
+ }
+ else if (*sint_ptr == 2)
+ {
+ netif_set_down(netif);
+ }
+ }
+ break;
+ }
+}
+#endif /* SNMP_SAFE_REQUESTS */
+
+/**
+ * Returns atentry object definitions.
+ *
+ * @param ident_len the address length (6)
+ * @param ident points to objectname.atifindex.atnetaddress
+ * @param od points to object definition.
+ */
+static void
+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (5) */
+ ident_len += 5;
+ ident -= 5;
+
+ if (ident_len == 6)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ switch (ident[0])
+ {
+ case 1: /* atIfIndex */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 2: /* atPhysAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = 6; /** @todo try to use netif::hwaddr_len */
+ break;
+ case 3: /* atNetAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+atentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+#if LWIP_ARP
+ u8_t id;
+ struct eth_addr* ethaddr_ret;
+ ip_addr_t* ipaddr_ret;
+#endif /* LWIP_ARP */
+ ip_addr_t ip;
+ struct netif *netif;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
+
+ snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+ snmp_oidtoip(&od->id_inst_ptr[2], &ip);
+
+#if LWIP_ARP /** @todo implement a netif_find_addr */
+ if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
+ {
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* atIfIndex */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = od->id_inst_ptr[1];
+ }
+ break;
+ case 2: /* atPhysAddress */
+ {
+ struct eth_addr *dst = (struct eth_addr*)value;
+
+ *dst = *ethaddr_ret;
+ }
+ break;
+ case 3: /* atNetAddress */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+
+ *dst = *ipaddr_ret;
+ }
+ break;
+ }
+ }
+#endif /* LWIP_ARP */
+}
+
+static void
+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ u8_t id;
+
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));
+ switch (id)
+ {
+ case 1: /* ipForwarding */
+ case 2: /* ipDefaultTTL */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 3: /* ipInReceives */
+ case 4: /* ipInHdrErrors */
+ case 5: /* ipInAddrErrors */
+ case 6: /* ipForwDatagrams */
+ case 7: /* ipInUnknownProtos */
+ case 8: /* ipInDiscards */
+ case 9: /* ipInDelivers */
+ case 10: /* ipOutRequests */
+ case 11: /* ipOutDiscards */
+ case 12: /* ipOutNoRoutes */
+ case 14: /* ipReasmReqds */
+ case 15: /* ipReasmOKs */
+ case 16: /* ipReasmFails */
+ case 17: /* ipFragOKs */
+ case 18: /* ipFragFails */
+ case 19: /* ipFragCreates */
+ case 23: /* ipRoutingDiscards */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 13: /* ipReasmTimeout */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+ip_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* ipForwarding */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+#if IP_FORWARD
+ /* forwarding */
+ *sint_ptr = 1;
+#else
+ /* not-forwarding */
+ *sint_ptr = 2;
+#endif
+ }
+ break;
+ case 2: /* ipDefaultTTL */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = IP_DEFAULT_TTL;
+ }
+ break;
+ case 3: /* ipInReceives */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipinreceives;
+ }
+ break;
+ case 4: /* ipInHdrErrors */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipinhdrerrors;
+ }
+ break;
+ case 5: /* ipInAddrErrors */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipinaddrerrors;
+ }
+ break;
+ case 6: /* ipForwDatagrams */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipforwdatagrams;
+ }
+ break;
+ case 7: /* ipInUnknownProtos */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipinunknownprotos;
+ }
+ break;
+ case 8: /* ipInDiscards */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipindiscards;
+ }
+ break;
+ case 9: /* ipInDelivers */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipindelivers;
+ }
+ break;
+ case 10: /* ipOutRequests */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipoutrequests;
+ }
+ break;
+ case 11: /* ipOutDiscards */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipoutdiscards;
+ }
+ break;
+ case 12: /* ipOutNoRoutes */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipoutnoroutes;
+ }
+ break;
+ case 13: /* ipReasmTimeout */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+#if IP_REASSEMBLY
+ *sint_ptr = IP_REASS_MAXAGE;
+#else
+ *sint_ptr = 0;
+#endif
+ }
+ break;
+ case 14: /* ipReasmReqds */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipreasmreqds;
+ }
+ break;
+ case 15: /* ipReasmOKs */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipreasmoks;
+ }
+ break;
+ case 16: /* ipReasmFails */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipreasmfails;
+ }
+ break;
+ case 17: /* ipFragOKs */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipfragoks;
+ }
+ break;
+ case 18: /* ipFragFails */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipfragfails;
+ }
+ break;
+ case 19: /* ipFragCreates */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = ipfragcreates;
+ }
+ break;
+ case 23: /* ipRoutingDiscards */
+ /** @todo can lwIP discard routes at all?? hardwire this to 0?? */
+ {
+ u32_t *uint_ptr = (u32_t*)value;
+ *uint_ptr = iproutingdiscards;
+ }
+ break;
+ };
+}
+
+/**
+ * Test ip object value before setting.
+ *
+ * @param od is the object definition
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value from.
+ *
+ * @note we allow set if the value matches the hardwired value,
+ * otherwise return badvalue.
+ */
+static u8_t
+ip_set_test(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id, set_ok;
+ s32_t *sint_ptr = (s32_t*)value;
+
+ LWIP_UNUSED_ARG(len);
+ set_ok = 0;
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* ipForwarding */
+#if IP_FORWARD
+ /* forwarding */
+ if (*sint_ptr == 1)
+#else
+ /* not-forwarding */
+ if (*sint_ptr == 2)
+#endif
+ {
+ set_ok = 1;
+ }
+ break;
+ case 2: /* ipDefaultTTL */
+ if (*sint_ptr == IP_DEFAULT_TTL)
+ {
+ set_ok = 1;
+ }
+ break;
+ };
+ return set_ok;
+}
+
+static void
+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (4) */
+ ident_len += 4;
+ ident -= 4;
+
+ if (ident_len == 5)
+ {
+ u8_t id;
+
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ switch (id)
+ {
+ case 1: /* ipAdEntAddr */
+ case 3: /* ipAdEntNetMask */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ case 2: /* ipAdEntIfIndex */
+ case 4: /* ipAdEntBcastAddr */
+ case 5: /* ipAdEntReasmMaxSize */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+ u16_t ifidx;
+ ip_addr_t ip;
+ struct netif *netif = netif_list;
+
+ LWIP_UNUSED_ARG(len);
+ snmp_oidtoip(&od->id_inst_ptr[1], &ip);
+ ifidx = 0;
+ while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))
+ {
+ netif = netif->next;
+ ifidx++;
+ }
+
+ if (netif != NULL)
+ {
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* ipAdEntAddr */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+ *dst = netif->ip_addr;
+ }
+ break;
+ case 2: /* ipAdEntIfIndex */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = ifidx + 1;
+ }
+ break;
+ case 3: /* ipAdEntNetMask */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+ *dst = netif->netmask;
+ }
+ break;
+ case 4: /* ipAdEntBcastAddr */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+
+ /* lwIP oddity, there's no broadcast
+ address in the netif we can rely on */
+ *sint_ptr = IPADDR_BROADCAST & 1;
+ }
+ break;
+ case 5: /* ipAdEntReasmMaxSize */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+#if IP_REASSEMBLY
+ /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
+ * but only if receiving one fragmented packet at a time.
+ * The current solution is to calculate for 2 simultaneous packets...
+ */
+ *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *
+ (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN)));
+#else
+ /** @todo returning MTU would be a bad thing and
+ returning a wild guess like '576' isn't good either */
+ *sint_ptr = 0;
+#endif
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * @note
+ * lwIP IP routing is currently using the network addresses in netif_list.
+ * if no suitable network IP is found in netif_list, the default_netif is used.
+ */
+static void
+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ u8_t id;
+
+ /* return to object name, adding index depth (4) */
+ ident_len += 4;
+ ident -= 4;
+
+ if (ident_len == 5)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ switch (id)
+ {
+ case 1: /* ipRouteDest */
+ case 7: /* ipRouteNextHop */
+ case 11: /* ipRouteMask */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ case 2: /* ipRouteIfIndex */
+ case 3: /* ipRouteMetric1 */
+ case 4: /* ipRouteMetric2 */
+ case 5: /* ipRouteMetric3 */
+ case 6: /* ipRouteMetric4 */
+ case 8: /* ipRouteType */
+ case 10: /* ipRouteAge */
+ case 12: /* ipRouteMetric5 */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 9: /* ipRouteProto */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 13: /* ipRouteInfo */
+ /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+ od->v_len = iprouteinfo.len * sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ struct netif *netif;
+ ip_addr_t dest;
+ s32_t *ident;
+ u8_t id;
+
+ ident = od->id_inst_ptr;
+ snmp_oidtoip(&ident[1], &dest);
+
+ if (ip_addr_isany(&dest))
+ {
+ /* ip_route() uses default netif for default route */
+ netif = netif_default;
+ }
+ else
+ {
+ /* not using ip_route(), need exact match! */
+ netif = netif_list;
+ while ((netif != NULL) &&
+ !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )
+ {
+ netif = netif->next;
+ }
+ }
+ if (netif != NULL)
+ {
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ switch (id)
+ {
+ case 1: /* ipRouteDest */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+
+ if (ip_addr_isany(&dest))
+ {
+ /* default rte has 0.0.0.0 dest */
+ ip_addr_set_zero(dst);
+ }
+ else
+ {
+ /* netifs have netaddress dest */
+ ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask);
+ }
+ }
+ break;
+ case 2: /* ipRouteIfIndex */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+
+ snmp_netiftoifindex(netif, sint_ptr);
+ }
+ break;
+ case 3: /* ipRouteMetric1 */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+
+ if (ip_addr_isany(&dest))
+ {
+ /* default rte has metric 1 */
+ *sint_ptr = 1;
+ }
+ else
+ {
+ /* other rtes have metric 0 */
+ *sint_ptr = 0;
+ }
+ }
+ break;
+ case 4: /* ipRouteMetric2 */
+ case 5: /* ipRouteMetric3 */
+ case 6: /* ipRouteMetric4 */
+ case 12: /* ipRouteMetric5 */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ /* not used */
+ *sint_ptr = -1;
+ }
+ break;
+ case 7: /* ipRouteNextHop */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+
+ if (ip_addr_isany(&dest))
+ {
+ /* default rte: gateway */
+ *dst = netif->gw;
+ }
+ else
+ {
+ /* other rtes: netif ip_addr */
+ *dst = netif->ip_addr;
+ }
+ }
+ break;
+ case 8: /* ipRouteType */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+
+ if (ip_addr_isany(&dest))
+ {
+ /* default rte is indirect */
+ *sint_ptr = 4;
+ }
+ else
+ {
+ /* other rtes are direct */
+ *sint_ptr = 3;
+ }
+ }
+ break;
+ case 9: /* ipRouteProto */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ /* locally defined routes */
+ *sint_ptr = 2;
+ }
+ break;
+ case 10: /* ipRouteAge */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ /** @todo (sysuptime - timestamp last change) / 100
+ @see snmp_insert_iprteidx_tree() */
+ *sint_ptr = 0;
+ }
+ break;
+ case 11: /* ipRouteMask */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+
+ if (ip_addr_isany(&dest))
+ {
+ /* default rte use 0.0.0.0 mask */
+ ip_addr_set_zero(dst);
+ }
+ else
+ {
+ /* other rtes use netmask */
+ *dst = netif->netmask;
+ }
+ }
+ break;
+ case 13: /* ipRouteInfo */
+ objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t)));
+ break;
+ }
+ }
+}
+
+static void
+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (5) */
+ ident_len += 5;
+ ident -= 5;
+
+ if (ident_len == 6)
+ {
+ u8_t id;
+
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ switch (id)
+ {
+ case 1: /* ipNetToMediaIfIndex */
+ case 4: /* ipNetToMediaType */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 2: /* ipNetToMediaPhysAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+ od->v_len = 6; /** @todo try to use netif::hwaddr_len */
+ break;
+ case 3: /* ipNetToMediaNetAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+#if LWIP_ARP
+ u8_t id;
+ struct eth_addr* ethaddr_ret;
+ ip_addr_t* ipaddr_ret;
+#endif /* LWIP_ARP */
+ ip_addr_t ip;
+ struct netif *netif;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
+
+ snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+ snmp_oidtoip(&od->id_inst_ptr[2], &ip);
+
+#if LWIP_ARP /** @todo implement a netif_find_addr */
+ if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
+ {
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* ipNetToMediaIfIndex */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = od->id_inst_ptr[1];
+ }
+ break;
+ case 2: /* ipNetToMediaPhysAddress */
+ {
+ struct eth_addr *dst = (struct eth_addr*)value;
+
+ *dst = *ethaddr_ret;
+ }
+ break;
+ case 3: /* ipNetToMediaNetAddress */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+
+ *dst = *ipaddr_ret;
+ }
+ break;
+ case 4: /* ipNetToMediaType */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ /* dynamic (?) */
+ *sint_ptr = 3;
+ }
+ break;
+ }
+ }
+#endif /* LWIP_ARP */
+}
+
+static void
+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if ((ident_len == 2) &&
+ (ident[0] > 0) && (ident[0] < 27))
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+icmp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u32_t *uint_ptr = (u32_t*)value;
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* icmpInMsgs */
+ *uint_ptr = icmpinmsgs;
+ break;
+ case 2: /* icmpInErrors */
+ *uint_ptr = icmpinerrors;
+ break;
+ case 3: /* icmpInDestUnreachs */
+ *uint_ptr = icmpindestunreachs;
+ break;
+ case 4: /* icmpInTimeExcds */
+ *uint_ptr = icmpintimeexcds;
+ break;
+ case 5: /* icmpInParmProbs */
+ *uint_ptr = icmpinparmprobs;
+ break;
+ case 6: /* icmpInSrcQuenchs */
+ *uint_ptr = icmpinsrcquenchs;
+ break;
+ case 7: /* icmpInRedirects */
+ *uint_ptr = icmpinredirects;
+ break;
+ case 8: /* icmpInEchos */
+ *uint_ptr = icmpinechos;
+ break;
+ case 9: /* icmpInEchoReps */
+ *uint_ptr = icmpinechoreps;
+ break;
+ case 10: /* icmpInTimestamps */
+ *uint_ptr = icmpintimestamps;
+ break;
+ case 11: /* icmpInTimestampReps */
+ *uint_ptr = icmpintimestampreps;
+ break;
+ case 12: /* icmpInAddrMasks */
+ *uint_ptr = icmpinaddrmasks;
+ break;
+ case 13: /* icmpInAddrMaskReps */
+ *uint_ptr = icmpinaddrmaskreps;
+ break;
+ case 14: /* icmpOutMsgs */
+ *uint_ptr = icmpoutmsgs;
+ break;
+ case 15: /* icmpOutErrors */
+ *uint_ptr = icmpouterrors;
+ break;
+ case 16: /* icmpOutDestUnreachs */
+ *uint_ptr = icmpoutdestunreachs;
+ break;
+ case 17: /* icmpOutTimeExcds */
+ *uint_ptr = icmpouttimeexcds;
+ break;
+ case 18: /* icmpOutParmProbs */
+ *uint_ptr = icmpoutparmprobs;
+ break;
+ case 19: /* icmpOutSrcQuenchs */
+ *uint_ptr = icmpoutsrcquenchs;
+ break;
+ case 20: /* icmpOutRedirects */
+ *uint_ptr = icmpoutredirects;
+ break;
+ case 21: /* icmpOutEchos */
+ *uint_ptr = icmpoutechos;
+ break;
+ case 22: /* icmpOutEchoReps */
+ *uint_ptr = icmpoutechoreps;
+ break;
+ case 23: /* icmpOutTimestamps */
+ *uint_ptr = icmpouttimestamps;
+ break;
+ case 24: /* icmpOutTimestampReps */
+ *uint_ptr = icmpouttimestampreps;
+ break;
+ case 25: /* icmpOutAddrMasks */
+ *uint_ptr = icmpoutaddrmasks;
+ break;
+ case 26: /* icmpOutAddrMaskReps */
+ *uint_ptr = icmpoutaddrmaskreps;
+ break;
+ }
+}
+
+#if LWIP_TCP
+/** @todo tcp grp */
+static void
+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ u8_t id;
+
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
+
+ switch (id)
+ {
+ case 1: /* tcpRtoAlgorithm */
+ case 2: /* tcpRtoMin */
+ case 3: /* tcpRtoMax */
+ case 4: /* tcpMaxConn */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 5: /* tcpActiveOpens */
+ case 6: /* tcpPassiveOpens */
+ case 7: /* tcpAttemptFails */
+ case 8: /* tcpEstabResets */
+ case 10: /* tcpInSegs */
+ case 11: /* tcpOutSegs */
+ case 12: /* tcpRetransSegs */
+ case 14: /* tcpInErrs */
+ case 15: /* tcpOutRsts */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 9: /* tcpCurrEstab */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+ od->v_len = sizeof(u32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+tcp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u32_t *uint_ptr = (u32_t*)value;
+ s32_t *sint_ptr = (s32_t*)value;
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* tcpRtoAlgorithm, vanj(4) */
+ *sint_ptr = 4;
+ break;
+ case 2: /* tcpRtoMin */
+ /* @todo not the actual value, a guess,
+ needs to be calculated */
+ *sint_ptr = 1000;
+ break;
+ case 3: /* tcpRtoMax */
+ /* @todo not the actual value, a guess,
+ needs to be calculated */
+ *sint_ptr = 60000;
+ break;
+ case 4: /* tcpMaxConn */
+ *sint_ptr = MEMP_NUM_TCP_PCB;
+ break;
+ case 5: /* tcpActiveOpens */
+ *uint_ptr = tcpactiveopens;
+ break;
+ case 6: /* tcpPassiveOpens */
+ *uint_ptr = tcppassiveopens;
+ break;
+ case 7: /* tcpAttemptFails */
+ *uint_ptr = tcpattemptfails;
+ break;
+ case 8: /* tcpEstabResets */
+ *uint_ptr = tcpestabresets;
+ break;
+ case 9: /* tcpCurrEstab */
+ {
+ u16_t tcpcurrestab = 0;
+ struct tcp_pcb *pcb = tcp_active_pcbs;
+ while (pcb != NULL)
+ {
+ if ((pcb->state == ESTABLISHED) ||
+ (pcb->state == CLOSE_WAIT))
+ {
+ tcpcurrestab++;
+ }
+ pcb = pcb->next;
+ }
+ *uint_ptr = tcpcurrestab;
+ }
+ break;
+ case 10: /* tcpInSegs */
+ *uint_ptr = tcpinsegs;
+ break;
+ case 11: /* tcpOutSegs */
+ *uint_ptr = tcpoutsegs;
+ break;
+ case 12: /* tcpRetransSegs */
+ *uint_ptr = tcpretranssegs;
+ break;
+ case 14: /* tcpInErrs */
+ *uint_ptr = tcpinerrs;
+ break;
+ case 15: /* tcpOutRsts */
+ *uint_ptr = tcpoutrsts;
+ break;
+ }
+}
+#ifdef THIS_SEEMS_UNUSED
+static void
+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (10) */
+ ident_len += 10;
+ ident -= 10;
+
+ if (ident_len == 11)
+ {
+ u8_t id;
+
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ id = ident[0];
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
+
+ switch (id)
+ {
+ case 1: /* tcpConnState */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ case 2: /* tcpConnLocalAddress */
+ case 4: /* tcpConnRemAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ case 3: /* tcpConnLocalPort */
+ case 5: /* tcpConnRemPort */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ ip_addr_t lip, rip;
+ u16_t lport, rport;
+ s32_t *ident;
+
+ ident = od->id_inst_ptr;
+ snmp_oidtoip(&ident[1], &lip);
+ lport = ident[5];
+ snmp_oidtoip(&ident[6], &rip);
+ rport = ident[10];
+
+ /** @todo find matching PCB */
+}
+#endif /* if 0 */
+#endif
+
+static void
+udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if ((ident_len == 2) &&
+ (ident[0] > 0) && (ident[0] < 6))
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+udp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u32_t *uint_ptr = (u32_t*)value;
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* udpInDatagrams */
+ *uint_ptr = udpindatagrams;
+ break;
+ case 2: /* udpNoPorts */
+ *uint_ptr = udpnoports;
+ break;
+ case 3: /* udpInErrors */
+ *uint_ptr = udpinerrors;
+ break;
+ case 4: /* udpOutDatagrams */
+ *uint_ptr = udpoutdatagrams;
+ break;
+ }
+}
+
+static void
+udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (5) */
+ ident_len += 5;
+ ident -= 5;
+
+ if (ident_len == 6)
+ {
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ switch (ident[0])
+ {
+ case 1: /* udpLocalAddress */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+ od->v_len = 4;
+ break;
+ case 2: /* udpLocalPort */
+ od->instance = MIB_OBJECT_TAB;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+udpentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+ struct udp_pcb *pcb;
+ ip_addr_t ip;
+ u16_t port;
+
+ LWIP_UNUSED_ARG(len);
+ snmp_oidtoip(&od->id_inst_ptr[1], &ip);
+ LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff));
+ port = (u16_t)od->id_inst_ptr[5];
+
+ pcb = udp_pcbs;
+ while ((pcb != NULL) &&
+ !(ip_addr_cmp(&pcb->local_ip, &ip) &&
+ (pcb->local_port == port)))
+ {
+ pcb = pcb->next;
+ }
+
+ if (pcb != NULL)
+ {
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* udpLocalAddress */
+ {
+ ip_addr_t *dst = (ip_addr_t*)value;
+ *dst = pcb->local_ip;
+ }
+ break;
+ case 2: /* udpLocalPort */
+ {
+ s32_t *sint_ptr = (s32_t*)value;
+ *sint_ptr = pcb->local_port;
+ }
+ break;
+ }
+ }
+}
+
+static void
+snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+ /* return to object name, adding index depth (1) */
+ ident_len += 1;
+ ident -= 1;
+ if (ident_len == 2)
+ {
+ u8_t id;
+
+ od->id_inst_len = ident_len;
+ od->id_inst_ptr = ident;
+
+ LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+ id = (u8_t)ident[0];
+ switch (id)
+ {
+ case 1: /* snmpInPkts */
+ case 2: /* snmpOutPkts */
+ case 3: /* snmpInBadVersions */
+ case 4: /* snmpInBadCommunityNames */
+ case 5: /* snmpInBadCommunityUses */
+ case 6: /* snmpInASNParseErrs */
+ case 8: /* snmpInTooBigs */
+ case 9: /* snmpInNoSuchNames */
+ case 10: /* snmpInBadValues */
+ case 11: /* snmpInReadOnlys */
+ case 12: /* snmpInGenErrs */
+ case 13: /* snmpInTotalReqVars */
+ case 14: /* snmpInTotalSetVars */
+ case 15: /* snmpInGetRequests */
+ case 16: /* snmpInGetNexts */
+ case 17: /* snmpInSetRequests */
+ case 18: /* snmpInGetResponses */
+ case 19: /* snmpInTraps */
+ case 20: /* snmpOutTooBigs */
+ case 21: /* snmpOutNoSuchNames */
+ case 22: /* snmpOutBadValues */
+ case 24: /* snmpOutGenErrs */
+ case 25: /* snmpOutGetRequests */
+ case 26: /* snmpOutGetNexts */
+ case 27: /* snmpOutSetRequests */
+ case 28: /* snmpOutGetResponses */
+ case 29: /* snmpOutTraps */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_ONLY;
+ od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+ od->v_len = sizeof(u32_t);
+ break;
+ case 30: /* snmpEnableAuthenTraps */
+ od->instance = MIB_OBJECT_SCALAR;
+ od->access = MIB_OBJECT_READ_WRITE;
+ od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+ od->v_len = sizeof(s32_t);
+ break;
+ default:
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));
+ od->instance = MIB_OBJECT_NONE;
+ break;
+ };
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));
+ od->instance = MIB_OBJECT_NONE;
+ }
+}
+
+static void
+snmp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+ u32_t *uint_ptr = (u32_t*)value;
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ switch (id)
+ {
+ case 1: /* snmpInPkts */
+ *uint_ptr = snmpinpkts;
+ break;
+ case 2: /* snmpOutPkts */
+ *uint_ptr = snmpoutpkts;
+ break;
+ case 3: /* snmpInBadVersions */
+ *uint_ptr = snmpinbadversions;
+ break;
+ case 4: /* snmpInBadCommunityNames */
+ *uint_ptr = snmpinbadcommunitynames;
+ break;
+ case 5: /* snmpInBadCommunityUses */
+ *uint_ptr = snmpinbadcommunityuses;
+ break;
+ case 6: /* snmpInASNParseErrs */
+ *uint_ptr = snmpinasnparseerrs;
+ break;
+ case 8: /* snmpInTooBigs */
+ *uint_ptr = snmpintoobigs;
+ break;
+ case 9: /* snmpInNoSuchNames */
+ *uint_ptr = snmpinnosuchnames;
+ break;
+ case 10: /* snmpInBadValues */
+ *uint_ptr = snmpinbadvalues;
+ break;
+ case 11: /* snmpInReadOnlys */
+ *uint_ptr = snmpinreadonlys;
+ break;
+ case 12: /* snmpInGenErrs */
+ *uint_ptr = snmpingenerrs;
+ break;
+ case 13: /* snmpInTotalReqVars */
+ *uint_ptr = snmpintotalreqvars;
+ break;
+ case 14: /* snmpInTotalSetVars */
+ *uint_ptr = snmpintotalsetvars;
+ break;
+ case 15: /* snmpInGetRequests */
+ *uint_ptr = snmpingetrequests;
+ break;
+ case 16: /* snmpInGetNexts */
+ *uint_ptr = snmpingetnexts;
+ break;
+ case 17: /* snmpInSetRequests */
+ *uint_ptr = snmpinsetrequests;
+ break;
+ case 18: /* snmpInGetResponses */
+ *uint_ptr = snmpingetresponses;
+ break;
+ case 19: /* snmpInTraps */
+ *uint_ptr = snmpintraps;
+ break;
+ case 20: /* snmpOutTooBigs */
+ *uint_ptr = snmpouttoobigs;
+ break;
+ case 21: /* snmpOutNoSuchNames */
+ *uint_ptr = snmpoutnosuchnames;
+ break;
+ case 22: /* snmpOutBadValues */
+ *uint_ptr = snmpoutbadvalues;
+ break;
+ case 24: /* snmpOutGenErrs */
+ *uint_ptr = snmpoutgenerrs;
+ break;
+ case 25: /* snmpOutGetRequests */
+ *uint_ptr = snmpoutgetrequests;
+ break;
+ case 26: /* snmpOutGetNexts */
+ *uint_ptr = snmpoutgetnexts;
+ break;
+ case 27: /* snmpOutSetRequests */
+ *uint_ptr = snmpoutsetrequests;
+ break;
+ case 28: /* snmpOutGetResponses */
+ *uint_ptr = snmpoutgetresponses;
+ break;
+ case 29: /* snmpOutTraps */
+ *uint_ptr = snmpouttraps;
+ break;
+ case 30: /* snmpEnableAuthenTraps */
+ *uint_ptr = *snmpenableauthentraps_ptr;
+ break;
+ };
+}
+
+/**
+ * Test snmp object value before setting.
+ *
+ * @param od is the object definition
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value from.
+ */
+static u8_t
+snmp_set_test(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id, set_ok;
+
+ LWIP_UNUSED_ARG(len);
+ set_ok = 0;
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ if (id == 30)
+ {
+ /* snmpEnableAuthenTraps */
+ s32_t *sint_ptr = (s32_t*)value;
+
+ if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)
+ {
+ /* we should have writable non-volatile mem here */
+ if ((*sint_ptr == 1) || (*sint_ptr == 2))
+ {
+ set_ok = 1;
+ }
+ }
+ else
+ {
+ /* const or hardwired value */
+ if (*sint_ptr == snmpenableauthentraps_default)
+ {
+ set_ok = 1;
+ }
+ }
+ }
+ return set_ok;
+}
+
+static void
+snmp_set_value(struct obj_def *od, u16_t len, void *value)
+{
+ u8_t id;
+
+ LWIP_UNUSED_ARG(len);
+ LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+ id = (u8_t)od->id_inst_ptr[0];
+ if (id == 30)
+ {
+ /* snmpEnableAuthenTraps */
+ /* @todo @fixme: which kind of pointer is 'value'? s32_t or u8_t??? */
+ u8_t *ptr = (u8_t*)value;
+ *snmpenableauthentraps_ptr = *ptr;
+ }
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib_structs.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib_structs.c
new file mode 100644
index 0000000000..2f185cb436
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/mib_structs.c
@@ -0,0 +1,1174 @@
+/**
+ * @file
+ * MIB tree access/construction functions.
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp_structs.h"
+#include "lwip/memp.h"
+#include "lwip/netif.h"
+
+/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
+const s32_t prefix[4] = {1, 3, 6, 1};
+
+#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)
+/** node stack entry (old news?) */
+struct nse
+{
+ /** right child */
+ struct mib_node* r_ptr;
+ /** right child identifier */
+ s32_t r_id;
+ /** right child next level */
+ u8_t r_nl;
+};
+static u8_t node_stack_cnt;
+static struct nse node_stack[NODE_STACK_SIZE];
+
+/**
+ * Pushes nse struct onto stack.
+ */
+static void
+push_node(struct nse* node)
+{
+ LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));
+ if (node_stack_cnt < NODE_STACK_SIZE)
+ {
+ node_stack[node_stack_cnt] = *node;
+ node_stack_cnt++;
+ }
+}
+
+/**
+ * Pops nse struct from stack.
+ */
+static void
+pop_node(struct nse* node)
+{
+ if (node_stack_cnt > 0)
+ {
+ node_stack_cnt--;
+ *node = node_stack[node_stack_cnt];
+ }
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));
+}
+
+/**
+ * Conversion from ifIndex to lwIP netif
+ * @param ifindex is a s32_t object sub-identifier
+ * @param netif points to returned netif struct pointer
+ */
+void
+snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
+{
+ struct netif *nif = netif_list;
+ s32_t i, ifidx;
+
+ ifidx = ifindex - 1;
+ i = 0;
+ while ((nif != NULL) && (i < ifidx))
+ {
+ nif = nif->next;
+ i++;
+ }
+ *netif = nif;
+}
+
+/**
+ * Conversion from lwIP netif to ifIndex
+ * @param netif points to a netif struct
+ * @param ifidx points to s32_t object sub-identifier
+ */
+void
+snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
+{
+ struct netif *nif = netif_list;
+ u16_t i;
+
+ i = 0;
+ while ((nif != NULL) && (nif != netif))
+ {
+ nif = nif->next;
+ i++;
+ }
+ *ifidx = i+1;
+}
+
+/**
+ * Conversion from oid to lwIP ip_addr
+ * @param ident points to s32_t ident[4] input
+ * @param ip points to output struct
+ */
+void
+snmp_oidtoip(s32_t *ident, ip_addr_t *ip)
+{
+ IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
+}
+
+/**
+ * Conversion from lwIP ip_addr to oid
+ * @param ip points to input struct
+ * @param ident points to s32_t ident[4] output
+ */
+void
+snmp_iptooid(ip_addr_t *ip, s32_t *ident)
+{
+ ident[0] = ip4_addr1(ip);
+ ident[1] = ip4_addr2(ip);
+ ident[2] = ip4_addr3(ip);
+ ident[3] = ip4_addr4(ip);
+}
+
+struct mib_list_node *
+snmp_mib_ln_alloc(s32_t id)
+{
+ struct mib_list_node *ln;
+
+ ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE);
+ if (ln != NULL)
+ {
+ ln->prev = NULL;
+ ln->next = NULL;
+ ln->objid = id;
+ ln->nptr = NULL;
+ }
+ return ln;
+}
+
+void
+snmp_mib_ln_free(struct mib_list_node *ln)
+{
+ memp_free(MEMP_SNMP_NODE, ln);
+}
+
+struct mib_list_rootnode *
+snmp_mib_lrn_alloc(void)
+{
+ struct mib_list_rootnode *lrn;
+
+ lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE);
+ if (lrn != NULL)
+ {
+ lrn->get_object_def = noleafs_get_object_def;
+ lrn->get_value = noleafs_get_value;
+ lrn->set_test = noleafs_set_test;
+ lrn->set_value = noleafs_set_value;
+ lrn->node_type = MIB_NODE_LR;
+ lrn->maxlength = 0;
+ lrn->head = NULL;
+ lrn->tail = NULL;
+ lrn->count = 0;
+ }
+ return lrn;
+}
+
+void
+snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
+{
+ memp_free(MEMP_SNMP_ROOTNODE, lrn);
+}
+
+/**
+ * Inserts node in idx list in a sorted
+ * (ascending order) fashion and
+ * allocates the node if needed.
+ *
+ * @param rn points to the root node
+ * @param objid is the object sub identifier
+ * @param insn points to a pointer to the inserted node
+ * used for constructing the tree.
+ * @return -1 if failed, 1 if inserted, 2 if present.
+ */
+s8_t
+snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)
+{
+ struct mib_list_node *nn;
+ s8_t insert;
+
+ LWIP_ASSERT("rn != NULL",rn != NULL);
+
+ /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */
+ insert = 0;
+ if (rn->head == NULL)
+ {
+ /* empty list, add first node */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));
+ nn = snmp_mib_ln_alloc(objid);
+ if (nn != NULL)
+ {
+ rn->head = nn;
+ rn->tail = nn;
+ *insn = nn;
+ insert = 1;
+ }
+ else
+ {
+ insert = -1;
+ }
+ }
+ else
+ {
+ struct mib_list_node *n;
+ /* at least one node is present */
+ n = rn->head;
+ while ((n != NULL) && (insert == 0))
+ {
+ if (n->objid == objid)
+ {
+ /* node is already there */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));
+ *insn = n;
+ insert = 2;
+ }
+ else if (n->objid < objid)
+ {
+ if (n->next == NULL)
+ {
+ /* alloc and insert at the tail */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));
+ nn = snmp_mib_ln_alloc(objid);
+ if (nn != NULL)
+ {
+ nn->next = NULL;
+ nn->prev = n;
+ n->next = nn;
+ rn->tail = nn;
+ *insn = nn;
+ insert = 1;
+ }
+ else
+ {
+ /* insertion failure */
+ insert = -1;
+ }
+ }
+ else
+ {
+ /* there's more to explore: traverse list */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));
+ n = n->next;
+ }
+ }
+ else
+ {
+ /* n->objid > objid */
+ /* alloc and insert between n->prev and n */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));
+ nn = snmp_mib_ln_alloc(objid);
+ if (nn != NULL)
+ {
+ if (n->prev == NULL)
+ {
+ /* insert at the head */
+ nn->next = n;
+ nn->prev = NULL;
+ rn->head = nn;
+ n->prev = nn;
+ }
+ else
+ {
+ /* insert in the middle */
+ nn->next = n;
+ nn->prev = n->prev;
+ n->prev->next = nn;
+ n->prev = nn;
+ }
+ *insn = nn;
+ insert = 1;
+ }
+ else
+ {
+ /* insertion failure */
+ insert = -1;
+ }
+ }
+ }
+ }
+ if (insert == 1)
+ {
+ rn->count += 1;
+ }
+ LWIP_ASSERT("insert != 0",insert != 0);
+ return insert;
+}
+
+/**
+ * Finds node in idx list and returns deletion mark.
+ *
+ * @param rn points to the root node
+ * @param objid is the object sub identifier
+ * @param fn returns pointer to found node
+ * @return 0 if not found, 1 if deletable,
+ * 2 can't delete (2 or more children), 3 not a list_node
+ */
+s8_t
+snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)
+{
+ s8_t fc;
+ struct mib_list_node *n;
+
+ LWIP_ASSERT("rn != NULL",rn != NULL);
+ n = rn->head;
+ while ((n != NULL) && (n->objid != objid))
+ {
+ n = n->next;
+ }
+ if (n == NULL)
+ {
+ fc = 0;
+ }
+ else if (n->nptr == NULL)
+ {
+ /* leaf, can delete node */
+ fc = 1;
+ }
+ else
+ {
+ struct mib_list_rootnode *r;
+
+ if (n->nptr->node_type == MIB_NODE_LR)
+ {
+ r = (struct mib_list_rootnode *)n->nptr;
+ if (r->count > 1)
+ {
+ /* can't delete node */
+ fc = 2;
+ }
+ else
+ {
+ /* count <= 1, can delete node */
+ fc = 1;
+ }
+ }
+ else
+ {
+ /* other node type */
+ fc = 3;
+ }
+ }
+ *fn = n;
+ return fc;
+}
+
+/**
+ * Removes node from idx list
+ * if it has a single child left.
+ *
+ * @param rn points to the root node
+ * @param n points to the node to delete
+ * @return the nptr to be freed by caller
+ */
+struct mib_list_rootnode *
+snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
+{
+ struct mib_list_rootnode *next;
+
+ LWIP_ASSERT("rn != NULL",rn != NULL);
+ LWIP_ASSERT("n != NULL",n != NULL);
+
+ /* caller must remove this sub-tree */
+ next = (struct mib_list_rootnode*)(n->nptr);
+ rn->count -= 1;
+
+ if (n == rn->head)
+ {
+ rn->head = n->next;
+ if (n->next != NULL)
+ {
+ /* not last node, new list begin */
+ n->next->prev = NULL;
+ }
+ }
+ else if (n == rn->tail)
+ {
+ rn->tail = n->prev;
+ if (n->prev != NULL)
+ {
+ /* not last node, new list end */
+ n->prev->next = NULL;
+ }
+ }
+ else
+ {
+ /* node must be in the middle */
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+ }
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));
+ snmp_mib_ln_free(n);
+ if (rn->count == 0)
+ {
+ rn->head = NULL;
+ rn->tail = NULL;
+ }
+ return next;
+}
+
+
+
+/**
+ * Searches tree for the supplied (scalar?) object identifier.
+ *
+ * @param node points to the root of the tree ('.internet')
+ * @param ident_len the length of the supplied object identifier
+ * @param ident points to the array of sub identifiers
+ * @param np points to the found object instance (return)
+ * @return pointer to the requested parent (!) node if success, NULL otherwise
+ */
+struct mib_node *
+snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)
+{
+ u8_t node_type, ext_level;
+
+ ext_level = 0;
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));
+ while (node != NULL)
+ {
+ node_type = node->node_type;
+ if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
+ {
+ struct mib_array_node *an;
+ u16_t i;
+
+ if (ident_len > 0)
+ {
+ /* array node (internal ROM or RAM, fixed length) */
+ an = (struct mib_array_node *)node;
+ i = 0;
+ while ((i < an->maxlength) && (an->objid[i] != *ident))
+ {
+ i++;
+ }
+ if (i < an->maxlength)
+ {
+ /* found it, if available proceed to child, otherwise inspect leaf */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
+ if (an->nptr[i] == NULL)
+ {
+ /* a scalar leaf OR table,
+ inspect remaining instance number / table index */
+ np->ident_len = ident_len;
+ np->ident = ident;
+ return (struct mib_node*)an;
+ }
+ else
+ {
+ /* follow next child pointer */
+ ident++;
+ ident_len--;
+ node = an->nptr[i];
+ }
+ }
+ else
+ {
+ /* search failed, identifier mismatch (nosuchname) */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));
+ return NULL;
+ }
+ }
+ else
+ {
+ /* search failed, short object identifier (nosuchname) */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));
+ return NULL;
+ }
+ }
+ else if(node_type == MIB_NODE_LR)
+ {
+ struct mib_list_rootnode *lrn;
+ struct mib_list_node *ln;
+
+ if (ident_len > 0)
+ {
+ /* list root node (internal 'RAM', variable length) */
+ lrn = (struct mib_list_rootnode *)node;
+ ln = lrn->head;
+ /* iterate over list, head to tail */
+ while ((ln != NULL) && (ln->objid != *ident))
+ {
+ ln = ln->next;
+ }
+ if (ln != NULL)
+ {
+ /* found it, proceed to child */;
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
+ if (ln->nptr == NULL)
+ {
+ np->ident_len = ident_len;
+ np->ident = ident;
+ return (struct mib_node*)lrn;
+ }
+ else
+ {
+ /* follow next child pointer */
+ ident_len--;
+ ident++;
+ node = ln->nptr;
+ }
+ }
+ else
+ {
+ /* search failed */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));
+ return NULL;
+ }
+ }
+ else
+ {
+ /* search failed, short object identifier (nosuchname) */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));
+ return NULL;
+ }
+ }
+ else if(node_type == MIB_NODE_EX)
+ {
+ struct mib_external_node *en;
+ u16_t i, len;
+
+ if (ident_len > 0)
+ {
+ /* external node (addressing and access via functions) */
+ en = (struct mib_external_node *)node;
+
+ i = 0;
+ len = en->level_length(en->addr_inf,ext_level);
+ while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))
+ {
+ i++;
+ }
+ if (i < len)
+ {
+ s32_t debug_id;
+
+ en->get_objid(en->addr_inf,ext_level,i,&debug_id);
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));
+ if ((ext_level + 1) == en->tree_levels)
+ {
+ np->ident_len = ident_len;
+ np->ident = ident;
+ return (struct mib_node*)en;
+ }
+ else
+ {
+ /* found it, proceed to child */
+ ident_len--;
+ ident++;
+ ext_level++;
+ }
+ }
+ else
+ {
+ /* search failed */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));
+ return NULL;
+ }
+ }
+ else
+ {
+ /* search failed, short object identifier (nosuchname) */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));
+ return NULL;
+ }
+ }
+ else if (node_type == MIB_NODE_SC)
+ {
+ mib_scalar_node *sn;
+
+ sn = (mib_scalar_node *)node;
+ if ((ident_len == 1) && (*ident == 0))
+ {
+ np->ident_len = ident_len;
+ np->ident = ident;
+ return (struct mib_node*)sn;
+ }
+ else
+ {
+ /* search failed, short object identifier (nosuchname) */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));
+ return NULL;
+ }
+ }
+ else
+ {
+ /* unknown node_type */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));
+ return NULL;
+ }
+ }
+ /* done, found nothing */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));
+ return NULL;
+}
+
+/**
+ * Test table for presence of at least one table entry.
+ */
+static u8_t
+empty_table(struct mib_node *node)
+{
+ u8_t node_type;
+ u8_t empty = 0;
+
+ if (node != NULL)
+ {
+ node_type = node->node_type;
+ if (node_type == MIB_NODE_LR)
+ {
+ struct mib_list_rootnode *lrn;
+ lrn = (struct mib_list_rootnode *)node;
+ if ((lrn->count == 0) || (lrn->head == NULL))
+ {
+ empty = 1;
+ }
+ }
+ else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
+ {
+ struct mib_array_node *an;
+ an = (struct mib_array_node *)node;
+ if ((an->maxlength == 0) || (an->nptr == NULL))
+ {
+ empty = 1;
+ }
+ }
+ else if (node_type == MIB_NODE_EX)
+ {
+ struct mib_external_node *en;
+ en = (struct mib_external_node *)node;
+ if (en->tree_levels == 0)
+ {
+ empty = 1;
+ }
+ }
+ }
+ return empty;
+}
+
+/**
+ * Tree expansion.
+ */
+struct mib_node *
+snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
+{
+ u8_t node_type, ext_level, climb_tree;
+
+ ext_level = 0;
+ /* reset node stack */
+ node_stack_cnt = 0;
+ while (node != NULL)
+ {
+ climb_tree = 0;
+ node_type = node->node_type;
+ if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
+ {
+ struct mib_array_node *an;
+ u16_t i;
+
+ /* array node (internal ROM or RAM, fixed length) */
+ an = (struct mib_array_node *)node;
+ if (ident_len > 0)
+ {
+ i = 0;
+ while ((i < an->maxlength) && (an->objid[i] < *ident))
+ {
+ i++;
+ }
+ if (i < an->maxlength)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
+ /* add identifier to oidret */
+ oidret->id[oidret->len] = an->objid[i];
+ (oidret->len)++;
+
+ if (an->nptr[i] == NULL)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
+ /* leaf node (e.g. in a fixed size table) */
+ if (an->objid[i] > *ident)
+ {
+ return (struct mib_node*)an;
+ }
+ else if ((i + 1) < an->maxlength)
+ {
+ /* an->objid[i] == *ident */
+ (oidret->len)--;
+ oidret->id[oidret->len] = an->objid[i + 1];
+ (oidret->len)++;
+ return (struct mib_node*)an;
+ }
+ else
+ {
+ /* (i + 1) == an->maxlength */
+ (oidret->len)--;
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ u8_t j;
+ struct nse cur_node;
+
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
+ /* non-leaf, store right child ptr and id */
+ LWIP_ASSERT("i < 0xff", i < 0xff);
+ j = (u8_t)i + 1;
+ while ((j < an->maxlength) && (empty_table(an->nptr[j])))
+ {
+ j++;
+ }
+ if (j < an->maxlength)
+ {
+ cur_node.r_ptr = an->nptr[j];
+ cur_node.r_id = an->objid[j];
+ cur_node.r_nl = 0;
+ }
+ else
+ {
+ cur_node.r_ptr = NULL;
+ }
+ push_node(&cur_node);
+ if (an->objid[i] == *ident)
+ {
+ ident_len--;
+ ident++;
+ }
+ else
+ {
+ /* an->objid[i] < *ident */
+ ident_len = 0;
+ }
+ /* follow next child pointer */
+ node = an->nptr[i];
+ }
+ }
+ else
+ {
+ /* i == an->maxlength */
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ u8_t j;
+ /* ident_len == 0, complete with leftmost '.thing' */
+ j = 0;
+ while ((j < an->maxlength) && empty_table(an->nptr[j]))
+ {
+ j++;
+ }
+ if (j < an->maxlength)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));
+ oidret->id[oidret->len] = an->objid[j];
+ (oidret->len)++;
+ if (an->nptr[j] == NULL)
+ {
+ /* leaf node */
+ return (struct mib_node*)an;
+ }
+ else
+ {
+ /* no leaf, continue */
+ node = an->nptr[j];
+ }
+ }
+ else
+ {
+ /* j == an->maxlength */
+ climb_tree = 1;
+ }
+ }
+ }
+ else if(node_type == MIB_NODE_LR)
+ {
+ struct mib_list_rootnode *lrn;
+ struct mib_list_node *ln;
+
+ /* list root node (internal 'RAM', variable length) */
+ lrn = (struct mib_list_rootnode *)node;
+ if (ident_len > 0)
+ {
+ ln = lrn->head;
+ /* iterate over list, head to tail */
+ while ((ln != NULL) && (ln->objid < *ident))
+ {
+ ln = ln->next;
+ }
+ if (ln != NULL)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
+ oidret->id[oidret->len] = ln->objid;
+ (oidret->len)++;
+ if (ln->nptr == NULL)
+ {
+ /* leaf node */
+ if (ln->objid > *ident)
+ {
+ return (struct mib_node*)lrn;
+ }
+ else if (ln->next != NULL)
+ {
+ /* ln->objid == *ident */
+ (oidret->len)--;
+ oidret->id[oidret->len] = ln->next->objid;
+ (oidret->len)++;
+ return (struct mib_node*)lrn;
+ }
+ else
+ {
+ /* ln->next == NULL */
+ (oidret->len)--;
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ struct mib_list_node *jn;
+ struct nse cur_node;
+
+ /* non-leaf, store right child ptr and id */
+ jn = ln->next;
+ while ((jn != NULL) && empty_table(jn->nptr))
+ {
+ jn = jn->next;
+ }
+ if (jn != NULL)
+ {
+ cur_node.r_ptr = jn->nptr;
+ cur_node.r_id = jn->objid;
+ cur_node.r_nl = 0;
+ }
+ else
+ {
+ cur_node.r_ptr = NULL;
+ }
+ push_node(&cur_node);
+ if (ln->objid == *ident)
+ {
+ ident_len--;
+ ident++;
+ }
+ else
+ {
+ /* ln->objid < *ident */
+ ident_len = 0;
+ }
+ /* follow next child pointer */
+ node = ln->nptr;
+ }
+
+ }
+ else
+ {
+ /* ln == NULL */
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ struct mib_list_node *jn;
+ /* ident_len == 0, complete with leftmost '.thing' */
+ jn = lrn->head;
+ while ((jn != NULL) && empty_table(jn->nptr))
+ {
+ jn = jn->next;
+ }
+ if (jn != NULL)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));
+ oidret->id[oidret->len] = jn->objid;
+ (oidret->len)++;
+ if (jn->nptr == NULL)
+ {
+ /* leaf node */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));
+ return (struct mib_node*)lrn;
+ }
+ else
+ {
+ /* no leaf, continue */
+ node = jn->nptr;
+ }
+ }
+ else
+ {
+ /* jn == NULL */
+ climb_tree = 1;
+ }
+ }
+ }
+ else if(node_type == MIB_NODE_EX)
+ {
+ struct mib_external_node *en;
+ s32_t ex_id;
+
+ /* external node (addressing and access via functions) */
+ en = (struct mib_external_node *)node;
+ if (ident_len > 0)
+ {
+ u16_t i, len;
+
+ i = 0;
+ len = en->level_length(en->addr_inf,ext_level);
+ while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))
+ {
+ i++;
+ }
+ if (i < len)
+ {
+ /* add identifier to oidret */
+ en->get_objid(en->addr_inf,ext_level,i,&ex_id);
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));
+ oidret->id[oidret->len] = ex_id;
+ (oidret->len)++;
+
+ if ((ext_level + 1) == en->tree_levels)
+ {
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
+ /* leaf node */
+ if (ex_id > *ident)
+ {
+ return (struct mib_node*)en;
+ }
+ else if ((i + 1) < len)
+ {
+ /* ex_id == *ident */
+ en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);
+ (oidret->len)--;
+ oidret->id[oidret->len] = ex_id;
+ (oidret->len)++;
+ return (struct mib_node*)en;
+ }
+ else
+ {
+ /* (i + 1) == len */
+ (oidret->len)--;
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ u8_t j;
+ struct nse cur_node;
+
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
+ /* non-leaf, store right child ptr and id */
+ LWIP_ASSERT("i < 0xff", i < 0xff);
+ j = (u8_t)i + 1;
+ if (j < len)
+ {
+ /* right node is the current external node */
+ cur_node.r_ptr = node;
+ en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);
+ cur_node.r_nl = ext_level + 1;
+ }
+ else
+ {
+ cur_node.r_ptr = NULL;
+ }
+ push_node(&cur_node);
+ if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)
+ {
+ ident_len--;
+ ident++;
+ }
+ else
+ {
+ /* external id < *ident */
+ ident_len = 0;
+ }
+ /* proceed to child */
+ ext_level++;
+ }
+ }
+ else
+ {
+ /* i == len (en->level_len()) */
+ climb_tree = 1;
+ }
+ }
+ else
+ {
+ /* ident_len == 0, complete with leftmost '.thing' */
+ en->get_objid(en->addr_inf,ext_level,0,&ex_id);
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));
+ oidret->id[oidret->len] = ex_id;
+ (oidret->len)++;
+ if ((ext_level + 1) == en->tree_levels)
+ {
+ /* leaf node */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));
+ return (struct mib_node*)en;
+ }
+ else
+ {
+ /* no leaf, proceed to child */
+ ext_level++;
+ }
+ }
+ }
+ else if(node_type == MIB_NODE_SC)
+ {
+ mib_scalar_node *sn;
+
+ /* scalar node */
+ sn = (mib_scalar_node *)node;
+ if (ident_len > 0)
+ {
+ /* at .0 */
+ climb_tree = 1;
+ }
+ else
+ {
+ /* ident_len == 0, complete object identifier */
+ oidret->id[oidret->len] = 0;
+ (oidret->len)++;
+ /* leaf node */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));
+ return (struct mib_node*)sn;
+ }
+ }
+ else
+ {
+ /* unknown/unhandled node_type */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));
+ return NULL;
+ }
+
+ if (climb_tree)
+ {
+ struct nse child;
+
+ /* find right child ptr */
+ child.r_ptr = NULL;
+ child.r_id = 0;
+ child.r_nl = 0;
+ while ((node_stack_cnt > 0) && (child.r_ptr == NULL))
+ {
+ pop_node(&child);
+ /* trim returned oid */
+ (oidret->len)--;
+ }
+ if (child.r_ptr != NULL)
+ {
+ /* incoming ident is useless beyond this point */
+ ident_len = 0;
+ oidret->id[oidret->len] = child.r_id;
+ oidret->len++;
+ node = child.r_ptr;
+ ext_level = child.r_nl;
+ }
+ else
+ {
+ /* tree ends here ... */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));
+ return NULL;
+ }
+ }
+ }
+ /* done, found nothing */
+ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));
+ return NULL;
+}
+
+/**
+ * Test object identifier for the iso.org.dod.internet prefix.
+ *
+ * @param ident_len the length of the supplied object identifier
+ * @param ident points to the array of sub identifiers
+ * @return 1 if it matches, 0 otherwise
+ */
+u8_t
+snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)
+{
+ if ((ident_len > 3) &&
+ (ident[0] == 1) && (ident[1] == 3) &&
+ (ident[2] == 6) && (ident[3] == 1))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * Expands object identifier to the iso.org.dod.internet
+ * prefix for use in getnext operation.
+ *
+ * @param ident_len the length of the supplied object identifier
+ * @param ident points to the array of sub identifiers
+ * @param oidret points to returned expanded object identifier
+ * @return 1 if it matches, 0 otherwise
+ *
+ * @note ident_len 0 is allowed, expanding to the first known object id!!
+ */
+u8_t
+snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
+{
+ const s32_t *prefix_ptr;
+ s32_t *ret_ptr;
+ u8_t i;
+
+ i = 0;
+ prefix_ptr = &prefix[0];
+ ret_ptr = &oidret->id[0];
+ ident_len = ((ident_len < 4)?ident_len:4);
+ while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))
+ {
+ *ret_ptr++ = *prefix_ptr++;
+ ident++;
+ i++;
+ }
+ if (i == ident_len)
+ {
+ /* match, complete missing bits */
+ while (i < 4)
+ {
+ *ret_ptr++ = *prefix_ptr++;
+ i++;
+ }
+ oidret->len = i;
+ return 1;
+ }
+ else
+ {
+ /* i != ident_len */
+ return 0;
+ }
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_in.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_in.c
new file mode 100644
index 0000000000..2dfb55b253
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_in.c
@@ -0,0 +1,1437 @@
+/**
+ * @file
+ * SNMP input message processing (RFC1157).
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp.h"
+#include "lwip/snmp_asn1.h"
+#include "lwip/snmp_msg.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/ip_addr.h"
+#include "lwip/memp.h"
+#include "lwip/udp.h"
+#include "lwip/stats.h"
+
+#include <string.h>
+
+/* public (non-static) constants */
+/** SNMP v1 == 0 */
+const s32_t snmp_version = 0;
+/** default SNMP community string */
+const char snmp_publiccommunity[7] = "public";
+
+/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
+struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
+/* UDP Protocol Control Block */
+struct udp_pcb *snmp1_pcb;
+
+static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
+static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
+
+
+/**
+ * Starts SNMP Agent.
+ * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
+ */
+void
+snmp_init(void)
+{
+ struct snmp_msg_pstat *msg_ps;
+ u8_t i;
+
+ snmp1_pcb = udp_new();
+ if (snmp1_pcb != NULL)
+ {
+ udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
+ udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
+ }
+ msg_ps = &msg_input_list[0];
+ for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
+ {
+ msg_ps->state = SNMP_MSG_EMPTY;
+ msg_ps->error_index = 0;
+ msg_ps->error_status = SNMP_ES_NOERROR;
+ msg_ps++;
+ }
+ trap_msg.pcb = snmp1_pcb;
+
+#ifdef SNMP_PRIVATE_MIB_INIT
+ /* If defined, rhis must be a function-like define to initialize the
+ * private MIB after the stack has been initialized.
+ * The private MIB can also be initialized in tcpip_callback (or after
+ * the stack is initialized), this define is only for convenience. */
+ SNMP_PRIVATE_MIB_INIT();
+#endif /* SNMP_PRIVATE_MIB_INIT */
+
+ /* The coldstart trap will only be output
+ if our outgoing interface is up & configured */
+ snmp_coldstart_trap();
+}
+
+static void
+snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
+{
+ snmp_varbind_list_free(&msg_ps->outvb);
+ msg_ps->outvb = msg_ps->invb;
+ msg_ps->invb.head = NULL;
+ msg_ps->invb.tail = NULL;
+ msg_ps->invb.count = 0;
+ msg_ps->error_status = error;
+ msg_ps->error_index = 1 + msg_ps->vb_idx;
+ snmp_send_response(msg_ps);
+ snmp_varbind_list_free(&msg_ps->outvb);
+ msg_ps->state = SNMP_MSG_EMPTY;
+}
+
+static void
+snmp_ok_response(struct snmp_msg_pstat *msg_ps)
+{
+ err_t err_ret;
+
+ err_ret = snmp_send_response(msg_ps);
+ if (err_ret == ERR_MEM)
+ {
+ /* serious memory problem, can't return tooBig */
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
+ }
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&msg_ps->invb);
+ snmp_varbind_list_free(&msg_ps->outvb);
+ msg_ps->state = SNMP_MSG_EMPTY;
+}
+
+/**
+ * Service an internal or external event for SNMP GET.
+ *
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
+ * @param msg_ps points to the assosicated message process state
+ */
+static void
+snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
+{
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
+
+ if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
+ {
+ struct mib_external_node *en;
+ struct snmp_name_ptr np;
+
+ /* get_object_def() answer*/
+ en = msg_ps->ext_mib_node;
+ np = msg_ps->ext_name_ptr;
+
+ /* translate answer into a known lifeform */
+ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
+ if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) &&
+ (msg_ps->ext_object_def.access & MIB_ACCESS_READ))
+ {
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
+ en->get_value_q(request_id, &msg_ps->ext_object_def);
+ }
+ else
+ {
+ en->get_object_def_pc(request_id, np.ident_len, np.ident);
+ /* search failed, object id points to unknown object (nosuchname) */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
+ {
+ struct mib_external_node *en;
+ struct snmp_varbind *vb;
+
+ /* get_value() answer */
+ en = msg_ps->ext_mib_node;
+
+ /* allocate output varbind */
+ vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
+ LWIP_ASSERT("vb != NULL",vb != NULL);
+ if (vb != NULL)
+ {
+ vb->next = NULL;
+ vb->prev = NULL;
+
+ /* move name from invb to outvb */
+ vb->ident = msg_ps->vb_ptr->ident;
+ vb->ident_len = msg_ps->vb_ptr->ident_len;
+ /* ensure this memory is refereced once only */
+ msg_ps->vb_ptr->ident = NULL;
+ msg_ps->vb_ptr->ident_len = 0;
+
+ vb->value_type = msg_ps->ext_object_def.asn_type;
+ LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
+ vb->value_len = (u8_t)msg_ps->ext_object_def.v_len;
+ if (vb->value_len > 0)
+ {
+ LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
+ vb->value = memp_malloc(MEMP_SNMP_VALUE);
+ LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
+ if (vb->value != NULL)
+ {
+ en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ /* search again (if vb_idx < msg_ps->invb.count) */
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ en->get_value_pc(request_id, &msg_ps->ext_object_def);
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
+ msg_ps->vb_ptr->ident = vb->ident;
+ msg_ps->vb_ptr->ident_len = vb->ident_len;
+ memp_free(MEMP_SNMP_VARBIND, vb);
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+ else
+ {
+ /* vb->value_len == 0, empty value (e.g. empty string) */
+ en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
+ vb->value = NULL;
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ /* search again (if vb_idx < msg_ps->invb.count) */
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ }
+ else
+ {
+ en->get_value_pc(request_id, &msg_ps->ext_object_def);
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+
+ while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx < msg_ps->invb.count))
+ {
+ struct mib_node *mn;
+ struct snmp_name_ptr np;
+
+ if (msg_ps->vb_idx == 0)
+ {
+ msg_ps->vb_ptr = msg_ps->invb.head;
+ }
+ else
+ {
+ msg_ps->vb_ptr = msg_ps->vb_ptr->next;
+ }
+ /** test object identifier for .iso.org.dod.internet prefix */
+ if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident))
+ {
+ mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
+ msg_ps->vb_ptr->ident + 4, &np);
+ if (mn != NULL)
+ {
+ if (mn->node_type == MIB_NODE_EX)
+ {
+ /* external object */
+ struct mib_external_node *en = (struct mib_external_node*)mn;
+
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
+ /* save en && args in msg_ps!! */
+ msg_ps->ext_mib_node = en;
+ msg_ps->ext_name_ptr = np;
+
+ en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
+ }
+ else
+ {
+ /* internal object */
+ struct obj_def object_def;
+
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
+ mn->get_object_def(np.ident_len, np.ident, &object_def);
+ if ((object_def.instance != MIB_OBJECT_NONE) &&
+ (object_def.access & MIB_ACCESS_READ))
+ {
+ mn = mn;
+ }
+ else
+ {
+ /* search failed, object id points to unknown object (nosuchname) */
+ mn = NULL;
+ }
+ if (mn != NULL)
+ {
+ struct snmp_varbind *vb;
+
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
+ /* allocate output varbind */
+ vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
+ LWIP_ASSERT("vb != NULL",vb != NULL);
+ if (vb != NULL)
+ {
+ vb->next = NULL;
+ vb->prev = NULL;
+
+ /* move name from invb to outvb */
+ vb->ident = msg_ps->vb_ptr->ident;
+ vb->ident_len = msg_ps->vb_ptr->ident_len;
+ /* ensure this memory is refereced once only */
+ msg_ps->vb_ptr->ident = NULL;
+ msg_ps->vb_ptr->ident_len = 0;
+
+ vb->value_type = object_def.asn_type;
+ LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
+ vb->value_len = (u8_t)object_def.v_len;
+ if (vb->value_len > 0)
+ {
+ LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
+ vb->value_len <= SNMP_MAX_VALUE_SIZE);
+ vb->value = memp_malloc(MEMP_SNMP_VALUE);
+ LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
+ if (vb->value != NULL)
+ {
+ mn->get_value(&object_def, vb->value_len, vb->value);
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
+ msg_ps->vb_ptr->ident = vb->ident;
+ msg_ps->vb_ptr->ident_len = vb->ident_len;
+ memp_free(MEMP_SNMP_VARBIND, vb);
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+ else
+ {
+ /* vb->value_len == 0, empty value (e.g. empty string) */
+ vb->value = NULL;
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mn = NULL;
+ }
+ if (mn == NULL)
+ {
+ /* mn == NULL, noSuchName */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx == msg_ps->invb.count))
+ {
+ snmp_ok_response(msg_ps);
+ }
+}
+
+/**
+ * Service an internal or external event for SNMP GETNEXT.
+ *
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
+ * @param msg_ps points to the assosicated message process state
+ */
+static void
+snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
+{
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
+
+ if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
+ {
+ struct mib_external_node *en;
+
+ /* get_object_def() answer*/
+ en = msg_ps->ext_mib_node;
+
+ /* translate answer into a known lifeform */
+ en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
+ if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
+ {
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
+ en->get_value_q(request_id, &msg_ps->ext_object_def);
+ }
+ else
+ {
+ en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
+ /* search failed, object id points to unknown object (nosuchname) */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
+ {
+ struct mib_external_node *en;
+ struct snmp_varbind *vb;
+
+ /* get_value() answer */
+ en = msg_ps->ext_mib_node;
+
+ LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
+ vb = snmp_varbind_alloc(&msg_ps->ext_oid,
+ msg_ps->ext_object_def.asn_type,
+ (u8_t)msg_ps->ext_object_def.v_len);
+ if (vb != NULL)
+ {
+ en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ en->get_value_pc(request_id, &msg_ps->ext_object_def);
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+
+ while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx < msg_ps->invb.count))
+ {
+ struct mib_node *mn;
+ struct snmp_obj_id oid;
+
+ if (msg_ps->vb_idx == 0)
+ {
+ msg_ps->vb_ptr = msg_ps->invb.head;
+ }
+ else
+ {
+ msg_ps->vb_ptr = msg_ps->vb_ptr->next;
+ }
+ if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
+ {
+ if (msg_ps->vb_ptr->ident_len > 3)
+ {
+ /* can offset ident_len and ident */
+ mn = snmp_expand_tree((struct mib_node*)&internet,
+ msg_ps->vb_ptr->ident_len - 4,
+ msg_ps->vb_ptr->ident + 4, &oid);
+ }
+ else
+ {
+ /* can't offset ident_len -4, ident + 4 */
+ mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
+ }
+ }
+ else
+ {
+ mn = NULL;
+ }
+ if (mn != NULL)
+ {
+ if (mn->node_type == MIB_NODE_EX)
+ {
+ /* external object */
+ struct mib_external_node *en = (struct mib_external_node*)mn;
+
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
+ /* save en && args in msg_ps!! */
+ msg_ps->ext_mib_node = en;
+ msg_ps->ext_oid = oid;
+
+ en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
+ }
+ else
+ {
+ /* internal object */
+ struct obj_def object_def;
+ struct snmp_varbind *vb;
+
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
+ mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
+
+ LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
+ vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len);
+ if (vb != NULL)
+ {
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
+ mn->get_value(&object_def, object_def.v_len, vb->value);
+ snmp_varbind_tail_add(&msg_ps->outvb, vb);
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
+ snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
+ }
+ }
+ }
+ if (mn == NULL)
+ {
+ /* mn == NULL, noSuchName */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx == msg_ps->invb.count))
+ {
+ snmp_ok_response(msg_ps);
+ }
+}
+
+/**
+ * Service an internal or external event for SNMP SET.
+ *
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
+ * @param msg_ps points to the assosicated message process state
+ */
+static void
+snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
+{
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
+
+ if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
+ {
+ struct mib_external_node *en;
+ struct snmp_name_ptr np;
+
+ /* get_object_def() answer*/
+ en = msg_ps->ext_mib_node;
+ np = msg_ps->ext_name_ptr;
+
+ /* translate answer into a known lifeform */
+ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
+ if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
+ {
+ msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
+ en->set_test_q(request_id, &msg_ps->ext_object_def);
+ }
+ else
+ {
+ en->get_object_def_pc(request_id, np.ident_len, np.ident);
+ /* search failed, object id points to unknown object (nosuchname) */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
+ {
+ struct mib_external_node *en;
+
+ /* set_test() answer*/
+ en = msg_ps->ext_mib_node;
+
+ if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE)
+ {
+ if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
+ (en->set_test_a(request_id,&msg_ps->ext_object_def,
+ msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
+ {
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ en->set_test_pc(request_id,&msg_ps->ext_object_def);
+ /* bad value */
+ snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
+ }
+ }
+ else
+ {
+ en->set_test_pc(request_id,&msg_ps->ext_object_def);
+ /* object not available for set */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
+ {
+ struct mib_external_node *en;
+ struct snmp_name_ptr np;
+
+ /* get_object_def() answer*/
+ en = msg_ps->ext_mib_node;
+ np = msg_ps->ext_name_ptr;
+
+ /* translate answer into a known lifeform */
+ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
+ if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
+ {
+ msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
+ en->set_value_q(request_id, &msg_ps->ext_object_def,
+ msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
+ }
+ else
+ {
+ en->get_object_def_pc(request_id, np.ident_len, np.ident);
+ /* set_value failed, object has disappeared for some odd reason?? */
+ snmp_error_response(msg_ps,SNMP_ES_GENERROR);
+ }
+ }
+ else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
+ {
+ struct mib_external_node *en;
+
+ /** set_value_a() */
+ en = msg_ps->ext_mib_node;
+ en->set_value_a(request_id, &msg_ps->ext_object_def,
+ msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
+
+ /** @todo use set_value_pc() if toobig */
+ msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
+ msg_ps->vb_idx += 1;
+ }
+
+ /* test all values before setting */
+ while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx < msg_ps->invb.count))
+ {
+ struct mib_node *mn;
+ struct snmp_name_ptr np;
+
+ if (msg_ps->vb_idx == 0)
+ {
+ msg_ps->vb_ptr = msg_ps->invb.head;
+ }
+ else
+ {
+ msg_ps->vb_ptr = msg_ps->vb_ptr->next;
+ }
+ /** test object identifier for .iso.org.dod.internet prefix */
+ if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident))
+ {
+ mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
+ msg_ps->vb_ptr->ident + 4, &np);
+ if (mn != NULL)
+ {
+ if (mn->node_type == MIB_NODE_EX)
+ {
+ /* external object */
+ struct mib_external_node *en = (struct mib_external_node*)mn;
+
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
+ /* save en && args in msg_ps!! */
+ msg_ps->ext_mib_node = en;
+ msg_ps->ext_name_ptr = np;
+
+ en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
+ }
+ else
+ {
+ /* internal object */
+ struct obj_def object_def;
+
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
+ mn->get_object_def(np.ident_len, np.ident, &object_def);
+ if (object_def.instance != MIB_OBJECT_NONE)
+ {
+ mn = mn;
+ }
+ else
+ {
+ /* search failed, object id points to unknown object (nosuchname) */
+ mn = NULL;
+ }
+ if (mn != NULL)
+ {
+ msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
+
+ if (object_def.access & MIB_ACCESS_WRITE)
+ {
+ if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
+ (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
+ {
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ msg_ps->vb_idx += 1;
+ }
+ else
+ {
+ /* bad value */
+ snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
+ }
+ }
+ else
+ {
+ /* object not available for set */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mn = NULL;
+ }
+ if (mn == NULL)
+ {
+ /* mn == NULL, noSuchName */
+ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
+ }
+ }
+
+ if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
+ (msg_ps->vb_idx == msg_ps->invb.count))
+ {
+ msg_ps->vb_idx = 0;
+ msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
+ }
+
+ /* set all values "atomically" (be as "atomic" as possible) */
+ while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
+ (msg_ps->vb_idx < msg_ps->invb.count))
+ {
+ struct mib_node *mn;
+ struct snmp_name_ptr np;
+
+ if (msg_ps->vb_idx == 0)
+ {
+ msg_ps->vb_ptr = msg_ps->invb.head;
+ }
+ else
+ {
+ msg_ps->vb_ptr = msg_ps->vb_ptr->next;
+ }
+ /* skip iso prefix test, was done previously while settesting() */
+ mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
+ msg_ps->vb_ptr->ident + 4, &np);
+ /* check if object is still available
+ (e.g. external hot-plug thingy present?) */
+ if (mn != NULL)
+ {
+ if (mn->node_type == MIB_NODE_EX)
+ {
+ /* external object */
+ struct mib_external_node *en = (struct mib_external_node*)mn;
+
+ msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
+ /* save en && args in msg_ps!! */
+ msg_ps->ext_mib_node = en;
+ msg_ps->ext_name_ptr = np;
+
+ en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
+ }
+ else
+ {
+ /* internal object */
+ struct obj_def object_def;
+
+ msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
+ mn->get_object_def(np.ident_len, np.ident, &object_def);
+ msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
+ mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
+ msg_ps->vb_idx += 1;
+ }
+ }
+ }
+ if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
+ (msg_ps->vb_idx == msg_ps->invb.count))
+ {
+ /* simply echo the input if we can set it
+ @todo do we need to return the actual value?
+ e.g. if value is silently modified or behaves sticky? */
+ msg_ps->outvb = msg_ps->invb;
+ msg_ps->invb.head = NULL;
+ msg_ps->invb.tail = NULL;
+ msg_ps->invb.count = 0;
+ snmp_ok_response(msg_ps);
+ }
+}
+
+
+/**
+ * Handle one internal or external event.
+ * Called for one async event. (recv external/private answer)
+ *
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
+ */
+void
+snmp_msg_event(u8_t request_id)
+{
+ struct snmp_msg_pstat *msg_ps;
+
+ if (request_id < SNMP_CONCURRENT_REQUESTS)
+ {
+ msg_ps = &msg_input_list[request_id];
+ if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
+ {
+ snmp_msg_getnext_event(request_id, msg_ps);
+ }
+ else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
+ {
+ snmp_msg_get_event(request_id, msg_ps);
+ }
+ else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
+ {
+ snmp_msg_set_event(request_id, msg_ps);
+ }
+ }
+}
+
+
+/* lwIP UDP receive callback function */
+static void
+snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+ struct snmp_msg_pstat *msg_ps;
+ u8_t req_idx;
+ err_t err_ret;
+ u16_t payload_len = p->tot_len;
+ u16_t payload_ofs = 0;
+ u16_t varbind_ofs = 0;
+
+ /* suppress unused argument warning */
+ LWIP_UNUSED_ARG(arg);
+
+ /* traverse input message process list, look for SNMP_MSG_EMPTY */
+ msg_ps = &msg_input_list[0];
+ req_idx = 0;
+ while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
+ {
+ req_idx++;
+ msg_ps++;
+ }
+ if (req_idx == SNMP_CONCURRENT_REQUESTS)
+ {
+ /* exceeding number of concurrent requests */
+ pbuf_free(p);
+ return;
+ }
+
+ /* accepting request */
+ snmp_inc_snmpinpkts();
+ /* record used 'protocol control block' */
+ msg_ps->pcb = pcb;
+ /* source address (network order) */
+ msg_ps->sip = *addr;
+ /* source port (host order (lwIP oddity)) */
+ msg_ps->sp = port;
+
+ /* check total length, version, community, pdu type */
+ err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
+ /* Only accept requests and requests without error (be robust) */
+ /* Reject response and trap headers or error requests as input! */
+ if ((err_ret != ERR_OK) ||
+ ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
+ (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
+ (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
+ ((msg_ps->error_status != SNMP_ES_NOERROR) ||
+ (msg_ps->error_index != 0)) )
+ {
+ /* header check failed drop request silently, do not return error! */
+ pbuf_free(p);
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
+ return;
+ }
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
+
+ /* Builds a list of variable bindings. Copy the varbinds from the pbuf
+ chain to glue them when these are divided over two or more pbuf's. */
+ err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
+ /* we've decoded the incoming message, release input msg now */
+ pbuf_free(p);
+ if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
+ {
+ /* varbind-list decode failed, or varbind list empty.
+ drop request silently, do not return error!
+ (errors are only returned for a specific varbind failure) */
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
+ return;
+ }
+
+ msg_ps->error_status = SNMP_ES_NOERROR;
+ msg_ps->error_index = 0;
+ /* find object for each variable binding */
+ msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+ /* first variable binding from list to inspect */
+ msg_ps->vb_idx = 0;
+
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
+
+ /* handle input event and as much objects as possible in one go */
+ snmp_msg_event(req_idx);
+}
+
+/**
+ * Checks and decodes incoming SNMP message header, logs header errors.
+ *
+ * @param p points to pbuf chain of SNMP message (UDP payload)
+ * @param ofs points to first octet of SNMP message
+ * @param pdu_len the length of the UDP payload
+ * @param ofs_ret returns the ofset of the variable bindings
+ * @param m_stat points to the current message request state return
+ * @return
+ * - ERR_OK SNMP header is sane and accepted
+ * - ERR_ARG SNMP header is either malformed or rejected
+ */
+static err_t
+snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
+{
+ err_t derr;
+ u16_t len, ofs_base;
+ u8_t len_octets;
+ u8_t type;
+ s32_t version;
+
+ ofs_base = ofs;
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) ||
+ (pdu_len != (1 + len_octets + len)) ||
+ (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
+ {
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets);
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
+ {
+ /* can't decode or no integer (version) */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
+ if (derr != ERR_OK)
+ {
+ /* can't decode */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ if (version != 0)
+ {
+ /* not version 1 */
+ snmp_inc_snmpinbadversions();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
+ {
+ /* can't decode or no octet string (community) */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
+ if (derr != ERR_OK)
+ {
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ /* add zero terminator */
+ len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
+ m_stat->community[len] = 0;
+ m_stat->com_strlen = (u8_t)len;
+ if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
+ {
+ /** @todo: move this if we need to check more names */
+ snmp_inc_snmpinbadcommunitynames();
+ snmp_authfail_trap();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if (derr != ERR_OK)
+ {
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ switch(type)
+ {
+ case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
+ /* GetRequest PDU */
+ snmp_inc_snmpingetrequests();
+ derr = ERR_OK;
+ break;
+ case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
+ /* GetNextRequest PDU */
+ snmp_inc_snmpingetnexts();
+ derr = ERR_OK;
+ break;
+ case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
+ /* GetResponse PDU */
+ snmp_inc_snmpingetresponses();
+ derr = ERR_ARG;
+ break;
+ case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
+ /* SetRequest PDU */
+ snmp_inc_snmpinsetrequests();
+ derr = ERR_OK;
+ break;
+ case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
+ /* Trap PDU */
+ snmp_inc_snmpintraps();
+ derr = ERR_ARG;
+ break;
+ default:
+ snmp_inc_snmpinasnparseerrs();
+ derr = ERR_ARG;
+ break;
+ }
+ if (derr != ERR_OK)
+ {
+ /* unsupported input PDU for this agent (no parse error) */
+ return ERR_ARG;
+ }
+ m_stat->rt = type & 0x1F;
+ ofs += (1 + len_octets);
+ if (len != (pdu_len - (ofs - ofs_base)))
+ {
+ /* decoded PDU length does not equal actual payload length */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
+ {
+ /* can't decode or no integer (request ID) */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
+ if (derr != ERR_OK)
+ {
+ /* can't decode */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
+ {
+ /* can't decode or no integer (error-status) */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ /* must be noError (0) for incoming requests.
+ log errors for mib-2 completeness and for debug purposes */
+ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
+ if (derr != ERR_OK)
+ {
+ /* can't decode */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ switch (m_stat->error_status)
+ {
+ case SNMP_ES_TOOBIG:
+ snmp_inc_snmpintoobigs();
+ break;
+ case SNMP_ES_NOSUCHNAME:
+ snmp_inc_snmpinnosuchnames();
+ break;
+ case SNMP_ES_BADVALUE:
+ snmp_inc_snmpinbadvalues();
+ break;
+ case SNMP_ES_READONLY:
+ snmp_inc_snmpinreadonlys();
+ break;
+ case SNMP_ES_GENERROR:
+ snmp_inc_snmpingenerrs();
+ break;
+ }
+ ofs += (1 + len_octets + len);
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
+ {
+ /* can't decode or no integer (error-index) */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ /* must be 0 for incoming requests.
+ decode anyway to catch bad integers (and dirty tricks) */
+ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
+ if (derr != ERR_OK)
+ {
+ /* can't decode */
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ *ofs_ret = ofs;
+ return ERR_OK;
+}
+
+static err_t
+snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
+{
+ err_t derr;
+ u16_t len, vb_len;
+ u8_t len_octets;
+ u8_t type;
+
+ /* variable binding list */
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
+ if ((derr != ERR_OK) ||
+ (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
+ {
+ snmp_inc_snmpinasnparseerrs();
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets);
+
+ /* start with empty list */
+ m_stat->invb.count = 0;
+ m_stat->invb.head = NULL;
+ m_stat->invb.tail = NULL;
+
+ while (vb_len > 0)
+ {
+ struct snmp_obj_id oid, oid_value;
+ struct snmp_varbind *vb;
+
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) ||
+ (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
+ (len == 0) || (len > vb_len))
+ {
+ snmp_inc_snmpinasnparseerrs();
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&m_stat->invb);
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets);
+ vb_len -= (1 + len_octets);
+
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
+ {
+ /* can't decode object name length */
+ snmp_inc_snmpinasnparseerrs();
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&m_stat->invb);
+ return ERR_ARG;
+ }
+ derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
+ if (derr != ERR_OK)
+ {
+ /* can't decode object name */
+ snmp_inc_snmpinasnparseerrs();
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&m_stat->invb);
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ vb_len -= (1 + len_octets + len);
+
+ snmp_asn1_dec_type(p, ofs, &type);
+ derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
+ if (derr != ERR_OK)
+ {
+ /* can't decode object value length */
+ snmp_inc_snmpinasnparseerrs();
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&m_stat->invb);
+ return ERR_ARG;
+ }
+
+ switch (type)
+ {
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
+ vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
+ if (vb != NULL)
+ {
+ s32_t *vptr = (s32_t*)vb->value;
+
+ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ break;
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
+ vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
+ if (vb != NULL)
+ {
+ u32_t *vptr = (u32_t*)vb->value;
+
+ derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
+ LWIP_ASSERT("invalid length", len <= 0xff);
+ vb = snmp_varbind_alloc(&oid, type, (u8_t)len);
+ if (vb != NULL)
+ {
+ derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
+ vb = snmp_varbind_alloc(&oid, type, 0);
+ if (vb != NULL)
+ {
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ derr = ERR_OK;
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
+ derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
+ if (derr == ERR_OK)
+ {
+ vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
+ if (vb != NULL)
+ {
+ u8_t i = oid_value.len;
+ s32_t *vptr = (s32_t*)vb->value;
+
+ while(i > 0)
+ {
+ i--;
+ vptr[i] = oid_value.id[i];
+ }
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ derr = ERR_OK;
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ }
+ break;
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
+ if (len == 4)
+ {
+ /* must be exactly 4 octets! */
+ vb = snmp_varbind_alloc(&oid, type, 4);
+ if (vb != NULL)
+ {
+ derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
+ snmp_varbind_tail_add(&m_stat->invb, vb);
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ }
+ else
+ {
+ derr = ERR_ARG;
+ }
+ break;
+ default:
+ derr = ERR_ARG;
+ break;
+ }
+ if (derr != ERR_OK)
+ {
+ snmp_inc_snmpinasnparseerrs();
+ /* free varbinds (if available) */
+ snmp_varbind_list_free(&m_stat->invb);
+ return ERR_ARG;
+ }
+ ofs += (1 + len_octets + len);
+ vb_len -= (1 + len_octets + len);
+ }
+
+ if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
+ {
+ snmp_add_snmpintotalsetvars(m_stat->invb.count);
+ }
+ else
+ {
+ snmp_add_snmpintotalreqvars(m_stat->invb.count);
+ }
+
+ *ofs_ret = ofs;
+ return ERR_OK;
+}
+
+struct snmp_varbind*
+snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
+{
+ struct snmp_varbind *vb;
+
+ vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
+ LWIP_ASSERT("vb != NULL",vb != NULL);
+ if (vb != NULL)
+ {
+ u8_t i;
+
+ vb->next = NULL;
+ vb->prev = NULL;
+ i = oid->len;
+ vb->ident_len = i;
+ if (i > 0)
+ {
+ LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
+ /* allocate array of s32_t for our object identifier */
+ vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
+ LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
+ if (vb->ident == NULL)
+ {
+ memp_free(MEMP_SNMP_VARBIND, vb);
+ return NULL;
+ }
+ while(i > 0)
+ {
+ i--;
+ vb->ident[i] = oid->id[i];
+ }
+ }
+ else
+ {
+ /* i == 0, pass zero length object identifier */
+ vb->ident = NULL;
+ }
+ vb->value_type = type;
+ vb->value_len = len;
+ if (len > 0)
+ {
+ LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
+ /* allocate raw bytes for our object value */
+ vb->value = memp_malloc(MEMP_SNMP_VALUE);
+ LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
+ if (vb->value == NULL)
+ {
+ if (vb->ident != NULL)
+ {
+ memp_free(MEMP_SNMP_VALUE, vb->ident);
+ }
+ memp_free(MEMP_SNMP_VARBIND, vb);
+ return NULL;
+ }
+ }
+ else
+ {
+ /* ASN1_NUL type, or zero length ASN1_OC_STR */
+ vb->value = NULL;
+ }
+ }
+ return vb;
+}
+
+void
+snmp_varbind_free(struct snmp_varbind *vb)
+{
+ if (vb->value != NULL )
+ {
+ memp_free(MEMP_SNMP_VALUE, vb->value);
+ }
+ if (vb->ident != NULL )
+ {
+ memp_free(MEMP_SNMP_VALUE, vb->ident);
+ }
+ memp_free(MEMP_SNMP_VARBIND, vb);
+}
+
+void
+snmp_varbind_list_free(struct snmp_varbind_root *root)
+{
+ struct snmp_varbind *vb, *prev;
+
+ vb = root->tail;
+ while ( vb != NULL )
+ {
+ prev = vb->prev;
+ snmp_varbind_free(vb);
+ vb = prev;
+ }
+ root->count = 0;
+ root->head = NULL;
+ root->tail = NULL;
+}
+
+void
+snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
+{
+ if (root->count == 0)
+ {
+ /* add first varbind to list */
+ root->head = vb;
+ root->tail = vb;
+ }
+ else
+ {
+ /* add nth varbind to list tail */
+ root->tail->next = vb;
+ vb->prev = root->tail;
+ root->tail = vb;
+ }
+ root->count += 1;
+}
+
+struct snmp_varbind*
+snmp_varbind_tail_remove(struct snmp_varbind_root *root)
+{
+ struct snmp_varbind* vb;
+
+ if (root->count > 0)
+ {
+ /* remove tail varbind */
+ vb = root->tail;
+ root->tail = vb->prev;
+ vb->prev->next = NULL;
+ root->count -= 1;
+ }
+ else
+ {
+ /* nothing to remove */
+ vb = NULL;
+ }
+ return vb;
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_out.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_out.c
new file mode 100644
index 0000000000..4778bee6f4
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/snmp/msg_out.c
@@ -0,0 +1,681 @@
+/**
+ * @file
+ * SNMP output message processing (RFC1157).
+ *
+ * Output responses and traps are build in two passes:
+ *
+ * Pass 0: iterate over the output message backwards to determine encoding lengths
+ * Pass 1: the actual forward encoding of internal form into ASN1
+ *
+ * The single-pass encoding method described by Comer & Stevens
+ * requires extra buffer space and copying for reversal of the packet.
+ * The buffer requirement can be prohibitively large for big payloads
+ * (>= 484) therefore we use the two encoding passes.
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/udp.h"
+#include "lwip/netif.h"
+#include "lwip/snmp.h"
+#include "lwip/snmp_asn1.h"
+#include "lwip/snmp_msg.h"
+
+struct snmp_trap_dst
+{
+ /* destination IP address in network order */
+ ip_addr_t dip;
+ /* set to 0 when disabled, >0 when enabled */
+ u8_t enable;
+};
+struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
+
+/** TRAP message structure */
+struct snmp_msg_trap trap_msg;
+
+static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
+static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
+static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
+
+static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
+static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
+static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
+
+/**
+ * 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)
+{
+ if (dst_idx < SNMP_TRAP_DESTINATIONS)
+ {
+ trap_dst[dst_idx].enable = 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, ip_addr_t *dst)
+{
+ if (dst_idx < SNMP_TRAP_DESTINATIONS)
+ {
+ ip_addr_set(&trap_dst[dst_idx].dip, dst);
+ }
+}
+
+/**
+ * Sends a 'getresponse' message to the request originator.
+ *
+ * @param m_stat points to the current message request state source
+ * @return ERR_OK when success, ERR_MEM if we're out of memory
+ *
+ * @note the caller is responsible for filling in outvb in the m_stat
+ * and provide error-status and index (except for tooBig errors) ...
+ */
+err_t
+snmp_send_response(struct snmp_msg_pstat *m_stat)
+{
+ struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
+ struct pbuf *p;
+ u16_t tot_len;
+ err_t err;
+
+ /* pass 0, calculate length fields */
+ tot_len = snmp_varbind_list_sum(&m_stat->outvb);
+ tot_len = snmp_resp_header_sum(m_stat, tot_len);
+
+ /* try allocating pbuf(s) for complete response */
+ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
+ if (p == NULL)
+ {
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
+
+ /* can't construct reply, return error-status tooBig */
+ m_stat->error_status = SNMP_ES_TOOBIG;
+ m_stat->error_index = 0;
+ /* pass 0, recalculate lengths, for empty varbind-list */
+ tot_len = snmp_varbind_list_sum(&emptyvb);
+ tot_len = snmp_resp_header_sum(m_stat, tot_len);
+ /* retry allocation once for header and empty varbind-list */
+ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
+ }
+ if (p != NULL)
+ {
+ /* first pbuf alloc try or retry alloc success */
+ u16_t ofs;
+
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
+
+ /* pass 1, size error, encode packet ino the pbuf(s) */
+ ofs = snmp_resp_header_enc(m_stat, p);
+ if (m_stat->error_status == SNMP_ES_TOOBIG)
+ {
+ snmp_varbind_list_enc(&emptyvb, p, ofs);
+ }
+ else
+ {
+ snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
+ }
+
+ switch (m_stat->error_status)
+ {
+ case SNMP_ES_TOOBIG:
+ snmp_inc_snmpouttoobigs();
+ break;
+ case SNMP_ES_NOSUCHNAME:
+ snmp_inc_snmpoutnosuchnames();
+ break;
+ case SNMP_ES_BADVALUE:
+ snmp_inc_snmpoutbadvalues();
+ break;
+ case SNMP_ES_GENERROR:
+ snmp_inc_snmpoutgenerrs();
+ break;
+ }
+ snmp_inc_snmpoutgetresponses();
+ snmp_inc_snmpoutpkts();
+
+ /** @todo do we need separate rx and tx pcbs for threaded case? */
+ /** connect to the originating source */
+ udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
+ err = udp_send(m_stat->pcb, p);
+ if (err == ERR_MEM)
+ {
+ /** @todo release some memory, retry and return tooBig? tooMuchHassle? */
+ err = ERR_MEM;
+ }
+ else
+ {
+ err = ERR_OK;
+ }
+ /** disassociate remote address and port with this pcb */
+ udp_disconnect(m_stat->pcb);
+
+ pbuf_free(p);
+ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
+ return err;
+ }
+ else
+ {
+ /* first pbuf alloc try or retry alloc failed
+ very low on memory, couldn't return tooBig */
+ return ERR_MEM;
+ }
+}
+
+
+/**
+ * Sends an generic or enterprise specific trap message.
+ *
+ * @param generic_trap is the trap code
+ * @param eoid points to enterprise object identifier
+ * @param specific_trap used for enterprise traps when generic_trap == 6
+ * @return ERR_OK when success, ERR_MEM if we're out of memory
+ *
+ * @note the caller is responsible for filling in outvb in the trap_msg
+ * @note the use of the enterpise 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(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
+{
+ struct snmp_trap_dst *td;
+ struct netif *dst_if;
+ ip_addr_t dst_ip;
+ struct pbuf *p;
+ u16_t i,tot_len;
+
+ for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
+ {
+ if ((td->enable != 0) && !ip_addr_isany(&td->dip))
+ {
+ /* network order trap destination */
+ ip_addr_copy(trap_msg.dip, td->dip);
+ /* lookup current source address for this dst */
+ dst_if = ip_route(&td->dip);
+ ip_addr_copy(dst_ip, dst_if->ip_addr);
+ /* @todo: what about IPv6? */
+ trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
+ trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
+ trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
+ trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
+ trap_msg.gen_trap = generic_trap;
+ trap_msg.spc_trap = specific_trap;
+ if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
+ {
+ /* enterprise-Specific trap */
+ trap_msg.enterprise = eoid;
+ }
+ else
+ {
+ /* generic (MIB-II) trap */
+ snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
+ }
+ snmp_get_sysuptime(&trap_msg.ts);
+
+ /* pass 0, calculate length fields */
+ tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
+ tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
+
+ /* allocate pbuf(s) */
+ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
+ if (p != NULL)
+ {
+ u16_t ofs;
+
+ /* pass 1, encode packet ino the pbuf(s) */
+ ofs = snmp_trap_header_enc(&trap_msg, p);
+ snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
+
+ snmp_inc_snmpouttraps();
+ snmp_inc_snmpoutpkts();
+
+ /** send to the TRAP destination */
+ udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
+
+ pbuf_free(p);
+ }
+ else
+ {
+ return ERR_MEM;
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+void
+snmp_coldstart_trap(void)
+{
+ trap_msg.outvb.head = NULL;
+ trap_msg.outvb.tail = NULL;
+ trap_msg.outvb.count = 0;
+ snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
+}
+
+void
+snmp_authfail_trap(void)
+{
+ u8_t enable;
+ snmp_get_snmpenableauthentraps(&enable);
+ if (enable == 1)
+ {
+ trap_msg.outvb.head = NULL;
+ trap_msg.outvb.tail = NULL;
+ trap_msg.outvb.count = 0;
+ snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
+ }
+}
+
+/**
+ * Sums response header field lengths from tail to head and
+ * returns resp_header_lengths for second encoding pass.
+ *
+ * @param vb_len varbind-list length
+ * @param rhl points to returned header lengths
+ * @return the required lenght for encoding the response header
+ */
+static u16_t
+snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
+{
+ u16_t tot_len;
+ struct snmp_resp_header_lengths *rhl;
+
+ rhl = &m_stat->rhl;
+ tot_len = vb_len;
+ snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
+ snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
+ tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
+
+ snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
+ snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
+ tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
+
+ snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
+ snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
+ tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
+
+ rhl->pdulen = tot_len;
+ snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
+ tot_len += 1 + rhl->pdulenlen;
+
+ rhl->comlen = m_stat->com_strlen;
+ snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
+ tot_len += 1 + rhl->comlenlen + rhl->comlen;
+
+ snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);
+ snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
+ tot_len += 1 + rhl->verlen + rhl->verlenlen;
+
+ rhl->seqlen = tot_len;
+ snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
+ tot_len += 1 + rhl->seqlenlen;
+
+ return tot_len;
+}
+
+/**
+ * Sums trap header field lengths from tail to head and
+ * returns trap_header_lengths for second encoding pass.
+ *
+ * @param vb_len varbind-list length
+ * @param thl points to returned header lengths
+ * @return the required lenght for encoding the trap header
+ */
+static u16_t
+snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
+{
+ u16_t tot_len;
+ struct snmp_trap_header_lengths *thl;
+
+ thl = &m_trap->thl;
+ tot_len = vb_len;
+
+ snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
+ snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
+ tot_len += 1 + thl->tslen + thl->tslenlen;
+
+ snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
+ snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
+ tot_len += 1 + thl->strplen + thl->strplenlen;
+
+ snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
+ snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
+ tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
+
+ thl->aaddrlen = 4;
+ snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
+ tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
+
+ snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
+ snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
+ tot_len += 1 + thl->eidlen + thl->eidlenlen;
+
+ thl->pdulen = tot_len;
+ snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
+ tot_len += 1 + thl->pdulenlen;
+
+ thl->comlen = sizeof(snmp_publiccommunity) - 1;
+ snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
+ tot_len += 1 + thl->comlenlen + thl->comlen;
+
+ snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
+ snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
+ tot_len += 1 + thl->verlen + thl->verlenlen;
+
+ thl->seqlen = tot_len;
+ snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
+ tot_len += 1 + thl->seqlenlen;
+
+ return tot_len;
+}
+
+/**
+ * Sums varbind lengths from tail to head and
+ * annotates lengths in varbind for second encoding pass.
+ *
+ * @param root points to the root of the variable binding list
+ * @return the required lenght for encoding the variable bindings
+ */
+static u16_t
+snmp_varbind_list_sum(struct snmp_varbind_root *root)
+{
+ struct snmp_varbind *vb;
+ u32_t *uint_ptr;
+ s32_t *sint_ptr;
+ u16_t tot_len;
+
+ tot_len = 0;
+ vb = root->tail;
+ while ( vb != NULL )
+ {
+ /* encoded value lenght depends on type */
+ switch (vb->value_type)
+ {
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
+ sint_ptr = (s32_t*)vb->value;
+ snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
+ break;
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
+ uint_ptr = (u32_t*)vb->value;
+ snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
+ vb->vlen = vb->value_len;
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
+ sint_ptr = (s32_t*)vb->value;
+ snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
+ break;
+ default:
+ /* unsupported type */
+ vb->vlen = 0;
+ break;
+ };
+ /* encoding length of value length field */
+ snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
+ snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
+ snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
+
+ vb->seqlen = 1 + vb->vlenlen + vb->vlen;
+ vb->seqlen += 1 + vb->olenlen + vb->olen;
+ snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
+
+ /* varbind seq */
+ tot_len += 1 + vb->seqlenlen + vb->seqlen;
+
+ vb = vb->prev;
+ }
+
+ /* varbind-list seq */
+ root->seqlen = tot_len;
+ snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
+ tot_len += 1 + root->seqlenlen;
+
+ return tot_len;
+}
+
+/**
+ * Encodes response header from head to tail.
+ */
+static u16_t
+snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
+{
+ u16_t ofs;
+
+ ofs = 0;
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
+ ofs += m_stat->rhl.seqlenlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
+ ofs += m_stat->rhl.verlenlen;
+ snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
+ ofs += m_stat->rhl.verlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
+ ofs += m_stat->rhl.comlenlen;
+ snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
+ ofs += m_stat->rhl.comlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
+ ofs += m_stat->rhl.pdulenlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
+ ofs += m_stat->rhl.ridlenlen;
+ snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
+ ofs += m_stat->rhl.ridlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
+ ofs += m_stat->rhl.errstatlenlen;
+ snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
+ ofs += m_stat->rhl.errstatlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
+ ofs += m_stat->rhl.erridxlenlen;
+ snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
+ ofs += m_stat->rhl.erridxlen;
+
+ return ofs;
+}
+
+/**
+ * Encodes trap header from head to tail.
+ */
+static u16_t
+snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
+{
+ u16_t ofs;
+
+ ofs = 0;
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
+ ofs += m_trap->thl.seqlenlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
+ ofs += m_trap->thl.verlenlen;
+ snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
+ ofs += m_trap->thl.verlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
+ ofs += m_trap->thl.comlenlen;
+ snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);
+ ofs += m_trap->thl.comlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
+ ofs += m_trap->thl.pdulenlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
+ ofs += m_trap->thl.eidlenlen;
+ snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
+ ofs += m_trap->thl.eidlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
+ ofs += m_trap->thl.aaddrlenlen;
+ snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
+ ofs += m_trap->thl.aaddrlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
+ ofs += m_trap->thl.gtrplenlen;
+ snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
+ ofs += m_trap->thl.gtrplen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
+ ofs += m_trap->thl.strplenlen;
+ snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
+ ofs += m_trap->thl.strplen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
+ ofs += m_trap->thl.tslenlen;
+ snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
+ ofs += m_trap->thl.tslen;
+
+ return ofs;
+}
+
+/**
+ * Encodes varbind list from head to tail.
+ */
+static u16_t
+snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
+{
+ struct snmp_varbind *vb;
+ s32_t *sint_ptr;
+ u32_t *uint_ptr;
+ u8_t *raw_ptr;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, root->seqlen);
+ ofs += root->seqlenlen;
+
+ vb = root->head;
+ while ( vb != NULL )
+ {
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, vb->seqlen);
+ ofs += vb->seqlenlen;
+
+ snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, vb->olen);
+ ofs += vb->olenlen;
+ snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
+ ofs += vb->olen;
+
+ snmp_asn1_enc_type(p, ofs, vb->value_type);
+ ofs += 1;
+ snmp_asn1_enc_length(p, ofs, vb->vlen);
+ ofs += vb->vlenlen;
+
+ switch (vb->value_type)
+ {
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
+ sint_ptr = (s32_t*)vb->value;
+ snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
+ break;
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
+ uint_ptr = (u32_t*)vb->value;
+ snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
+ case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
+ raw_ptr = (u8_t*)vb->value;
+ snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
+ break;
+ case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
+ sint_ptr = (s32_t*)vb->value;
+ snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
+ break;
+ default:
+ /* unsupported type */
+ break;
+ };
+ ofs += vb->vlen;
+ vb = vb->next;
+ }
+ return ofs;
+}
+
+#endif /* LWIP_SNMP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/stats.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/stats.c
new file mode 100644
index 0000000000..69f97d41fc
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/stats.c
@@ -0,0 +1,176 @@
+/**
+ * @file
+ * Statistics module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+
+#include <string.h>
+
+struct stats_ lwip_stats;
+
+void stats_init(void)
+{
+#ifdef LWIP_DEBUG
+#if MEMP_STATS
+ const char * memp_names[] = {
+#define LWIP_MEMPOOL(name,num,size,desc) desc,
+#include "lwip/memp_std.h"
+ };
+ int i;
+ for (i = 0; i < MEMP_MAX; i++) {
+ lwip_stats.memp[i].name = memp_names[i];
+ }
+#endif /* MEMP_STATS */
+#if MEM_STATS
+ lwip_stats.mem.name = "MEM";
+#endif /* MEM_STATS */
+#endif /* LWIP_DEBUG */
+}
+
+#if LWIP_STATS_DISPLAY
+void
+stats_display_proto(struct stats_proto *proto, char *name)
+{
+ LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
+ LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
+ LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
+ LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
+ LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
+ LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));
+ LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));
+ LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));
+ LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));
+ LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));
+ LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));
+ LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));
+ LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
+}
+
+#if IGMP_STATS
+void
+stats_display_igmp(struct stats_igmp *igmp)
+{
+ LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
+ LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
+ LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
+ LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
+ LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
+ LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
+ LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
+ LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
+ LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
+ LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
+ LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
+ LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
+ LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
+ LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
+ LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
+}
+#endif /* IGMP_STATS */
+
+#if MEM_STATS || MEMP_STATS
+void
+stats_display_mem(struct stats_mem *mem, char *name)
+{
+ LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
+ LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
+ LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));
+ LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));
+ LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
+}
+
+#if MEMP_STATS
+void
+stats_display_memp(struct stats_mem *mem, int index)
+{
+ char * memp_names[] = {
+#define LWIP_MEMPOOL(name,num,size,desc) desc,
+#include "lwip/memp_std.h"
+ };
+ if(index < MEMP_MAX) {
+ stats_display_mem(mem, memp_names[index]);
+ }
+}
+#endif /* MEMP_STATS */
+#endif /* MEM_STATS || MEMP_STATS */
+
+#if SYS_STATS
+void
+stats_display_sys(struct stats_sys *sys)
+{
+ LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
+ LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
+ LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
+ LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
+ LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
+ LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
+ LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
+ LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
+ LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
+ LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
+}
+#endif /* SYS_STATS */
+
+void
+stats_display(void)
+{
+ s16_t i;
+
+ LINK_STATS_DISPLAY();
+ ETHARP_STATS_DISPLAY();
+ IPFRAG_STATS_DISPLAY();
+ IP_STATS_DISPLAY();
+ IGMP_STATS_DISPLAY();
+ ICMP_STATS_DISPLAY();
+ UDP_STATS_DISPLAY();
+ TCP_STATS_DISPLAY();
+ MEM_STATS_DISPLAY();
+ for (i = 0; i < MEMP_MAX; i++) {
+ MEMP_STATS_DISPLAY(i);
+ }
+ SYS_STATS_DISPLAY();
+}
+#endif /* LWIP_STATS_DISPLAY */
+
+#endif /* LWIP_STATS */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp.c
new file mode 100644
index 0000000000..c629bc4e8a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp.c
@@ -0,0 +1,1635 @@
+/**
+ * @file
+ * Transmission Control Protocol for IP
+ *
+ * This file contains common functions for the TCP implementation, such as functinos
+ * 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.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/snmp.h"
+#include "lwip/tcp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/debug.h"
+#include "lwip/stats.h"
+
+#include <string.h>
+
+const char * const tcp_state_str[] = {
+ "CLOSED",
+ "LISTEN",
+ "SYN_SENT",
+ "SYN_RCVD",
+ "ESTABLISHED",
+ "FIN_WAIT_1",
+ "FIN_WAIT_2",
+ "CLOSE_WAIT",
+ "CLOSING",
+ "LAST_ACK",
+ "TIME_WAIT"
+};
+
+/* Incremented every coarse grained timer shot (typically every 500 ms). */
+u32_t tcp_ticks;
+const u8_t tcp_backoff[13] =
+ { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
+ /* Times per slowtmr hits */
+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;
+/** List of all TCP PCBs in LISTEN state */
+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;
+/** List of all TCP PCBs in TIME-WAIT state */
+struct tcp_pcb *tcp_tw_pcbs;
+
+#define NUM_TCP_PCB_LISTS 4
+#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3
+/** 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};
+
+/** Only used for temporary storage. */
+struct tcp_pcb *tcp_tmp_pcb;
+
+/** Timer counter to handle calling slow-timer from tcp_tmr() */
+static u8_t tcp_timer;
+static u16_t tcp_new_port(void);
+
+/**
+ * Called periodically to dispatch TCP timers.
+ *
+ */
+void
+tcp_tmr(void)
+{
+ /* Call tcp_fasttmr() every 250 ms */
+ tcp_fasttmr();
+
+ if (++tcp_timer & 1) {
+ /* Call tcp_tmr() every 500 ms, i.e., every other timer
+ tcp_tmr() is called. */
+ tcp_slowtmr();
+ }
+}
+
+/**
+ * Closes the TX side of a connection held by the PCB.
+ * For tcp_close(), a RST is sent if the application didn't receive all data
+ * (tcp_recved() not called for all data passed to recv callback).
+ *
+ * Listening pcbs are freed and may not be referenced any more.
+ * Connection pcbs are freed if not yet connected and may not be referenced
+ * any more. If a connection is established (at least SYN received or in
+ * 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.
+ *
+ * @param pcb the tcp_pcb to close
+ * @return ERR_OK if connection has been closed
+ * another err_t if closing failed and pcb is not freed
+ */
+static err_t
+tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
+{
+ err_t err;
+
+ if (rst_on_unacked_data && (pcb->state != LISTEN)) {
+ if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
+ /* Not all data received by application, send RST to tell the remote
+ side about this. */
+ LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
+
+ /* don't call tcp_abort here: we must not deallocate the pcb since
+ that might not be expected when calling tcp_close */
+ tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
+ pcb->local_port, pcb->remote_port);
+
+ tcp_pcb_purge(pcb);
+
+ /* TODO: to which state do we move now? */
+
+ /* move to TIME_WAIT since we close actively */
+ TCP_RMV(&tcp_active_pcbs, pcb);
+ pcb->state = TIME_WAIT;
+ TCP_REG(&tcp_tw_pcbs, pcb);
+
+ return ERR_OK;
+ }
+ }
+
+ switch (pcb->state) {
+ case CLOSED:
+ /* Closing a pcb in the CLOSED state might seem erroneous,
+ * however, it is in this state once allocated and as yet unused
+ * and the user needs some way to free it should the need arise.
+ * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
+ * or for a pcb that has been used and then entered the CLOSED state
+ * is erroneous, but this should never happen as the pcb has in those cases
+ * been freed, and so any remaining handles are bogus. */
+ err = ERR_OK;
+ if (pcb->local_port != 0) {
+ TCP_RMV(&tcp_bound_pcbs, pcb);
+ }
+ memp_free(MEMP_TCP_PCB, pcb);
+ pcb = NULL;
+ break;
+ case LISTEN:
+ err = ERR_OK;
+ tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
+ memp_free(MEMP_TCP_PCB_LISTEN, pcb);
+ pcb = NULL;
+ break;
+ case SYN_SENT:
+ err = ERR_OK;
+ tcp_pcb_remove(&tcp_active_pcbs, pcb);
+ memp_free(MEMP_TCP_PCB, pcb);
+ pcb = NULL;
+ snmp_inc_tcpattemptfails();
+ break;
+ case SYN_RCVD:
+ err = tcp_send_fin(pcb);
+ if (err == ERR_OK) {
+ snmp_inc_tcpattemptfails();
+ pcb->state = FIN_WAIT_1;
+ }
+ break;
+ case ESTABLISHED:
+ err = tcp_send_fin(pcb);
+ if (err == ERR_OK) {
+ snmp_inc_tcpestabresets();
+ pcb->state = FIN_WAIT_1;
+ }
+ break;
+ case CLOSE_WAIT:
+ err = tcp_send_fin(pcb);
+ if (err == ERR_OK) {
+ snmp_inc_tcpestabresets();
+ pcb->state = LAST_ACK;
+ }
+ break;
+ default:
+ /* Has already been closed, do nothing. */
+ err = ERR_OK;
+ pcb = NULL;
+ break;
+ }
+
+ if (pcb != NULL && err == ERR_OK) {
+ /* To ensure all data has been sent when tcp_close returns, we have
+ to make sure tcp_output doesn't fail.
+ Since we don't really have to ensure all data has been sent when tcp_close
+ returns (unsent data is sent from tcp timer functions, also), we don't care
+ for the return value of tcp_output for now. */
+ /* @todo: When implementing SO_LINGER, this must be changed somehow:
+ If SOF_LINGER is set, the data should be sent and acked before close returns.
+ This can only be valid for sequential APIs, not for the raw API. */
+ tcp_output(pcb);
+ }
+ return err;
+}
+
+/**
+ * Closes the connection held by the PCB.
+ *
+ * Listening pcbs are freed and may not be referenced any more.
+ * Connection pcbs are freed if not yet connected and may not be referenced
+ * any more. If a connection is established (at least SYN received or in
+ * 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).
+ *
+ * @param pcb the tcp_pcb to close
+ * @return ERR_OK if connection has been closed
+ * another err_t if closing failed and pcb is not freed
+ */
+err_t
+tcp_close(struct tcp_pcb *pcb)
+{
+#if TCP_DEBUG
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
+ tcp_debug_print_state(pcb->state);
+#endif /* TCP_DEBUG */
+
+ if (pcb->state != LISTEN) {
+ /* Set a flag not to receive any more data... */
+ pcb->flags |= TF_RXCLOSED;
+ }
+ /* ... and close */
+ return tcp_close_shutdown(pcb, 1);
+}
+
+/**
+ * Causes all or part of a full-duplex connection of this PCB to be shut down.
+ * This doesn't deallocate the PCB!
+ *
+ * @param pcb PCB to shutdown
+ * @param shut_rx shut down receive side if this is != 0
+ * @param shut_tx shut down send side if this is != 0
+ * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down)
+ * another err_t on error.
+ */
+err_t
+tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
+{
+ if (pcb->state == LISTEN) {
+ return ERR_CONN;
+ }
+ if (shut_rx) {
+ /* shut down the receive side: free buffered data... */
+ if (pcb->refused_data != NULL) {
+ pbuf_free(pcb->refused_data);
+ pcb->refused_data = NULL;
+ }
+ /* ... and set a flag not to receive any more data */
+ pcb->flags |= TF_RXCLOSED;
+ }
+ if (shut_tx) {
+ /* This can't happen twice since if it succeeds, the pcb's state is changed.
+ Only close in these states as the others directly deallocate the PCB */
+ switch (pcb->state) {
+ case SYN_RCVD:
+ case ESTABLISHED:
+ case CLOSE_WAIT:
+ return tcp_close_shutdown(pcb, 0);
+ default:
+ /* don't shut down other states */
+ break;
+ }
+ }
+ /* @todo: return another err_t if not in correct state or already shut? */
+ return ERR_OK;
+}
+
+/**
+ * Abandons a connection and optionally sends a RST to the remote
+ * host. Deletes the local protocol control block. This is done when
+ * a connection is killed because of shortage of memory.
+ *
+ * @param pcb the tcp_pcb to abort
+ * @param reset boolean to indicate whether a reset should be sent
+ */
+void
+tcp_abandon(struct tcp_pcb *pcb, int reset)
+{
+ u32_t seqno, ackno;
+ u16_t remote_port, local_port;
+ ip_addr_t remote_ip, local_ip;
+#if LWIP_CALLBACK_API
+ tcp_err_fn errf;
+#endif /* LWIP_CALLBACK_API */
+ void *errf_arg;
+
+ /* pcb->state LISTEN not allowed here */
+ LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs",
+ pcb->state != LISTEN);
+ /* Figure out on which TCP PCB list we are, and remove us. If we
+ are in an active state, call the receive function associated with
+ the PCB with a NULL argument, and send an RST to the remote end. */
+ if (pcb->state == TIME_WAIT) {
+ tcp_pcb_remove(&tcp_tw_pcbs, pcb);
+ memp_free(MEMP_TCP_PCB, pcb);
+ } else {
+ seqno = pcb->snd_nxt;
+ ackno = pcb->rcv_nxt;
+ ip_addr_copy(local_ip, pcb->local_ip);
+ ip_addr_copy(remote_ip, pcb->remote_ip);
+ local_port = pcb->local_port;
+ remote_port = pcb->remote_port;
+#if LWIP_CALLBACK_API
+ errf = pcb->errf;
+#endif /* LWIP_CALLBACK_API */
+ errf_arg = pcb->callback_arg;
+ tcp_pcb_remove(&tcp_active_pcbs, pcb);
+ if (pcb->unacked != NULL) {
+ tcp_segs_free(pcb->unacked);
+ }
+ if (pcb->unsent != NULL) {
+ tcp_segs_free(pcb->unsent);
+ }
+#if TCP_QUEUE_OOSEQ
+ if (pcb->ooseq != NULL) {
+ tcp_segs_free(pcb->ooseq);
+ }
+#endif /* TCP_QUEUE_OOSEQ */
+ memp_free(MEMP_TCP_PCB, pcb);
+ TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
+ if (reset) {
+ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
+ tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
+ }
+ }
+}
+
+/**
+ * Aborts the connection by sending a RST (reset) segment to the remote
+ * host. The pcb is deallocated. This function never fails.
+ *
+ * ATTENTION: When calling this from one of the TCP callbacks, make
+ * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
+ * or you will risk accessing deallocated memory or memory leaks!
+ *
+ * @param pcb the tcp pcb to abort
+ */
+void
+tcp_abort(struct tcp_pcb *pcb)
+{
+ tcp_abandon(pcb, 1);
+}
+
+/**
+ * Binds the connection to a local portnumber and IP address. If the
+ * IP address is not given (i.e., ipaddr == NULL), the IP address of
+ * the outgoing network interface is used instead.
+ *
+ * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
+ * already bound!)
+ * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
+ * to any local address
+ * @param port the local port to bind to
+ * @return ERR_USE if the port is already in use
+ * ERR_VAL if bind failed because the PCB is not in a valid state
+ * ERR_OK if bound
+ */
+err_t
+tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
+{
+ int i;
+ int max_pcb_list = NUM_TCP_PCB_LISTS;
+ struct tcp_pcb *cpcb;
+
+ LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL);
+
+#if SO_REUSE
+ /* Unless the REUSEADDR flag is set,
+ we have to check the pcbs in TIME-WAIT state, also.
+ We do not dump TIME_WAIT pcb's; they can still be matched by incoming
+ packets using both local and remote IP addresses and ports to distinguish.
+ */
+ if ((pcb->so_options & SOF_REUSEADDR) != 0) {
+ max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
+ }
+#endif /* SO_REUSE */
+
+ if (port == 0) {
+ port = tcp_new_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 (cpcb->local_port == port) {
+#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
+ tcp_connect. */
+ if (((pcb->so_options & SOF_REUSEADDR) == 0) ||
+ ((cpcb->so_options & SOF_REUSEADDR) == 0))
+#endif /* SO_REUSE */
+ {
+ if (ip_addr_isany(&(cpcb->local_ip)) ||
+ ip_addr_isany(ipaddr) ||
+ ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
+ return ERR_USE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!ip_addr_isany(ipaddr)) {
+ pcb->local_ip = *ipaddr;
+ }
+ pcb->local_port = port;
+ TCP_REG(&tcp_bound_pcbs, pcb);
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
+ return ERR_OK;
+}
+#if LWIP_CALLBACK_API
+/**
+ * Default accept callback if no accept callback is specified by the user.
+ */
+static err_t
+tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_UNUSED_ARG(err);
+
+ return ERR_ABRT;
+}
+#endif /* LWIP_CALLBACK_API */
+
+/**
+ * Set the state of the connection to be LISTEN, which means that it
+ * is able to accept incoming connections. The protocol control block
+ * is reallocated in order to consume less memory. Setting the
+ * connection to LISTEN is an irreversible process.
+ *
+ * @param pcb the original tcp_pcb
+ * @param backlog the incoming connections queue limit
+ * @return tcp_pcb used for listening, consumes less memory.
+ *
+ * @note The original tcp_pcb is freed. This function therefore has to be
+ * called like this:
+ * tpcb = tcp_listen(tpcb);
+ */
+struct tcp_pcb *
+tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
+{
+ struct tcp_pcb_listen *lpcb;
+
+ LWIP_UNUSED_ARG(backlog);
+ LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
+
+ /* already listening? */
+ if (pcb->state == LISTEN) {
+ return pcb;
+ }
+#if SO_REUSE
+ if ((pcb->so_options & SOF_REUSEADDR) != 0) {
+ /* 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
+ 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) {
+ if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
+ /* this address/port is already used */
+ return NULL;
+ }
+ }
+ }
+ }
+#endif /* SO_REUSE */
+ lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
+ if (lpcb == NULL) {
+ return NULL;
+ }
+ lpcb->callback_arg = pcb->callback_arg;
+ lpcb->local_port = pcb->local_port;
+ lpcb->state = LISTEN;
+ lpcb->prio = pcb->prio;
+ lpcb->so_options = pcb->so_options;
+ lpcb->so_options |= SOF_ACCEPTCONN;
+ lpcb->ttl = pcb->ttl;
+ lpcb->tos = pcb->tos;
+ ip_addr_copy(lpcb->local_ip, pcb->local_ip);
+ if (pcb->local_port != 0) {
+ TCP_RMV(&tcp_bound_pcbs, pcb);
+ }
+ memp_free(MEMP_TCP_PCB, pcb);
+#if LWIP_CALLBACK_API
+ lpcb->accept = tcp_accept_null;
+#endif /* LWIP_CALLBACK_API */
+#if TCP_LISTEN_BACKLOG
+ lpcb->accepts_pending = 0;
+ lpcb->backlog = (backlog ? backlog : 1);
+#endif /* TCP_LISTEN_BACKLOG */
+ TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
+ return (struct tcp_pcb *)lpcb;
+}
+
+/**
+ * Update the state that tracks the available window space to advertise.
+ *
+ * Returns how much extra window would be advertised if we sent an
+ * update now.
+ */
+u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
+{
+ u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
+
+ if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {
+ /* we can advertise more window */
+ pcb->rcv_ann_wnd = pcb->rcv_wnd;
+ return new_right_edge - pcb->rcv_ann_right_edge;
+ } else {
+ if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
+ /* Can happen due to other end sending out of advertised window,
+ * but within actual available (but not yet advertised) window */
+ pcb->rcv_ann_wnd = 0;
+ } else {
+ /* keep the right edge of window constant */
+ u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
+ LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff);
+ pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;
+ }
+ return 0;
+ }
+}
+
+/**
+ * This function should be called by the application when it has
+ * processed the data. The purpose is to advertise a larger window
+ * when the data has been processed.
+ *
+ * @param pcb the tcp_pcb for which data is read
+ * @param len the amount of bytes that have been read by the application
+ */
+void
+tcp_recved(struct tcp_pcb *pcb, u16_t len)
+{
+ int wnd_inflation;
+
+ LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
+ len <= 0xffff - pcb->rcv_wnd );
+
+ pcb->rcv_wnd += len;
+ if (pcb->rcv_wnd > TCP_WND) {
+ pcb->rcv_wnd = TCP_WND;
+ }
+
+ wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
+
+ /* If the change in the right edge of window is significant (default
+ * watermark is TCP_WND/4), then send an explicit update now.
+ * Otherwise wait for a packet to be sent in the normal course of
+ * events (or more window to be available later) */
+ if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {
+ tcp_ack_now(pcb);
+ tcp_output(pcb);
+ }
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
+ len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
+}
+
+/**
+ * A nastly hack featuring 'goto' statements that allocates a
+ * new TCP local port.
+ *
+ * @return a new (free) local TCP port number
+ */
+static u16_t
+tcp_new_port(void)
+{
+ int i;
+ struct tcp_pcb *pcb;
+#ifndef TCP_LOCAL_PORT_RANGE_START
+/* From http://www.iana.org/assignments/port-numbers:
+ "The Dynamic and/or Private Ports are those from 49152 through 65535" */
+#define TCP_LOCAL_PORT_RANGE_START 0xc000
+#define TCP_LOCAL_PORT_RANGE_END 0xffff
+#endif
+ static u16_t port = TCP_LOCAL_PORT_RANGE_START;
+
+ again:
+ if (port++ >= TCP_LOCAL_PORT_RANGE_END) {
+ 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 == port) {
+ goto again;
+ }
+ }
+ }
+ return port;
+}
+
+/**
+ * Connects to another host. The function given as the "connected"
+ * argument will be called when the connection has been established.
+ *
+ * @param pcb the tcp_pcb used to establish the connection
+ * @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 (or on error)
+ * @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
+ */
+err_t
+tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
+ tcp_connected_fn connected)
+{
+ err_t ret;
+ u32_t iss;
+ u16_t old_local_port;
+
+ LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
+ if (ipaddr != NULL) {
+ pcb->remote_ip = *ipaddr;
+ } else {
+ return ERR_VAL;
+ }
+ pcb->remote_port = port;
+
+ /* check if we have a route to the remote host */
+ if (ip_addr_isany(&(pcb->local_ip))) {
+ /* no local IP address set, yet. */
+ struct netif *netif = ip_route(&(pcb->remote_ip));
+ if (netif == NULL) {
+ /* Don't even try to send a SYN packet if we have no route
+ since that will fail. */
+ return ERR_RTE;
+ }
+ /* Use the netif's IP address as local address. */
+ ip_addr_copy(pcb->local_ip, netif->ip_addr);
+ }
+
+ old_local_port = pcb->local_port;
+ if (pcb->local_port == 0) {
+ pcb->local_port = tcp_new_port();
+ }
+#if SO_REUSE
+ if ((pcb->so_options & SOF_REUSEADDR) != 0) {
+ /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure
+ now that the 5-tuple is unique. */
+ struct tcp_pcb *cpcb;
+ int i;
+ /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
+ for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
+ 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)) {
+ /* linux returns EISCONN here, but ERR_USE should be OK for us */
+ return ERR_USE;
+ }
+ }
+ }
+ }
+#endif /* SO_REUSE */
+ iss = tcp_next_iss();
+ pcb->rcv_nxt = 0;
+ pcb->snd_nxt = iss;
+ pcb->lastack = iss - 1;
+ pcb->snd_lbb = iss - 1;
+ pcb->rcv_wnd = TCP_WND;
+ pcb->rcv_ann_wnd = TCP_WND;
+ pcb->rcv_ann_right_edge = pcb->rcv_nxt;
+ pcb->snd_wnd = TCP_WND;
+ /* 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 = (TCP_MSS > 536) ? 536 : TCP_MSS;
+#if TCP_CALCULATE_EFF_SEND_MSS
+ pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */
+ pcb->cwnd = 1;
+ pcb->ssthresh = pcb->mss * 10;
+#if LWIP_CALLBACK_API
+ pcb->connected = connected;
+#else /* LWIP_CALLBACK_API */
+ LWIP_UNUSED_ARG(connected);
+#endif /* LWIP_CALLBACK_API */
+
+ /* Send a SYN together with the MSS option. */
+ ret = tcp_enqueue_flags(pcb, TCP_SYN);
+ if (ret == ERR_OK) {
+ /* SYN segment was enqueued, changed the pcbs state now */
+ pcb->state = SYN_SENT;
+ if (old_local_port != 0) {
+ TCP_RMV(&tcp_bound_pcbs, pcb);
+ }
+ TCP_REG(&tcp_active_pcbs, pcb);
+ snmp_inc_tcpactiveopens();
+
+ tcp_output(pcb);
+ }
+ return ret;
+}
+
+/**
+ * Called every 500 ms and implements the retransmission timer and the timer that
+ * removes PCBs that have been in TIME-WAIT for enough time. It also increments
+ * various timers such as the inactivity timer in each PCB.
+ *
+ * Automatically called from tcp_tmr().
+ */
+void
+tcp_slowtmr(void)
+{
+ struct tcp_pcb *pcb, *prev;
+ u16_t eff_wnd;
+ u8_t pcb_remove; /* flag if a PCB should be removed */
+ u8_t pcb_reset; /* flag if a RST should be sent when removing */
+ err_t err;
+
+ err = ERR_OK;
+
+ ++tcp_ticks;
+
+ /* Steps through all of the active PCBs. */
+ prev = NULL;
+ pcb = tcp_active_pcbs;
+ if (pcb == NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
+ }
+ 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);
+
+ pcb_remove = 0;
+ pcb_reset = 0;
+
+ if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
+ ++pcb_remove;
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
+ }
+ else if (pcb->nrtx == TCP_MAXRTX) {
+ ++pcb_remove;
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
+ } else {
+ if (pcb->persist_backoff > 0) {
+ /* If snd_wnd is zero, use persist timer to send 1 byte probes
+ * instead of using the standard retransmission mechanism. */
+ pcb->persist_cnt++;
+ if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
+ pcb->persist_cnt = 0;
+ if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
+ pcb->persist_backoff++;
+ }
+ tcp_zero_window_probe(pcb);
+ }
+ } else {
+ /* Increase the retransmission timer if it is running */
+ if(pcb->rtime >= 0)
+ ++pcb->rtime;
+
+ if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
+ /* Time for a retransmission. */
+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
+ " pcb->rto %"S16_F"\n",
+ pcb->rtime, pcb->rto));
+
+ /* Double retransmission time-out unless we are trying to
+ * connect to somebody (i.e., we are in SYN_SENT). */
+ if (pcb->state != SYN_SENT) {
+ pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
+ }
+
+ /* Reset the retransmission timer. */
+ pcb->rtime = 0;
+
+ /* Reduce congestion window and ssthresh. */
+ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
+ pcb->ssthresh = eff_wnd >> 1;
+ if (pcb->ssthresh < (pcb->mss << 1)) {
+ pcb->ssthresh = (pcb->mss << 1);
+ }
+ pcb->cwnd = pcb->mss;
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
+ " ssthresh %"U16_F"\n",
+ pcb->cwnd, pcb->ssthresh));
+
+ /* The following needs to be called AFTER cwnd is set to one
+ mss - STJ */
+ tcp_rexmit_rto(pcb);
+ }
+ }
+ }
+ /* Check if this PCB has stayed too long in FIN-WAIT-2 */
+ if (pcb->state == FIN_WAIT_2) {
+ 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"));
+ }
+ }
+
+ /* Check if KEEPALIVE should be sent */
+ if((pcb->so_options & SOF_KEEPALIVE) &&
+ ((pcb->state == ESTABLISHED) ||
+ (pcb->state == CLOSE_WAIT))) {
+#if LWIP_TCP_KEEPALIVE
+ if((u32_t)(tcp_ticks - pcb->tmr) >
+ (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
+ / TCP_SLOW_INTERVAL)
+#else
+ if((u32_t)(tcp_ticks - pcb->tmr) >
+ (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
+#endif /* LWIP_TCP_KEEPALIVE */
+ {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
+ ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
+ ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+
+ ++pcb_remove;
+ ++pcb_reset;
+ }
+#if LWIP_TCP_KEEPALIVE
+ else if((u32_t)(tcp_ticks - pcb->tmr) >
+ (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
+ / TCP_SLOW_INTERVAL)
+#else
+ else if((u32_t)(tcp_ticks - pcb->tmr) >
+ (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
+ / TCP_SLOW_INTERVAL)
+#endif /* LWIP_TCP_KEEPALIVE */
+ {
+ tcp_keepalive(pcb);
+ pcb->keep_cnt_sent++;
+ }
+ }
+
+ /* 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 &&
+ (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
+ tcp_segs_free(pcb->ooseq);
+ pcb->ooseq = NULL;
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
+ }
+#endif /* TCP_QUEUE_OOSEQ */
+
+ /* Check if this PCB has stayed too long in SYN-RCVD */
+ if (pcb->state == SYN_RCVD) {
+ 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"));
+ }
+ }
+
+ /* Check if this PCB has stayed too long in LAST-ACK */
+ 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"));
+ }
+ }
+
+ /* If the PCB should be removed, do it. */
+ if (pcb_remove) {
+ struct tcp_pcb *pcb2;
+ tcp_pcb_purge(pcb);
+ /* Remove PCB from tcp_active_pcbs list. */
+ if (prev != NULL) {
+ LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
+ prev->next = pcb->next;
+ } else {
+ /* This PCB was the first. */
+ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
+ tcp_active_pcbs = pcb->next;
+ }
+
+ TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
+ if (pcb_reset) {
+ tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
+ pcb->local_port, pcb->remote_port);
+ }
+
+ pcb2 = pcb;
+ pcb = pcb->next;
+ memp_free(MEMP_TCP_PCB, pcb2);
+ } else {
+ /* get the 'next' element now and work with 'prev' below (in case of abort) */
+ prev = pcb;
+ pcb = pcb->next;
+
+ /* We check if we should poll the connection. */
+ ++prev->polltmr;
+ if (prev->polltmr >= prev->pollinterval) {
+ prev->polltmr = 0;
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
+ TCP_EVENT_POLL(prev, err);
+ /* if err == ERR_ABRT, 'prev' is already deallocated */
+ if (err == ERR_OK) {
+ tcp_output(prev);
+ }
+ }
+ }
+ }
+
+
+ /* Steps through all of the TIME-WAIT PCBs. */
+ prev = NULL;
+ pcb = tcp_tw_pcbs;
+ while (pcb != NULL) {
+ LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
+ pcb_remove = 0;
+
+ /* Check if this PCB has stayed long enough in TIME-WAIT */
+ if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
+ ++pcb_remove;
+ }
+
+
+
+ /* If the PCB should be removed, do it. */
+ if (pcb_remove) {
+ struct tcp_pcb *pcb2;
+ tcp_pcb_purge(pcb);
+ /* Remove PCB from tcp_tw_pcbs list. */
+ if (prev != NULL) {
+ LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
+ prev->next = pcb->next;
+ } else {
+ /* This PCB was the first. */
+ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
+ tcp_tw_pcbs = pcb->next;
+ }
+ pcb2 = pcb;
+ pcb = pcb->next;
+ memp_free(MEMP_TCP_PCB, pcb2);
+ } else {
+ prev = pcb;
+ pcb = pcb->next;
+ }
+ }
+}
+
+/**
+ * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously
+ * "refused" by upper layer (application) and sends delayed ACKs.
+ *
+ * Automatically called from tcp_tmr().
+ */
+void
+tcp_fasttmr(void)
+{
+ struct tcp_pcb *pcb = tcp_active_pcbs;
+
+ while(pcb != NULL) {
+ struct tcp_pcb *next = pcb->next;
+ /* If there is data which was previously "refused" by upper layer */
+ if (pcb->refused_data != NULL) {
+ /* Notify again application with data previously received. */
+ err_t err;
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
+ TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
+ if (err == ERR_OK) {
+ pcb->refused_data = NULL;
+ } else if (err == ERR_ABRT) {
+ /* if err == ERR_ABRT, 'pcb' is already deallocated */
+ pcb = NULL;
+ }
+ }
+
+ /* send delayed ACKs */
+ if (pcb && (pcb->flags & TF_ACK_DELAY)) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
+ tcp_ack_now(pcb);
+ tcp_output(pcb);
+ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
+ }
+
+ pcb = next;
+ }
+}
+
+/**
+ * Deallocates a list of TCP segments (tcp_seg structures).
+ *
+ * @param seg tcp_seg list of TCP segments to free
+ */
+void
+tcp_segs_free(struct tcp_seg *seg)
+{
+ while (seg != NULL) {
+ struct tcp_seg *next = seg->next;
+ tcp_seg_free(seg);
+ seg = next;
+ }
+}
+
+/**
+ * Frees a TCP segment (tcp_seg structure).
+ *
+ * @param seg single tcp_seg to free
+ */
+void
+tcp_seg_free(struct tcp_seg *seg)
+{
+ if (seg != NULL) {
+ if (seg->p != NULL) {
+ pbuf_free(seg->p);
+#if TCP_DEBUG
+ seg->p = NULL;
+#endif /* TCP_DEBUG */
+ }
+ memp_free(MEMP_TCP_SEG, seg);
+ }
+}
+
+/**
+ * Sets the priority of a connection.
+ *
+ * @param pcb the tcp_pcb to manipulate
+ * @param prio new priority
+ */
+void
+tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
+{
+ pcb->prio = prio;
+}
+
+#if TCP_QUEUE_OOSEQ
+/**
+ * Returns a copy of the given TCP segment.
+ * The pbuf and data are not copied, only the pointers
+ *
+ * @param seg the old tcp_seg
+ * @return a copy of seg
+ */
+struct tcp_seg *
+tcp_seg_copy(struct tcp_seg *seg)
+{
+ struct tcp_seg *cseg;
+
+ cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
+ if (cseg == NULL) {
+ return NULL;
+ }
+ SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));
+ pbuf_ref(cseg->p);
+ return cseg;
+}
+#endif /* TCP_QUEUE_OOSEQ */
+
+#if LWIP_CALLBACK_API
+/**
+ * Default receive callback that is called if the user didn't register
+ * a recv callback for the pcb.
+ */
+err_t
+tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+ LWIP_UNUSED_ARG(arg);
+ if (p != NULL) {
+ tcp_recved(pcb, p->tot_len);
+ pbuf_free(p);
+ } else if (err == ERR_OK) {
+ return tcp_close(pcb);
+ }
+ return ERR_OK;
+}
+#endif /* LWIP_CALLBACK_API */
+
+/**
+ * Kills the oldest active connection that has lower priority than prio.
+ *
+ * @param prio minimum priority
+ */
+static void
+tcp_kill_prio(u8_t prio)
+{
+ struct tcp_pcb *pcb, *inactive;
+ u32_t inactivity;
+ u8_t mprio;
+
+
+ mprio = TCP_PRIO_MAX;
+
+ /* We kill the oldest active connection that has lower priority than prio. */
+ inactivity = 0;
+ inactive = NULL;
+ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+ if (pcb->prio <= prio &&
+ pcb->prio <= mprio &&
+ (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
+ inactivity = tcp_ticks - pcb->tmr;
+ inactive = pcb;
+ mprio = pcb->prio;
+ }
+ }
+ if (inactive != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
+ (void *)inactive, inactivity));
+ tcp_abort(inactive);
+ }
+}
+
+/**
+ * Kills the oldest connection that is in TIME_WAIT state.
+ * Called from tcp_alloc() if no more connections are available.
+ */
+static void
+tcp_kill_timewait(void)
+{
+ struct tcp_pcb *pcb, *inactive;
+ u32_t inactivity;
+
+ inactivity = 0;
+ inactive = NULL;
+ /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */
+ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+ if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
+ inactivity = tcp_ticks - pcb->tmr;
+ inactive = pcb;
+ }
+ }
+ if (inactive != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
+ (void *)inactive, inactivity));
+ tcp_abort(inactive);
+ }
+}
+
+/**
+ * Allocate a new tcp_pcb structure.
+ *
+ * @param prio priority for the new pcb
+ * @return a new tcp_pcb that initially is in state CLOSED
+ */
+struct tcp_pcb *
+tcp_alloc(u8_t prio)
+{
+ struct tcp_pcb *pcb;
+ u32_t iss;
+
+ pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
+ if (pcb == NULL) {
+ /* Try killing oldest connection in TIME-WAIT. */
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
+ tcp_kill_timewait();
+ /* Try to allocate a tcp_pcb again. */
+ pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
+ if (pcb == NULL) {
+ /* Try killing active connections with lower priority than the new one. */
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio));
+ tcp_kill_prio(prio);
+ /* Try to allocate a tcp_pcb again. */
+ pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
+ if (pcb != NULL) {
+ /* adjust err stats: memp_malloc failed twice before */
+ MEMP_STATS_DEC(err, MEMP_TCP_PCB);
+ }
+ }
+ if (pcb != NULL) {
+ /* adjust err stats: timewait PCB was freed above */
+ MEMP_STATS_DEC(err, MEMP_TCP_PCB);
+ }
+ }
+ if (pcb != NULL) {
+ memset(pcb, 0, sizeof(struct tcp_pcb));
+ pcb->prio = prio;
+ pcb->snd_buf = TCP_SND_BUF;
+ pcb->snd_queuelen = 0;
+ pcb->rcv_wnd = TCP_WND;
+ pcb->rcv_ann_wnd = TCP_WND;
+ pcb->tos = 0;
+ pcb->ttl = TCP_TTL;
+ /* 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 = (TCP_MSS > 536) ? 536 : TCP_MSS;
+ pcb->rto = 3000 / TCP_SLOW_INTERVAL;
+ pcb->sa = 0;
+ pcb->sv = 3000 / TCP_SLOW_INTERVAL;
+ pcb->rtime = -1;
+ pcb->cwnd = 1;
+ iss = tcp_next_iss();
+ pcb->snd_wl2 = iss;
+ pcb->snd_nxt = iss;
+ pcb->lastack = iss;
+ pcb->snd_lbb = iss;
+ pcb->tmr = tcp_ticks;
+
+ pcb->polltmr = 0;
+
+#if LWIP_CALLBACK_API
+ pcb->recv = tcp_recv_null;
+#endif /* LWIP_CALLBACK_API */
+
+ /* Init KEEPALIVE timer */
+ pcb->keep_idle = TCP_KEEPIDLE_DEFAULT;
+
+#if LWIP_TCP_KEEPALIVE
+ pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;
+ pcb->keep_cnt = TCP_KEEPCNT_DEFAULT;
+#endif /* LWIP_TCP_KEEPALIVE */
+
+ pcb->keep_cnt_sent = 0;
+ }
+ return pcb;
+}
+
+/**
+ * Creates a new TCP protocol control block but doesn't place it on
+ * any of the TCP PCB lists.
+ * The pcb is not put on any list until binding using tcp_bind().
+ *
+ * @internal: Maybe there should be a idle TCP PCB list where these
+ * PCBs are put on. Port reservation using tcp_bind() is implemented but
+ * allocated pcbs that are not bound can't be killed automatically if wanting
+ * to allocate a pcb with higher prio (@see tcp_kill_prio())
+ *
+ * @return a new tcp_pcb that initially is in state CLOSED
+ */
+struct tcp_pcb *
+tcp_new(void)
+{
+ return tcp_alloc(TCP_PRIO_NORMAL);
+}
+
+/**
+ * Used to specify the argument that should be passed callback
+ * functions.
+ *
+ * @param pcb tcp_pcb to set the callback argument
+ * @param arg void pointer argument to pass to callback functions
+ */
+void
+tcp_arg(struct tcp_pcb *pcb, void *arg)
+{
+ pcb->callback_arg = arg;
+}
+#if LWIP_CALLBACK_API
+
+/**
+ * Used to specify the function that should be called when a TCP
+ * connection receives data.
+ *
+ * @param pcb tcp_pcb to set the recv callback
+ * @param recv callback function to call for this pcb when data is received
+ */
+void
+tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
+{
+ pcb->recv = recv;
+}
+
+/**
+ * Used to specify the function that should be called when TCP data
+ * has been successfully delivered to the remote host.
+ *
+ * @param pcb tcp_pcb to set the sent callback
+ * @param sent callback function to call for this pcb when data is successfully sent
+ */
+void
+tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
+{
+ pcb->sent = sent;
+}
+
+/**
+ * Used to specify the function that should be called when a fatal error
+ * has occured on the connection.
+ *
+ * @param pcb tcp_pcb to set the err callback
+ * @param err callback function to call for this pcb when a fatal error
+ * has occured on the connection
+ */
+void
+tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
+{
+ pcb->errf = err;
+}
+
+/**
+ * Used for specifying the function that should be called when a
+ * LISTENing connection has been connected to another host.
+ *
+ * @param pcb tcp_pcb to set the accept callback
+ * @param accept callback function to call for this pcb when LISTENing
+ * connection has been connected to another host
+ */
+void
+tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
+{
+ pcb->accept = accept;
+}
+#endif /* LWIP_CALLBACK_API */
+
+
+/**
+ * Used to specify the function that should be called periodically
+ * from TCP. The interval is specified in terms of the TCP coarse
+ * timer interval, which is called twice a second.
+ *
+ */
+void
+tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
+{
+#if LWIP_CALLBACK_API
+ pcb->poll = poll;
+#else /* LWIP_CALLBACK_API */
+ LWIP_UNUSED_ARG(poll);
+#endif /* LWIP_CALLBACK_API */
+ pcb->pollinterval = interval;
+}
+
+/**
+ * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
+ * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
+ *
+ * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
+ */
+void
+tcp_pcb_purge(struct tcp_pcb *pcb)
+{
+ if (pcb->state != CLOSED &&
+ pcb->state != TIME_WAIT &&
+ pcb->state != LISTEN) {
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
+
+#if TCP_LISTEN_BACKLOG
+ if (pcb->state == SYN_RCVD) {
+ /* Need to find the corresponding listen_pcb and decrease its accepts_pending */
+ struct tcp_pcb_listen *lpcb;
+ LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
+ tcp_listen_pcbs.listen_pcbs != NULL);
+ for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+ if ((lpcb->local_port == pcb->local_port) &&
+ (ip_addr_isany(&lpcb->local_ip) ||
+ ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
+ /* port and address of the listen pcb match the timed-out pcb */
+ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
+ lpcb->accepts_pending > 0);
+ lpcb->accepts_pending--;
+ break;
+ }
+ }
+ }
+#endif /* TCP_LISTEN_BACKLOG */
+
+
+ if (pcb->refused_data != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
+ pbuf_free(pcb->refused_data);
+ pcb->refused_data = NULL;
+ }
+ if (pcb->unsent != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
+ }
+ if (pcb->unacked != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
+ }
+#if TCP_QUEUE_OOSEQ
+ if (pcb->ooseq != NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
+ }
+ tcp_segs_free(pcb->ooseq);
+ pcb->ooseq = NULL;
+#endif /* TCP_QUEUE_OOSEQ */
+
+ /* Stop the retransmission timer as it will expect data on unacked
+ queue if it fires */
+ pcb->rtime = -1;
+
+ tcp_segs_free(pcb->unsent);
+ tcp_segs_free(pcb->unacked);
+ pcb->unacked = pcb->unsent = NULL;
+#if TCP_OVERSIZE
+ pcb->unsent_oversize = 0;
+#endif /* TCP_OVERSIZE */
+ }
+}
+
+/**
+ * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
+ *
+ * @param pcblist PCB list to purge.
+ * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
+ */
+void
+tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
+{
+ TCP_RMV(pcblist, pcb);
+
+ tcp_pcb_purge(pcb);
+
+ /* if there is an outstanding delayed ACKs, send it */
+ if (pcb->state != TIME_WAIT &&
+ pcb->state != LISTEN &&
+ pcb->flags & TF_ACK_DELAY) {
+ pcb->flags |= TF_ACK_NOW;
+ tcp_output(pcb);
+ }
+
+ if (pcb->state != LISTEN) {
+ LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
+ LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
+#if TCP_QUEUE_OOSEQ
+ LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
+#endif /* TCP_QUEUE_OOSEQ */
+ }
+
+ pcb->state = CLOSED;
+
+ LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
+}
+
+/**
+ * Calculates a new initial sequence number for new connections.
+ *
+ * @return u32_t pseudo random sequence number
+ */
+u32_t
+tcp_next_iss(void)
+{
+ static u32_t iss = 6510;
+
+ iss += tcp_ticks; /* XXX */
+ return iss;
+}
+
+#if TCP_CALCULATE_EFF_SEND_MSS
+/**
+ * Calcluates the effective send mss that can be used for a specific IP address
+ * by using ip_route to determin the netif used to send to the address and
+ * calculating the minimum of TCP_MSS and that netif's mtu (if set).
+ */
+u16_t
+tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
+{
+ u16_t mss_s;
+ struct netif *outif;
+
+ outif = ip_route(addr);
+ if ((outif != NULL) && (outif->mtu != 0)) {
+ mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
+ /* RFC 1122, chap 4.2.2.6:
+ * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
+ * We correct for TCP options in tcp_write(), and don't support IP options.
+ */
+ sendmss = LWIP_MIN(sendmss, mss_s);
+ }
+ return sendmss;
+}
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */
+
+const char*
+tcp_debug_state_str(enum tcp_state s)
+{
+ return tcp_state_str[s];
+}
+
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
+/**
+ * Print a tcp header for debugging purposes.
+ *
+ * @param tcphdr pointer to a struct tcp_hdr
+ */
+void
+tcp_debug_print(struct tcp_hdr *tcphdr)
+{
+ LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
+ ntohs(tcphdr->src), ntohs(tcphdr->dest)));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n",
+ ntohl(tcphdr->seqno)));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n",
+ ntohl(tcphdr->ackno)));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (",
+ TCPH_HDRLEN(tcphdr),
+ TCPH_FLAGS(tcphdr) >> 5 & 1,
+ TCPH_FLAGS(tcphdr) >> 4 & 1,
+ TCPH_FLAGS(tcphdr) >> 3 & 1,
+ TCPH_FLAGS(tcphdr) >> 2 & 1,
+ TCPH_FLAGS(tcphdr) >> 1 & 1,
+ TCPH_FLAGS(tcphdr) & 1,
+ ntohs(tcphdr->wnd)));
+ tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
+ LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n",
+ ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
+ LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+}
+
+/**
+ * Print a tcp state for debugging purposes.
+ *
+ * @param s enum tcp_state to print
+ */
+void
+tcp_debug_print_state(enum tcp_state s)
+{
+ LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
+}
+
+/**
+ * Print tcp flags for debugging purposes.
+ *
+ * @param flags tcp flags, all active flags are printed
+ */
+void
+tcp_debug_print_flags(u8_t flags)
+{
+ if (flags & TCP_FIN) {
+ LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
+ }
+ if (flags & TCP_SYN) {
+ LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
+ }
+ if (flags & TCP_RST) {
+ LWIP_DEBUGF(TCP_DEBUG, ("RST "));
+ }
+ if (flags & TCP_PSH) {
+ LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
+ }
+ if (flags & TCP_ACK) {
+ LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
+ }
+ if (flags & TCP_URG) {
+ LWIP_DEBUGF(TCP_DEBUG, ("URG "));
+ }
+ if (flags & TCP_ECE) {
+ LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
+ }
+ if (flags & TCP_CWR) {
+ LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
+ }
+ LWIP_DEBUGF(TCP_DEBUG, ("\n"));
+}
+
+/**
+ * Print all tcp_pcbs in every list for debugging purposes.
+ */
+void
+tcp_debug_print_pcbs(void)
+{
+ struct tcp_pcb *pcb;
+ LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
+ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+ pcb->local_port, pcb->remote_port,
+ pcb->snd_nxt, pcb->rcv_nxt));
+ tcp_debug_print_state(pcb->state);
+ }
+ LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
+ for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+ pcb->local_port, pcb->remote_port,
+ pcb->snd_nxt, pcb->rcv_nxt));
+ tcp_debug_print_state(pcb->state);
+ }
+ LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
+ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+ pcb->local_port, pcb->remote_port,
+ pcb->snd_nxt, pcb->rcv_nxt));
+ tcp_debug_print_state(pcb->state);
+ }
+}
+
+/**
+ * Check state consistency of the tcp_pcb lists.
+ */
+s16_t
+tcp_pcbs_sane(void)
+{
+ struct tcp_pcb *pcb;
+ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
+ LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
+ LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
+ }
+ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
+ }
+ return 1;
+}
+#endif /* TCP_DEBUG */
+
+#endif /* LWIP_TCP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_in.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_in.c
new file mode 100644
index 0000000000..90952648d7
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_in.c
@@ -0,0 +1,1567 @@
+/**
+ * @file
+ * Transmission Control Protocol, incoming traffic
+ *
+ * The input processing functions of the TCP layer.
+ *
+ * These functions are generally called in the order (ip_input() ->)
+ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/tcp_impl.h"
+#include "lwip/def.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "arch/perf.h"
+
+/* 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 struct ip_hdr *iphdr;
+static u32_t seqno, ackno;
+static u8_t flags;
+static u16_t tcplen;
+
+static u8_t recv_flags;
+static struct pbuf *recv_data;
+
+struct tcp_pcb *tcp_input_pcb;
+
+/* Forward declarations. */
+static err_t tcp_process(struct tcp_pcb *pcb);
+static void tcp_receive(struct tcp_pcb *pcb);
+static void tcp_parseopt(struct tcp_pcb *pcb);
+
+static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
+static err_t tcp_timewait_input(struct tcp_pcb *pcb);
+
+/**
+ * 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
+ * the TCP finite state machine. This function is called by the IP layer (in
+ * ip_input()).
+ *
+ * @param p received TCP segment to process (p->payload pointing to the IP header)
+ * @param inp network interface on which this segment was received
+ */
+void
+tcp_input(struct pbuf *p, struct netif *inp)
+{
+ struct tcp_pcb *pcb, *prev;
+ struct tcp_pcb_listen *lpcb;
+#if SO_REUSE
+ struct tcp_pcb *lpcb_prev = NULL;
+ struct tcp_pcb_listen *lpcb_any = NULL;
+#endif /* SO_REUSE */
+ u8_t hdrlen;
+ err_t err;
+
+ PERF_START;
+
+ TCP_STATS_INC(tcp.recv);
+ snmp_inc_tcpinsegs();
+
+ iphdr = (struct ip_hdr *)p->payload;
+ tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+
+#if TCP_INPUT_DEBUG
+ tcp_debug_print(tcphdr);
+#endif
+
+ /* remove header from payload */
+ if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
+ /* drop short packets */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
+ TCP_STATS_INC(tcp.lenerr);
+ TCP_STATS_INC(tcp.drop);
+ snmp_inc_tcpinerrs();
+ pbuf_free(p);
+ return;
+ }
+
+ /* Don't even process incoming broadcasts/multicasts. */
+ if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
+ ip_addr_ismulticast(&current_iphdr_dest)) {
+ TCP_STATS_INC(tcp.proterr);
+ TCP_STATS_INC(tcp.drop);
+ snmp_inc_tcpinerrs();
+ pbuf_free(p);
+ return;
+ }
+
+#if CHECKSUM_CHECK_TCP
+ /* Verify TCP checksum. */
+ if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
+ IP_PROTO_TCP, p->tot_len) != 0) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
+ inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
+ IP_PROTO_TCP, p->tot_len)));
+#if TCP_DEBUG
+ tcp_debug_print(tcphdr);
+#endif /* TCP_DEBUG */
+ TCP_STATS_INC(tcp.chkerr);
+ TCP_STATS_INC(tcp.drop);
+ snmp_inc_tcpinerrs();
+ pbuf_free(p);
+ return;
+ }
+#endif
+
+ /* Move the payload pointer in the pbuf so that it points to the
+ TCP data instead of the TCP header. */
+ hdrlen = TCPH_HDRLEN(tcphdr);
+ if(pbuf_header(p, -(hdrlen * 4))){
+ /* drop short packets */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
+ TCP_STATS_INC(tcp.lenerr);
+ TCP_STATS_INC(tcp.drop);
+ snmp_inc_tcpinerrs();
+ pbuf_free(p);
+ return;
+ }
+
+ /* Convert fields in TCP header to host byte order. */
+ tcphdr->src = ntohs(tcphdr->src);
+ tcphdr->dest = ntohs(tcphdr->dest);
+ seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
+ ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
+ tcphdr->wnd = ntohs(tcphdr->wnd);
+
+ flags = TCPH_FLAGS(tcphdr);
+ tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
+
+ /* Demultiplex an incoming segment. First, we check if it is destined
+ for an active connection. */
+ prev = NULL;
+
+
+ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+ 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);
+ if (pcb->remote_port == tcphdr->src &&
+ pcb->local_port == tcphdr->dest &&
+ ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
+ ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
+
+ /* Move this PCB to the front of the list so that subsequent
+ lookups will be faster (we exploit locality in TCP segment
+ arrivals). */
+ LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
+ if (prev != NULL) {
+ prev->next = pcb->next;
+ pcb->next = tcp_active_pcbs;
+ tcp_active_pcbs = pcb;
+ }
+ LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
+ break;
+ }
+ prev = pcb;
+ }
+
+ if (pcb == NULL) {
+ /* If it did not go to an active connection, we check the connections
+ in the TIME-WAIT state. */
+ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+ LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
+ if (pcb->remote_port == tcphdr->src &&
+ pcb->local_port == tcphdr->dest &&
+ ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
+ ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
+ /* 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. */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
+ tcp_timewait_input(pcb);
+ pbuf_free(p);
+ return;
+ }
+ }
+
+ /* Finally, if we still did not get a match, we check all PCBs that
+ are LISTENing for incoming connections. */
+ prev = NULL;
+ for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+ if (lpcb->local_port == tcphdr->dest) {
+#if SO_REUSE
+ if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
+ /* found an exact match */
+ break;
+ } else if(ip_addr_isany(&(lpcb->local_ip))) {
+ /* found an ANY-match */
+ lpcb_any = lpcb;
+ lpcb_prev = prev;
+ }
+#else /* SO_REUSE */
+ if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
+ ip_addr_isany(&(lpcb->local_ip))) {
+ /* found a match */
+ break;
+ }
+#endif /* SO_REUSE */
+ }
+ prev = (struct tcp_pcb *)lpcb;
+ }
+#if SO_REUSE
+ /* first try specific local IP */
+ if (lpcb == NULL) {
+ /* only pass to ANY if no specific local IP has been found */
+ lpcb = lpcb_any;
+ prev = lpcb_prev;
+ }
+#endif /* SO_REUSE */
+ if (lpcb != NULL) {
+ /* Move this PCB to the front of the list so that subsequent
+ lookups will be faster (we exploit locality in TCP segment
+ arrivals). */
+ if (prev != NULL) {
+ ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
+ /* our successor is the remainder of the listening list */
+ lpcb->next = tcp_listen_pcbs.listen_pcbs;
+ /* put this listening pcb at the head of the listening list */
+ tcp_listen_pcbs.listen_pcbs = lpcb;
+ }
+
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
+ tcp_listen_input(lpcb);
+ pbuf_free(p);
+ return;
+ }
+ }
+
+#if TCP_INPUT_DEBUG
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
+ tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
+#endif /* TCP_INPUT_DEBUG */
+
+
+ if (pcb != NULL) {
+ /* The incoming segment belongs to a connection. */
+#if TCP_INPUT_DEBUG
+#if TCP_DEBUG
+ tcp_debug_print_state(pcb->state);
+#endif /* TCP_DEBUG */
+#endif /* TCP_INPUT_DEBUG */
+
+ /* Set up a tcp_seg structure. */
+ inseg.next = NULL;
+ inseg.len = p->tot_len;
+ inseg.p = p;
+ inseg.tcphdr = tcphdr;
+
+ recv_data = NULL;
+ recv_flags = 0;
+
+ /* If there is data which was previously "refused" by upper layer */
+ if (pcb->refused_data != NULL) {
+ /* Notify again application with data previously received. */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
+ TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
+ if (err == ERR_OK) {
+ pcb->refused_data = NULL;
+ } else if ((err == ERR_ABRT) || (tcplen > 0)) {
+ /* if err == ERR_ABRT, 'pcb' is already deallocated */
+ /* Drop incoming packets because pcb is "full" (only if the incoming
+ segment contains data). */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
+ TCP_STATS_INC(tcp.drop);
+ snmp_inc_tcpinerrs();
+ pbuf_free(p);
+ return;
+ }
+ }
+ tcp_input_pcb = pcb;
+ err = tcp_process(pcb);
+ /* A return value of ERR_ABRT means that tcp_abort() was called
+ and that the pcb has been freed. If so, we don't do anything. */
+ if (err != ERR_ABRT) {
+ if (recv_flags & TF_RESET) {
+ /* TF_RESET means that the connection was reset by the other
+ end. We then call the error callback to inform the
+ application that the connection is dead before we
+ deallocate the PCB. */
+ TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
+ tcp_pcb_remove(&tcp_active_pcbs, pcb);
+ memp_free(MEMP_TCP_PCB, pcb);
+ } else if (recv_flags & TF_CLOSED) {
+ /* The connection has been closed and we will deallocate the
+ PCB. */
+ tcp_pcb_remove(&tcp_active_pcbs, pcb);
+ memp_free(MEMP_TCP_PCB, pcb);
+ } else {
+ err = ERR_OK;
+ /* If the application has registered a "sent" function to be
+ called when new send buffer space is available, we call it
+ now. */
+ if (pcb->acked > 0) {
+ TCP_EVENT_SENT(pcb, pcb->acked, err);
+ if (err == ERR_ABRT) {
+ goto aborted;
+ }
+ }
+
+ if (recv_data != NULL) {
+ LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
+ if (pcb->flags & TF_RXCLOSED) {
+ /* received data although already closed -> abort (send RST) to
+ notify the remote host that not all data has been processed */
+ pbuf_free(recv_data);
+ tcp_abort(pcb);
+ goto aborted;
+ }
+ if (flags & TCP_PSH) {
+ recv_data->flags |= PBUF_FLAG_PUSH;
+ }
+
+ /* Notify application that data has been received. */
+ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
+ if (err == ERR_ABRT) {
+ goto aborted;
+ }
+
+ /* If the upper layer can't receive this data, store it */
+ if (err != ERR_OK) {
+ pcb->refused_data = recv_data;
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
+ }
+ }
+
+ /* If a FIN segment was received, we call the callback
+ function with a NULL buffer to indicate EOF. */
+ if (recv_flags & TF_GOT_FIN) {
+ /* correct rcv_wnd as the application won't call tcp_recved()
+ for the FIN's seqno */
+ if (pcb->rcv_wnd != TCP_WND) {
+ pcb->rcv_wnd++;
+ }
+ TCP_EVENT_CLOSED(pcb, err);
+ if (err == ERR_ABRT) {
+ goto aborted;
+ }
+ }
+
+ tcp_input_pcb = NULL;
+ /* Try to send something out. */
+ tcp_output(pcb);
+#if TCP_INPUT_DEBUG
+#if TCP_DEBUG
+ tcp_debug_print_state(pcb->state);
+#endif /* TCP_DEBUG */
+#endif /* TCP_INPUT_DEBUG */
+ }
+ }
+ /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
+ Below this line, 'pcb' may not be dereferenced! */
+aborted:
+ tcp_input_pcb = NULL;
+ recv_data = NULL;
+
+ /* give up our reference to inseg.p */
+ if (inseg.p != NULL)
+ {
+ pbuf_free(inseg.p);
+ inseg.p = NULL;
+ }
+ } 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);
+ tcp_rst(ackno, seqno + tcplen,
+ ip_current_dest_addr(), ip_current_src_addr(),
+ tcphdr->dest, tcphdr->src);
+ }
+ pbuf_free(p);
+ }
+
+ LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
+ PERF_STOP("tcp_input");
+}
+
+/**
+ * Called by tcp_input() when a segment arrives for a listening
+ * connection (from tcp_input()).
+ *
+ * @param pcb the tcp_pcb_listen for which a segment arrived
+ * @return ERR_OK if the segment was processed
+ * another err_t on error
+ *
+ * @note the return value is not (yet?) used in tcp_input()
+ * @note the segment which arrived is saved in global variables, therefore only the pcb
+ * involved is passed as a parameter to this function
+ */
+static err_t
+tcp_listen_input(struct tcp_pcb_listen *pcb)
+{
+ struct tcp_pcb *npcb;
+ err_t rc;
+
+ /* 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(ackno + 1, 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));
+#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));
+ return ERR_ABRT;
+ }
+#endif /* TCP_LISTEN_BACKLOG */
+ npcb = tcp_alloc(pcb->prio);
+ /* If a new PCB could not be created (probably due to lack of memory),
+ we don't do anything, but rely on the sender will retransmit the
+ SYN at a time when we have more memory available. */
+ if (npcb == NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
+ TCP_STATS_INC(tcp.memerr);
+ return ERR_MEM;
+ }
+#if TCP_LISTEN_BACKLOG
+ pcb->accepts_pending++;
+#endif /* TCP_LISTEN_BACKLOG */
+ /* Set up the new PCB. */
+ ip_addr_copy(npcb->local_ip, current_iphdr_dest);
+ npcb->local_port = pcb->local_port;
+ ip_addr_copy(npcb->remote_ip, current_iphdr_src);
+ npcb->remote_port = tcphdr->src;
+ npcb->state = SYN_RCVD;
+ npcb->rcv_nxt = seqno + 1;
+ npcb->rcv_ann_right_edge = npcb->rcv_nxt;
+ npcb->snd_wnd = tcphdr->wnd;
+ npcb->ssthresh = npcb->snd_wnd;
+ npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
+ npcb->callback_arg = pcb->callback_arg;
+#if LWIP_CALLBACK_API
+ npcb->accept = pcb->accept;
+#endif /* LWIP_CALLBACK_API */
+ /* inherit socket options */
+ npcb->so_options = pcb->so_options & SOF_INHERITED;
+ /* Register the new PCB so that we can begin receiving segments
+ for it. */
+ TCP_REG(&tcp_active_pcbs, npcb);
+
+ /* Parse any options in the SYN. */
+ tcp_parseopt(npcb);
+#if TCP_CALCULATE_EFF_SEND_MSS
+ npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */
+
+ snmp_inc_tcppassiveopens();
+
+ /* 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);
+ return rc;
+ }
+ return tcp_output(npcb);
+ }
+ return ERR_OK;
+}
+
+/**
+ * Called by tcp_input() when a segment arrives for a connection in
+ * TIME_WAIT.
+ *
+ * @param pcb the tcp_pcb for which a segment arrived
+ *
+ * @note the segment which arrived is saved in global variables, therefore only the pcb
+ * involved is passed as a parameter to this function
+ */
+static err_t
+tcp_timewait_input(struct tcp_pcb *pcb)
+{
+ /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
+ /* RFC 793 3.9 Event Processing - Segment Arrives:
+ * - first check sequence number - we skip that one in TIME_WAIT (always
+ * acceptable since we only send ACKs)
+ * - second check the RST bit (... return) */
+ if (flags & TCP_RST) {
+ return ERR_OK;
+ }
+ /* - fourth, check the SYN bit, */
+ if (flags & TCP_SYN) {
+ /* If an incoming segment is not acceptable, an acknowledgment
+ 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 */
+ tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
+ tcphdr->dest, tcphdr->src);
+ return ERR_OK;
+ }
+ } else if (flags & TCP_FIN) {
+ /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
+ Restart the 2 MSL time-wait timeout.*/
+ pcb->tmr = tcp_ticks;
+ }
+
+ if ((tcplen > 0)) {
+ /* Acknowledge data, FIN or out-of-window SYN */
+ pcb->flags |= TF_ACK_NOW;
+ return tcp_output(pcb);
+ }
+ return ERR_OK;
+}
+
+/**
+ * Implements the TCP state machine. Called by tcp_input. In some
+ * states tcp_receive() is called to receive data. The tcp_seg
+ * argument will be freed by the caller (tcp_input()) unless the
+ * recv_data pointer in the pcb is set.
+ *
+ * @param pcb the tcp_pcb for which a segment arrived
+ *
+ * @note the segment which arrived is saved in global variables, therefore only the pcb
+ * involved is passed as a parameter to this function
+ */
+static err_t
+tcp_process(struct tcp_pcb *pcb)
+{
+ struct tcp_seg *rseg;
+ u8_t acceptable = 0;
+ err_t err;
+
+ err = ERR_OK;
+
+ /* Process incoming RST segments. */
+ if (flags & TCP_RST) {
+ /* First, determine if the reset is acceptable. */
+ if (pcb->state == SYN_SENT) {
+ if (ackno == pcb->snd_nxt) {
+ acceptable = 1;
+ }
+ } else {
+ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
+ pcb->rcv_nxt+pcb->rcv_wnd)) {
+ acceptable = 1;
+ }
+ }
+
+ if (acceptable) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
+ LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
+ recv_flags |= TF_RESET;
+ pcb->flags &= ~TF_ACK_DELAY;
+ return ERR_RST;
+ } else {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
+ seqno, pcb->rcv_nxt));
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
+ seqno, pcb->rcv_nxt));
+ return ERR_OK;
+ }
+ }
+
+ if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
+ /* Cope with new connection attempt after remote end crashed */
+ tcp_ack_now(pcb);
+ return ERR_OK;
+ }
+
+ if ((pcb->flags & TF_RXCLOSED) == 0) {
+ /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
+ pcb->tmr = tcp_ticks;
+ }
+ pcb->keep_cnt_sent = 0;
+
+ tcp_parseopt(pcb);
+
+ /* Do different things depending on the TCP state. */
+ switch (pcb->state) {
+ case SYN_SENT:
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
+ pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
+ /* received SYN ACK with expected sequence number? */
+ if ((flags & TCP_ACK) && (flags & TCP_SYN)
+ && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
+ pcb->snd_buf++;
+ pcb->rcv_nxt = seqno + 1;
+ pcb->rcv_ann_right_edge = pcb->rcv_nxt;
+ pcb->lastack = ackno;
+ pcb->snd_wnd = tcphdr->wnd;
+ pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
+ pcb->state = ESTABLISHED;
+
+#if TCP_CALCULATE_EFF_SEND_MSS
+ pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */
+
+ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
+ * but for the default value of pcb->mss) */
+ pcb->ssthresh = pcb->mss * 10;
+
+ pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
+ LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
+ --pcb->snd_queuelen;
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
+ rseg = pcb->unacked;
+ pcb->unacked = rseg->next;
+
+ /* If there's nothing left to acknowledge, stop the retransmit
+ timer, otherwise reset it to start again */
+ if(pcb->unacked == NULL)
+ pcb->rtime = -1;
+ else {
+ pcb->rtime = 0;
+ pcb->nrtx = 0;
+ }
+
+ tcp_seg_free(rseg);
+
+ /* Call the user specified function to call when sucessfully
+ * connected. */
+ TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
+ if (err == ERR_ABRT) {
+ return ERR_ABRT;
+ }
+ tcp_ack_now(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. */
+ tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
+ tcphdr->dest, tcphdr->src);
+ }
+ break;
+ case SYN_RCVD:
+ if (flags & TCP_ACK) {
+ /* expected ACK number? */
+ if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
+ u16_t old_cwnd;
+ pcb->state = ESTABLISHED;
+ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
+#if LWIP_CALLBACK_API
+ LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
+#endif
+ /* Call the accept function. */
+ TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
+ if (err != ERR_OK) {
+ /* If the accept function returns with an error, we abort
+ * the connection. */
+ /* Already aborted? */
+ if (err != ERR_ABRT) {
+ tcp_abort(pcb);
+ }
+ return ERR_ABRT;
+ }
+ old_cwnd = pcb->cwnd;
+ /* If there was any data contained within this ACK,
+ * we'd better pass it on to the application as well. */
+ tcp_receive(pcb);
+
+ /* Prevent ACK for SYN to generate a sent event */
+ if (pcb->acked != 0) {
+ pcb->acked--;
+ }
+
+ pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
+
+ if (recv_flags & TF_GOT_FIN) {
+ tcp_ack_now(pcb);
+ pcb->state = CLOSE_WAIT;
+ }
+ } else {
+ /* incorrect ACK number, send RST */
+ tcp_rst(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:
+ /* FALLTHROUGH */
+ case ESTABLISHED:
+ tcp_receive(pcb);
+ if (recv_flags & TF_GOT_FIN) { /* passive close */
+ tcp_ack_now(pcb);
+ pcb->state = CLOSE_WAIT;
+ }
+ break;
+ case FIN_WAIT_1:
+ tcp_receive(pcb);
+ if (recv_flags & TF_GOT_FIN) {
+ if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
+ LWIP_DEBUGF(TCP_DEBUG,
+ ("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);
+ TCP_RMV(&tcp_active_pcbs, pcb);
+ pcb->state = TIME_WAIT;
+ TCP_REG(&tcp_tw_pcbs, pcb);
+ } else {
+ tcp_ack_now(pcb);
+ pcb->state = CLOSING;
+ }
+ } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
+ pcb->state = FIN_WAIT_2;
+ }
+ break;
+ case FIN_WAIT_2:
+ tcp_receive(pcb);
+ if (recv_flags & TF_GOT_FIN) {
+ 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);
+ TCP_RMV(&tcp_active_pcbs, pcb);
+ pcb->state = TIME_WAIT;
+ TCP_REG(&tcp_tw_pcbs, pcb);
+ }
+ break;
+ case CLOSING:
+ tcp_receive(pcb);
+ if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
+ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
+ tcp_pcb_purge(pcb);
+ TCP_RMV(&tcp_active_pcbs, pcb);
+ pcb->state = TIME_WAIT;
+ TCP_REG(&tcp_tw_pcbs, pcb);
+ }
+ break;
+ case LAST_ACK:
+ tcp_receive(pcb);
+ if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
+ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
+ /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
+ recv_flags |= TF_CLOSED;
+ }
+ break;
+ default:
+ break;
+ }
+ return ERR_OK;
+}
+
+#if TCP_QUEUE_OOSEQ
+/**
+ * Insert segment into the list (segments covered with new one will be deleted)
+ *
+ * Called from tcp_receive()
+ */
+static void
+tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
+{
+ struct tcp_seg *old_seg;
+
+ if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
+ /* received segment overlaps all following segments */
+ tcp_segs_free(next);
+ next = NULL;
+ }
+ else {
+ /* delete some following segments
+ oos queue may have segments with FIN flag */
+ while (next &&
+ TCP_SEQ_GEQ((seqno + cseg->len),
+ (next->tcphdr->seqno + next->len))) {
+ /* cseg with FIN already processed */
+ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
+ TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
+ }
+ old_seg = next;
+ next = next->next;
+ tcp_seg_free(old_seg);
+ }
+ if (next &&
+ TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
+ /* We need to trim the incoming segment. */
+ cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
+ pbuf_realloc(cseg->p, cseg->len);
+ }
+ }
+ cseg->next = next;
+}
+#endif /* TCP_QUEUE_OOSEQ */
+
+/**
+ * Called by tcp_process. Checks if the given segment is an ACK for outstanding
+ * data, and if so frees the memory of the buffered data. Next, is places the
+ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
+ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
+ * i it has been removed from the buffer.
+ *
+ * If the incoming segment constitutes an ACK for a segment that was used for RTT
+ * estimation, the RTT is estimated here as well.
+ *
+ * Called from tcp_process().
+ */
+static void
+tcp_receive(struct tcp_pcb *pcb)
+{
+ struct tcp_seg *next;
+#if TCP_QUEUE_OOSEQ
+ struct tcp_seg *prev, *cseg;
+#endif /* TCP_QUEUE_OOSEQ */
+ struct pbuf *p;
+ s32_t off;
+ s16_t m;
+ u32_t right_wnd_edge;
+ u16_t new_tot_len;
+ int found_dupack = 0;
+
+ if (flags & TCP_ACK) {
+ right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
+
+ /* Update window. */
+ if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
+ (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
+ (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
+ pcb->snd_wnd = tcphdr->wnd;
+ pcb->snd_wl1 = seqno;
+ pcb->snd_wl2 = ackno;
+ if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
+ pcb->persist_backoff = 0;
+ }
+ LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
+#if TCP_WND_DEBUG
+ } else {
+ if (pcb->snd_wnd != tcphdr->wnd) {
+ LWIP_DEBUGF(TCP_WND_DEBUG,
+ ("tcp_receive: no window update lastack %"U32_F" ackno %"
+ U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
+ pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
+ }
+#endif /* TCP_WND_DEBUG */
+ }
+
+ /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
+ * duplicate ack if:
+ * 1) It doesn't ACK new data
+ * 2) length of received packet is zero (i.e. no payload)
+ * 3) the advertised window hasn't changed
+ * 4) There is outstanding unacknowledged data (retransmission timer running)
+ * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
+ *
+ * If it passes all five, should process as a dupack:
+ * a) dupacks < 3: do nothing
+ * b) dupacks == 3: fast retransmit
+ * c) dupacks > 3: increase cwnd
+ *
+ * If it only passes 1-3, should reset dupack counter (and add to
+ * stats, which we don't do in lwIP)
+ *
+ * If it only passes 1, should reset dupack counter
+ *
+ */
+
+ /* Clause 1 */
+ if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
+ pcb->acked = 0;
+ /* Clause 2 */
+ if (tcplen == 0) {
+ /* Clause 3 */
+ if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
+ /* Clause 4 */
+ if (pcb->rtime >= 0) {
+ /* Clause 5 */
+ if (pcb->lastack == ackno) {
+ found_dupack = 1;
+ if (pcb->dupacks + 1 > pcb->dupacks)
+ ++pcb->dupacks;
+ if (pcb->dupacks > 3) {
+ /* Inflate the congestion window, but not if it means that
+ the value overflows. */
+ if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
+ pcb->cwnd += pcb->mss;
+ }
+ } else if (pcb->dupacks == 3) {
+ /* Do fast retransmit */
+ tcp_rexmit_fast(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. */
+
+ /* Reset the "IN Fast Retransmit" flag, since we are no longer
+ in fast retransmit. Also reset the congestion window to the
+ slow start threshold. */
+ if (pcb->flags & TF_INFR) {
+ pcb->flags &= ~TF_INFR;
+ pcb->cwnd = pcb->ssthresh;
+ }
+
+ /* Reset the number of retransmissions. */
+ pcb->nrtx = 0;
+
+ /* Reset the retransmission time-out. */
+ pcb->rto = (pcb->sa >> 3) + pcb->sv;
+
+ /* Update the send buffer space. Diff between the two can never exceed 64K? */
+ pcb->acked = (u16_t)(ackno - pcb->lastack);
+
+ pcb->snd_buf += pcb->acked;
+
+ /* Reset the fast retransmit variables. */
+ pcb->dupacks = 0;
+ pcb->lastack = ackno;
+
+ /* Update the congestion control variables (cwnd and
+ ssthresh). */
+ if (pcb->state >= ESTABLISHED) {
+ if (pcb->cwnd < pcb->ssthresh) {
+ if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
+ pcb->cwnd += pcb->mss;
+ }
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
+ } else {
+ u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
+ if (new_cwnd > pcb->cwnd) {
+ pcb->cwnd = new_cwnd;
+ }
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
+ }
+ }
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
+ ackno,
+ pcb->unacked != NULL?
+ ntohl(pcb->unacked->tcphdr->seqno): 0,
+ pcb->unacked != NULL?
+ ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
+
+ /* Remove segment from the unacknowledged list if the incoming
+ ACK acknowlegdes them. */
+ while (pcb->unacked != NULL &&
+ TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
+ TCP_TCPLEN(pcb->unacked), ackno)) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
+ ntohl(pcb->unacked->tcphdr->seqno),
+ ntohl(pcb->unacked->tcphdr->seqno) +
+ TCP_TCPLEN(pcb->unacked)));
+
+ next = pcb->unacked;
+ pcb->unacked = pcb->unacked->next;
+
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
+ LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+ /* Prevent ACK for FIN to generate a sent event */
+ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
+ pcb->acked--;
+ }
+
+ pcb->snd_queuelen -= pbuf_clen(next->p);
+ tcp_seg_free(next);
+
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
+ if (pcb->snd_queuelen != 0) {
+ LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
+ pcb->unsent != NULL);
+ }
+ }
+
+ /* If there's nothing left to acknowledge, stop the retransmit
+ timer, otherwise reset it to start again */
+ if(pcb->unacked == NULL)
+ pcb->rtime = -1;
+ else
+ pcb->rtime = 0;
+
+ pcb->polltmr = 0;
+ } else {
+ /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
+ pcb->acked = 0;
+ }
+
+ /* 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
+ rationale is that lwIP puts all outstanding segments on the
+ ->unsent list after a retransmission, so these segments may
+ in fact have been sent once. */
+ while (pcb->unsent != NULL &&
+ TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
+ TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
+ ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
+ TCP_TCPLEN(pcb->unsent)));
+
+ next = pcb->unsent;
+ pcb->unsent = pcb->unsent->next;
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
+ LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+ /* Prevent ACK for FIN to generate a sent event */
+ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
+ pcb->acked--;
+ }
+ pcb->snd_queuelen -= pbuf_clen(next->p);
+ tcp_seg_free(next);
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
+ if (pcb->snd_queuelen != 0) {
+ LWIP_ASSERT("tcp_receive: valid queue length",
+ pcb->unacked != NULL || pcb->unsent != NULL);
+ }
+ }
+ /* End of ACK for new data processing. */
+
+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
+ pcb->rttest, pcb->rtseq, ackno));
+
+ /* RTT estimation calculations. This is done by checking if the
+ incoming segment acknowledges the segment we use to take a
+ round-trip time measurement. */
+ if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
+ /* diff between this shouldn't exceed 32K since this are tcp timer ticks
+ and a round-trip shouldn't be that long... */
+ m = (s16_t)(tcp_ticks - pcb->rttest);
+
+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
+ m, m * TCP_SLOW_INTERVAL));
+
+ /* This is taken directly from VJs original code in his paper */
+ m = m - (pcb->sa >> 3);
+ pcb->sa += m;
+ if (m < 0) {
+ m = -m;
+ }
+ m = m - (pcb->sv >> 2);
+ pcb->sv += m;
+ pcb->rto = (pcb->sa >> 3) + pcb->sv;
+
+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
+ pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
+
+ pcb->rttest = 0;
+ }
+ }
+
+ /* If the incoming segment contains data, we must process it
+ further. */
+ if (tcplen > 0) {
+ /* This code basically does three things:
+
+ +) If the incoming segment contains data that is the next
+ in-sequence data, this data is passed to the application. This
+ might involve trimming the first edge of the data. The rcv_nxt
+ variable and the advertised window are adjusted.
+
+ +) If the incoming segment has data that is above the next
+ sequence number expected (->rcv_nxt), the segment is placed on
+ the ->ooseq queue. This is done by finding the appropriate
+ place in the ->ooseq queue (which is ordered by sequence
+ number) and trim the segment in both ends if needed. An
+ immediate ACK is sent to indicate that we received an
+ out-of-sequence segment.
+
+ +) Finally, we check if the first segment on the ->ooseq queue
+ now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
+ rcv_nxt > ooseq->seqno, we must trim the first edge of the
+ segment on ->ooseq before we adjust rcv_nxt. The data in the
+ segments that are now on sequence are chained onto the
+ incoming segment so that we only need to call the application
+ once.
+ */
+
+ /* First, we check if we must trim the first edge. We have to do
+ this if the sequence number of the incoming segment is less
+ than rcv_nxt, and the sequence number plus the length of the
+ segment is larger than rcv_nxt. */
+ /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
+ if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
+ if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
+ /* Trimming the first edge is done by pushing the payload
+ pointer in the pbuf downwards. This is somewhat tricky since
+ we do not want to discard the full contents of the pbuf up to
+ the new starting point of the data since we have to keep the
+ TCP header which is present in the first pbuf in the chain.
+
+ What is done is really quite a nasty hack: the first pbuf in
+ the pbuf chain is pointed to by inseg.p. Since we need to be
+ able to deallocate the whole pbuf, we cannot change this
+ inseg.p pointer to point to any of the later pbufs in the
+ chain. Instead, we point the ->payload pointer in the first
+ pbuf to data in one of the later pbufs. We also set the
+ inseg.data pointer to point to the right place. This way, the
+ ->p pointer will still point to the first pbuf, but the
+ ->p->payload pointer will point to data in another pbuf.
+
+ After we are done with adjusting the pbuf pointers we must
+ adjust the ->data pointer in the seg and the segment
+ length.*/
+
+ off = pcb->rcv_nxt - seqno;
+ p = inseg.p;
+ LWIP_ASSERT("inseg.p != NULL", inseg.p);
+ LWIP_ASSERT("insane offset!", (off < 0x7fff));
+ if (inseg.p->len < off) {
+ LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
+ new_tot_len = (u16_t)(inseg.p->tot_len - off);
+ while (p->len < off) {
+ off -= p->len;
+ /* KJM following line changed (with addition of new_tot_len var)
+ to fix bug #9076
+ inseg.p->tot_len -= p->len; */
+ p->tot_len = new_tot_len;
+ p->len = 0;
+ p = p->next;
+ }
+ if(pbuf_header(p, (s16_t)-off)) {
+ /* Do we need to cope with this failing? Assert for now */
+ LWIP_ASSERT("pbuf_header failed", 0);
+ }
+ } else {
+ if(pbuf_header(inseg.p, (s16_t)-off)) {
+ /* Do we need to cope with this failing? Assert for now */
+ LWIP_ASSERT("pbuf_header failed", 0);
+ }
+ }
+ inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
+ inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
+ }
+ else {
+ if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
+ /* the whole segment is < rcv_nxt */
+ /* must be a duplicate of a packet that has already been correctly handled */
+
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
+ tcp_ack_now(pcb);
+ }
+ }
+
+ /* The sequence number must be within the window (above rcv_nxt
+ and below rcv_nxt + rcv_wnd) in order to be further
+ processed. */
+ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
+ pcb->rcv_nxt + pcb->rcv_wnd - 1)){
+ if (pcb->rcv_nxt == seqno) {
+ /* The incoming segment is the next in sequence. We check if
+ we have to trim the end of the segment and update rcv_nxt
+ and pass the data to the application. */
+ tcplen = TCP_TCPLEN(&inseg);
+
+ if (tcplen > pcb->rcv_wnd) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG,
+ ("tcp_receive: other end overran receive window"
+ "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
+ seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
+ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
+ /* Must remove the FIN from the header as we're trimming
+ * that byte of sequence-space from the packet */
+ TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
+ }
+ /* Adjust length of segment to fit in the window. */
+ inseg.len = pcb->rcv_wnd;
+ if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
+ inseg.len -= 1;
+ }
+ pbuf_realloc(inseg.p, inseg.len);
+ tcplen = TCP_TCPLEN(&inseg);
+ LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
+ (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
+ }
+#if TCP_QUEUE_OOSEQ
+ /* Received in-sequence data, adjust ooseq data if:
+ - FIN has been received or
+ - inseq overlaps with ooseq */
+ if (pcb->ooseq != NULL) {
+ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG,
+ ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
+ /* Received in-order FIN means anything that was received
+ * out of order must now have been received in-order, so
+ * bin the ooseq queue */
+ while (pcb->ooseq != NULL) {
+ struct tcp_seg *old_ooseq = pcb->ooseq;
+ pcb->ooseq = pcb->ooseq->next;
+ tcp_seg_free(old_ooseq);
+ }
+ }
+ else {
+ next = pcb->ooseq;
+ /* Remove all segments on ooseq that are covered by inseg already.
+ * FIN is copied from ooseq to inseg if present. */
+ while (next &&
+ TCP_SEQ_GEQ(seqno + tcplen,
+ next->tcphdr->seqno + next->len)) {
+ /* inseg cannot have FIN here (already processed above) */
+ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
+ (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
+ TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
+ tcplen = TCP_TCPLEN(&inseg);
+ }
+ prev = next;
+ next = next->next;
+ tcp_seg_free(prev);
+ }
+ /* Now trim right side of inseg if it overlaps with the first
+ * segment on ooseq */
+ if (next &&
+ TCP_SEQ_GT(seqno + tcplen,
+ next->tcphdr->seqno)) {
+ /* inseg cannot have FIN here (already processed above) */
+ inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
+ if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
+ inseg.len -= 1;
+ }
+ pbuf_realloc(inseg.p, inseg.len);
+ tcplen = TCP_TCPLEN(&inseg);
+ LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
+ (seqno + tcplen) == next->tcphdr->seqno);
+ }
+ pcb->ooseq = next;
+ }
+ }
+#endif /* TCP_QUEUE_OOSEQ */
+
+ pcb->rcv_nxt = seqno + tcplen;
+
+ /* Update the receiver's (our) window. */
+ LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
+ pcb->rcv_wnd -= tcplen;
+
+ tcp_update_rcv_ann_wnd(pcb);
+
+ /* If there is data in the segment, we make preparations to
+ pass this up to the application. The ->recv_data variable
+ is used for holding the pbuf that goes to the
+ application. The code for reassembling out-of-sequence data
+ chains its data on this pbuf as well.
+
+ If the segment was a FIN, we set the TF_GOT_FIN flag that will
+ be used to indicate to the application that the remote side has
+ closed its end of the connection. */
+ if (inseg.p->tot_len > 0) {
+ 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. */
+ inseg.p = NULL;
+ }
+ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
+ recv_flags |= TF_GOT_FIN;
+ }
+
+#if TCP_QUEUE_OOSEQ
+ /* We now check if we have segments on the ->ooseq queue that
+ are now in sequence. */
+ while (pcb->ooseq != NULL &&
+ pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
+
+ cseg = pcb->ooseq;
+ seqno = pcb->ooseq->tcphdr->seqno;
+
+ pcb->rcv_nxt += TCP_TCPLEN(cseg);
+ LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
+ pcb->rcv_wnd >= TCP_TCPLEN(cseg));
+ pcb->rcv_wnd -= TCP_TCPLEN(cseg);
+
+ tcp_update_rcv_ann_wnd(pcb);
+
+ if (cseg->p->tot_len > 0) {
+ /* Chain this pbuf onto the pbuf that we will pass to
+ the application. */
+ if (recv_data) {
+ pbuf_cat(recv_data, cseg->p);
+ } else {
+ recv_data = cseg->p;
+ }
+ cseg->p = NULL;
+ }
+ if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
+ recv_flags |= TF_GOT_FIN;
+ if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
+ pcb->state = CLOSE_WAIT;
+ }
+ }
+
+ pcb->ooseq = cseg->next;
+ tcp_seg_free(cseg);
+ }
+#endif /* TCP_QUEUE_OOSEQ */
+
+
+ /* Acknowledge the segment(s). */
+ tcp_ack(pcb);
+
+ } else {
+ /* We get here if the incoming segment is out-of-sequence. */
+ tcp_send_empty_ack(pcb);
+#if TCP_QUEUE_OOSEQ
+ /* We queue the segment on the ->ooseq queue. */
+ if (pcb->ooseq == NULL) {
+ pcb->ooseq = tcp_seg_copy(&inseg);
+ } else {
+ /* If the queue is not empty, we walk through the queue and
+ try to find a place where the sequence number of the
+ incoming segment is between the sequence numbers of the
+ previous and the next segment on the ->ooseq queue. That is
+ the place where we put the incoming segment. If needed, we
+ trim the second edges of the previous and the incoming
+ segment so that it will fit into the sequence.
+
+ If the incoming segment has the same sequence number as a
+ segment on the ->ooseq queue, we discard the segment that
+ contains less data. */
+
+ prev = NULL;
+ for(next = pcb->ooseq; next != NULL; next = next->next) {
+ if (seqno == next->tcphdr->seqno) {
+ /* The sequence number of the incoming segment is the
+ same as the sequence number of the segment on
+ ->ooseq. We check the lengths to see which one to
+ discard. */
+ if (inseg.len > next->len) {
+ /* The incoming segment is larger than the old
+ segment. We replace some segments with the new
+ one. */
+ cseg = tcp_seg_copy(&inseg);
+ if (cseg != NULL) {
+ if (prev != NULL) {
+ prev->next = cseg;
+ } else {
+ pcb->ooseq = cseg;
+ }
+ tcp_oos_insert_segment(cseg, next);
+ }
+ break;
+ } else {
+ /* Either the lenghts are the same or the incoming
+ segment was smaller than the old one; in either
+ case, we ditch the incoming segment. */
+ break;
+ }
+ } else {
+ if (prev == NULL) {
+ if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
+ /* The sequence number of the incoming segment is lower
+ than the sequence number of the first segment on the
+ queue. We put the incoming segment first on the
+ queue. */
+ cseg = tcp_seg_copy(&inseg);
+ if (cseg != NULL) {
+ pcb->ooseq = cseg;
+ tcp_oos_insert_segment(cseg, next);
+ }
+ break;
+ }
+ } else {
+ /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
+ TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
+ if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
+ /* The sequence number of the incoming segment is in
+ between the sequence numbers of the previous and
+ the next segment on ->ooseq. We trim trim the previous
+ segment, delete next segments that included in received segment
+ and trim received, if needed. */
+ cseg = tcp_seg_copy(&inseg);
+ if (cseg != NULL) {
+ if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
+ /* We need to trim the prev segment. */
+ prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
+ pbuf_realloc(prev->p, prev->len);
+ }
+ prev->next = cseg;
+ tcp_oos_insert_segment(cseg, next);
+ }
+ break;
+ }
+ }
+ /* If the "next" segment is the last segment on the
+ ooseq queue, we add the incoming segment to the end
+ of the list. */
+ if (next->next == NULL &&
+ TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
+ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
+ /* segment "next" already contains all data */
+ break;
+ }
+ next->next = tcp_seg_copy(&inseg);
+ if (next->next != NULL) {
+ if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
+ /* We need to trim the last segment. */
+ next->len = (u16_t)(seqno - next->tcphdr->seqno);
+ pbuf_realloc(next->p, next->len);
+ }
+ /* check if the remote side overruns our receive window */
+ if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
+ LWIP_DEBUGF(TCP_INPUT_DEBUG,
+ ("tcp_receive: other end overran receive window"
+ "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
+ seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
+ if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
+ /* Must remove the FIN from the header as we're trimming
+ * that byte of sequence-space from the packet */
+ TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
+ }
+ /* Adjust length of segment to fit in the window. */
+ next->next->len = 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",
+ (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
+ }
+ }
+ break;
+ }
+ }
+ prev = next;
+ }
+ }
+#endif /* TCP_QUEUE_OOSEQ */
+
+ }
+ } else {
+ /* The incoming segment is not withing the window. */
+ tcp_send_empty_ack(pcb);
+ }
+ } else {
+ /* Segments with length 0 is taken care of here. Segments that
+ fall out of the window are ACKed. */
+ /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
+ TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
+ if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
+ tcp_ack_now(pcb);
+ }
+ }
+}
+
+/**
+ * Parses the options contained in the incoming segment.
+ *
+ * Called from tcp_listen_input() and tcp_process().
+ * Currently, only the MSS option is supported!
+ *
+ * @param pcb the tcp_pcb for which a segment arrived
+ */
+static void
+tcp_parseopt(struct tcp_pcb *pcb)
+{
+ u16_t c, max_c;
+ u16_t mss;
+ u8_t *opts, opt;
+#if LWIP_TCP_TIMESTAMPS
+ u32_t tsval;
+#endif
+
+ opts = (u8_t *)tcphdr + TCP_HLEN;
+
+ /* Parse the TCP MSS option, if present. */
+ if(TCPH_HDRLEN(tcphdr) > 0x5) {
+ max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
+ for (c = 0; c < max_c; ) {
+ opt = opts[c];
+ switch (opt) {
+ case 0x00:
+ /* End of options. */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
+ return;
+ case 0x01:
+ /* NOP option. */
+ ++c;
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
+ break;
+ case 0x02:
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
+ if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
+ /* Bad length */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
+ return;
+ }
+ /* An MSS option with the right option length. */
+ mss = (opts[c + 2] << 8) | opts[c + 3];
+ /* Limit the mss to the configured TCP_MSS and prevent division by zero */
+ pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
+ /* Advance to next option */
+ c += 0x04;
+ break;
+#if LWIP_TCP_TIMESTAMPS
+ case 0x08:
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
+ if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
+ /* Bad length */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
+ return;
+ }
+ /* TCP timestamp option with valid length */
+ tsval = (opts[c+2]) | (opts[c+3] << 8) |
+ (opts[c+4] << 16) | (opts[c+5] << 24);
+ if (flags & TCP_SYN) {
+ pcb->ts_recent = ntohl(tsval);
+ pcb->flags |= TF_TIMESTAMP;
+ } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
+ pcb->ts_recent = ntohl(tsval);
+ }
+ /* Advance to next option */
+ c += 0x0A;
+ break;
+#endif
+ default:
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
+ if (opts[c + 1] == 0) {
+ 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;
+ }
+ /* All other options have a length field, so that we easily
+ can skip past them. */
+ c += opts[c + 1];
+ }
+ }
+ }
+}
+
+#endif /* LWIP_TCP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_out.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_out.c
new file mode 100644
index 0000000000..0cc48b1cdb
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/tcp_out.c
@@ -0,0 +1,1471 @@
+/**
+ * @file
+ * Transmission Control Protocol, outgoing traffic
+ *
+ * The output functions of TCP.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/tcp_impl.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/sys.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+
+#include <string.h>
+
+/* Define some copy-macros for checksum-on-copy so that the code looks
+ nicer by preventing too many ifdef's. */
+#if TCP_CHECKSUM_ON_COPY
+#define TCP_DATA_COPY(dst, src, len, seg) do { \
+ tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
+ len, &seg->chksum, &seg->chksum_swapped); \
+ seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
+#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \
+ tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
+#else /* TCP_CHECKSUM_ON_COPY*/
+#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len)
+#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
+#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) */
+#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
+#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
+#endif
+
+/* Forward declarations.*/
+static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
+
+/** Allocate a pbuf and create a tcphdr at p->payload, used for output
+ * functions other than the default tcp_output -> tcp_output_segment
+ * (e.g. tcp_send_empty_ack, etc.)
+ *
+ * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)
+ * @param optlen length of header-options
+ * @param datalen length of tcp data to reserve in pbuf
+ * @param seqno_be seqno in network byte order (big-endian)
+ * @return pbuf with p->payload being the tcp_hdr
+ */
+static struct pbuf *
+tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
+ u32_t seqno_be /* already in network byte order */)
+{
+ struct tcp_hdr *tcphdr;
+ struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
+ if (p != NULL) {
+ LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
+ (p->len >= TCP_HLEN + optlen));
+ tcphdr = (struct tcp_hdr *)p->payload;
+ tcphdr->src = htons(pcb->local_port);
+ tcphdr->dest = htons(pcb->remote_port);
+ tcphdr->seqno = seqno_be;
+ tcphdr->ackno = htonl(pcb->rcv_nxt);
+ TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
+ tcphdr->wnd = htons(pcb->rcv_ann_wnd);
+ tcphdr->chksum = 0;
+ tcphdr->urgp = 0;
+
+ /* If we're sending a packet, update the announced right window edge */
+ pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
+ }
+ return p;
+}
+
+/**
+ * Called by tcp_close() to send a segment including FIN flag but not data.
+ *
+ * @param pcb the tcp_pcb over which to send a segment
+ * @return ERR_OK if sent, another err_t otherwise
+ */
+err_t
+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);
+
+ 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 */
+ TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
+ return ERR_OK;
+ }
+ }
+ /* no data, no length, flags, copy=1, no optdata */
+ return tcp_enqueue_flags(pcb, TCP_FIN);
+}
+
+/**
+ * Create a TCP segment with prefilled header.
+ *
+ * Called by tcp_write and tcp_enqueue_flags.
+ *
+ * @param pcb Protocol control block for the TCP connection.
+ * @param p pbuf that is used to hold the TCP header.
+ * @param flags TCP flags for header.
+ * @param seqno TCP sequence number of this packet
+ * @param optflags options to include in TCP header
+ * @return a new tcp_seg pointing to p, or NULL.
+ * The TCP header is filled in except ackno and wnd.
+ * p is freed on failure.
+ */
+static struct tcp_seg *
+tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)
+{
+ struct tcp_seg *seg;
+ u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
+
+ if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
+ pbuf_free(p);
+ return NULL;
+ }
+ seg->flags = optflags;
+ seg->next = NULL;
+ seg->p = p;
+ seg->len = p->tot_len - optlen;
+#if TCP_OVERSIZE_DBGCHECK
+ seg->oversize_left = 0;
+#endif /* TCP_OVERSIZE_DBGCHECK */
+#if TCP_CHECKSUM_ON_COPY
+ seg->chksum = 0;
+ seg->chksum_swapped = 0;
+ /* check optflags */
+ LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
+ (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
+#endif /* TCP_CHECKSUM_ON_COPY */
+
+ /* build TCP header */
+ if (pbuf_header(p, TCP_HLEN)) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
+ TCP_STATS_INC(tcp.err);
+ tcp_seg_free(seg);
+ return NULL;
+ }
+ seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
+ seg->tcphdr->src = htons(pcb->local_port);
+ seg->tcphdr->dest = htons(pcb->remote_port);
+ seg->tcphdr->seqno = htonl(seqno);
+ /* ackno is set in tcp_output */
+ TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
+ /* wnd and chksum are set in tcp_output */
+ seg->tcphdr->urgp = 0;
+ return seg;
+}
+
+/**
+ * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
+ *
+ * This function is like pbuf_alloc(layer, length, PBUF_RAM) except
+ * there may be extra bytes available at the end.
+ *
+ * @param layer flag to define header size.
+ * @param length size of the pbuf's payload.
+ * @param max_length maximum usable size of payload+oversize.
+ * @param oversize pointer to a u16_t that will receive the number of usable tail bytes.
+ * @param pcb The TCP connection that willo enqueue the pbuf.
+ * @param apiflags API flags given to tcp_write.
+ * @param first_seg true when this pbuf will be used in the first enqueued segment.
+ * @param
+ */
+#if TCP_OVERSIZE
+static struct pbuf *
+tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
+ u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,
+ u8_t first_seg)
+{
+ struct pbuf *p;
+ u16_t alloc = length;
+
+#if LWIP_NETIF_TX_SINGLE_PBUF
+ LWIP_UNUSED_ARG(max_length);
+ LWIP_UNUSED_ARG(pcb);
+ LWIP_UNUSED_ARG(apiflags);
+ LWIP_UNUSED_ARG(first_seg);
+ /* always create MSS-sized pbufs */
+ alloc = TCP_MSS;
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+ if (length < max_length) {
+ /* Should we allocate an oversized pbuf, or just the minimum
+ * length required? If tcp_write is going to be called again
+ * before this segment is transmitted, we want the oversized
+ * buffer. If the segment will be transmitted immediately, we can
+ * save memory by allocating only length. We use a simple
+ * heuristic based on the following information:
+ *
+ * Did the user set TCP_WRITE_FLAG_MORE?
+ *
+ * Will the Nagle algorithm defer transmission of this segment?
+ */
+ if ((apiflags & TCP_WRITE_FLAG_MORE) ||
+ (!(pcb->flags & TF_NODELAY) &&
+ (!first_seg ||
+ pcb->unsent != NULL ||
+ pcb->unacked != NULL))) {
+ alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
+ }
+ }
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+ p = pbuf_alloc(layer, alloc, PBUF_RAM);
+ if (p == NULL) {
+ return NULL;
+ }
+ LWIP_ASSERT("need unchained pbuf", p->next == NULL);
+ *oversize = p->len - length;
+ /* trim p->len to the currently used size */
+ p->len = p->tot_len = length;
+ return p;
+}
+#else /* TCP_OVERSIZE */
+#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
+#endif /* TCP_OVERSIZE */
+
+#if TCP_CHECKSUM_ON_COPY
+/** Add a checksum of newly added data to the segment */
+static void
+tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
+ u8_t *seg_chksum_swapped)
+{
+ u32_t helper;
+ /* add chksum to old chksum and fold to u16_t */
+ helper = chksum + *seg_chksum;
+ chksum = FOLD_U32T(helper);
+ if ((len & 1) != 0) {
+ *seg_chksum_swapped = 1 - *seg_chksum_swapped;
+ chksum = SWAP_BYTES_IN_WORD(chksum);
+ }
+ *seg_chksum = chksum;
+}
+#endif /* TCP_CHECKSUM_ON_COPY */
+
+/** 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)
+ * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise
+ */
+static err_t
+tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
+{
+ /* connection is in invalid state for data transmission? */
+ if ((pcb->state != ESTABLISHED) &&
+ (pcb->state != CLOSE_WAIT) &&
+ (pcb->state != SYN_SENT) &&
+ (pcb->state != SYN_RCVD)) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
+ return ERR_CONN;
+ } else if (len == 0) {
+ return ERR_OK;
+ }
+
+ /* fail on too much data */
+ if (len > pcb->snd_buf) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
+ len, pcb->snd_buf));
+ pcb->flags |= TF_NAGLEMEMERR;
+ return ERR_MEM;
+ }
+
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
+
+ /* If total number of pbufs on the unsent/unacked queues exceeds the
+ * configured maximum, return an error */
+ /* check for configured max queuelen and possible overflow */
+ if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
+ pcb->snd_queuelen, TCP_SND_QUEUELEN));
+ TCP_STATS_INC(tcp.memerr);
+ pcb->flags |= TF_NAGLEMEMERR;
+ return ERR_MEM;
+ }
+ if (pcb->snd_queuelen != 0) {
+ LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
+ pcb->unacked != NULL || pcb->unsent != NULL);
+ } else {
+ LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
+ pcb->unacked == NULL && pcb->unsent == NULL);
+ }
+ return ERR_OK;
+}
+
+/**
+ * Write data for sending (but does not send it immediately).
+ *
+ * It waits in the expectation of more data being sent soon (as
+ * 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().
+ *
+ * @param pcb Protocol control block for the TCP connection to enqueue data for.
+ * @param arg Pointer to the data to be enqueued for sending.
+ * @param len Data length in bytes
+ * @param apiflags combination of following flags :
+ * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
+ * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
+ * @return ERR_OK if enqueued, another err_t on error
+ */
+err_t
+tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
+{
+ struct pbuf *concat_p = NULL;
+ 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 = 0;
+ u8_t optflags = 0;
+#if TCP_OVERSIZE
+ u16_t oversize = 0;
+ u16_t oversize_used = 0;
+#endif /* TCP_OVERSIZE */
+#if TCP_CHECKSUM_ON_COPY
+ u16_t concat_chksum = 0;
+ u8_t concat_chksum_swapped = 0;
+ u16_t concat_chksummed = 0;
+#endif /* TCP_CHECKSUM_ON_COPY */
+ err_t err;
+
+#if LWIP_NETIF_TX_SINGLE_PBUF
+ /* Always copy to try to create single pbufs for TX */
+ apiflags |= TCP_WRITE_FLAG_COPY;
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
+ (void *)pcb, arg, len, (u16_t)apiflags));
+ LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)",
+ arg != NULL, return ERR_ARG;);
+
+ err = tcp_write_checks(pcb, len);
+ if (err != ERR_OK) {
+ return err;
+ }
+ queuelen = pcb->snd_queuelen;
+
+#if LWIP_TCP_TIMESTAMPS
+ if ((pcb->flags & TF_TIMESTAMP)) {
+ optflags = TF_SEG_OPTS_TS;
+ optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
+ }
+#endif /* LWIP_TCP_TIMESTAMPS */
+
+
+ /*
+ * TCP segmentation is done in three phases with increasing complexity:
+ *
+ * 1. Copy data directly into an oversized pbuf.
+ * 2. Chain a new pbuf to the end of pcb->unsent.
+ * 3. Create new segments.
+ *
+ * We may run out of memory at any point. In that case we must
+ * return ERR_MEM and not change anything in pcb. Therefore, all
+ * changes are recorded in local variables and committed at the end
+ * of the function. Some pcb fields are maintained in local copies:
+ *
+ * queuelen = pcb->snd_queuelen
+ * oversize = pcb->unsent_oversize
+ *
+ * These variables are set consistently by the phases:
+ *
+ * seg points to the last segment tampered with.
+ *
+ * pos records progress as data is segmented.
+ */
+
+ /* Find the tail of the unsent queue. */
+ if (pcb->unsent != NULL) {
+ u16_t space;
+ u16_t unsent_optlen;
+
+ /* @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);
+
+ /* Usable space at the end of the last unsent segment */
+ unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
+ space = pcb->mss - (last_unsent->len + unsent_optlen);
+
+ /*
+ * Phase 1: Copy data directly into an oversized pbuf.
+ *
+ * The number of bytes copied is recorded in the oversize_used
+ * variable. The actual copying is done at the bottom of the
+ * function.
+ */
+#if TCP_OVERSIZE
+#if TCP_OVERSIZE_DBGCHECK
+ /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
+ LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
+ pcb->unsent_oversize == last_unsent->oversize_left);
+#endif /* TCP_OVERSIZE_DBGCHECK */
+ oversize = pcb->unsent_oversize;
+ if (oversize > 0) {
+ LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
+ seg = last_unsent;
+ oversize_used = oversize < len ? oversize : len;
+ pos += oversize_used;
+ oversize -= oversize_used;
+ space -= oversize_used;
+ }
+ /* now we are either finished or oversize is zero */
+ LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
+#endif /* TCP_OVERSIZE */
+
+ /*
+ * Phase 2: Chain a new pbuf to the end of pcb->unsent.
+ *
+ * We don't extend segments containing SYN/FIN flags or options
+ * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
+ * the end.
+ */
+ if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
+ u16_t seglen = space < len - pos ? space : len - pos;
+ seg = last_unsent;
+
+ /* Create a pbuf with a copy or reference to seglen bytes. We
+ * can use PBUF_RAW here since the data appears in the middle of
+ * a segment. A header will never be prepended. */
+ if (apiflags & TCP_WRITE_FLAG_COPY) {
+ /* Data is copied */
+ if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
+ ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
+ seglen));
+ goto memerr;
+ }
+#if TCP_OVERSIZE_DBGCHECK
+ last_unsent->oversize_left = oversize;
+#endif /* TCP_OVERSIZE_DBGCHECK */
+ TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
+#if TCP_CHECKSUM_ON_COPY
+ concat_chksummed += seglen;
+#endif /* TCP_CHECKSUM_ON_COPY */
+ } else {
+ /* Data is not copied */
+ if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
+ ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
+ goto memerr;
+ }
+#if TCP_CHECKSUM_ON_COPY
+ /* calculate the checksum of nocopy-data */
+ tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
+ &concat_chksum, &concat_chksum_swapped);
+ concat_chksummed += seglen;
+#endif /* TCP_CHECKSUM_ON_COPY */
+ /* reference the non-volatile payload data */
+ concat_p->payload = (u8_t*)arg + pos;
+ }
+
+ pos += seglen;
+ queuelen += pbuf_clen(concat_p);
+ }
+ } else {
+#if TCP_OVERSIZE
+ LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
+ pcb->unsent_oversize == 0);
+#endif /* TCP_OVERSIZE */
+ }
+
+ /*
+ * Phase 3: Create new segments.
+ *
+ * The new segments are chained together in the local 'queue'
+ * variable, ready to be appended to pcb->unsent.
+ */
+ while (pos < len) {
+ struct pbuf *p;
+ u16_t left = len - pos;
+ u16_t max_len = pcb->mss - optlen;
+ u16_t seglen = left > max_len ? max_len : left;
+#if TCP_CHECKSUM_ON_COPY
+ u16_t chksum = 0;
+ u8_t chksum_swapped = 0;
+#endif /* TCP_CHECKSUM_ON_COPY */
+
+ if (apiflags & TCP_WRITE_FLAG_COPY) {
+ /* If copy is set, memory should be allocated and data copied
+ * into pbuf */
+ if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
+ goto memerr;
+ }
+ LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
+ (p->len >= seglen));
+ TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
+ } else {
+ /* Copy is not set: First allocate a pbuf for holding the data.
+ * Since the referenced data is available at least until it is
+ * sent out on the link (as it has to be ACKed by the remote
+ * party) we can safely use PBUF_ROM instead of PBUF_REF here.
+ */
+ struct pbuf *p2;
+#if TCP_OVERSIZE
+ LWIP_ASSERT("oversize == 0", oversize == 0);
+#endif /* TCP_OVERSIZE */
+ if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
+ goto memerr;
+ }
+#if TCP_CHECKSUM_ON_COPY
+ /* calculate the checksum of nocopy-data */
+ chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
+#endif /* TCP_CHECKSUM_ON_COPY */
+ /* reference the non-volatile payload data */
+ p2->payload = (u8_t*)arg + pos;
+
+ /* Second, allocate a pbuf for the headers. */
+ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
+ /* If allocation fails, we have to deallocate the data pbuf as
+ * well. */
+ pbuf_free(p2);
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
+ goto memerr;
+ }
+ /* Concatenate the headers and data pbufs together. */
+ pbuf_cat(p/*header*/, p2/*data*/);
+ }
+
+ 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 > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
+ pbuf_free(p);
+ goto memerr;
+ }
+
+ if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
+ goto memerr;
+ }
+#if TCP_OVERSIZE_DBGCHECK
+ seg->oversize_left = oversize;
+#endif /* TCP_OVERSIZE_DBGCHECK */
+#if TCP_CHECKSUM_ON_COPY
+ seg->chksum = chksum;
+ seg->chksum_swapped = chksum_swapped;
+ seg->flags |= TF_SEG_DATA_CHECKSUMMED;
+#endif /* TCP_CHECKSUM_ON_COPY */
+
+ /* 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",
+ ntohl(seg->tcphdr->seqno),
+ ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
+
+ pos += seglen;
+ }
+
+ /*
+ * All three segmentation phases were successful. We can commit the
+ * transaction.
+ */
+
+ /*
+ * Phase 1: If data has been added to the preallocated tail of
+ * last_unsent, we update the length fields of the pbuf chain.
+ */
+#if TCP_OVERSIZE
+ if (oversize_used > 0) {
+ struct pbuf *p;
+ /* Bump tot_len of whole chain, len of tail */
+ for (p = last_unsent->p; p; p = p->next) {
+ p->tot_len += oversize_used;
+ if (p->next == NULL) {
+ TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
+ p->len += oversize_used;
+ }
+ }
+ last_unsent->len += oversize_used;
+#if TCP_OVERSIZE_DBGCHECK
+ last_unsent->oversize_left -= oversize_used;
+#endif /* TCP_OVERSIZE_DBGCHECK */
+ }
+ pcb->unsent_oversize = oversize;
+#endif /* TCP_OVERSIZE */
+
+ /*
+ * Phase 2: concat_p can be concatenated onto last_unsent->p
+ */
+ if (concat_p != NULL) {
+ LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
+ (last_unsent != NULL));
+ pbuf_cat(last_unsent->p, concat_p);
+ last_unsent->len += concat_p->tot_len;
+#if TCP_CHECKSUM_ON_COPY
+ if (concat_chksummed) {
+ if (concat_chksum_swapped) {
+ concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
+ }
+ tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
+ &last_unsent->chksum_swapped);
+ last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
+ }
+#endif /* TCP_CHECKSUM_ON_COPY */
+ }
+
+ /*
+ * 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.
+ */
+ pcb->snd_lbb += len;
+ pcb->snd_buf -= len;
+ 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:
+ pcb->flags |= TF_NAGLEMEMERR;
+ TCP_STATS_INC(tcp.memerr);
+
+ if (concat_p != NULL) {
+ pbuf_free(concat_p);
+ }
+ if (queue != NULL) {
+ tcp_segs_free(queue);
+ }
+ 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;
+}
+
+/**
+ * Enqueue TCP options for transmission.
+ *
+ * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
+ *
+ * @param pcb Protocol control block for the TCP connection.
+ * @param flags TCP header flags to set in the outgoing segment.
+ * @param optdata pointer to TCP options, or NULL.
+ * @param optlen length of TCP options in bytes.
+ */
+err_t
+tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
+{
+ struct pbuf *p;
+ struct tcp_seg *seg;
+ 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);
+
+ /* check for configured max queuelen and possible overflow */
+ if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
+ pcb->snd_queuelen, TCP_SND_QUEUELEN));
+ TCP_STATS_INC(tcp.memerr);
+ pcb->flags |= TF_NAGLEMEMERR;
+ return ERR_MEM;
+ }
+
+ if (flags & TCP_SYN) {
+ optflags = TF_SEG_OPTS_MSS;
+ }
+#if LWIP_TCP_TIMESTAMPS
+ if ((pcb->flags & TF_TIMESTAMP)) {
+ optflags |= TF_SEG_OPTS_TS;
+ }
+#endif /* LWIP_TCP_TIMESTAMPS */
+ optlen = LWIP_TCP_OPT_LENGTH(optflags);
+
+ /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
+ * We need one available snd_buf byte to do that.
+ * This means we can't send FIN while snd_buf==0. A better fix would be to
+ * not include SYN and FIN sequence numbers in the snd_buf count. */
+ if (pcb->snd_buf == 0) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
+ TCP_STATS_INC(tcp.memerr);
+ return ERR_MEM;
+ }
+
+ /* Allocate pbuf with room for TCP header + options */
+ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
+ pcb->flags |= TF_NAGLEMEMERR;
+ TCP_STATS_INC(tcp.memerr);
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
+ (p->len >= optlen));
+
+ /* Allocate memory for tcp_seg, and fill in fields. */
+ if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
+ pcb->flags |= TF_NAGLEMEMERR;
+ TCP_STATS_INC(tcp.memerr);
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
+ LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
+
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
+ ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
+ ntohl(seg->tcphdr->seqno),
+ ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
+ (u16_t)flags));
+
+ /* Now append seg to pcb->unsent queue */
+ if (pcb->unsent == NULL) {
+ pcb->unsent = seg;
+ } else {
+ struct tcp_seg *useg;
+ for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
+ useg->next = seg;
+ }
+#if TCP_OVERSIZE
+ /* The new unsent tail has no space */
+ pcb->unsent_oversize = 0;
+#endif /* TCP_OVERSIZE */
+
+ /* SYN and FIN bump the sequence number */
+ if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
+ pcb->snd_lbb++;
+ /* optlen does not influence snd_buf */
+ pcb->snd_buf--;
+ }
+ if (flags & TCP_FIN) {
+ pcb->flags |= TF_FIN;
+ }
+
+ /* update number of segments on the queues */
+ pcb->snd_queuelen += pbuf_clen(seg->p);
+ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
+ if (pcb->snd_queuelen != 0) {
+ LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
+ pcb->unacked != NULL || pcb->unsent != NULL);
+ }
+
+ return ERR_OK;
+}
+
+
+#if LWIP_TCP_TIMESTAMPS
+/* Build a timestamp option (12 bytes long) at the specified options pointer)
+ *
+ * @param pcb tcp_pcb
+ * @param opts option pointer where to store the timestamp option
+ */
+static void
+tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
+{
+ /* Pad with two NOP options to make everything nicely aligned */
+ opts[0] = PP_HTONL(0x0101080A);
+ opts[1] = htonl(sys_now());
+ opts[2] = htonl(pcb->ts_recent);
+}
+#endif
+
+/** Send an ACK without data.
+ *
+ * @param pcb Protocol control block for the TCP connection to send the ACK
+ */
+err_t
+tcp_send_empty_ack(struct tcp_pcb *pcb)
+{
+ struct pbuf *p;
+ struct tcp_hdr *tcphdr;
+ u8_t optlen = 0;
+
+#if LWIP_TCP_TIMESTAMPS
+ if (pcb->flags & TF_TIMESTAMP) {
+ optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
+ }
+#endif
+
+ p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
+ if (p == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
+ return ERR_BUF;
+ }
+ tcphdr = (struct tcp_hdr *)p->payload;
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
+ ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
+ /* remove ACK flags from the PCB, as we send an empty ACK now */
+ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
+
+ /* NB. MSS option is only sent on SYNs, so ignore it here */
+#if LWIP_TCP_TIMESTAMPS
+ pcb->ts_lastacksent = pcb->rcv_nxt;
+
+ if (pcb->flags & TF_TIMESTAMP) {
+ tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
+ }
+#endif
+
+#if CHECKSUM_GEN_TCP
+ tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
+ IP_PROTO_TCP, p->tot_len);
+#endif
+#if LWIP_NETIF_HWADDRHINT
+ ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+ IP_PROTO_TCP, &(pcb->addr_hint));
+#else /* LWIP_NETIF_HWADDRHINT*/
+ ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+ IP_PROTO_TCP);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ pbuf_free(p);
+
+ return ERR_OK;
+}
+
+/**
+ * Find out what we can send and send it
+ *
+ * @param pcb Protocol control block for the TCP connection to send data
+ * @return ERR_OK if data has been sent or nothing to send
+ * another err_t on error
+ */
+err_t
+tcp_output(struct tcp_pcb *pcb)
+{
+ struct tcp_seg *seg, *useg;
+ u32_t wnd, snd_nxt;
+#if TCP_CWND_DEBUG
+ s16_t i = 0;
+#endif /* TCP_CWND_DEBUG */
+
+ /* First, check if we are invoked by the TCP input processing
+ code. If so, we do not output anything. Instead, we rely on the
+ input processing code to call us when input processing is done
+ with. */
+ if (tcp_input_pcb == pcb) {
+ return ERR_OK;
+ }
+
+ wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
+
+ seg = pcb->unsent;
+
+ /* If the TF_ACK_NOW flag is set and no data will be sent (either
+ * because the ->unsent queue is empty or because the window does
+ * not allow it), construct an empty ACK segment and send it.
+ *
+ * If data is to be sent, we will just piggyback the ACK (see below).
+ */
+ if (pcb->flags & TF_ACK_NOW &&
+ (seg == NULL ||
+ ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
+ return tcp_send_empty_ack(pcb);
+ }
+
+ /* useg should point to last segment on unacked queue */
+ useg = pcb->unacked;
+ if (useg != NULL) {
+ for (; useg->next != NULL; useg = useg->next);
+ }
+
+#if TCP_OUTPUT_DEBUG
+ if (seg == NULL) {
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
+ (void*)pcb->unsent));
+ }
+#endif /* TCP_OUTPUT_DEBUG */
+#if TCP_CWND_DEBUG
+ if (seg == NULL) {
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
+ ", cwnd %"U16_F", wnd %"U32_F
+ ", seg == NULL, ack %"U32_F"\n",
+ pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
+ } else {
+ LWIP_DEBUGF(TCP_CWND_DEBUG,
+ ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
+ ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
+ pcb->snd_wnd, pcb->cwnd, wnd,
+ ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
+ ntohl(seg->tcphdr->seqno), pcb->lastack));
+ }
+#endif /* TCP_CWND_DEBUG */
+ /* data available and window allows it to be sent? */
+ while (seg != NULL &&
+ ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
+ LWIP_ASSERT("RST not expected here!",
+ (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
+ /* Stop sending if the nagle algorithm would prevent it
+ * Don't stop:
+ * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
+ * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
+ * either seg->next != NULL or pcb->unacked == NULL;
+ * RST is no sent using tcp_write/tcp_output.
+ */
+ if((tcp_do_output_nagle(pcb) == 0) &&
+ ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
+ break;
+ }
+#if TCP_CWND_DEBUG
+ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
+ pcb->snd_wnd, pcb->cwnd, wnd,
+ ntohl(seg->tcphdr->seqno) + seg->len -
+ pcb->lastack,
+ ntohl(seg->tcphdr->seqno), pcb->lastack, i));
+ ++i;
+#endif /* TCP_CWND_DEBUG */
+
+ pcb->unsent = seg->next;
+
+ if (pcb->state != SYN_SENT) {
+ TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
+ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
+ }
+
+ tcp_output_segment(seg, pcb);
+ snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
+ if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
+ pcb->snd_nxt = snd_nxt;
+ }
+ /* put segment on unacknowledged list if length > 0 */
+ if (TCP_TCPLEN(seg) > 0) {
+ seg->next = NULL;
+ /* unacked list is empty? */
+ if (pcb->unacked == NULL) {
+ pcb->unacked = seg;
+ useg = seg;
+ /* unacked list is not empty? */
+ } else {
+ /* In the case of fast retransmit, the packet should not go to the tail
+ * of the unacked queue, but rather somewhere before it. We need to check for
+ * this case. -STJ Jul 27, 2004 */
+ if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), 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(ntohl((*cur_seg)->tcphdr->seqno), 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 = useg->next;
+ }
+ }
+ /* do not queue empty segments on the unacked list */
+ } else {
+ tcp_seg_free(seg);
+ }
+ seg = pcb->unsent;
+ }
+#if TCP_OVERSIZE
+ if (pcb->unsent == NULL) {
+ /* last unsent has been removed, reset unsent_oversize */
+ pcb->unsent_oversize = 0;
+ }
+#endif /* TCP_OVERSIZE */
+
+ if (seg != NULL && pcb->persist_backoff == 0 &&
+ ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
+ /* prepare for persist timer */
+ pcb->persist_cnt = 0;
+ pcb->persist_backoff = 1;
+ }
+
+ pcb->flags &= ~TF_NAGLEMEMERR;
+ return ERR_OK;
+}
+
+/**
+ * Called by tcp_output() to actually send a TCP segment over IP.
+ *
+ * @param seg the tcp_seg to send
+ * @param pcb the tcp_pcb for the TCP connection used to send the segment
+ */
+static void
+tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
+{
+ u16_t len;
+ struct netif *netif;
+ u32_t *opts;
+
+ /** @bug Exclude retransmitted segments from this count. */
+ snmp_inc_tcpoutsegs();
+
+ /* The TCP header has already been constructed, but the ackno and
+ wnd fields remain. */
+ seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
+
+ /* advertise our receive window size in this TCP segment */
+ seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
+
+ pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
+
+ /* Add any requested options. NB MSS option is only set on SYN
+ packets, so ignore it here */
+ LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
+ opts = (u32_t *)(void *)(seg->tcphdr + 1);
+ if (seg->flags & TF_SEG_OPTS_MSS) {
+ TCP_BUILD_MSS_OPTION(*opts);
+ opts += 1;
+ }
+#if LWIP_TCP_TIMESTAMPS
+ pcb->ts_lastacksent = pcb->rcv_nxt;
+
+ if (seg->flags & TF_SEG_OPTS_TS) {
+ tcp_build_timestamp_option(pcb, opts);
+ opts += 3;
+ }
+#endif
+
+ /* Set retransmission timer running if it is not currently enabled
+ This must be set before checking the route. */
+ if (pcb->rtime == -1) {
+ pcb->rtime = 0;
+ }
+
+ /* If we don't have a local IP address, we get one by
+ calling ip_route(). */
+ if (ip_addr_isany(&(pcb->local_ip))) {
+ netif = ip_route(&(pcb->remote_ip));
+ if (netif == NULL) {
+ return;
+ }
+ ip_addr_copy(pcb->local_ip, netif->ip_addr);
+ }
+
+ if (pcb->rttest == 0) {
+ pcb->rttest = tcp_ticks;
+ pcb->rtseq = ntohl(seg->tcphdr->seqno);
+
+ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
+ }
+ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
+ htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
+ seg->len));
+
+ len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
+
+ seg->p->len -= len;
+ seg->p->tot_len -= len;
+
+ seg->p->payload = seg->tcphdr;
+
+ seg->tcphdr->chksum = 0;
+#if CHECKSUM_GEN_TCP
+#if TCP_CHECKSUM_ON_COPY
+ {
+ u32_t acc;
+#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
+ u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
+ &(pcb->remote_ip),
+ IP_PROTO_TCP, seg->p->tot_len);
+#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(seg->tcphdr) * 4));
+ }
+
+ /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
+ acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
+ &(pcb->remote_ip),
+ IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
+ /* add payload checksum */
+ if (seg->chksum_swapped) {
+ seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
+ seg->chksum_swapped = 0;
+ }
+ acc += (u16_t)~(seg->chksum);
+ seg->tcphdr->chksum = FOLD_U32T(acc);
+#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
+ if (chksum_slow != seg->tcphdr->chksum) {
+ LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
+ ("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 = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
+ &(pcb->remote_ip),
+ IP_PROTO_TCP, seg->p->tot_len);
+#endif /* TCP_CHECKSUM_ON_COPY */
+#endif /* CHECKSUM_GEN_TCP */
+ TCP_STATS_INC(tcp.xmit);
+
+#if LWIP_NETIF_HWADDRHINT
+ ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+ IP_PROTO_TCP, &(pcb->addr_hint));
+#else /* LWIP_NETIF_HWADDRHINT*/
+ ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
+ IP_PROTO_TCP);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+}
+
+/**
+ * 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 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(u32_t seqno, u32_t ackno,
+ ip_addr_t *local_ip, ip_addr_t *remote_ip,
+ u16_t local_port, u16_t remote_port)
+{
+ struct pbuf *p;
+ struct tcp_hdr *tcphdr;
+ p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
+ if (p == NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
+ return;
+ }
+ LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
+ (p->len >= sizeof(struct tcp_hdr)));
+
+ tcphdr = (struct tcp_hdr *)p->payload;
+ tcphdr->src = htons(local_port);
+ tcphdr->dest = htons(remote_port);
+ tcphdr->seqno = htonl(seqno);
+ tcphdr->ackno = htonl(ackno);
+ TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
+ tcphdr->wnd = PP_HTONS(TCP_WND);
+ tcphdr->chksum = 0;
+ tcphdr->urgp = 0;
+
+#if CHECKSUM_GEN_TCP
+ tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
+ IP_PROTO_TCP, p->tot_len);
+#endif
+ TCP_STATS_INC(tcp.xmit);
+ snmp_inc_tcpoutrsts();
+ /* Send output with hardcoded TTL since we have no access to the pcb */
+ ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
+ pbuf_free(p);
+ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
+}
+
+/**
+ * Requeue all unacked segments for retransmission
+ *
+ * Called by tcp_slowtmr() for slow retransmission.
+ *
+ * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
+ */
+void
+tcp_rexmit_rto(struct tcp_pcb *pcb)
+{
+ struct tcp_seg *seg;
+
+ if (pcb->unacked == NULL) {
+ return;
+ }
+
+ /* Move all unacked segments to the head of the unsent queue */
+ for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
+ /* concatenate unsent queue after unacked queue */
+ seg->next = pcb->unsent;
+ /* unsent queue is the concatenated queue (of unacked, unsent) */
+ pcb->unsent = pcb->unacked;
+ /* unacked queue is now empty */
+ pcb->unacked = NULL;
+
+ /* increment number of retransmissions */
+ ++pcb->nrtx;
+
+ /* Don't take any RTT measurements after retransmitting. */
+ pcb->rttest = 0;
+
+ /* Do the actual retransmission */
+ tcp_output(pcb);
+}
+
+/**
+ * Requeue the first unacked segment for retransmission
+ *
+ * Called by tcp_receive() for fast retramsmit.
+ *
+ * @param pcb the tcp_pcb for which to retransmit the first unacked segment
+ */
+void
+tcp_rexmit(struct tcp_pcb *pcb)
+{
+ struct tcp_seg *seg;
+ struct tcp_seg **cur_seg;
+
+ if (pcb->unacked == NULL) {
+ return;
+ }
+
+ /* Move the first unacked segment to the unsent queue */
+ /* Keep the unsent queue sorted. */
+ seg = pcb->unacked;
+ pcb->unacked = seg->next;
+
+ cur_seg = &(pcb->unsent);
+ while (*cur_seg &&
+ TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
+ cur_seg = &((*cur_seg)->next );
+ }
+ seg->next = *cur_seg;
+ *cur_seg = seg;
+
+ ++pcb->nrtx;
+
+ /* Don't take any rtt measurements after retransmitting. */
+ pcb->rttest = 0;
+
+ /* Do the actual retransmission. */
+ snmp_inc_tcpretranssegs();
+ /* No need to call tcp_output: we are always called from tcp_input()
+ and thus tcp_output directly returns. */
+}
+
+
+/**
+ * Handle retransmission after three dupacks received
+ *
+ * @param pcb the tcp_pcb for which to retransmit the first unacked segment
+ */
+void
+tcp_rexmit_fast(struct tcp_pcb *pcb)
+{
+ if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
+ /* This is fast retransmit. Retransmit the first unacked segment. */
+ LWIP_DEBUGF(TCP_FR_DEBUG,
+ ("tcp_receive: dupacks %"U16_F" (%"U32_F
+ "), fast retransmit %"U32_F"\n",
+ (u16_t)pcb->dupacks, pcb->lastack,
+ ntohl(pcb->unacked->tcphdr->seqno)));
+ tcp_rexmit(pcb);
+
+ /* Set ssthresh to half of the minimum of the current
+ * cwnd and the advertised window */
+ if (pcb->cwnd > pcb->snd_wnd) {
+ pcb->ssthresh = pcb->snd_wnd / 2;
+ } else {
+ pcb->ssthresh = pcb->cwnd / 2;
+ }
+
+ /* The minimum value for ssthresh should be 2 MSS */
+ if (pcb->ssthresh < 2*pcb->mss) {
+ LWIP_DEBUGF(TCP_FR_DEBUG,
+ ("tcp_receive: The minimum value for ssthresh %"U16_F
+ " should be min 2 mss %"U16_F"...\n",
+ pcb->ssthresh, 2*pcb->mss));
+ pcb->ssthresh = 2*pcb->mss;
+ }
+
+ pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
+ pcb->flags |= TF_INFR;
+ }
+}
+
+
+/**
+ * Send keepalive packets to keep a connection active although
+ * no data is sent over it.
+ *
+ * Called by tcp_slowtmr()
+ *
+ * @param pcb the tcp_pcb for which to send a keepalive packet
+ */
+void
+tcp_keepalive(struct tcp_pcb *pcb)
+{
+ struct pbuf *p;
+ struct tcp_hdr *tcphdr;
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
+ ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
+ tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
+
+ p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
+ if(p == NULL) {
+ LWIP_DEBUGF(TCP_DEBUG,
+ ("tcp_keepalive: could not allocate memory for pbuf\n"));
+ return;
+ }
+ tcphdr = (struct tcp_hdr *)p->payload;
+
+#if CHECKSUM_GEN_TCP
+ tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
+ IP_PROTO_TCP, p->tot_len);
+#endif
+ TCP_STATS_INC(tcp.xmit);
+
+ /* Send output to IP */
+#if LWIP_NETIF_HWADDRHINT
+ ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
+ &(pcb->addr_hint));
+#else /* LWIP_NETIF_HWADDRHINT*/
+ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+ pbuf_free(p);
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
+ pcb->snd_nxt - 1, pcb->rcv_nxt));
+}
+
+
+/**
+ * Send persist timer zero-window probes to keep a connection active
+ * when a window update is lost.
+ *
+ * Called by tcp_slowtmr()
+ *
+ * @param pcb the tcp_pcb for which to send a zero-window probe packet
+ */
+void
+tcp_zero_window_probe(struct tcp_pcb *pcb)
+{
+ struct pbuf *p;
+ struct tcp_hdr *tcphdr;
+ struct tcp_seg *seg;
+ u16_t len;
+ u8_t is_fin;
+
+ LWIP_DEBUGF(TCP_DEBUG,
+ ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
+ U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
+ ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+
+ LWIP_DEBUGF(TCP_DEBUG,
+ ("tcp_zero_window_probe: tcp_ticks %"U32_F
+ " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
+ tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
+
+ seg = pcb->unacked;
+
+ if(seg == NULL) {
+ seg = pcb->unsent;
+ }
+ if(seg == NULL) {
+ return;
+ }
+
+ is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
+ /* we want to send one seqno: either FIN or data (no options) */
+ len = is_fin ? 0 : 1;
+
+ p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
+ if(p == NULL) {
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
+ return;
+ }
+ tcphdr = (struct tcp_hdr *)p->payload;
+
+ if (is_fin) {
+ /* FIN segment, no data */
+ TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
+ } else {
+ /* Data segment, copy in one byte from the head of the unacked queue */
+ struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
+ char *d = ((char *)p->payload + TCP_HLEN);
+ pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
+ }
+
+#if CHECKSUM_GEN_TCP
+ tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
+ IP_PROTO_TCP, p->tot_len);
+#endif
+ TCP_STATS_INC(tcp.xmit);
+
+ /* Send output to IP */
+#if LWIP_NETIF_HWADDRHINT
+ ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
+ &(pcb->addr_hint));
+#else /* LWIP_NETIF_HWADDRHINT*/
+ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+ pbuf_free(p);
+
+ LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
+ " ackno %"U32_F".\n",
+ pcb->snd_nxt - 1, pcb->rcv_nxt));
+}
+#endif /* LWIP_TCP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/timers.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/timers.c
new file mode 100644
index 0000000000..f0e92ccebe
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/timers.c
@@ -0,0 +1,482 @@
+/**
+ * @file
+ * Stack-internal timers implementation.
+ * This file includes timer callbacks for stack-internal timers as well as
+ * functions to set up or stop timers and check for expired timers.
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ * Simon Goldschmidt
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/timers.h"
+#include "lwip/tcp_impl.h"
+
+#if LWIP_TIMERS
+
+#include "lwip/def.h"
+#include "lwip/memp.h"
+#include "lwip/tcpip.h"
+
+#include "lwip/ip_frag.h"
+#include "netif/etharp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/igmp.h"
+#include "lwip/dns.h"
+
+
+/** The one and only timeout list */
+static struct sys_timeo *next_timeout;
+#if NO_SYS
+static u32_t timeouts_last_time;
+#endif /* NO_SYS */
+
+#if LWIP_TCP
+/** global variable that shows if the tcp timer is currently scheduled or not */
+static int tcpip_tcp_timer_active;
+
+/**
+ * Timer callback function that calls tcp_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+tcpip_tcp_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+
+ /* call TCP timer handler */
+ tcp_tmr();
+ /* timer still needed? */
+ if (tcp_active_pcbs || tcp_tw_pcbs) {
+ /* restart timer */
+ sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+ } else {
+ /* disable timer */
+ tcpip_tcp_timer_active = 0;
+ }
+}
+
+/**
+ * Called from TCP_REG when registering a new PCB:
+ * the reason is to have the TCP timer only running when
+ * there are active (or time-wait) PCBs.
+ */
+void
+tcp_timer_needed(void)
+{
+ /* timer is off but needed again? */
+ if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
+ /* enable and start timer */
+ tcpip_tcp_timer_active = 1;
+ sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+ }
+}
+#endif /* LWIP_TCP */
+
+#if IP_REASSEMBLY
+/**
+ * Timer callback function that calls ip_reass_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+ip_reass_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
+ ip_reass_tmr();
+ sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
+}
+#endif /* IP_REASSEMBLY */
+
+#if LWIP_ARP
+/**
+ * Timer callback function that calls etharp_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+arp_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
+ etharp_tmr();
+ sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
+}
+#endif /* LWIP_ARP */
+
+#if LWIP_DHCP
+/**
+ * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+dhcp_timer_coarse(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
+ dhcp_coarse_tmr();
+ sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
+}
+
+/**
+ * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+dhcp_timer_fine(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
+ dhcp_fine_tmr();
+ sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
+}
+#endif /* LWIP_DHCP */
+
+#if LWIP_AUTOIP
+/**
+ * Timer callback function that calls autoip_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+autoip_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
+ autoip_tmr();
+ sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
+}
+#endif /* LWIP_AUTOIP */
+
+#if LWIP_IGMP
+/**
+ * Timer callback function that calls igmp_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+igmp_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
+ igmp_tmr();
+ sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
+}
+#endif /* LWIP_IGMP */
+
+#if LWIP_DNS
+/**
+ * Timer callback function that calls dns_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+dns_timer(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+ LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
+ dns_tmr();
+ sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
+}
+#endif /* LWIP_DNS */
+
+/** Initialize this module */
+void sys_timeouts_init(void)
+{
+#if IP_REASSEMBLY
+ sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
+#endif /* IP_REASSEMBLY */
+#if LWIP_ARP
+ sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
+#endif /* LWIP_ARP */
+#if LWIP_DHCP
+ sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
+ sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
+#endif /* LWIP_DHCP */
+#if LWIP_AUTOIP
+ sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
+#endif /* LWIP_AUTOIP */
+#if LWIP_IGMP
+ sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
+#endif /* LWIP_IGMP */
+#if LWIP_DNS
+ sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
+#endif /* LWIP_DNS */
+
+#if NO_SYS
+ /* Initialise timestamp for sys_check_timeouts */
+ timeouts_last_time = sys_now();
+#endif
+}
+
+/**
+ * Create a one-shot timer (aka timeout). Timeouts are processed in the
+ * following cases:
+ * - while waiting for a message using sys_timeouts_mbox_fetch()
+ * - by calling sys_check_timeouts() (NO_SYS==1 only)
+ *
+ * @param msecs time in milliseconds after that the timer should expire
+ * @param handler callback function to call when msecs have elapsed
+ * @param arg argument to pass to the callback function
+ */
+#if LWIP_DEBUG_TIMERNAMES
+void
+sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
+#else /* LWIP_DEBUG_TIMERNAMES */
+void
+sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
+#endif /* LWIP_DEBUG_TIMERNAMES */
+{
+ struct sys_timeo *timeout, *t;
+
+ timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
+ if (timeout == NULL) {
+ LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
+ return;
+ }
+ timeout->next = NULL;
+ timeout->h = handler;
+ timeout->arg = arg;
+ timeout->time = msecs;
+#if LWIP_DEBUG_TIMERNAMES
+ timeout->handler_name = handler_name;
+ LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
+ (void *)timeout, msecs, handler_name, (void *)arg));
+#endif /* LWIP_DEBUG_TIMERNAMES */
+
+ if (next_timeout == NULL) {
+ next_timeout = timeout;
+ return;
+ }
+
+ if (next_timeout->time > msecs) {
+ next_timeout->time -= msecs;
+ timeout->next = next_timeout;
+ next_timeout = timeout;
+ } else {
+ for(t = next_timeout; t != NULL; t = t->next) {
+ timeout->time -= t->time;
+ if (t->next == NULL || t->next->time > timeout->time) {
+ if (t->next != NULL) {
+ t->next->time -= timeout->time;
+ }
+ timeout->next = t->next;
+ t->next = timeout;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Go through timeout list (for this task only) and remove the first matching
+ * entry, even though the timeout has not triggered yet.
+ *
+ * @note This function only works as expected if there is only one timeout
+ * calling 'handler' in the list of timeouts.
+ *
+ * @param handler callback function that would be called by the timeout
+ * @param arg callback argument that would be passed to handler
+*/
+void
+sys_untimeout(sys_timeout_handler handler, void *arg)
+{
+ struct sys_timeo *prev_t, *t;
+
+ if (next_timeout == NULL) {
+ return;
+ }
+
+ for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
+ if ((t->h == handler) && (t->arg == arg)) {
+ /* We have a match */
+ /* Unlink from previous in list */
+ if (prev_t == NULL) {
+ next_timeout = t->next;
+ } else {
+ prev_t->next = t->next;
+ }
+ /* If not the last one, add time of this one back to next */
+ if (t->next != NULL) {
+ t->next->time += t->time;
+ }
+ memp_free(MEMP_SYS_TIMEOUT, t);
+ return;
+ }
+ }
+ return;
+}
+
+#if NO_SYS
+
+/** Handle timeouts for NO_SYS==1 (i.e. without using
+ * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
+ * handler functions when timeouts expire.
+ *
+ * Must be called periodically from your main loop.
+ */
+void
+sys_check_timeouts(void)
+{
+ struct sys_timeo *tmptimeout;
+ u32_t diff;
+ sys_timeout_handler handler;
+ void *arg;
+ int had_one;
+ u32_t now;
+
+ now = sys_now();
+ if (next_timeout) {
+ /* this cares for wraparounds */
+ diff = LWIP_U32_DIFF(now, timeouts_last_time);
+ do
+ {
+ had_one = 0;
+ tmptimeout = next_timeout;
+ if (tmptimeout->time <= diff) {
+ /* timeout has expired */
+ had_one = 1;
+ timeouts_last_time = now;
+ diff -= tmptimeout->time;
+ next_timeout = tmptimeout->next;
+ handler = tmptimeout->h;
+ arg = tmptimeout->arg;
+#if LWIP_DEBUG_TIMERNAMES
+ if (handler != NULL) {
+ LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
+ tmptimeout->handler_name, arg));
+ }
+#endif /* LWIP_DEBUG_TIMERNAMES */
+ memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
+ if (handler != NULL) {
+ handler(arg);
+ }
+ }
+ /* repeat until all expired timers have been called */
+ }while(had_one);
+ }
+}
+
+/** Set back the timestamp of the last call to sys_check_timeouts()
+ * This is necessary if sys_check_timeouts() hasn't been called for a long
+ * time (e.g. while saving energy) to prevent all timer functions of that
+ * period being called.
+ */
+void
+sys_restart_timeouts(void)
+{
+ timeouts_last_time = sys_now();
+}
+
+#else /* NO_SYS */
+
+/**
+ * Wait (forever) for a message to arrive in an mbox.
+ * While waiting, timeouts are processed.
+ *
+ * @param mbox the mbox to fetch the message from
+ * @param msg the place to store the message
+ */
+void
+sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
+{
+ u32_t time_needed;
+ struct sys_timeo *tmptimeout;
+ sys_timeout_handler handler;
+ void *arg;
+
+ again:
+ if (!next_timeout) {
+ time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
+ } else {
+ if (next_timeout->time > 0) {
+ time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
+ } else {
+ time_needed = SYS_ARCH_TIMEOUT;
+ }
+
+ if (time_needed == SYS_ARCH_TIMEOUT) {
+ /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
+ could be fetched. We should now call the timeout handler and
+ deallocate the memory allocated for the timeout. */
+ tmptimeout = next_timeout;
+ next_timeout = tmptimeout->next;
+ handler = tmptimeout->h;
+ arg = tmptimeout->arg;
+#if LWIP_DEBUG_TIMERNAMES
+ if (handler != NULL) {
+ LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
+ tmptimeout->handler_name, arg));
+ }
+#endif /* LWIP_DEBUG_TIMERNAMES */
+ memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
+ if (handler != NULL) {
+ /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
+ timeout handler function. */
+ LOCK_TCPIP_CORE();
+ handler(arg);
+ UNLOCK_TCPIP_CORE();
+ }
+ LWIP_TCPIP_THREAD_ALIVE();
+
+ /* We try again to fetch a message from the mbox. */
+ goto again;
+ } else {
+ /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
+ occured. The time variable is set to the number of
+ milliseconds we waited for the message. */
+ if (time_needed < next_timeout->time) {
+ next_timeout->time -= time_needed;
+ } else {
+ next_timeout->time = 0;
+ }
+ }
+ }
+}
+
+#endif /* NO_SYS */
+
+#else /* LWIP_TIMERS */
+/* Satisfy the TCP code which calls this function */
+void
+tcp_timer_needed(void)
+{
+}
+#endif /* LWIP_TIMERS */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/udp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/udp.c
new file mode 100644
index 0000000000..4596ba2b79
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/core/udp.c
@@ -0,0 +1,966 @@
+/**
+ * @file
+ * User Datagram Protocol module
+ *
+ */
+
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+
+/* udp.c
+ *
+ * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
+ *
+ */
+
+/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/udp.h"
+#include "lwip/def.h"
+#include "lwip/memp.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "arch/perf.h"
+#include "lwip/dhcp.h"
+
+#include <string.h>
+
+/* The list of UDP PCBs */
+/* exported in udp.h (was static) */
+struct udp_pcb *udp_pcbs;
+
+/**
+ * Process an incoming UDP datagram.
+ *
+ * Given an incoming UDP datagram (as a chain of pbufs) this function
+ * finds a corresponding UDP PCB and hands over the pbuf to the pcbs
+ * recv function. If no pcb is found or the datagram is incorrect, the
+ * pbuf is freed.
+ *
+ * @param p pbuf to be demultiplexed to a UDP PCB.
+ * @param inp network interface on which the datagram was received.
+ *
+ */
+void
+udp_input(struct pbuf *p, struct netif *inp)
+{
+ struct udp_hdr *udphdr;
+ struct udp_pcb *pcb, *prev;
+ struct udp_pcb *uncon_pcb;
+ struct ip_hdr *iphdr;
+ u16_t src, dest;
+ u8_t local_match;
+ u8_t broadcast;
+
+ PERF_START;
+
+ UDP_STATS_INC(udp.recv);
+
+ iphdr = (struct ip_hdr *)p->payload;
+
+ /* Check minimum length (IP header + UDP header)
+ * and move payload pointer to UDP header */
+ if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
+ /* drop short packets */
+ LWIP_DEBUGF(UDP_DEBUG,
+ ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
+ UDP_STATS_INC(udp.lenerr);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpinerrors();
+ pbuf_free(p);
+ goto end;
+ }
+
+ udphdr = (struct udp_hdr *)p->payload;
+
+ /* is broadcast packet ? */
+ broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);
+
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
+
+ /* convert src and dest ports to host byte order */
+ src = ntohs(udphdr->src);
+ dest = ntohs(udphdr->dest);
+
+ udp_debug_print(udphdr);
+
+ /* print the UDP source and destination */
+ LWIP_DEBUGF(UDP_DEBUG,
+ ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
+ "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
+ ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
+ ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
+ ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
+ ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
+
+#if LWIP_DHCP
+ pcb = NULL;
+ /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by
+ the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */
+ if (dest == DHCP_CLIENT_PORT) {
+ /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */
+ if (src == DHCP_SERVER_PORT) {
+ if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
+ /* accept the packe if
+ (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
+ - inp->dhcp->pcb->remote == ANY or iphdr->src */
+ if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
+ ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {
+ pcb = inp->dhcp->pcb;
+ }
+ }
+ }
+ } else
+#endif /* LWIP_DHCP */
+ {
+ prev = NULL;
+ local_match = 0;
+ uncon_pcb = NULL;
+ /* Iterate through the UDP pcb list for a matching pcb.
+ * 'Perfect match' pcbs (connected to the remote port & ip address) are
+ * preferred. If no perfect match is found, the first unconnected pcb that
+ * matches the local port and ip address gets the datagram. */
+ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
+ local_match = 0;
+ /* print the PCB local and remote address */
+ LWIP_DEBUGF(UDP_DEBUG,
+ ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
+ "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
+ ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
+ ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
+ ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
+ ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
+
+ /* compare PCB local addr+port to UDP destination addr+port */
+ if ((pcb->local_port == dest) &&
+ ((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
+ ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||
+#if LWIP_IGMP
+ ip_addr_ismulticast(&current_iphdr_dest) ||
+#endif /* LWIP_IGMP */
+#if IP_SOF_BROADCAST_RECV
+ (broadcast && (pcb->so_options & SOF_BROADCAST)))) {
+#else /* IP_SOF_BROADCAST_RECV */
+ (broadcast))) {
+#endif /* IP_SOF_BROADCAST_RECV */
+ local_match = 1;
+ if ((uncon_pcb == NULL) &&
+ ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
+ /* the first unconnected matching PCB */
+ uncon_pcb = pcb;
+ }
+ }
+ /* compare PCB remote addr+port to UDP source addr+port */
+ if ((local_match != 0) &&
+ (pcb->remote_port == src) &&
+ (ip_addr_isany(&pcb->remote_ip) ||
+ ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {
+ /* the first fully matching PCB */
+ if (prev != NULL) {
+ /* move the pcb to the front of udp_pcbs so that is
+ found faster next time */
+ prev->next = pcb->next;
+ pcb->next = udp_pcbs;
+ udp_pcbs = pcb;
+ } else {
+ UDP_STATS_INC(udp.cachehit);
+ }
+ break;
+ }
+ prev = pcb;
+ }
+ /* no fully matching pcb found? then look for an unconnected pcb */
+ if (pcb == NULL) {
+ pcb = uncon_pcb;
+ }
+ }
+
+ /* Check checksum if this is a match or if it was directed at us. */
+ if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
+#if LWIP_UDPLITE
+ if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
+ /* Do the UDP Lite checksum */
+#if CHECKSUM_CHECK_UDP
+ u16_t chklen = ntohs(udphdr->len);
+ if (chklen < sizeof(struct udp_hdr)) {
+ if (chklen == 0) {
+ /* For UDP-Lite, checksum length of 0 means checksum
+ over the complete packet (See RFC 3828 chap. 3.1) */
+ chklen = p->tot_len;
+ } else {
+ /* At least the UDP-Lite header must be covered by the
+ checksum! (Again, see RFC 3828 chap. 3.1) */
+ UDP_STATS_INC(udp.chkerr);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpinerrors();
+ pbuf_free(p);
+ goto end;
+ }
+ }
+ if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,
+ IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
+ UDP_STATS_INC(udp.chkerr);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpinerrors();
+ pbuf_free(p);
+ goto end;
+ }
+#endif /* CHECKSUM_CHECK_UDP */
+ } else
+#endif /* LWIP_UDPLITE */
+ {
+#if CHECKSUM_CHECK_UDP
+ if (udphdr->chksum != 0) {
+ if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
+ IP_PROTO_UDP, p->tot_len) != 0) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("udp_input: UDP datagram discarded due to failing checksum\n"));
+ UDP_STATS_INC(udp.chkerr);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpinerrors();
+ pbuf_free(p);
+ goto end;
+ }
+ }
+#endif /* CHECKSUM_CHECK_UDP */
+ }
+ if(pbuf_header(p, -UDP_HLEN)) {
+ /* Can we cope with this failing? Just assert for now */
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpinerrors();
+ pbuf_free(p);
+ goto end;
+ }
+ if (pcb != NULL) {
+ snmp_inc_udpindatagrams();
+#if SO_REUSE && SO_REUSE_RXTOALL
+ if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&
+ ((pcb->so_options & SOF_REUSEADDR) != 0)) {
+ /* pass broadcast- or multicast packets to all multicast pcbs
+ if SOF_REUSEADDR is set on the first match */
+ struct udp_pcb *mpcb;
+ u8_t p_header_changed = 0;
+ for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
+ if (mpcb != pcb) {
+ /* compare PCB local addr+port to UDP destination addr+port */
+ if ((mpcb->local_port == dest) &&
+ ((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
+ ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||
+#if LWIP_IGMP
+ ip_addr_ismulticast(&current_iphdr_dest) ||
+#endif /* LWIP_IGMP */
+#if IP_SOF_BROADCAST_RECV
+ (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
+#else /* IP_SOF_BROADCAST_RECV */
+ (broadcast))) {
+#endif /* IP_SOF_BROADCAST_RECV */
+ /* pass a copy of the packet to all local matches */
+ if (mpcb->recv != NULL) {
+ struct pbuf *q;
+ /* for that, move payload to IP header again */
+ if (p_header_changed == 0) {
+ pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
+ p_header_changed = 1;
+ }
+ q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+ if (q != NULL) {
+ err_t err = pbuf_copy(q, p);
+ if (err == ERR_OK) {
+ /* move payload to UDP data */
+ pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
+ mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (p_header_changed) {
+ /* and move payload to UDP data again */
+ pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
+ }
+ }
+#endif /* SO_REUSE && SO_REUSE_RXTOALL */
+ /* callback */
+ if (pcb->recv != NULL) {
+ /* now the recv function is responsible for freeing p */
+ pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
+ } else {
+ /* no recv function registered? then we have to free the pbuf! */
+ pbuf_free(p);
+ goto end;
+ }
+ } else {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
+
+#if LWIP_ICMP
+ /* No match was found, send ICMP destination port unreachable unless
+ destination address was broadcast/multicast. */
+ if (!broadcast &&
+ !ip_addr_ismulticast(&current_iphdr_dest)) {
+ /* move payload pointer back to ip header */
+ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
+ LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
+ icmp_dest_unreach(p, ICMP_DUR_PORT);
+ }
+#endif /* LWIP_ICMP */
+ UDP_STATS_INC(udp.proterr);
+ UDP_STATS_INC(udp.drop);
+ snmp_inc_udpnoports();
+ pbuf_free(p);
+ }
+ } else {
+ pbuf_free(p);
+ }
+end:
+ PERF_STOP("udp_input");
+}
+
+/**
+ * Send data using UDP.
+ *
+ * @param pcb UDP PCB used to send the data.
+ * @param p chain of pbuf's to be sent.
+ *
+ * The datagram will be sent to the current remote_ip & remote_port
+ * stored in pcb. If the pcb is not bound to a port, it will
+ * automatically be bound to a random port.
+ *
+ * @return lwIP error code.
+ * - ERR_OK. Successful. No error occured.
+ * - ERR_MEM. Out of memory.
+ * - ERR_RTE. Could not find route to destination address.
+ * - More errors could be returned by lower protocol layers.
+ *
+ * @see udp_disconnect() udp_sendto()
+ */
+err_t
+udp_send(struct udp_pcb *pcb, struct pbuf *p)
+{
+ /* send to the packet using remote ip and port stored in the pcb */
+ return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
+}
+
+#if LWIP_CHECKSUM_ON_COPY
+/** Same as udp_send() but with checksum
+ */
+err_t
+udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
+ u8_t have_chksum, u16_t chksum)
+{
+ /* send to the packet using remote ip and port stored in the pcb */
+ return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
+ have_chksum, chksum);
+}
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+/**
+ * Send data to a specified address using UDP.
+ *
+ * @param pcb UDP PCB used to send the data.
+ * @param p chain of pbuf's to be sent.
+ * @param dst_ip Destination IP address.
+ * @param dst_port Destination UDP port.
+ *
+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
+ *
+ * If the PCB already has a remote address association, it will
+ * be restored after the data is sent.
+ *
+ * @return lwIP error code (@see udp_send for possible error codes)
+ *
+ * @see udp_disconnect() udp_send()
+ */
+err_t
+udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port)
+{
+#if LWIP_CHECKSUM_ON_COPY
+ return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
+}
+
+/** Same as udp_sendto(), but with checksum */
+err_t
+udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
+ u16_t dst_port, u8_t have_chksum, u16_t chksum)
+{
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ struct netif *netif;
+
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
+
+ /* find the outgoing network interface for this packet */
+#if LWIP_IGMP
+ netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
+#else
+ netif = ip_route(dst_ip);
+#endif /* LWIP_IGMP */
+
+ /* no outgoing network interface could be found? */
+ if (netif == NULL) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
+ UDP_STATS_INC(udp.rterr);
+ return ERR_RTE;
+ }
+#if LWIP_CHECKSUM_ON_COPY
+ return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
+#else /* LWIP_CHECKSUM_ON_COPY */
+ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
+#endif /* LWIP_CHECKSUM_ON_COPY */
+}
+
+/**
+ * Send data to a specified address using UDP.
+ * The netif used for sending can be specified.
+ *
+ * This function exists mainly for DHCP, to be able to send UDP packets
+ * on a netif that is still down.
+ *
+ * @param pcb UDP PCB used to send the data.
+ * @param p chain of pbuf's to be sent.
+ * @param dst_ip Destination IP address.
+ * @param dst_port Destination UDP port.
+ * @param netif the netif used for sending.
+ *
+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
+ *
+ * @return lwIP error code (@see udp_send for possible error codes)
+ *
+ * @see udp_disconnect() udp_send()
+ */
+err_t
+udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
+{
+#if LWIP_CHECKSUM_ON_COPY
+ return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);
+}
+
+/** Same as udp_sendto_if(), but with checksum */
+err_t
+udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
+ u16_t dst_port, struct netif *netif, u8_t have_chksum,
+ u16_t chksum)
+{
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ struct udp_hdr *udphdr;
+ ip_addr_t *src_ip;
+ err_t err;
+ struct pbuf *q; /* q will be sent down the stack */
+
+#if IP_SOF_BROADCAST
+ /* broadcast filter? */
+ if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+ return ERR_VAL;
+ }
+#endif /* IP_SOF_BROADCAST */
+
+ /* 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"));
+ err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
+ return err;
+ }
+ }
+
+ /* not enough space to add an UDP header to first pbuf in given p chain? */
+ if (pbuf_header(p, UDP_HLEN)) {
+ /* allocate header in a separate new pbuf */
+ q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
+ /* new header pbuf could not be allocated? */
+ if (q == NULL) {
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
+ return ERR_MEM;
+ }
+ if (p->tot_len != 0) {
+ /* chain header q in front of given pbuf p (only if p contains data) */
+ pbuf_chain(q, p);
+ }
+ /* first pbuf q points to header pbuf */
+ LWIP_DEBUGF(UDP_DEBUG,
+ ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
+ } else {
+ /* adding space for header within p succeeded */
+ /* first pbuf q equals given pbuf */
+ q = p;
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
+ }
+ LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
+ (q->len >= sizeof(struct udp_hdr)));
+ /* q now represents the packet to be sent */
+ udphdr = (struct udp_hdr *)q->payload;
+ udphdr->src = htons(pcb->local_port);
+ udphdr->dest = htons(dst_port);
+ /* in UDP, 0 checksum means 'no checksum' */
+ udphdr->chksum = 0x0000;
+
+ /* Multicast Loop? */
+#if LWIP_IGMP
+ if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {
+ q->flags |= PBUF_FLAG_MCASTLOOP;
+ }
+#endif /* LWIP_IGMP */
+
+
+ /* PCB local address is IP_ANY_ADDR? */
+ if (ip_addr_isany(&pcb->local_ip)) {
+ /* use outgoing network interface IP address as source address */
+ src_ip = &(netif->ip_addr);
+ } else {
+ /* check if UDP PCB local IP address is correct
+ * this could be an old address if netif->ip_addr has changed */
+ if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
+ /* local_ip doesn't match, drop the packet */
+ if (q != p) {
+ /* free the header pbuf */
+ pbuf_free(q);
+ q = NULL;
+ /* p is still referenced by the caller, and will live on */
+ }
+ return ERR_VAL;
+ }
+ /* use UDP PCB local IP address as source address */
+ src_ip = &(pcb->local_ip);
+ }
+
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
+
+#if LWIP_UDPLITE
+ /* UDP Lite protocol? */
+ if (pcb->flags & UDP_FLAGS_UDPLITE) {
+ u16_t chklen, chklen_hdr;
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
+ /* set UDP message length in UDP header */
+ chklen_hdr = chklen = pcb->chksum_len_tx;
+ if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {
+ if (chklen != 0) {
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));
+ }
+ /* For UDP-Lite, checksum length of 0 means checksum
+ over the complete packet. (See RFC 3828 chap. 3.1)
+ At least the UDP-Lite header must be covered by the
+ checksum, therefore, if chksum_len has an illegal
+ value, we generate the checksum over the complete
+ packet to be safe. */
+ chklen_hdr = 0;
+ chklen = q->tot_len;
+ }
+ udphdr->len = htons(chklen_hdr);
+ /* calculate checksum */
+#if CHECKSUM_GEN_UDP
+ udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
+ IP_PROTO_UDPLITE, q->tot_len,
+#if !LWIP_CHECKSUM_ON_COPY
+ chklen);
+#else /* !LWIP_CHECKSUM_ON_COPY */
+ (have_chksum ? UDP_HLEN : chklen));
+ if (have_chksum) {
+ u32_t acc;
+ acc = udphdr->chksum + (u16_t)~(chksum);
+ udphdr->chksum = FOLD_U32T(acc);
+ }
+#endif /* !LWIP_CHECKSUM_ON_COPY */
+
+ /* chksum zero must become 0xffff, as zero means 'no checksum' */
+ if (udphdr->chksum == 0x0000) {
+ udphdr->chksum = 0xffff;
+ }
+#endif /* CHECKSUM_GEN_UDP */
+ /* output to IP */
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = &(pcb->addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ } else
+#endif /* LWIP_UDPLITE */
+ { /* UDP */
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
+ udphdr->len = htons(q->tot_len);
+ /* calculate checksum */
+#if CHECKSUM_GEN_UDP
+ if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
+ u16_t udpchksum;
+#if LWIP_CHECKSUM_ON_COPY
+ if (have_chksum) {
+ u32_t acc;
+ udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
+ q->tot_len, UDP_HLEN);
+ acc = udpchksum + (u16_t)~(chksum);
+ udpchksum = FOLD_U32T(acc);
+ } else
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ {
+ udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
+ }
+
+ /* chksum zero must become 0xffff, as zero means 'no checksum' */
+ if (udpchksum == 0x0000) {
+ udpchksum = 0xffff;
+ }
+ udphdr->chksum = udpchksum;
+ }
+#endif /* CHECKSUM_GEN_UDP */
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
+ /* output to IP */
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = &(pcb->addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
+#if LWIP_NETIF_HWADDRHINT
+ netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+ }
+ /* TODO: must this be increased even if error occured? */
+ snmp_inc_udpoutdatagrams();
+
+ /* did we chain a separate header pbuf earlier? */
+ if (q != p) {
+ /* free the header pbuf */
+ pbuf_free(q);
+ q = NULL;
+ /* p is still referenced by the caller, and will live on */
+ }
+
+ UDP_STATS_INC(udp.xmit);
+ return err;
+}
+
+/**
+ * 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_ADDR_ANY to
+ * bind to all local interfaces.
+ * @param port local UDP port to bind with. Use 0 to automatically bind
+ * to a random port between UDP_LOCAL_PORT_RANGE_START and
+ * UDP_LOCAL_PORT_RANGE_END.
+ *
+ * ipaddr & port are expected to be in the same byte order as in the pcb.
+ *
+ * @return lwIP error code.
+ * - ERR_OK. Successful. No error occured.
+ * - ERR_USE. The specified ipaddr and port are already bound to by
+ * another UDP PCB.
+ *
+ * @see udp_disconnect()
+ */
+err_t
+udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
+{
+ struct udp_pcb *ipcb;
+ u8_t rebind;
+
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
+ ip_addr_debug_print(UDP_DEBUG, ipaddr);
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
+
+ rebind = 0;
+ /* Check for double bind and rebind of the same pcb */
+ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
+ /* is this UDP PCB already on active list? */
+ if (pcb == ipcb) {
+ /* pcb may occur at most once in active list */
+ LWIP_ASSERT("rebind == 0", rebind == 0);
+ /* pcb already in list, just rebind */
+ rebind = 1;
+ }
+
+ /* By default, we don't allow to bind to a port that any other udp
+ PCB is alread bound to, unless *all* PCBs with that port have tha
+ REUSEADDR flag set. */
+#if SO_REUSE
+ else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
+ ((ipcb->so_options & SOF_REUSEADDR) == 0)) {
+#else /* SO_REUSE */
+ /* port matches that of PCB in list and REUSEADDR not set -> reject */
+ else {
+#endif /* SO_REUSE */
+ if ((ipcb->local_port == port) &&
+ /* IP address matches, or one is IP_ADDR_ANY? */
+ (ip_addr_isany(&(ipcb->local_ip)) ||
+ ip_addr_isany(ipaddr) ||
+ ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
+ /* other PCB already binds to this local IP and port */
+ LWIP_DEBUGF(UDP_DEBUG,
+ ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
+ return ERR_USE;
+ }
+ }
+ }
+
+ ip_addr_set(&pcb->local_ip, ipaddr);
+
+ /* no port specified? */
+ if (port == 0) {
+#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" */
+#define UDP_LOCAL_PORT_RANGE_START 0xc000
+#define UDP_LOCAL_PORT_RANGE_END 0xffff
+#endif
+ port = UDP_LOCAL_PORT_RANGE_START;
+ ipcb = udp_pcbs;
+ while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
+ if (ipcb->local_port == port) {
+ /* port is already used by another udp_pcb */
+ port++;
+ /* restart scanning all udp pcbs */
+ ipcb = udp_pcbs;
+ } else {
+ /* go on with next udp pcb */
+ ipcb = ipcb->next;
+ }
+ }
+ if (ipcb != NULL) {
+ /* no more ports available in local range */
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
+ return ERR_USE;
+ }
+ }
+ pcb->local_port = port;
+ snmp_insert_udpidx_tree(pcb);
+ /* pcb not active yet? */
+ if (rebind == 0) {
+ /* place the PCB on the active list if not already there */
+ pcb->next = udp_pcbs;
+ udp_pcbs = pcb;
+ }
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
+ ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
+ ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
+ pcb->local_port));
+ return ERR_OK;
+}
+/**
+ * Connect an UDP PCB.
+ *
+ * This will associate the UDP PCB with the remote address.
+ *
+ * @param pcb UDP PCB to be connected with remote address ipaddr and port.
+ * @param ipaddr remote IP address to connect with.
+ * @param port remote UDP port to connect with.
+ *
+ * @return lwIP error code
+ *
+ * ipaddr & port are expected to be in the same byte order as in the pcb.
+ *
+ * The udp pcb is bound to a random local port if not already bound.
+ *
+ * @see udp_disconnect()
+ */
+err_t
+udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
+{
+ struct udp_pcb *ipcb;
+
+ if (pcb->local_port == 0) {
+ err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
+ if (err != ERR_OK) {
+ return err;
+ }
+ }
+
+ ip_addr_set(&pcb->remote_ip, ipaddr);
+ pcb->remote_port = port;
+ pcb->flags |= UDP_FLAGS_CONNECTED;
+/** TODO: this functionality belongs in upper layers */
+#ifdef LWIP_UDP_TODO
+ /* Nail down local IP for netconn_addr()/getsockname() */
+ if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
+ struct netif *netif;
+
+ if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
+ LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
+ UDP_STATS_INC(udp.rterr);
+ return ERR_RTE;
+ }
+ /** TODO: this will bind the udp pcb locally, to the interface which
+ is used to route output packets to the remote address. However, we
+ might want to accept incoming packets on any interface! */
+ pcb->local_ip = netif->ip_addr;
+ } else if (ip_addr_isany(&pcb->remote_ip)) {
+ pcb->local_ip.addr = 0;
+ }
+#endif
+ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+ ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
+ ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
+ ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
+ pcb->local_port));
+
+ /* Insert UDP PCB into the list of active UDP PCBs. */
+ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
+ if (pcb == ipcb) {
+ /* already on the list, just return */
+ return ERR_OK;
+ }
+ }
+ /* PCB not yet on the list, add PCB now */
+ pcb->next = udp_pcbs;
+ udp_pcbs = pcb;
+ return ERR_OK;
+}
+
+/**
+ * Disconnect a UDP PCB
+ *
+ * @param pcb the udp pcb to disconnect.
+ */
+void
+udp_disconnect(struct udp_pcb *pcb)
+{
+ /* reset remote address association */
+ ip_addr_set_any(&pcb->remote_ip);
+ pcb->remote_port = 0;
+ /* mark PCB as unconnected */
+ pcb->flags &= ~UDP_FLAGS_CONNECTED;
+}
+
+/**
+ * Set a receive callback for a UDP PCB
+ *
+ * This callback will be called when receiving a datagram for the pcb.
+ *
+ * @param pcb the pcb for wich to set the recv callback
+ * @param recv function pointer of the callback function
+ * @param recv_arg additional argument to pass to the callback function
+ */
+void
+udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
+{
+ /* remember recv() callback and user data */
+ pcb->recv = recv;
+ pcb->recv_arg = recv_arg;
+}
+
+/**
+ * Remove an UDP 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.
+ *
+ * @see udp_new()
+ */
+void
+udp_remove(struct udp_pcb *pcb)
+{
+ struct udp_pcb *pcb2;
+
+ snmp_delete_udpidx_tree(pcb);
+ /* pcb to be removed is first in list? */
+ if (udp_pcbs == pcb) {
+ /* make list start at 2nd pcb */
+ udp_pcbs = udp_pcbs->next;
+ /* pcb not 1st in list */
+ } else {
+ for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
+ /* find pcb in udp_pcbs list */
+ if (pcb2->next != NULL && pcb2->next == pcb) {
+ /* remove pcb from list */
+ pcb2->next = pcb->next;
+ }
+ }
+ }
+ memp_free(MEMP_UDP_PCB, pcb);
+}
+
+/**
+ * Create a UDP PCB.
+ *
+ * @return The UDP PCB which was created. NULL if the PCB data structure
+ * could not be allocated.
+ *
+ * @see udp_remove()
+ */
+struct udp_pcb *
+udp_new(void)
+{
+ struct udp_pcb *pcb;
+ pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
+ /* could allocate UDP PCB? */
+ if (pcb != NULL) {
+ /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
+ * which means checksum is generated over the whole datagram per default
+ * (recommended as default by RFC 3828). */
+ /* initialize PCB to all zeroes */
+ memset(pcb, 0, sizeof(struct udp_pcb));
+ pcb->ttl = UDP_TTL;
+ }
+ return pcb;
+}
+
+#if UDP_DEBUG
+/**
+ * Print UDP header information for debug purposes.
+ *
+ * @param udphdr pointer to the udp header in memory.
+ */
+void
+udp_debug_print(struct udp_hdr *udphdr)
+{
+ LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
+ LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
+ ntohs(udphdr->src), ntohs(udphdr->dest)));
+ LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n",
+ ntohs(udphdr->len), ntohs(udphdr->chksum)));
+ LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
+}
+#endif /* UDP_DEBUG */
+
+#endif /* LWIP_UDP */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/autoip.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/autoip.h
new file mode 100644
index 0000000000..23c264a1e0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/autoip.h
@@ -0,0 +1,119 @@
+/**
+ * @file
+ *
+ * AutoIP Automatic LinkLocal IP Configuration
+ */
+
+/*
+ *
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
+ * 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: Dominik Spies <kontakt@dspies.de>
+ *
+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
+ * with RFC 3927.
+ *
+ *
+ * Please coordinate changes and requests with Dominik Spies
+ * <kontakt@dspies.de>
+ */
+
+#ifndef __LWIP_AUTOIP_H__
+#define __LWIP_AUTOIP_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+#include "netif/etharp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* AutoIP Timing */
+#define AUTOIP_TMR_INTERVAL 100
+#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
+
+/* 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 */
+#define AUTOIP_STATE_OFF 0
+#define AUTOIP_STATE_PROBING 1
+#define AUTOIP_STATE_ANNOUNCING 2
+#define AUTOIP_STATE_BOUND 3
+
+struct autoip
+{
+ ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
+ u8_t state; /* current AutoIP state machine state */
+ u8_t sent_num; /* sent number of probes or announces, dependent on state */
+ u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
+ u8_t lastconflict; /* ticks until a conflict can be solved by defending */
+ u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */
+};
+
+
+/** Init srand, has to be called before entering mainloop */
+void autoip_init(void);
+
+/** Set a struct autoip allocated by the application to work with */
+void autoip_set_struct(struct netif *netif, struct autoip *autoip);
+
+/** Start AutoIP client */
+err_t autoip_start(struct netif *netif);
+
+/** Stop AutoIP client */
+err_t autoip_stop(struct netif *netif);
+
+/** Handles every incoming ARP Packet, called by etharp_arp_input */
+void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
+
+/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
+void autoip_tmr(void);
+
+/** Handle a possible change in the network configuration */
+void autoip_network_changed(struct netif *netif);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_AUTOIP */
+
+#endif /* __LWIP_AUTOIP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/icmp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/icmp.h
new file mode 100644
index 0000000000..d47a7d8a2e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/icmp.h
@@ -0,0 +1,111 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_ICMP_H__
+#define __LWIP_ICMP_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ICMP_ER 0 /* echo reply */
+#define ICMP_DUR 3 /* destination unreachable */
+#define ICMP_SQ 4 /* source quench */
+#define ICMP_RD 5 /* redirect */
+#define ICMP_ECHO 8 /* echo */
+#define ICMP_TE 11 /* time exceeded */
+#define ICMP_PP 12 /* parameter problem */
+#define ICMP_TS 13 /* timestamp */
+#define ICMP_TSR 14 /* timestamp reply */
+#define ICMP_IRQ 15 /* information request */
+#define ICMP_IR 16 /* information reply */
+
+enum icmp_dur_type {
+ ICMP_DUR_NET = 0, /* net unreachable */
+ ICMP_DUR_HOST = 1, /* host unreachable */
+ ICMP_DUR_PROTO = 2, /* protocol unreachable */
+ ICMP_DUR_PORT = 3, /* port unreachable */
+ ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
+ ICMP_DUR_SR = 5 /* source route failed */
+};
+
+enum icmp_te_type {
+ ICMP_TE_TTL = 0, /* time to live exceeded in transit */
+ ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
+};
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+/** This is the standard ICMP header only that the u32_t data
+ * is splitted 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.
+ */
+PACK_STRUCT_BEGIN
+struct icmp_echo_hdr {
+ PACK_STRUCT_FIELD(u8_t type);
+ PACK_STRUCT_FIELD(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
+
+#define ICMPH_TYPE(hdr) ((hdr)->type)
+#define ICMPH_CODE(hdr) ((hdr)->code)
+
+/** Combines type and code to an u16_t */
+#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
+#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
+
+
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+
+void icmp_input(struct pbuf *p, struct netif *inp);
+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
+
+#endif /* LWIP_ICMP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_ICMP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/igmp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/igmp.h
new file mode 100644
index 0000000000..8aabac2481
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/igmp.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002 CITEL Technologies 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 CITEL Technologies Ltd 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 CITEL TECHNOLOGIES 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 CITEL TECHNOLOGIES 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 a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+*/
+
+#ifndef __LWIP_IGMP_H__
+#define __LWIP_IGMP_H__
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* IGMP timer */
+#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
+#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
+#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
+
+/* MAC Filter Actions, these are passed to a netif's
+ * igmp_mac_filter callback function. */
+#define IGMP_DEL_MAC_FILTER 0
+#define IGMP_ADD_MAC_FILTER 1
+
+
+/**
+ * igmp group structure - there is
+ * a list of groups for each interface
+ * these should really be linked from the interface, but
+ * if we keep them separate we will not affect the lwip original code
+ * too much
+ *
+ * There will be a group for the all systems group address but this
+ * will not run the state machine as it is used to kick off reports
+ * from all the other groups
+ */
+struct igmp_group {
+ /** next link */
+ struct igmp_group *next;
+ /** interface on which the group is active */
+ struct netif *netif;
+ /** multicast address */
+ ip_addr_t group_address;
+ /** signifies we were the last person to report */
+ u8_t last_reporter_flag;
+ /** current state of the group */
+ u8_t group_state;
+ /** timer for reporting, negative is OFF */
+ u16_t timer;
+ /** counter of simultaneous uses */
+ u8_t use;
+};
+
+/* Prototypes */
+void igmp_init(void);
+err_t igmp_start(struct netif *netif);
+err_t igmp_stop(struct netif *netif);
+void igmp_report_groups(struct netif *netif);
+struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
+void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
+err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
+err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
+void igmp_tmr(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IGMP */
+
+#endif /* __LWIP_IGMP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet.h
new file mode 100644
index 0000000000..7bff49b59e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet.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: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_INET_H__
+#define __LWIP_INET_H__
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/ip_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** For compatibility with BSD code */
+struct in_addr {
+ u32_t s_addr;
+};
+
+/** 255.255.255.255 */
+#define INADDR_NONE IPADDR_NONE
+/** 127.0.0.1 */
+#define INADDR_LOOPBACK IPADDR_LOOPBACK
+/** 0.0.0.0 */
+#define INADDR_ANY IPADDR_ANY
+/** 255.255.255.255 */
+#define INADDR_BROADCAST IPADDR_BROADCAST
+
+/* Definitions of the bits in an Internet address integer.
+
+ On subnets, host and network parts are found according to
+ the subnet mask, not these masks. */
+#define IN_CLASSA(a) IP_CLASSA(a)
+#define IN_CLASSA_NET IP_CLASSA_NET
+#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
+#define IN_CLASSA_HOST IP_CLASSA_HOST
+#define IN_CLASSA_MAX IP_CLASSA_MAX
+
+#define IN_CLASSB(b) IP_CLASSB(b)
+#define IN_CLASSB_NET IP_CLASSB_NET
+#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
+#define IN_CLASSB_HOST IP_CLASSB_HOST
+#define IN_CLASSB_MAX IP_CLASSB_MAX
+
+#define IN_CLASSC(c) IP_CLASSC(c)
+#define IN_CLASSC_NET IP_CLASSC_NET
+#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
+#define IN_CLASSC_HOST IP_CLASSC_HOST
+#define IN_CLASSC_MAX IP_CLASSC_MAX
+
+#define IN_CLASSD(d) IP_CLASSD(d)
+#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
+#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
+#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
+#define IN_CLASSD_MAX IP_CLASSD_MAX
+
+#define IN_MULTICAST(a) IP_MULTICAST(a)
+
+#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
+#define IN_BADCLASS(a) IP_BADCLASS(a)
+
+#define IN_LOOPBACKNET IP_LOOPBACKNET
+
+#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
+#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
+/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
+#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
+
+/* directly map this to the lwip internal functions */
+#define inet_addr(cp) ipaddr_addr(cp)
+#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
+#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
+#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_INET_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet_chksum.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet_chksum.h
new file mode 100644
index 0000000000..79a2d90f2f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/inet_chksum.h
@@ -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: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_INET_CHKSUM_H__
+#define __LWIP_INET_CHKSUM_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+
+/** Swap the bytes in an u16_t: much like htons() for little-endian */
+#ifndef SWAP_BYTES_IN_WORD
+#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
+/* little endian and PLATFORM_BYTESWAP defined */
+#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
+#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
+/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
+#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
+#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
+#endif /* SWAP_BYTES_IN_WORD */
+
+/** Split an u32_t in two u16_ts and add them up */
+#ifndef FOLD_U32T
+#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
+#endif
+
+#if LWIP_CHECKSUM_ON_COPY
+/** Function-like macro: same as MEMCPY but returns the checksum of copied data
+ as u16_t */
+#ifndef LWIP_CHKSUM_COPY
+#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
+#ifndef LWIP_CHKSUM_COPY_ALGORITHM
+#define LWIP_CHKSUM_COPY_ALGORITHM 1
+#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
+#endif /* LWIP_CHKSUM_COPY */
+#else /* LWIP_CHECKSUM_ON_COPY */
+#define LWIP_CHKSUM_COPY_ALGORITHM 0
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+u16_t inet_chksum(void *dataptr, u16_t len);
+u16_t inet_chksum_pbuf(struct pbuf *p);
+u16_t inet_chksum_pseudo(struct pbuf *p,
+ ip_addr_t *src, ip_addr_t *dest,
+ u8_t proto, u16_t proto_len);
+u16_t inet_chksum_pseudo_partial(struct pbuf *p,
+ ip_addr_t *src, ip_addr_t *dest,
+ u8_t proto, u16_t proto_len, u16_t chksum_len);
+#if LWIP_CHKSUM_COPY_ALGORITHM
+u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
+#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_INET_H__ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip.h
new file mode 100644
index 0000000000..74f501d1ab
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip.h
@@ -0,0 +1,213 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP_H__
+#define __LWIP_IP_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/err.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Currently, the function ip_output_if_opt() is only used with IGMP */
+#define IP_OPTIONS_SEND LWIP_IGMP
+
+#define IP_HLEN 20
+
+#define IP_PROTO_ICMP 1
+#define IP_PROTO_IGMP 2
+#define IP_PROTO_UDP 17
+#define IP_PROTO_UDPLITE 136
+#define IP_PROTO_TCP 6
+
+/* This is passed as the destination address to ip_output_if (not
+ to ip_output), meaning that an IP header already is constructed
+ in the pbuf. This is used when TCP retransmits. */
+#ifdef IP_HDRINCL
+#undef IP_HDRINCL
+#endif /* IP_HDRINCL */
+#define IP_HDRINCL NULL
+
+#if LWIP_NETIF_HWADDRHINT
+#define IP_PCB_ADDRHINT ;u8_t addr_hint
+#else
+#define IP_PCB_ADDRHINT
+#endif /* LWIP_NETIF_HWADDRHINT */
+
+/* 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. */
+#define IP_PCB \
+ /* ip addresses in network byte order */ \
+ ip_addr_t local_ip; \
+ ip_addr_t remote_ip; \
+ /* 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_ADDRHINT
+
+struct ip_pcb {
+/* Common members of all PCB types */
+ IP_PCB;
+};
+
+/*
+ * Option flags per-socket. These are the same like SO_XXX.
+ */
+/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
+#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
+#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
+#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
+/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
+#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
+/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
+#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
+/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
+/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
+
+/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
+#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
+
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_hdr {
+ /* version / header length / type of service */
+ PACK_STRUCT_FIELD(u16_t _v_hl_tos);
+ /* total length */
+ PACK_STRUCT_FIELD(u16_t _len);
+ /* identification */
+ PACK_STRUCT_FIELD(u16_t _id);
+ /* fragment offset field */
+ PACK_STRUCT_FIELD(u16_t _offset);
+#define IP_RF 0x8000U /* reserved fragment flag */
+#define IP_DF 0x4000U /* dont fragment flag */
+#define IP_MF 0x2000U /* more fragments flag */
+#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
+ /* time to live */
+ PACK_STRUCT_FIELD(u8_t _ttl);
+ /* protocol*/
+ PACK_STRUCT_FIELD(u8_t _proto);
+ /* checksum */
+ PACK_STRUCT_FIELD(u16_t _chksum);
+ /* source and destination IP addresses */
+ PACK_STRUCT_FIELD(ip_addr_p_t src);
+ PACK_STRUCT_FIELD(ip_addr_p_t dest);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
+#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
+#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
+#define IPH_LEN(hdr) ((hdr)->_len)
+#define IPH_ID(hdr) ((hdr)->_id)
+#define IPH_OFFSET(hdr) ((hdr)->_offset)
+#define IPH_TTL(hdr) ((hdr)->_ttl)
+#define IPH_PROTO(hdr) ((hdr)->_proto)
+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
+
+#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
+#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
+
+/** The interface that provided the packet for the current callback invocation. */
+extern struct netif *current_netif;
+/** Header of the input packet currently being processed. */
+extern const struct ip_hdr *current_header;
+/** Source IP address of current_header */
+extern ip_addr_t current_iphdr_src;
+/** Destination IP address of current_header */
+extern ip_addr_t current_iphdr_dest;
+
+#define ip_init() /* Compatibility define, not init needed. */
+struct netif *ip_route(ip_addr_t *dest);
+err_t ip_input(struct pbuf *p, struct netif *inp);
+err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto);
+err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto,
+ struct netif *netif);
+#if LWIP_NETIF_HWADDRHINT
+err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT */
+#if IP_OPTIONS_SEND
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+ u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+ u16_t optlen);
+#endif /* IP_OPTIONS_SEND */
+/** Get the interface that received 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 ip_current_netif() (current_netif)
+/** Get the IP 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 ip_current_header() (current_header)
+/** Source IP address of current_header */
+#define ip_current_src_addr() (&current_iphdr_src)
+/** Destination IP address of current_header */
+#define ip_current_dest_addr() (&current_iphdr_dest)
+
+#if IP_DEBUG
+void ip_debug_print(struct pbuf *p);
+#else
+#define ip_debug_print(p)
+#endif /* IP_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_H__ */
+
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_addr.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_addr.h
new file mode 100644
index 0000000000..77f84e02cf
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_addr.h
@@ -0,0 +1,244 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP_ADDR_H__
+#define __LWIP_IP_ADDR_H__
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is the aligned version of ip_addr_t,
+ used as local variable, on the stack, etc. */
+struct ip_addr {
+ u32_t addr;
+};
+
+/* This is the packed version of ip_addr_t,
+ used in network headers that are itself packed */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr_packed {
+ PACK_STRUCT_FIELD(u32_t addr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+/** ip_addr_t uses a struct for convenience only, so that the same defines can
+ * operate both on ip_addr_t as well as on ip_addr_p_t. */
+typedef struct ip_addr ip_addr_t;
+typedef struct ip_addr_packed ip_addr_p_t;
+
+/*
+ * struct ipaddr2 is used in the definition of the ARP packet format in
+ * order to support compilers that don't have structure packing.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr2 {
+ PACK_STRUCT_FIELD(u16_t addrw[2]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+/* Forward declaration to not include netif.h */
+struct netif;
+
+extern const ip_addr_t ip_addr_any;
+extern const ip_addr_t ip_addr_broadcast;
+
+/** IP_ADDR_ can be used as a fixed IP address
+ * for the wildcard and the broadcast address
+ */
+#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
+#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
+
+/** 255.255.255.255 */
+#define IPADDR_NONE ((u32_t)0xffffffffUL)
+/** 127.0.0.1 */
+#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
+/** 0.0.0.0 */
+#define IPADDR_ANY ((u32_t)0x00000000UL)
+/** 255.255.255.255 */
+#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
+
+/* Definitions of the bits in an Internet address integer.
+
+ On subnets, host and network parts are found according to
+ the subnet mask, not these masks. */
+#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
+#define IP_CLASSA_NET 0xff000000
+#define IP_CLASSA_NSHIFT 24
+#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
+#define IP_CLASSA_MAX 128
+
+#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
+#define IP_CLASSB_NET 0xffff0000
+#define IP_CLASSB_NSHIFT 16
+#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
+#define IP_CLASSB_MAX 65536
+
+#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
+#define IP_CLASSC_NET 0xffffff00
+#define IP_CLASSC_NSHIFT 8
+#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
+
+#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
+#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
+#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
+#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
+#define IP_MULTICAST(a) IP_CLASSD(a)
+
+#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
+#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
+
+#define IP_LOOPBACKNET 127 /* official! */
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+/** Set an IP address given by the four byte-parts */
+#define IP4_ADDR(ipaddr, a,b,c,d) \
+ (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
+ ((u32_t)((b) & 0xff) << 16) | \
+ ((u32_t)((c) & 0xff) << 8) | \
+ (u32_t)((d) & 0xff)
+#else
+/** Set an IP address given by the four byte-parts.
+ Little-endian version that prevents the use of htonl. */
+#define IP4_ADDR(ipaddr, a,b,c,d) \
+ (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
+ ((u32_t)((c) & 0xff) << 16) | \
+ ((u32_t)((b) & 0xff) << 8) | \
+ (u32_t)((a) & 0xff)
+#endif
+
+/** MEMCPY-like copying of IP addresses where addresses are known to be
+ * 16-bit-aligned if the port is correctly configured (so a port could define
+ * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
+#ifndef IPADDR2_COPY
+#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
+#endif
+
+/** Copy IP address - faster than ip_addr_set: no NULL check */
+#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
+/** Safely copy one IP address to another (src may be NULL) */
+#define ip_addr_set(dest, src) ((dest)->addr = \
+ ((src) == NULL ? 0 : \
+ (src)->addr))
+/** Set complete address to zero */
+#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
+/** Set address to IPADDR_ANY (no need for htonl()) */
+#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
+/** Set address to loopback address */
+#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
+/** Safely copy one IP address to another and change byte order
+ * from host- to network-order. */
+#define ip_addr_set_hton(dest, src) ((dest)->addr = \
+ ((src) == NULL ? 0:\
+ htonl((src)->addr)))
+/** IPv4 only: set the IP address given as an u32_t */
+#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
+/** IPv4 only: get the IP address as an u32_t */
+#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
+
+/** Get the network address by combining host address with netmask */
+#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
+
+/**
+ * Determine if two address are on the same network.
+ *
+ * @arg addr1 IP address 1
+ * @arg addr2 IP address 2
+ * @arg mask network identifier mask
+ * @return !0 if the network identifiers of both address match
+ */
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
+ (mask)->addr) == \
+ ((addr2)->addr & \
+ (mask)->addr))
+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
+
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
+
+#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
+u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
+
+#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
+u8_t ip4_addr_netmask_valid(u32_t netmask);
+
+#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
+
+#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
+
+#define ip_addr_debug_print(debug, ipaddr) \
+ LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
+ ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
+ ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
+ ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
+ ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
+
+/* Get one byte from the 4-byte address */
+#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
+#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
+#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
+#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
+/* These are cast to u16_t, with the intent that they are often arguments
+ * to printf using the U16_F format from cc.h. */
+#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
+#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
+#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
+#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
+
+/** For backwards compatibility */
+#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
+
+u32_t ipaddr_addr(const char *cp);
+int ipaddr_aton(const char *cp, ip_addr_t *addr);
+/** returns ptr to static buffer; not reentrant! */
+char *ipaddr_ntoa(const ip_addr_t *addr);
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_ADDR_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_frag.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_frag.h
new file mode 100644
index 0000000000..77b5eb1eef
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/ipv4/lwip/ip_frag.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: Jani Monoses <jani@iv.ro>
+ *
+ */
+
+#ifndef __LWIP_IP_FRAG_H__
+#define __LWIP_IP_FRAG_H__
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/ip_addr.h"
+#include "lwip/ip.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if IP_REASSEMBLY
+/* The IP reassembly timer interval in milliseconds. */
+#define IP_TMR_INTERVAL 1000
+
+/* IP reassembly helper struct.
+ * This is exported because memp needs to know the size.
+ */
+struct ip_reassdata {
+ struct ip_reassdata *next;
+ struct pbuf *p;
+ struct ip_hdr iphdr;
+ u16_t datagram_len;
+ u8_t flags;
+ u8_t timer;
+};
+
+void ip_reass_init(void);
+void ip_reass_tmr(void);
+struct pbuf * ip_reass(struct pbuf *p);
+#endif /* IP_REASSEMBLY */
+
+#if IP_FRAG
+#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+/** A custom pbuf that holds a reference to another pbuf, which is freed
+ * when this custom pbuf is freed. This is used to create a custom PBUF_REF
+ * that points into the original pbuf. */
+struct pbuf_custom_ref {
+ /** 'base class' */
+ struct pbuf_custom pc;
+ /** pointer to the original pbuf that is referenced */
+ struct pbuf *original;
+};
+#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
+
+err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
+#endif /* IP_FRAG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_FRAG_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api.h
new file mode 100644
index 0000000000..91b9e5d243
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api.h
@@ -0,0 +1,284 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_API_H__
+#define __LWIP_API_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include <stddef.h> /* for size_t */
+
+#include "lwip/netbuf.h"
+#include "lwip/sys.h"
+#include "lwip/ip_addr.h"
+#include "lwip/err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Throughout this file, IP addresses and port numbers are expected to be in
+ * the same byte order as in the corresponding pcb.
+ */
+
+/* Flags for netconn_write (u8_t) */
+#define NETCONN_NOFLAG 0x00
+#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
+#define NETCONN_COPY 0x01
+#define NETCONN_MORE 0x02
+#define NETCONN_DONTBLOCK 0x04
+
+/* Flags for struct netconn.flags (u8_t) */
+/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
+ this temporarily stores whether to wake up the original application task
+ if data couldn't be sent in the first try. */
+#define NETCONN_FLAG_WRITE_DELAYED 0x01
+/** Should this netconn avoid blocking? */
+#define NETCONN_FLAG_NON_BLOCKING 0x02
+/** Was the last connect action a non-blocking one? */
+#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
+/** If this is set, a TCP netconn must call netconn_recved() to update
+ the TCP receive window (done automatically if not set). */
+#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
+/** If a nonblocking write has been rejected before, poll_tcp needs to
+ check if the netconn is writable again */
+#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
+
+
+/* Helpers to process several netconn_types by the same code */
+#define NETCONNTYPE_GROUP(t) (t&0xF0)
+#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
+
+/** Protocol family and type of the netconn */
+enum netconn_type {
+ NETCONN_INVALID = 0,
+ /* NETCONN_TCP Group */
+ NETCONN_TCP = 0x10,
+ /* NETCONN_UDP Group */
+ NETCONN_UDP = 0x20,
+ NETCONN_UDPLITE = 0x21,
+ NETCONN_UDPNOCHKSUM= 0x22,
+ /* NETCONN_RAW Group */
+ NETCONN_RAW = 0x40
+};
+
+/** Current state of the netconn. Non-TCP netconns are always
+ * in state NETCONN_NONE! */
+enum netconn_state {
+ NETCONN_NONE,
+ NETCONN_WRITE,
+ NETCONN_LISTEN,
+ NETCONN_CONNECT,
+ NETCONN_CLOSE
+};
+
+/** Use to inform the callback function about changes */
+enum netconn_evt {
+ NETCONN_EVT_RCVPLUS,
+ NETCONN_EVT_RCVMINUS,
+ NETCONN_EVT_SENDPLUS,
+ NETCONN_EVT_SENDMINUS,
+ NETCONN_EVT_ERROR
+};
+
+#if LWIP_IGMP
+/** Used for netconn_join_leave_group() */
+enum netconn_igmp {
+ NETCONN_JOIN,
+ NETCONN_LEAVE
+};
+#endif /* LWIP_IGMP */
+
+/* forward-declare some structs to avoid to include their headers */
+struct ip_pcb;
+struct tcp_pcb;
+struct udp_pcb;
+struct raw_pcb;
+struct netconn;
+struct api_msg_msg;
+
+/** A callback prototype to inform about events for a netconn */
+typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
+
+/** A netconn descriptor */
+struct netconn {
+ /** type of the netconn (TCP, UDP or RAW) */
+ enum netconn_type type;
+ /** current state of the netconn */
+ enum netconn_state state;
+ /** the lwIP internal protocol control block */
+ union {
+ struct ip_pcb *ip;
+ struct tcp_pcb *tcp;
+ struct udp_pcb *udp;
+ struct raw_pcb *raw;
+ } pcb;
+ /** the last error this netconn had */
+ err_t last_err;
+ /** sem that is used to synchroneously execute functions in the core context */
+ sys_sem_t op_completed;
+ /** mbox where received packets are stored until they are fetched
+ by the netconn application thread (can grow quite big) */
+ sys_mbox_t recvmbox;
+#if LWIP_TCP
+ /** mbox where new connections are stored until processed
+ by the application thread */
+ sys_mbox_t acceptmbox;
+#endif /* LWIP_TCP */
+ /** only used for socket layer */
+#if LWIP_SOCKET
+ int socket;
+#endif /* LWIP_SOCKET */
+#if LWIP_SO_RCVTIMEO
+ /** timeout to wait for new data to be received
+ (or connections to arrive for listening netconns) */
+ int recv_timeout;
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+ /** maximum amount of bytes queued in recvmbox
+ not used for TCP: adjust TCP_WND instead! */
+ int recv_bufsize;
+ /** number of bytes currently in recvmbox to be received,
+ tested against recv_bufsize to limit bytes on recvmbox
+ for UDP and RAW, used for FIONREAD */
+ s16_t recv_avail;
+#endif /* LWIP_SO_RCVBUF */
+ /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
+ u8_t flags;
+#if LWIP_TCP
+ /** TCP: when data passed to netconn_write doesn't fit into the send buffer,
+ this temporarily stores how much is already sent. */
+ size_t write_offset;
+ /** TCP: when data passed to netconn_write doesn't fit into the send buffer,
+ this temporarily stores the message.
+ Also used during connect and close. */
+ struct api_msg_msg *current_msg;
+#endif /* LWIP_TCP */
+ /** A callback function that is informed about events for this netconn */
+ netconn_callback callback;
+};
+
+/** Register an Network connection event */
+#define API_EVENT(c,e,l) if (c->callback) { \
+ (*c->callback)(c, e, l); \
+ }
+
+/** Set conn->last_err to err but don't overwrite fatal errors */
+#define NETCONN_SET_SAFE_ERR(conn, err) do { \
+ SYS_ARCH_DECL_PROTECT(lev); \
+ SYS_ARCH_PROTECT(lev); \
+ if (!ERR_IS_FATAL((conn)->last_err)) { \
+ (conn)->last_err = err; \
+ } \
+ SYS_ARCH_UNPROTECT(lev); \
+} while(0);
+
+/* Network connection functions: */
+#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
+#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
+struct
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
+ netconn_callback callback);
+err_t netconn_delete(struct netconn *conn);
+/** Get the type of a netconn (as enum netconn_type). */
+#define netconn_type(conn) (conn->type)
+
+err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
+ u16_t *port, u8_t local);
+#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
+#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
+
+err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
+err_t netconn_connect(struct netconn *conn, 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);
+#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
+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_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
+void netconn_recved(struct netconn *conn, u32_t length);
+err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
+ ip_addr_t *addr, u16_t port);
+err_t netconn_send(struct netconn *conn, struct netbuf *buf);
+err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
+ u8_t apiflags);
+err_t netconn_close(struct netconn *conn);
+err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
+
+#if LWIP_IGMP
+err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
+ ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
+#endif /* LWIP_IGMP */
+#if LWIP_DNS
+err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
+#endif /* LWIP_DNS */
+
+#define netconn_err(conn) ((conn)->last_err)
+#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
+
+/** Set the blocking status of netconn calls (@todo: write/send is missing) */
+#define netconn_set_nonblocking(conn, val) do { if(val) { \
+ (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
+} else { \
+ (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
+/** Get the blocking status of netconn calls (@todo: write/send is missing) */
+#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
+
+/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
+#define netconn_set_noautorecved(conn, val) do { if(val) { \
+ (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
+} else { \
+ (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
+/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
+#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
+
+#if LWIP_SO_RCVTIMEO
+/** Set the receive timeout in milliseconds */
+#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
+/** Get the receive timeout in milliseconds */
+#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
+#endif /* LWIP_SO_RCVTIMEO */
+#if LWIP_SO_RCVBUF
+/** Set the receive buffer in bytes */
+#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
+/** Get the receive buffer in bytes */
+#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
+#endif /* LWIP_SO_RCVBUF*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_NETCONN */
+
+#endif /* __LWIP_API_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api_msg.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api_msg.h
new file mode 100644
index 0000000000..f99d8c3b71
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/api_msg.h
@@ -0,0 +1,174 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_API_MSG_H__
+#define __LWIP_API_MSG_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include <stddef.h> /* for size_t */
+
+#include "lwip/ip_addr.h"
+#include "lwip/err.h"
+#include "lwip/sys.h"
+#include "lwip/igmp.h"
+#include "lwip/api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For the netconn API, these values are use as a bitmask! */
+#define NETCONN_SHUT_RD 1
+#define NETCONN_SHUT_WR 2
+#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
+
+/* IP addresses and port numbers are expected to be in
+ * the same byte order as in the corresponding pcb.
+ */
+/** This struct includes everything that is necessary to execute a function
+ for a netconn in another thread context (mainly used to process netconns
+ in the tcpip_thread context to be thread safe). */
+struct api_msg_msg {
+ /** The netconn which to process - always needed: it includes the semaphore
+ which is used to block the application thread until the function finished. */
+ struct netconn *conn;
+ /** The return value of the function executed in tcpip_thread. */
+ err_t err;
+ /** Depending on the executed function, one of these union members is used */
+ union {
+ /** used for do_send */
+ struct netbuf *b;
+ /** used for do_newconn */
+ struct {
+ u8_t proto;
+ } n;
+ /** used for do_bind and do_connect */
+ struct {
+ ip_addr_t *ipaddr;
+ u16_t port;
+ } bc;
+ /** used for do_getaddr */
+ struct {
+ ip_addr_t *ipaddr;
+ u16_t *port;
+ u8_t local;
+ } ad;
+ /** used for do_write */
+ struct {
+ const void *dataptr;
+ size_t len;
+ u8_t apiflags;
+ } w;
+ /** used for do_recv */
+ struct {
+ u32_t len;
+ } r;
+ /** used for do_close (/shutdown) */
+ struct {
+ u8_t shut;
+ } sd;
+#if LWIP_IGMP
+ /** used for do_join_leave_group */
+ struct {
+ ip_addr_t *multiaddr;
+ ip_addr_t *netif_addr;
+ enum netconn_igmp join_or_leave;
+ } jl;
+#endif /* LWIP_IGMP */
+#if TCP_LISTEN_BACKLOG
+ struct {
+ u8_t backlog;
+ } lb;
+#endif /* TCP_LISTEN_BACKLOG */
+ } msg;
+};
+
+/** This struct contains a function to execute in another thread context and
+ a struct api_msg_msg that serves as an argument for this function.
+ This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */
+struct api_msg {
+ /** function to execute in tcpip_thread context */
+ void (* function)(struct api_msg_msg *msg);
+ /** arguments for this function */
+ struct api_msg_msg msg;
+};
+
+#if LWIP_DNS
+/** As do_gethostbyname requires more arguments but doesn't require a netconn,
+ it has its own struct (to avoid struct api_msg getting bigger than necessary).
+ do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
+ (see netconn_gethostbyname). */
+struct dns_api_msg {
+ /** Hostname to query or dotted IP address string */
+ const char *name;
+ /** Rhe resolved address is stored here */
+ ip_addr_t *addr;
+ /** This semaphore is posted when the name is resolved, the application thread
+ should wait on it. */
+ sys_sem_t *sem;
+ /** Errors are given back here */
+ err_t *err;
+};
+#endif /* LWIP_DNS */
+
+void do_newconn ( struct api_msg_msg *msg);
+void do_delconn ( struct api_msg_msg *msg);
+void do_bind ( struct api_msg_msg *msg);
+void do_connect ( struct api_msg_msg *msg);
+void do_disconnect ( struct api_msg_msg *msg);
+void do_listen ( struct api_msg_msg *msg);
+void do_send ( struct api_msg_msg *msg);
+void do_recv ( struct api_msg_msg *msg);
+void do_write ( struct api_msg_msg *msg);
+void do_getaddr ( struct api_msg_msg *msg);
+void do_close ( struct api_msg_msg *msg);
+void do_shutdown ( struct api_msg_msg *msg);
+#if LWIP_IGMP
+void do_join_leave_group( struct api_msg_msg *msg);
+#endif /* LWIP_IGMP */
+
+#if LWIP_DNS
+void do_gethostbyname(void *arg);
+#endif /* LWIP_DNS */
+
+struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);
+void netconn_free(struct netconn *conn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_NETCONN */
+
+#endif /* __LWIP_API_MSG_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/arch.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/arch.h
new file mode 100644
index 0000000000..524af6be03
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/arch.h
@@ -0,0 +1,238 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_ARCH_H__
+#define __LWIP_ARCH_H__
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#include "arch/cc.h"
+
+/** Temporary: define format string for size_t if not defined in cc.h */
+#ifndef SZT_F
+#define SZT_F U32_F
+#endif /* SZT_F */
+/** Temporary upgrade helper: define format string for u8_t as hex if not
+ defined in cc.h */
+#ifndef X8_F
+#define X8_F "02x"
+#endif /* X8_F */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PACK_STRUCT_BEGIN
+#define PACK_STRUCT_BEGIN
+#endif /* PACK_STRUCT_BEGIN */
+
+#ifndef PACK_STRUCT_END
+#define PACK_STRUCT_END
+#endif /* PACK_STRUCT_END */
+
+#ifndef PACK_STRUCT_FIELD
+#define PACK_STRUCT_FIELD(x) x
+#endif /* PACK_STRUCT_FIELD */
+
+
+#ifndef LWIP_UNUSED_ARG
+#define LWIP_UNUSED_ARG(x) (void)x
+#endif /* LWIP_UNUSED_ARG */
+
+
+#ifdef LWIP_PROVIDE_ERRNO
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Arg list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Function not implemented */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+
+#define EDEADLOCK EDEADLK
+
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#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 */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale NFS file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+
+
+#define ENSROK 0 /* DNS server returned answer with no data */
+#define ENSRNODATA 160 /* DNS server returned answer with no data */
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
+#define ENSRSERVFAIL 162 /* DNS server returned general failure */
+#define ENSRNOTFOUND 163 /* Domain name not found */
+#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
+#define ENSRREFUSED 165 /* DNS server refused query */
+#define ENSRBADQUERY 166 /* Misformatted DNS query */
+#define ENSRBADNAME 167 /* Misformatted domain name */
+#define ENSRBADFAMILY 168 /* Unsupported address family */
+#define ENSRBADRESP 169 /* Misformatted DNS reply */
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
+#define ENSROF 172 /* End of file */
+#define ENSRFILE 173 /* Error reading file */
+#define ENSRNOMEM 174 /* Out of memory */
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */
+#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
+#define ENSRCNAMELOOP 177 /* Domain name is too long */
+
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* LWIP_PROVIDE_ERRNO */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_ARCH_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/debug.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/debug.h
new file mode 100644
index 0000000000..d8359ea3a5
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/debug.h
@@ -0,0 +1,98 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_DEBUG_H__
+#define __LWIP_DEBUG_H__
+
+#include "lwip/arch.h"
+
+/** lower two bits indicate debug level
+ * - 0 all
+ * - 1 warning
+ * - 2 serious
+ * - 3 severe
+ */
+#define LWIP_DBG_LEVEL_ALL 0x00
+#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
+#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
+#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
+#define LWIP_DBG_LEVEL_SEVERE 0x03
+#define LWIP_DBG_MASK_LEVEL 0x03
+
+/** flag for LWIP_DEBUGF to enable that debug message */
+#define LWIP_DBG_ON 0x80U
+/** flag for LWIP_DEBUGF to disable that debug message */
+#define LWIP_DBG_OFF 0x00U
+
+/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
+#define LWIP_DBG_TRACE 0x40U
+/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
+#define LWIP_DBG_STATE 0x20U
+/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
+#define LWIP_DBG_FRESH 0x10U
+/** flag for LWIP_DEBUGF to halt after printing this debug message */
+#define LWIP_DBG_HALT 0x08U
+
+#ifndef LWIP_NOASSERT
+#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
+ LWIP_PLATFORM_ASSERT(message); } while(0)
+#else /* LWIP_NOASSERT */
+#define LWIP_ASSERT(message, assertion)
+#endif /* LWIP_NOASSERT */
+
+/** if "expression" isn't true, then print "message" and execute "handler" expression */
+#ifndef LWIP_ERROR
+#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
+ LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
+#endif /* LWIP_ERROR */
+
+#ifdef LWIP_DEBUG
+/** print debug message only if debug message type is enabled...
+ * AND is of correct type AND is at least LWIP_DBG_LEVEL
+ */
+#define LWIP_DEBUGF(debug, message) do { \
+ if ( \
+ ((debug) & LWIP_DBG_ON) && \
+ ((debug) & LWIP_DBG_TYPES_ON) && \
+ ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
+ LWIP_PLATFORM_DIAG(message); \
+ if ((debug) & LWIP_DBG_HALT) { \
+ while(1); \
+ } \
+ } \
+ } while(0)
+
+#else /* LWIP_DEBUG */
+#define LWIP_DEBUGF(debug, message)
+#endif /* LWIP_DEBUG */
+
+#endif /* __LWIP_DEBUG_H__ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/def.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/def.h
new file mode 100644
index 0000000000..9b6de6a8b8
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/def.h
@@ -0,0 +1,127 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_DEF_H__
+#define __LWIP_DEF_H__
+
+/* arch.h might define NULL already */
+#include "lwip/arch.h"
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
+#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/** Get the absolute difference between 2 u32_t values (correcting overflows)
+ * 'a' is expected to be 'higher' (without overflow) than 'b'. */
+#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
+
+/* Endianess-optimized shifting of two u8_t to create one u16_t */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
+#else
+#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
+#endif
+
+#ifndef LWIP_PLATFORM_BYTESWAP
+#define LWIP_PLATFORM_BYTESWAP 0
+#endif
+
+#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
+/* workaround for naming collisions on some platforms */
+
+#ifdef htons
+#undef htons
+#endif /* htons */
+#ifdef htonl
+#undef htonl
+#endif /* htonl */
+#ifdef ntohs
+#undef ntohs
+#endif /* ntohs */
+#ifdef ntohl
+#undef ntohl
+#endif /* ntohl */
+
+#define htons(x) lwip_htons(x)
+#define ntohs(x) lwip_ntohs(x)
+#define htonl(x) lwip_htonl(x)
+#define ntohl(x) lwip_ntohl(x)
+#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define lwip_htons(x) (x)
+#define lwip_ntohs(x) (x)
+#define lwip_htonl(x) (x)
+#define lwip_ntohl(x) (x)
+#define PP_HTONS(x) (x)
+#define PP_NTOHS(x) (x)
+#define PP_HTONL(x) (x)
+#define PP_NTOHL(x) (x)
+#else /* BYTE_ORDER != BIG_ENDIAN */
+#if LWIP_PLATFORM_BYTESWAP
+#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
+#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
+#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
+#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
+#else /* LWIP_PLATFORM_BYTESWAP */
+u16_t lwip_htons(u16_t x);
+u16_t lwip_ntohs(u16_t x);
+u32_t lwip_htonl(u32_t x);
+u32_t lwip_ntohl(u32_t x);
+#endif /* LWIP_PLATFORM_BYTESWAP */
+
+/* These macros should be calculated by the preprocessor and are used
+ with compile-time constants only (so that there is no little-endian
+ overhead at runtime). */
+#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
+#define PP_NTOHS(x) PP_HTONS(x)
+#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
+ (((x) & 0xff00) << 8) | \
+ (((x) & 0xff0000UL) >> 8) | \
+ (((x) & 0xff000000UL) >> 24))
+#define PP_NTOHL(x) PP_HTONL(x)
+
+#endif /* BYTE_ORDER == BIG_ENDIAN */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_DEF_H__ */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dhcp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dhcp.h
new file mode 100644
index 0000000000..32d93381d1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dhcp.h
@@ -0,0 +1,242 @@
+/** @file
+ */
+
+#ifndef __LWIP_DHCP_H__
+#define __LWIP_DHCP_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** period (in seconds) of the application calling dhcp_coarse_tmr() */
+#define DHCP_COARSE_TIMER_SECS 60
+/** 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() */
+#define DHCP_FINE_TIMER_MSECS 500
+
+#define DHCP_CHADDR_LEN 16U
+#define DHCP_SNAME_LEN 64U
+#define DHCP_FILE_LEN 128U
+
+struct dhcp
+{
+ /** transaction identifier of last sent request */
+ u32_t xid;
+ /** our connection to the DHCP server */
+ struct udp_pcb *pcb;
+ /** incoming msg */
+ struct dhcp_msg *msg_in;
+ /** current DHCP state machine state */
+ 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;
+
+ struct pbuf *p_out; /* pbuf of outcoming msg */
+ struct dhcp_msg *msg_out; /* outgoing msg */
+ u16_t options_out_len; /* outgoing msg options length */
+ 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 */
+ ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
+ ip_addr_t offered_ip_addr;
+ ip_addr_t offered_sn_mask;
+ ip_addr_t offered_gw_addr;
+
+ u32_t offered_t0_lease; /* lease period (in seconds) */
+ u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
+ u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
+ /* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
+ integrate with possible TFTP-client for booting? */
+#if LWIP_DHCP_BOOTP_FILE
+ ip_addr_t offered_si_addr;
+ char boot_file_name[DHCP_FILE_LEN];
+#endif /* LWIP_DHCP_BOOTPFILE */
+};
+
+/* MUST be compiled with "pack structs" or equivalent! */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** minimum set of fields of any DHCP message */
+struct dhcp_msg
+{
+ PACK_STRUCT_FIELD(u8_t op);
+ PACK_STRUCT_FIELD(u8_t htype);
+ PACK_STRUCT_FIELD(u8_t hlen);
+ PACK_STRUCT_FIELD(u8_t hops);
+ PACK_STRUCT_FIELD(u32_t xid);
+ PACK_STRUCT_FIELD(u16_t secs);
+ PACK_STRUCT_FIELD(u16_t flags);
+ PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
+ PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
+ PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
+ PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
+ PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
+ PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
+ PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
+ PACK_STRUCT_FIELD(u32_t cookie);
+#define DHCP_MIN_OPTIONS_LEN 68U
+/** make sure user does not configure this too small */
+#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
+# undef DHCP_OPTIONS_LEN
+#endif
+/** allow this to be configured in lwipopts.h, but not too small */
+#if (!defined(DHCP_OPTIONS_LEN))
+/** set this to be sufficient for your options in outgoing DHCP msgs */
+# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
+#endif
+ PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
+/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
+#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
+void dhcp_cleanup(struct netif *netif);
+/** start DHCP configuration */
+err_t dhcp_start(struct netif *netif);
+/** enforce early lease renewal (not needed normally)*/
+err_t dhcp_renew(struct netif *netif);
+/** release the DHCP lease, usually called before dhcp_stop()*/
+err_t dhcp_release(struct netif *netif);
+/** stop DHCP configuration */
+void dhcp_stop(struct netif *netif);
+/** inform server of our manual IP address */
+void dhcp_inform(struct netif *netif);
+/** Handle a possible change in the network configuration */
+void dhcp_network_changed(struct netif *netif);
+
+/** if enabled, check whether the offered IP address is not in use, using ARP */
+#if DHCP_DOES_ARP_CHECK
+void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
+#endif
+
+/** to be called every minute */
+void dhcp_coarse_tmr(void);
+/** to be called every half second */
+void dhcp_fine_tmr(void);
+
+/** DHCP message item offsets and length */
+#define DHCP_OP_OFS 0
+#define DHCP_HTYPE_OFS 1
+#define DHCP_HLEN_OFS 2
+#define DHCP_HOPS_OFS 3
+#define DHCP_XID_OFS 4
+#define DHCP_SECS_OFS 8
+#define DHCP_FLAGS_OFS 10
+#define DHCP_CIADDR_OFS 12
+#define DHCP_YIADDR_OFS 16
+#define DHCP_SIADDR_OFS 20
+#define DHCP_GIADDR_OFS 24
+#define DHCP_CHADDR_OFS 28
+#define DHCP_SNAME_OFS 44
+#define DHCP_FILE_OFS 108
+#define DHCP_MSG_LEN 236
+
+#define DHCP_COOKIE_OFS DHCP_MSG_LEN
+#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
+
+#define DHCP_CLIENT_PORT 68
+#define DHCP_SERVER_PORT 67
+
+/** DHCP client states */
+#define DHCP_OFF 0
+#define DHCP_REQUESTING 1
+#define DHCP_INIT 2
+#define DHCP_REBOOTING 3
+#define DHCP_REBINDING 4
+#define DHCP_RENEWING 5
+#define DHCP_SELECTING 6
+#define DHCP_INFORMING 7
+#define DHCP_CHECKING 8
+#define DHCP_PERMANENT 9
+#define DHCP_BOUND 10
+/** not yet implemented #define DHCP_RELEASING 11 */
+#define DHCP_BACKING_OFF 12
+
+/** AUTOIP cooperatation flags */
+#define DHCP_AUTOIP_COOP_STATE_OFF 0
+#define DHCP_AUTOIP_COOP_STATE_ON 1
+
+#define DHCP_BOOTREQUEST 1
+#define DHCP_BOOTREPLY 2
+
+/** DHCP message types */
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER 2
+#define DHCP_REQUEST 3
+#define DHCP_DECLINE 4
+#define DHCP_ACK 5
+#define DHCP_NAK 6
+#define DHCP_RELEASE 7
+#define DHCP_INFORM 8
+
+/** DHCP hardware type, currently only ethernet is supported */
+#define DHCP_HTYPE_ETH 1
+
+#define DHCP_MAGIC_COOKIE 0x63825363UL
+
+/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
+
+/** BootP options */
+#define DHCP_OPTION_PAD 0
+#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
+#define DHCP_OPTION_ROUTER 3
+#define DHCP_OPTION_DNS_SERVER 6
+#define DHCP_OPTION_HOSTNAME 12
+#define DHCP_OPTION_IP_TTL 23
+#define DHCP_OPTION_MTU 26
+#define DHCP_OPTION_BROADCAST 28
+#define DHCP_OPTION_TCP_TTL 37
+#define DHCP_OPTION_END 255
+
+/** DHCP options */
+#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
+#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
+#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
+
+#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
+#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
+
+#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
+
+#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
+#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
+
+#define DHCP_OPTION_T1 58 /* T1 renewal time */
+#define DHCP_OPTION_T2 59 /* T2 rebinding time */
+#define DHCP_OPTION_US 60
+#define DHCP_OPTION_CLIENT_ID 61
+#define DHCP_OPTION_TFTP_SERVERNAME 66
+#define DHCP_OPTION_BOOTFILE 67
+
+/** possible combinations of overloading the file and sname fields with options */
+#define DHCP_OVERLOAD_NONE 0
+#define DHCP_OVERLOAD_FILE 1
+#define DHCP_OVERLOAD_SNAME 2
+#define DHCP_OVERLOAD_SNAME_FILE 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_DHCP */
+
+#endif /*__LWIP_DHCP_H__*/
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dns.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dns.h
new file mode 100644
index 0000000000..6c7d9b0739
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/dns.h
@@ -0,0 +1,124 @@
+/**
+ * lwip DNS resolver header file.
+
+ * Author: Jim Pettinato
+ * April 2007
+
+ * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
+ *
+ * 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 __LWIP_DNS_H__
+#define __LWIP_DNS_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** DNS timer period */
+#define DNS_TMR_INTERVAL 1000
+
+/** DNS field TYPE used for "Resource Records" */
+#define DNS_RRTYPE_A 1 /* a host address */
+#define DNS_RRTYPE_NS 2 /* an authoritative name server */
+#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
+#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
+#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
+#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
+#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
+#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
+#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
+#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
+#define DNS_RRTYPE_WKS 11 /* a well known service description */
+#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
+#define DNS_RRTYPE_HINFO 13 /* host information */
+#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
+#define DNS_RRTYPE_MX 15 /* mail exchange */
+#define DNS_RRTYPE_TXT 16 /* text strings */
+
+/** DNS field CLASS used for "Resource Records" */
+#define DNS_RRCLASS_IN 1 /* the Internet */
+#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
+#define DNS_RRCLASS_CH 3 /* the CHAOS class */
+#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
+#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
+
+/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
+ that include memp.h, and that would possibly break portability (since socket.h defines some types
+ and constants possibly already define by the OS).
+ Calculation rule:
+ sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
+#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
+
+#if DNS_LOCAL_HOSTLIST
+/** struct used for local host-list */
+struct local_hostlist_entry {
+ /** static hostname */
+ const char *name;
+ /** static host address in network byteorder */
+ ip_addr_t addr;
+ struct local_hostlist_entry *next;
+};
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
+#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
+#endif
+#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/** Callback which is invoked when a hostname is found.
+ * A function of this type must be implemented by the application using the DNS resolver.
+ * @param name pointer to the name that was looked up.
+ * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
+ * or NULL if the name could not be found (or on any other error).
+ * @param callback_arg a user-specified callback argument passed to dns_gethostbyname
+*/
+typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
+
+void dns_init(void);
+void dns_tmr(void);
+void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
+ip_addr_t dns_getserver(u8_t numdns);
+err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
+ dns_found_callback found, void *callback_arg);
+
+#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
+err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
+#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_DNS */
+
+#endif /* __LWIP_DNS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/err.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/err.h
new file mode 100644
index 0000000000..ac907729fc
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/err.h
@@ -0,0 +1,85 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_ERR_H__
+#define __LWIP_ERR_H__
+
+#include "lwip/opt.h"
+#include "lwip/arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Define LWIP_ERR_T in cc.h if you want to use
+ * a different type for your platform (must be signed). */
+#ifdef LWIP_ERR_T
+typedef LWIP_ERR_T err_t;
+#else /* LWIP_ERR_T */
+typedef s8_t err_t;
+#endif /* LWIP_ERR_T*/
+
+/* Definitions for error constants. */
+
+#define ERR_OK 0 /* No error, everything OK. */
+#define ERR_MEM -1 /* Out of memory error. */
+#define ERR_BUF -2 /* Buffer error. */
+#define ERR_TIMEOUT -3 /* Timeout. */
+#define ERR_RTE -4 /* Routing problem. */
+#define ERR_INPROGRESS -5 /* Operation in progress */
+#define ERR_VAL -6 /* Illegal value. */
+#define ERR_WOULDBLOCK -7 /* Operation would block. */
+#define ERR_USE -8 /* Address in use. */
+#define ERR_ISCONN -9 /* Already connected. */
+
+#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
+
+#define ERR_ABRT -10 /* Connection aborted. */
+#define ERR_RST -11 /* Connection reset. */
+#define ERR_CLSD -12 /* Connection closed. */
+#define ERR_CONN -13 /* Not connected. */
+
+#define ERR_ARG -14 /* Illegal argument. */
+
+#define ERR_IF -15 /* Low-level netif error */
+
+
+#ifdef LWIP_DEBUG
+extern const char *lwip_strerr(err_t err);
+#else
+#define lwip_strerr(x) ""
+#endif /* LWIP_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_ERR_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/init.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/init.h
new file mode 100644
index 0000000000..77dcdfc775
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/init.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: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_INIT_H__
+#define __LWIP_INIT_H__
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** X.x.x: Major version of the stack */
+#define LWIP_VERSION_MAJOR 1U
+/** x.X.x: Minor version of the stack */
+#define LWIP_VERSION_MINOR 4U
+/** x.x.X: Revision of the stack */
+#define LWIP_VERSION_REVISION 0U
+/** For release candidates, this is set to 1..254
+ * For official releases, this is set to 255 (LWIP_RC_RELEASE)
+ * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
+#define LWIP_VERSION_RC 255U
+
+/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
+#define LWIP_RC_RELEASE 255U
+/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
+#define LWIP_RC_DEVELOPMENT 0U
+
+#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
+#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
+#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
+
+/** Provides the version of the stack */
+#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
+ LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
+
+/* Modules initialization */
+void lwip_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_INIT_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/mem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/mem.h
new file mode 100644
index 0000000000..f4b2f7c010
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/mem.h
@@ -0,0 +1,123 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_MEM_H__
+#define __LWIP_MEM_H__
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if MEM_LIBC_MALLOC
+
+#include <stddef.h> /* for size_t */
+
+typedef size_t mem_size_t;
+
+/* aliases for C library malloc() */
+#define mem_init()
+/* in case C library malloc() needs extra protection,
+ * allow these defines to be overridden.
+ */
+#ifndef mem_free
+#define mem_free free
+#endif
+#ifndef mem_malloc
+#define mem_malloc malloc
+#endif
+#ifndef mem_calloc
+#define mem_calloc calloc
+#endif
+/* Since there is no C library allocation function to shrink memory without
+ moving it, define this to nothing. */
+#ifndef mem_trim
+#define mem_trim(mem, size) (mem)
+#endif
+#else /* MEM_LIBC_MALLOC */
+
+/* MEM_SIZE would have to be aligned, but using 64000 here instead of
+ * 65535 leaves some room for alignment...
+ */
+#if MEM_SIZE > 64000L
+typedef u32_t mem_size_t;
+#define MEM_SIZE_F U32_F
+#else
+typedef u16_t mem_size_t;
+#define MEM_SIZE_F U16_F
+#endif /* MEM_SIZE > 64000 */
+
+#if MEM_USE_POOLS
+/** mem_init is not used when using pools instead of a heap */
+#define mem_init()
+/** mem_trim is not used when using pools instead of a heap:
+ we can't free part of a pool element and don't want to copy the rest */
+#define mem_trim(mem, size) (mem)
+#else /* MEM_USE_POOLS */
+/* lwIP alternative malloc */
+void mem_init(void);
+void *mem_trim(void *mem, mem_size_t size);
+#endif /* MEM_USE_POOLS */
+void *mem_malloc(mem_size_t size);
+void *mem_calloc(mem_size_t count, mem_size_t size);
+void mem_free(void *mem);
+#endif /* MEM_LIBC_MALLOC */
+
+/** Calculate memory size for an aligned buffer - returns the next highest
+ * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
+ * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
+ */
+#ifndef LWIP_MEM_ALIGN_SIZE
+#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
+#endif
+
+/** Calculate safe memory size for an aligned buffer when using an unaligned
+ * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the
+ * start (e.g. if buffer is u8_t[] and actual data will be u32_t*)
+ */
+#ifndef LWIP_MEM_ALIGN_BUFFER
+#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))
+#endif
+
+/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT
+ * so that ADDR % MEM_ALIGNMENT == 0
+ */
+#ifndef LWIP_MEM_ALIGN
+#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_MEM_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp.h
new file mode 100644
index 0000000000..f0d0739943
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp.h
@@ -0,0 +1,116 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#ifndef __LWIP_MEMP_H__
+#define __LWIP_MEMP_H__
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */
+typedef enum {
+#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
+#include "lwip/memp_std.h"
+ MEMP_MAX
+} memp_t;
+
+#if MEM_USE_POOLS
+/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
+typedef enum {
+ /* Get the first (via:
+ MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/
+ MEMP_POOL_HELPER_FIRST = ((u8_t)
+#define LWIP_MEMPOOL(name,num,size,desc)
+#define LWIP_MALLOC_MEMPOOL_START 1
+#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
+#define LWIP_MALLOC_MEMPOOL_END
+#include "lwip/memp_std.h"
+ ) ,
+ /* Get the last (via:
+ MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */
+ MEMP_POOL_HELPER_LAST = ((u8_t)
+#define LWIP_MEMPOOL(name,num,size,desc)
+#define LWIP_MALLOC_MEMPOOL_START
+#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
+#define LWIP_MALLOC_MEMPOOL_END 1
+#include "lwip/memp_std.h"
+ )
+} memp_pool_helper_t;
+
+/* The actual start and stop values are here (cast them over)
+ We use this helper type and these defines so we can avoid using const memp_t values */
+#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
+#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
+#endif /* MEM_USE_POOLS */
+
+#if MEMP_MEM_MALLOC || MEM_USE_POOLS
+extern const u16_t memp_sizes[MEMP_MAX];
+#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
+
+#if MEMP_MEM_MALLOC
+
+#include "mem.h"
+
+#define memp_init()
+#define memp_malloc(type) mem_malloc(memp_sizes[type])
+#define memp_free(type, mem) mem_free(mem)
+
+#else /* MEMP_MEM_MALLOC */
+
+#if MEM_USE_POOLS
+/** This structure is used to save the pool one element came from. */
+struct memp_malloc_helper
+{
+ memp_t poolnr;
+};
+#endif /* MEM_USE_POOLS */
+
+void memp_init(void);
+
+#if MEMP_OVERFLOW_CHECK
+void *memp_malloc_fn(memp_t type, const char* file, const int line);
+#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)
+#else
+void *memp_malloc(memp_t type);
+#endif
+void memp_free(memp_t type, void *mem);
+
+#endif /* MEMP_MEM_MALLOC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_MEMP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp_std.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp_std.h
new file mode 100644
index 0000000000..6ce408fb02
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/memp_std.h
@@ -0,0 +1,122 @@
+/*
+ * SETUP: Make sure we define everything we will need.
+ *
+ * We have create three types of pools:
+ * 1) MEMPOOL - standard pools
+ * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c
+ * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct
+ *
+ * If the include'r doesn't require any special treatment of each of the types
+ * above, then will declare #2 & #3 to be just standard mempools.
+ */
+#ifndef LWIP_MALLOC_MEMPOOL
+/* This treats "malloc pools" just like any other pool.
+ The pools are a little bigger to provide 'size' as the amount of user data. */
+#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
+#define LWIP_MALLOC_MEMPOOL_START
+#define LWIP_MALLOC_MEMPOOL_END
+#endif /* LWIP_MALLOC_MEMPOOL */
+
+#ifndef LWIP_PBUF_MEMPOOL
+/* This treats "pbuf pools" just like any other pool.
+ * Allocates buffers for a pbuf struct AND a payload size */
+#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc)
+#endif /* LWIP_PBUF_MEMPOOL */
+
+
+/*
+ * A list of internal pools used by LWIP.
+ *
+ * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)
+ * creates a pool name MEMP_pool_name. description is used in stats.c
+ */
+#if LWIP_RAW
+LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB")
+#endif /* LWIP_RAW */
+
+#if LWIP_UDP
+LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB")
+#endif /* LWIP_UDP */
+
+#if LWIP_TCP
+LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB")
+LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
+LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG")
+#endif /* LWIP_TCP */
+
+#if IP_REASSEMBLY
+LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
+#endif /* IP_REASSEMBLY */
+#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
+#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
+
+#if LWIP_NETCONN
+LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
+LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN")
+#endif /* LWIP_NETCONN */
+
+#if NO_SYS==0
+LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
+#if !LWIP_TCPIP_CORE_LOCKING_INPUT
+LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
+#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
+#endif /* NO_SYS==0 */
+
+#if ARP_QUEUEING
+LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
+#endif /* ARP_QUEUEING */
+
+#if LWIP_IGMP
+LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
+#endif /* LWIP_IGMP */
+
+#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
+LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
+#endif /* LWIP_TIMERS */
+
+#if LWIP_SNMP
+LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
+LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
+LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND")
+LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE")
+#endif /* LWIP_SNMP */
+#if LWIP_DNS && LWIP_SOCKET
+LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB")
+#endif /* LWIP_DNS && LWIP_SOCKET */
+#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST")
+#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+#if PPP_SUPPORT && PPPOE_SUPPORT
+LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
+#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
+
+/*
+ * A list of pools of pbuf's used by LWIP.
+ *
+ * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)
+ * creates a pool name MEMP_pool_name. description is used in stats.c
+ * This allocates enough space for the pbuf struct and a payload.
+ * (Example: pbuf_payload_size=0 allocates only size for the struct)
+ */
+LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM")
+LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL")
+
+
+/*
+ * Allow for user-defined pools; this must be explicitly set in lwipopts.h
+ * since the default is to NOT look for lwippools.h
+ */
+#if MEMP_USE_CUSTOM_POOLS
+#include "lwippools.h"
+#endif /* MEMP_USE_CUSTOM_POOLS */
+
+/*
+ * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later
+ * (#undef is ignored for something that is not defined)
+ */
+#undef LWIP_MEMPOOL
+#undef LWIP_MALLOC_MEMPOOL
+#undef LWIP_MALLOC_MEMPOOL_START
+#undef LWIP_MALLOC_MEMPOOL_END
+#undef LWIP_PBUF_MEMPOOL
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netbuf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netbuf.h
new file mode 100644
index 0000000000..7d247d71b6
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netbuf.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_NETBUF_H__
+#define __LWIP_NETBUF_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This netbuf has dest-addr/port set */
+#define NETBUF_FLAG_DESTADDR 0x01
+/** This netbuf includes a checksum */
+#define NETBUF_FLAG_CHKSUM 0x02
+
+struct netbuf {
+ struct pbuf *p, *ptr;
+ ip_addr_t addr;
+ u16_t port;
+#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
+#if LWIP_CHECKSUM_ON_COPY
+ u8_t flags;
+#endif /* LWIP_CHECKSUM_ON_COPY */
+ u16_t toport_chksum;
+#if LWIP_NETBUF_RECVINFO
+ ip_addr_t toaddr;
+#endif /* LWIP_NETBUF_RECVINFO */
+#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
+};
+
+/* Network buffer functions: */
+struct netbuf * netbuf_new (void);
+void netbuf_delete (struct netbuf *buf);
+void * netbuf_alloc (struct netbuf *buf, u16_t size);
+void netbuf_free (struct netbuf *buf);
+err_t netbuf_ref (struct netbuf *buf,
+ const void *dataptr, u16_t size);
+void netbuf_chain (struct netbuf *head,
+ struct netbuf *tail);
+
+err_t netbuf_data (struct netbuf *buf,
+ void **dataptr, u16_t *len);
+s8_t netbuf_next (struct netbuf *buf);
+void netbuf_first (struct netbuf *buf);
+
+
+#define netbuf_copy_partial(buf, dataptr, len, offset) \
+ pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
+#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
+#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
+#define netbuf_len(buf) ((buf)->p->tot_len)
+#define netbuf_fromaddr(buf) (&((buf)->addr))
+#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr)
+#define netbuf_fromport(buf) ((buf)->port)
+#if LWIP_NETBUF_RECVINFO
+#define netbuf_destaddr(buf) (&((buf)->toaddr))
+#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr)
+#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
+#endif /* LWIP_NETBUF_RECVINFO */
+#if LWIP_CHECKSUM_ON_COPY
+#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \
+ (buf)->toport_chksum = chksum; } while(0)
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_NETBUF_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netdb.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netdb.h
new file mode 100644
index 0000000000..7587e2f2d1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netdb.h
@@ -0,0 +1,124 @@
+/*
+ * 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_NETDB_H__
+#define __LWIP_NETDB_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS && LWIP_SOCKET
+
+#include <stddef.h> /* for size_t */
+
+#include "lwip/inet.h"
+#include "lwip/sockets.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* some rarely used options */
+#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
+#define LWIP_DNS_API_DECLARE_H_ERRNO 1
+#endif
+
+#ifndef LWIP_DNS_API_DEFINE_ERRORS
+#define LWIP_DNS_API_DEFINE_ERRORS 1
+#endif
+
+#ifndef LWIP_DNS_API_DECLARE_STRUCTS
+#define LWIP_DNS_API_DECLARE_STRUCTS 1
+#endif
+
+#if LWIP_DNS_API_DEFINE_ERRORS
+/** Errors used by the DNS API functions, h_errno can be one of them */
+#define EAI_NONAME 200
+#define EAI_SERVICE 201
+#define EAI_FAIL 202
+#define EAI_MEMORY 203
+
+#define HOST_NOT_FOUND 210
+#define NO_DATA 211
+#define NO_RECOVERY 212
+#define TRY_AGAIN 213
+#endif /* LWIP_DNS_API_DEFINE_ERRORS */
+
+#if LWIP_DNS_API_DECLARE_STRUCTS
+struct hostent {
+ char *h_name; /* Official name of the host. */
+ char **h_aliases; /* A pointer to an array of pointers to alternative host names,
+ terminated by a null pointer. */
+ int h_addrtype; /* Address type. */
+ int h_length; /* The length, in bytes, of the address. */
+ char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
+ network byte order) for the host, terminated by a null pointer. */
+#define h_addr h_addr_list[0] /* for backward compatibility */
+};
+
+struct addrinfo {
+ int ai_flags; /* Input flags. */
+ int ai_family; /* Address family of socket. */
+ int ai_socktype; /* Socket type. */
+ int ai_protocol; /* Protocol of socket. */
+ socklen_t ai_addrlen; /* Length of socket address. */
+ struct sockaddr *ai_addr; /* Socket address of socket. */
+ char *ai_canonname; /* Canonical name of service location. */
+ struct addrinfo *ai_next; /* Pointer to next in list. */
+};
+#endif /* LWIP_DNS_API_DECLARE_STRUCTS */
+
+#if LWIP_DNS_API_DECLARE_H_ERRNO
+/* application accessable error code set by the DNS API functions */
+extern int h_errno;
+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/
+
+struct hostent *lwip_gethostbyname(const char *name);
+int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop);
+void lwip_freeaddrinfo(struct addrinfo *ai);
+int lwip_getaddrinfo(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+
+#if LWIP_COMPAT_SOCKETS
+#define gethostbyname(name) lwip_gethostbyname(name)
+#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
+ lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
+#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
+#define getaddrinfo(nodname, servname, hints, res) \
+ lwip_getaddrinfo(nodname, servname, hints, res)
+#endif /* LWIP_COMPAT_SOCKETS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_DNS && LWIP_SOCKET */
+
+#endif /* __LWIP_NETDB_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netif.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netif.h
new file mode 100644
index 0000000000..a8790b5f6a
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netif.h
@@ -0,0 +1,315 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_NETIF_H__
+#define __LWIP_NETIF_H__
+
+#include "lwip/opt.h"
+
+#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
+
+#include "lwip/err.h"
+
+#include "lwip/ip_addr.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#if LWIP_DHCP
+struct dhcp;
+#endif
+#if LWIP_AUTOIP
+struct autoip;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Throughout this file, IP addresses are expected to be in
+ * the same byte order as in IP_PCB. */
+
+/** must be the maximum of all used hardware address lengths
+ across all types of interfaces in use */
+#define NETIF_MAX_HWADDR_LEN 6U
+
+/** Whether the network interface is 'up'. This is
+ * a software flag used to control whether this network
+ * interface is enabled and processes traffic.
+ * It is set by the startup code (for static IP configuration) or
+ * by dhcp/autoip when an address has been assigned.
+ */
+#define NETIF_FLAG_UP 0x01U
+/** If set, the netif has broadcast capability.
+ * Set by the netif driver in its init function. */
+#define NETIF_FLAG_BROADCAST 0x02U
+/** If set, the netif is one end of a point-to-point connection.
+ * Set by the netif driver in its init function. */
+#define NETIF_FLAG_POINTTOPOINT 0x04U
+/** If set, the interface is configured using DHCP.
+ * Set by the DHCP code when starting or stopping DHCP. */
+#define NETIF_FLAG_DHCP 0x08U
+/** If set, the interface has an active link
+ * (set by the network interface driver).
+ * Either set by the netif driver in its init function (if the link
+ * is up at that time) or at a later point once the link comes up
+ * (if link detection is supported by the hardware). */
+#define NETIF_FLAG_LINK_UP 0x10U
+/** If set, the netif is an ethernet device using ARP.
+ * Set by the netif driver in its init function.
+ * Used to check input packet types and use of DHCP. */
+#define NETIF_FLAG_ETHARP 0x20U
+/** If set, the netif is an ethernet device. It might not use
+ * ARP or TCP/IP if it is used for PPPoE only.
+ */
+#define NETIF_FLAG_ETHERNET 0x40U
+/** If set, the netif has IGMP capability.
+ * Set by the netif driver in its init function. */
+#define NETIF_FLAG_IGMP 0x80U
+
+/** Function prototype for netif init functions. Set up flags and output/linkoutput
+ * callback functions in this function.
+ *
+ * @param netif The netif to initialize
+ */
+typedef err_t (*netif_init_fn)(struct netif *netif);
+/** Function prototype for netif->input functions. This function is saved as 'input'
+ * callback function in the netif struct. Call it when a packet has been received.
+ *
+ * @param p The received packet, copied into a pbuf
+ * @param inp The netif which received the packet
+ */
+typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
+/** Function prototype for netif->output functions. Called by lwIP when a packet
+ * shall be sent. For ethernet netif, set this to 'etharp_output' and set
+ * 'linkoutput'.
+ *
+ * @param netif The netif which shall send a packet
+ * @param p The packet to send (p->payload points to IP header)
+ * @param ipaddr The IP address to which the packet shall be sent
+ */
+typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
+ ip_addr_t *ipaddr);
+/** Function prototype for netif->linkoutput functions. Only used for ethernet
+ * netifs. This function is called by ARP when a packet shall be sent.
+ *
+ * @param netif The netif which shall send a packet
+ * @param p The packet to send (raw ethernet packet)
+ */
+typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
+/** Function prototype for netif status- or link-callback functions. */
+typedef void (*netif_status_callback_fn)(struct netif *netif);
+/** Function prototype for netif igmp_mac_filter functions */
+typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
+ ip_addr_t *group, u8_t action);
+
+/** Generic data structure used for all lwIP network interfaces.
+ * The following fields should be filled in by the initialization
+ * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
+struct netif {
+ /** pointer to next in linked list */
+ struct netif *next;
+
+ /** IP address configuration in network byte order */
+ ip_addr_t ip_addr;
+ ip_addr_t netmask;
+ ip_addr_t gw;
+
+ /** This function is called by the network device driver
+ * to pass a packet up the TCP/IP stack. */
+ netif_input_fn input;
+ /** This function is called by the IP module when it wants
+ * to send a packet on the interface. This function typically
+ * first resolves the hardware address, then sends the packet. */
+ netif_output_fn output;
+ /** This function is called by the ARP module when it wants
+ * to send a packet on the interface. This function outputs
+ * the pbuf as-is on the link medium. */
+ netif_linkoutput_fn linkoutput;
+#if LWIP_NETIF_STATUS_CALLBACK
+ /** This function is called when the netif state is set to up or down
+ */
+ netif_status_callback_fn status_callback;
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+#if LWIP_NETIF_LINK_CALLBACK
+ /** This function is called when the netif link is set to up or down
+ */
+ netif_status_callback_fn link_callback;
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+ /** This field can be set by the device driver and could point
+ * to state information for the device. */
+ void *state;
+#if LWIP_DHCP
+ /** the DHCP client state information for this netif */
+ struct dhcp *dhcp;
+#endif /* LWIP_DHCP */
+#if LWIP_AUTOIP
+ /** the AutoIP client state information for this netif */
+ struct autoip *autoip;
+#endif
+#if LWIP_NETIF_HOSTNAME
+ /* the hostname for this netif, NULL is a valid value */
+ char* hostname;
+#endif /* LWIP_NETIF_HOSTNAME */
+ /** maximum transfer unit (in bytes) */
+ u16_t mtu;
+ /** number of bytes used in hwaddr */
+ u8_t hwaddr_len;
+ /** link level hardware address of this interface */
+ u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
+ /** flags (see NETIF_FLAG_ above) */
+ u8_t flags;
+ /** descriptive abbreviation */
+ char name[2];
+ /** number of this interface */
+ u8_t num;
+#if LWIP_SNMP
+ /** link type (from "snmp_ifType" enum from snmp.h) */
+ u8_t link_type;
+ /** (estimate) link speed */
+ u32_t link_speed;
+ /** timestamp at last change made (up/down) */
+ u32_t ts;
+ /** counters */
+ u32_t ifinoctets;
+ u32_t ifinucastpkts;
+ u32_t ifinnucastpkts;
+ u32_t ifindiscards;
+ u32_t ifoutoctets;
+ u32_t ifoutucastpkts;
+ u32_t ifoutnucastpkts;
+ u32_t ifoutdiscards;
+#endif /* LWIP_SNMP */
+#if LWIP_IGMP
+ /** This function could be called to add or delete a entry in the multicast
+ filter table of the ethernet MAC.*/
+ netif_igmp_mac_filter_fn igmp_mac_filter;
+#endif /* LWIP_IGMP */
+#if LWIP_NETIF_HWADDRHINT
+ u8_t *addr_hint;
+#endif /* LWIP_NETIF_HWADDRHINT */
+#if ENABLE_LOOPBACK
+ /* List of packets to be queued for ourselves. */
+ struct pbuf *loop_first;
+ struct pbuf *loop_last;
+#if LWIP_LOOPBACK_MAX_PBUFS
+ u16_t loop_cnt_current;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+#endif /* ENABLE_LOOPBACK */
+};
+
+#if LWIP_SNMP
+#define NETIF_INIT_SNMP(netif, type, speed) \
+ /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
+ (netif)->link_type = (type); \
+ /* your link speed here (units: bits per second) */ \
+ (netif)->link_speed = (speed); \
+ (netif)->ts = 0; \
+ (netif)->ifinoctets = 0; \
+ (netif)->ifinucastpkts = 0; \
+ (netif)->ifinnucastpkts = 0; \
+ (netif)->ifindiscards = 0; \
+ (netif)->ifoutoctets = 0; \
+ (netif)->ifoutucastpkts = 0; \
+ (netif)->ifoutnucastpkts = 0; \
+ (netif)->ifoutdiscards = 0
+#else /* LWIP_SNMP */
+#define NETIF_INIT_SNMP(netif, type, speed)
+#endif /* LWIP_SNMP */
+
+
+/** The list of network interfaces. */
+extern struct netif *netif_list;
+/** The default network interface. */
+extern struct netif *netif_default;
+
+void netif_init(void);
+
+struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+ ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
+
+void
+netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+ ip_addr_t *gw);
+void netif_remove(struct netif * netif);
+
+/* Returns a network interface given its name. The name is of the form
+ "et0", where the first two letters are the "name" field in the
+ netif structure, and the digit is in the num field in the same
+ structure. */
+struct netif *netif_find(char *name);
+
+void netif_set_default(struct netif *netif);
+
+void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
+void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
+void netif_set_gw(struct netif *netif, ip_addr_t *gw);
+
+void netif_set_up(struct netif *netif);
+void netif_set_down(struct netif *netif);
+/** Ask if an interface is up */
+#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)
+
+#if LWIP_NETIF_STATUS_CALLBACK
+void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+
+void netif_set_link_up(struct netif *netif);
+void netif_set_link_down(struct netif *netif);
+/** Ask if a link is up */
+#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)
+
+#if LWIP_NETIF_LINK_CALLBACK
+void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback);
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#if LWIP_NETIF_HOSTNAME
+#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)
+#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)
+#endif /* LWIP_NETIF_HOSTNAME */
+
+#if LWIP_IGMP
+#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)
+#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)
+#endif /* LWIP_IGMP */
+
+#if ENABLE_LOOPBACK
+err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip);
+void netif_poll(struct netif *netif);
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+void netif_poll_all(void);
+#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_NETIF_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netifapi.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netifapi.h
new file mode 100644
index 0000000000..33318efaf6
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/netifapi.h
@@ -0,0 +1,108 @@
+/*
+ * 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_NETIFAPI_H__
+#define __LWIP_NETIFAPI_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/sys.h"
+#include "lwip/netif.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*netifapi_void_fn)(struct netif *netif);
+typedef err_t (*netifapi_errt_fn)(struct netif *netif);
+
+struct netifapi_msg_msg {
+#if !LWIP_TCPIP_CORE_LOCKING
+ sys_sem_t sem;
+#endif /* !LWIP_TCPIP_CORE_LOCKING */
+ err_t err;
+ struct netif *netif;
+ union {
+ struct {
+ ip_addr_t *ipaddr;
+ ip_addr_t *netmask;
+ ip_addr_t *gw;
+ void *state;
+ netif_init_fn init;
+ netif_input_fn input;
+ } add;
+ struct {
+ netifapi_void_fn voidfunc;
+ netifapi_errt_fn errtfunc;
+ } common;
+ } msg;
+};
+
+struct netifapi_msg {
+ void (* function)(struct netifapi_msg_msg *msg);
+ struct netifapi_msg_msg msg;
+};
+
+
+/* API for application */
+err_t netifapi_netif_add ( struct netif *netif,
+ ip_addr_t *ipaddr,
+ ip_addr_t *netmask,
+ ip_addr_t *gw,
+ void *state,
+ netif_init_fn init,
+ netif_input_fn input);
+
+err_t netifapi_netif_set_addr ( struct netif *netif,
+ ip_addr_t *ipaddr,
+ ip_addr_t *netmask,
+ ip_addr_t *gw );
+
+err_t netifapi_netif_common ( struct netif *netif,
+ netifapi_void_fn voidfunc,
+ netifapi_errt_fn errtfunc);
+
+#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
+#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)
+#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL)
+#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)
+#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start)
+#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL)
+#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start)
+#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_NETIF_API */
+
+#endif /* __LWIP_NETIFAPI_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/opt.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/opt.h
new file mode 100644
index 0000000000..a1b876583f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/opt.h
@@ -0,0 +1,2043 @@
+/**
+ * @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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_OPT_H__
+#define __LWIP_OPT_H__
+
+/*
+ * Include user defined options first. Anything not defined in these files
+ * will be set to standard values. Override anything you dont 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.
+ */
+#ifndef SYS_LIGHTWEIGHT_PROT
+#define SYS_LIGHTWEIGHT_PROT 0
+#endif
+
+/**
+ * NO_SYS==1: Provides VERY minimal functionality. Otherwise,
+ * use lwIP facilities.
+ */
+#ifndef NO_SYS
+#define NO_SYS 0
+#endif
+
+/**
+ * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
+ * Mainly for compatibility to old versions.
+ */
+#ifndef NO_SYS_NO_TIMERS
+#define NO_SYS_NO_TIMERS 0
+#endif
+
+/**
+ * MEMCPY: override this if you have a faster implementation at hand than the
+ * one included in your C library
+ */
+#ifndef MEMCPY
+#define MEMCPY(dst,src,len) memcpy(dst,src,len)
+#endif
+
+/**
+ * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a
+ * call to memcpy() if the length is known at compile time and is small.
+ */
+#ifndef SMEMCPY
+#define SMEMCPY(dst,src,len) memcpy(dst,src,len)
+#endif
+
+/*
+ ------------------------------------
+ ---------- Memory options ----------
+ ------------------------------------
+*/
+/**
+ * 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.
+ */
+#ifndef MEM_LIBC_MALLOC
+#define MEM_LIBC_MALLOC 0
+#endif
+
+/**
+* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
+* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution
+* speed and usage from interrupts!
+*/
+#ifndef MEMP_MEM_MALLOC
+#define MEMP_MEM_MALLOC 0
+#endif
+
+/**
+ * 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
+ */
+#ifndef MEM_ALIGNMENT
+#define MEM_ALIGNMENT 1
+#endif
+
+/**
+ * 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.
+ */
+#ifndef MEM_SIZE
+#define MEM_SIZE 1600
+#endif
+
+/**
+ * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.
+ * This can be used to individually change the location of each pool.
+ * Default is one big array for all pools
+ */
+#ifndef MEMP_SEPARATE_POOLS
+#define MEMP_SEPARATE_POOLS 0
+#endif
+
+/**
+ * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable
+ * amount of bytes before and after each memp element in every pool and fills
+ * it with a prominent default value.
+ * MEMP_OVERFLOW_CHECK == 0 no checking
+ * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed
+ * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time
+ * memp_malloc() or memp_free() is called (useful but slow!)
+ */
+#ifndef MEMP_OVERFLOW_CHECK
+#define MEMP_OVERFLOW_CHECK 0
+#endif
+
+/**
+ * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make
+ * sure that there are no cycles in the linked lists.
+ */
+#ifndef MEMP_SANITY_CHECK
+#define MEMP_SANITY_CHECK 0
+#endif
+
+/**
+ * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set
+ * of memory pools of various sizes. When mem_malloc is called, an element of
+ * the smallest pool that can provide the length needed is returned.
+ * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled.
+ */
+#ifndef MEM_USE_POOLS
+#define MEM_USE_POOLS 0
+#endif
+
+/**
+ * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next
+ * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more
+ * reliable. */
+#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL
+#define MEM_USE_POOLS_TRY_BIGGER_POOL 0
+#endif
+
+/**
+ * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h
+ * that defines additional pools beyond the "standard" ones required
+ * by lwIP. If you set this to 1, you must have lwippools.h in your
+ * inlude path somewhere.
+ */
+#ifndef MEMP_USE_CUSTOM_POOLS
+#define MEMP_USE_CUSTOM_POOLS 0
+#endif
+
+/**
+ * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from
+ * interrupt context (or another context that doesn't allow waiting for a
+ * semaphore).
+ * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT,
+ * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs
+ * with each loop so that mem_free can run.
+ *
+ * ATTENTION: As you can see from the above description, this leads to dis-/
+ * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc
+ * can need longer.
+ *
+ * If you don't want that, at least for NO_SYS=0, you can still use the following
+ * functions to enqueue a deallocation call which then runs in the tcpip_thread
+ * context:
+ * - pbuf_free_callback(p);
+ * - mem_free_callback(m);
+ */
+#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0
+#endif
+
+/*
+ ------------------------------------------------
+ ---------- 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.
+ */
+#ifndef MEMP_NUM_PBUF
+#define MEMP_NUM_PBUF 16
+#endif
+
+/**
+ * MEMP_NUM_RAW_PCB: Number of raw connection PCBs
+ * (requires the LWIP_RAW option)
+ */
+#ifndef MEMP_NUM_RAW_PCB
+#define MEMP_NUM_RAW_PCB 4
+#endif
+
+/**
+ * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
+ * per active UDP "connection".
+ * (requires the LWIP_UDP option)
+ */
+#ifndef MEMP_NUM_UDP_PCB
+#define MEMP_NUM_UDP_PCB 4
+#endif
+
+/**
+ * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.
+ * (requires the LWIP_TCP option)
+ */
+#ifndef MEMP_NUM_TCP_PCB
+#define MEMP_NUM_TCP_PCB 5
+#endif
+
+/**
+ * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.
+ * (requires the LWIP_TCP option)
+ */
+#ifndef MEMP_NUM_TCP_PCB_LISTEN
+#define MEMP_NUM_TCP_PCB_LISTEN 8
+#endif
+
+/**
+ * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.
+ * (requires the LWIP_TCP option)
+ */
+#ifndef MEMP_NUM_TCP_SEG
+#define MEMP_NUM_TCP_SEG 16
+#endif
+
+/**
+ * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for
+ * reassembly (whole packets, not fragments!)
+ */
+#ifndef MEMP_NUM_REASSDATA
+#define MEMP_NUM_REASSDATA 5
+#endif
+
+/**
+ * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent
+ * (fragments, not whole packets!).
+ * This is only used with IP_FRAG_USES_STATIC_BUF==0 and
+ * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs
+ * where the packet is not yet sent when netif->output returns.
+ */
+#ifndef MEMP_NUM_FRAG_PBUF
+#define MEMP_NUM_FRAG_PBUF 15
+#endif
+
+/**
+ * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
+ * packets (pbufs) that are waiting for an ARP request (to resolve
+ * their destination address) to finish.
+ * (requires the ARP_QUEUEING option)
+ */
+#ifndef MEMP_NUM_ARP_QUEUE
+#define MEMP_NUM_ARP_QUEUE 30
+#endif
+
+/**
+ * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces
+ * can be members et the same time (one per netif - allsystems group -, plus one
+ * per netif membership).
+ * (requires the LWIP_IGMP option)
+ */
+#ifndef MEMP_NUM_IGMP_GROUP
+#define MEMP_NUM_IGMP_GROUP 8
+#endif
+
+/**
+ * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
+ * (requires NO_SYS==0)
+ */
+#ifndef MEMP_NUM_SYS_TIMEOUT
+#define MEMP_NUM_SYS_TIMEOUT 3
+#endif
+
+/**
+ * MEMP_NUM_NETBUF: the number of struct netbufs.
+ * (only needed if you use the sequential API, like api_lib.c)
+ */
+#ifndef MEMP_NUM_NETBUF
+#define MEMP_NUM_NETBUF 2
+#endif
+
+/**
+ * MEMP_NUM_NETCONN: the number of struct netconns.
+ * (only needed if you use the sequential API, like api_lib.c)
+ */
+#ifndef MEMP_NUM_NETCONN
+#define MEMP_NUM_NETCONN 4
+#endif
+
+/**
+ * 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)
+ */
+#ifndef MEMP_NUM_TCPIP_MSG_API
+#define MEMP_NUM_TCPIP_MSG_API 8
+#endif
+
+/**
+ * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used
+ * for incoming packets.
+ * (only needed if you use tcpip.c)
+ */
+#ifndef MEMP_NUM_TCPIP_MSG_INPKT
+#define MEMP_NUM_TCPIP_MSG_INPKT 8
+#endif
+
+/**
+ * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree.
+ */
+#ifndef MEMP_NUM_SNMP_NODE
+#define MEMP_NUM_SNMP_NODE 50
+#endif
+
+/**
+ * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree.
+ * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!
+ */
+#ifndef MEMP_NUM_SNMP_ROOTNODE
+#define MEMP_NUM_SNMP_ROOTNODE 30
+#endif
+
+/**
+ * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to
+ * be changed normally) - 2 of these are used per request (1 for input,
+ * 1 for output)
+ */
+#ifndef MEMP_NUM_SNMP_VARBIND
+#define MEMP_NUM_SNMP_VARBIND 2
+#endif
+
+/**
+ * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used
+ * (does not have to be changed normally) - 3 of these are used per request
+ * (1 for the value read and 2 for OIDs - input and output)
+ */
+#ifndef MEMP_NUM_SNMP_VALUE
+#define MEMP_NUM_SNMP_VALUE 3
+#endif
+
+/**
+ * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls
+ * (before freeing the corresponding memory using lwip_freeaddrinfo()).
+ */
+#ifndef MEMP_NUM_NETDB
+#define MEMP_NUM_NETDB 1
+#endif
+
+/**
+ * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list
+ * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1.
+ */
+#ifndef MEMP_NUM_LOCALHOSTLIST
+#define MEMP_NUM_LOCALHOSTLIST 1
+#endif
+
+/**
+ * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE
+ * interfaces (only used with PPPOE_SUPPORT==1)
+ */
+#ifndef MEMP_NUM_PPPOE_INTERFACES
+#define MEMP_NUM_PPPOE_INTERFACES 1
+#endif
+
+/**
+ * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
+ */
+#ifndef PBUF_POOL_SIZE
+#define PBUF_POOL_SIZE 16
+#endif
+
+/*
+ ---------------------------------
+ ---------- ARP options ----------
+ ---------------------------------
+*/
+/**
+ * LWIP_ARP==1: Enable ARP functionality.
+ */
+#ifndef LWIP_ARP
+#define LWIP_ARP 1
+#endif
+
+/**
+ * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.
+ */
+#ifndef ARP_TABLE_SIZE
+#define ARP_TABLE_SIZE 10
+#endif
+
+/**
+ * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
+ * resolution. By default, only the most recent packet is queued per IP address.
+ * This is sufficient for most protocols and mainly reduces TCP connection
+ * startup time. Set this to 1 if you know your application sends more than one
+ * packet in a row to an IP address that is not in the ARP cache.
+ */
+#ifndef ARP_QUEUEING
+#define ARP_QUEUEING 0
+#endif
+
+/**
+ * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be
+ * updated with the source MAC and IP addresses supplied in the packet.
+ * You may want to disable this if you do not trust LAN peers to have the
+ * correct addresses, or as a limited approach to attempt to handle
+ * spoofing. If disabled, lwIP will need to make a new ARP request if
+ * the peer is not already in the ARP table, adding a little latency.
+ * The peer *is* in the ARP table if it requested our address before.
+ * Also notice that this slows down input processing of every IP packet!
+ */
+#ifndef ETHARP_TRUST_IP_MAC
+#define ETHARP_TRUST_IP_MAC 0
+#endif
+
+/**
+ * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.
+ * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
+ * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
+ * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
+ */
+#ifndef ETHARP_SUPPORT_VLAN
+#define ETHARP_SUPPORT_VLAN 0
+#endif
+
+/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP
+ * might be disabled
+ */
+#ifndef LWIP_ETHERNET
+#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT)
+#endif
+
+/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure
+ * alignment of payload after that header. Since the header is 14 bytes long,
+ * without this padding e.g. addresses in the IP header will not be aligned
+ * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms.
+ */
+#ifndef ETH_PAD_SIZE
+#define ETH_PAD_SIZE 0
+#endif
+
+/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table
+ * entries (using etharp_add_static_entry/etharp_remove_static_entry).
+ */
+#ifndef ETHARP_SUPPORT_STATIC_ENTRIES
+#define ETHARP_SUPPORT_STATIC_ENTRIES 0
+#endif
+
+
+/*
+ --------------------------------
+ ---------- 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.
+ */
+#ifndef IP_FORWARD
+#define IP_FORWARD 0
+#endif
+
+/**
+ * IP_OPTIONS_ALLOWED: 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).
+ */
+#ifndef IP_OPTIONS_ALLOWED
+#define IP_OPTIONS_ALLOWED 1
+#endif
+
+/**
+ * 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.
+ */
+#ifndef IP_REASSEMBLY
+#define IP_REASSEMBLY 1
+#endif
+
+/**
+ * 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.
+ */
+#ifndef IP_FRAG
+#define IP_FRAG 1
+#endif
+
+/**
+ * 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.
+ */
+#ifndef IP_REASS_MAXAGE
+#define IP_REASS_MAXAGE 3
+#endif
+
+/**
+ * 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!
+ */
+#ifndef IP_REASS_MAX_PBUFS
+#define IP_REASS_MAX_PBUFS 10
+#endif
+
+/**
+ * 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 (or with LWIP_NETIF_TX_SINGLE_PBUF==1,
+ * new PBUF_RAM pbufs are used for fragments).
+ * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!
+ */
+#ifndef IP_FRAG_USES_STATIC_BUF
+#define IP_FRAG_USES_STATIC_BUF 0
+#endif
+
+/**
+ * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer
+ * (requires IP_FRAG_USES_STATIC_BUF==1)
+ */
+#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)
+#define IP_FRAG_MAX_MTU 1500
+#endif
+
+/**
+ * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.
+ */
+#ifndef IP_DEFAULT_TTL
+#define IP_DEFAULT_TTL 255
+#endif
+
+/**
+ * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast
+ * filter per pcb on udp and raw send operations. To enable broadcast filter
+ * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1.
+ */
+#ifndef IP_SOF_BROADCAST
+#define IP_SOF_BROADCAST 0
+#endif
+
+/**
+ * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast
+ * filter on recv operations.
+ */
+#ifndef IP_SOF_BROADCAST_RECV
+#define IP_SOF_BROADCAST_RECV 0
+#endif
+
+/*
+ ----------------------------------
+ ---------- ICMP options ----------
+ ----------------------------------
+*/
+/**
+ * LWIP_ICMP==1: Enable ICMP module inside the IP stack.
+ * Be careful, disable that make your product non-compliant to RFC1122
+ */
+#ifndef LWIP_ICMP
+#define LWIP_ICMP 1
+#endif
+
+/**
+ * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.
+ */
+#ifndef ICMP_TTL
+#define ICMP_TTL (IP_DEFAULT_TTL)
+#endif
+
+/**
+ * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only)
+ */
+#ifndef LWIP_BROADCAST_PING
+#define LWIP_BROADCAST_PING 0
+#endif
+
+/**
+ * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only)
+ */
+#ifndef LWIP_MULTICAST_PING
+#define LWIP_MULTICAST_PING 0
+#endif
+
+/*
+ ---------------------------------
+ ---------- RAW options ----------
+ ---------------------------------
+*/
+/**
+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
+ */
+#ifndef LWIP_RAW
+#define LWIP_RAW 1
+#endif
+
+/**
+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
+ */
+#ifndef RAW_TTL
+#define RAW_TTL (IP_DEFAULT_TTL)
+#endif
+
+/*
+ ----------------------------------
+ ---------- DHCP options ----------
+ ----------------------------------
+*/
+/**
+ * LWIP_DHCP==1: Enable DHCP module.
+ */
+#ifndef LWIP_DHCP
+#define LWIP_DHCP 0
+#endif
+
+/**
+ * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.
+ */
+#ifndef DHCP_DOES_ARP_CHECK
+#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP))
+#endif
+
+/*
+ ------------------------------------
+ ---------- AUTOIP options ----------
+ ------------------------------------
+*/
+/**
+ * LWIP_AUTOIP==1: Enable AUTOIP module.
+ */
+#ifndef LWIP_AUTOIP
+#define LWIP_AUTOIP 0
+#endif
+
+/**
+ * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on
+ * the same interface at the same time.
+ */
+#ifndef LWIP_DHCP_AUTOIP_COOP
+#define LWIP_DHCP_AUTOIP_COOP 0
+#endif
+
+/**
+ * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes
+ * that should be sent before falling back on AUTOIP. This can be set
+ * as low as 1 to get an AutoIP address very quickly, but you should
+ * be prepared to handle a changing IP address when DHCP overrides
+ * AutoIP.
+ */
+#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES
+#define LWIP_DHCP_AUTOIP_COOP_TRIES 9
+#endif
+
+/*
+ ----------------------------------
+ ---------- SNMP options ----------
+ ----------------------------------
+*/
+/**
+ * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP
+ * transport.
+ */
+#ifndef LWIP_SNMP
+#define LWIP_SNMP 0
+#endif
+
+/**
+ * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will
+ * allow. At least one request buffer is required.
+ * Does not have to be changed unless external MIBs answer request asynchronously
+ */
+#ifndef SNMP_CONCURRENT_REQUESTS
+#define SNMP_CONCURRENT_REQUESTS 1
+#endif
+
+/**
+ * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap
+ * destination is required
+ */
+#ifndef SNMP_TRAP_DESTINATIONS
+#define SNMP_TRAP_DESTINATIONS 1
+#endif
+
+/**
+ * SNMP_PRIVATE_MIB:
+ * When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB.
+ */
+#ifndef SNMP_PRIVATE_MIB
+#define SNMP_PRIVATE_MIB 0
+#endif
+
+/**
+ * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not
+ * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).
+ * Unsafe requests are disabled by default!
+ */
+#ifndef SNMP_SAFE_REQUESTS
+#define SNMP_SAFE_REQUESTS 1
+#endif
+
+/**
+ * The maximum length of strings used. This affects the size of
+ * MEMP_SNMP_VALUE elements.
+ */
+#ifndef SNMP_MAX_OCTET_STRING_LEN
+#define SNMP_MAX_OCTET_STRING_LEN 127
+#endif
+
+/**
+ * The maximum depth of the SNMP tree.
+ * With private MIBs enabled, this depends on your MIB!
+ * This affects the size of MEMP_SNMP_VALUE elements.
+ */
+#ifndef SNMP_MAX_TREE_DEPTH
+#define SNMP_MAX_TREE_DEPTH 15
+#endif
+
+/**
+ * The size of the MEMP_SNMP_VALUE elements, normally calculated from
+ * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.
+ */
+#ifndef SNMP_MAX_VALUE_SIZE
+#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))
+#endif
+
+/*
+ ----------------------------------
+ ---------- IGMP options ----------
+ ----------------------------------
+*/
+/**
+ * LWIP_IGMP==1: Turn on IGMP module.
+ */
+#ifndef LWIP_IGMP
+#define LWIP_IGMP 0
+#endif
+
+/*
+ ----------------------------------
+ ---------- DNS options -----------
+ ----------------------------------
+*/
+/**
+ * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS
+ * transport.
+ */
+#ifndef LWIP_DNS
+#define LWIP_DNS 0
+#endif
+
+/** DNS maximum number of entries to maintain locally. */
+#ifndef DNS_TABLE_SIZE
+#define DNS_TABLE_SIZE 4
+#endif
+
+/** DNS maximum host name length supported in the name table. */
+#ifndef DNS_MAX_NAME_LENGTH
+#define DNS_MAX_NAME_LENGTH 256
+#endif
+
+/** The maximum of DNS servers */
+#ifndef DNS_MAX_SERVERS
+#define DNS_MAX_SERVERS 2
+#endif
+
+/** DNS do a name checking between the query and the response. */
+#ifndef DNS_DOES_NAME_CHECK
+#define DNS_DOES_NAME_CHECK 1
+#endif
+
+/** DNS message max. size. Default value is RFC compliant. */
+#ifndef DNS_MSG_SIZE
+#define DNS_MSG_SIZE 512
+#endif
+
+/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled,
+ * you have to define
+ * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}}
+ * (an array of structs name/address, where address is an u32_t in network
+ * byte order).
+ *
+ * Instead, you can also use an external function:
+ * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name)
+ * that returns the IP address or INADDR_NONE if not found.
+ */
+#ifndef DNS_LOCAL_HOSTLIST
+#define DNS_LOCAL_HOSTLIST 0
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/** If this is turned on, the local host-list can be dynamically changed
+ * at runtime. */
+#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+/*
+ ---------------------------------
+ ---------- UDP options ----------
+ ---------------------------------
+*/
+/**
+ * LWIP_UDP==1: Turn on UDP.
+ */
+#ifndef LWIP_UDP
+#define LWIP_UDP 1
+#endif
+
+/**
+ * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)
+ */
+#ifndef LWIP_UDPLITE
+#define LWIP_UDPLITE 0
+#endif
+
+/**
+ * UDP_TTL: Default Time-To-Live value.
+ */
+#ifndef UDP_TTL
+#define UDP_TTL (IP_DEFAULT_TTL)
+#endif
+
+/**
+ * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.
+ */
+#ifndef LWIP_NETBUF_RECVINFO
+#define LWIP_NETBUF_RECVINFO 0
+#endif
+
+/*
+ ---------------------------------
+ ---------- TCP options ----------
+ ---------------------------------
+*/
+/**
+ * LWIP_TCP==1: Turn on TCP.
+ */
+#ifndef LWIP_TCP
+#define LWIP_TCP 1
+#endif
+
+/**
+ * TCP_TTL: Default Time-To-Live value.
+ */
+#ifndef TCP_TTL
+#define TCP_TTL (IP_DEFAULT_TTL)
+#endif
+
+/**
+ * TCP_WND: The size of a TCP window. This must be at least
+ * (2 * TCP_MSS) for things to work well
+ */
+#ifndef TCP_WND
+#define TCP_WND (4 * TCP_MSS)
+#endif
+
+/**
+ * TCP_MAXRTX: Maximum number of retransmissions of data segments.
+ */
+#ifndef TCP_MAXRTX
+#define TCP_MAXRTX 12
+#endif
+
+/**
+ * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
+ */
+#ifndef TCP_SYNMAXRTX
+#define TCP_SYNMAXRTX 6
+#endif
+
+/**
+ * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.
+ * Define to 0 if your device is low on memory.
+ */
+#ifndef TCP_QUEUE_OOSEQ
+#define TCP_QUEUE_OOSEQ (LWIP_TCP)
+#endif
+
+/**
+ * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
+ * you might want to increase this.)
+ * For the receive side, this MSS is advertised to the remote side
+ * when opening a connection. For the transmit size, this MSS sets
+ * an upper limit on the MSS advertised by the remote host.
+ */
+#ifndef TCP_MSS
+#define TCP_MSS 536
+#endif
+
+/**
+ * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really
+ * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which
+ * reflects the available reassembly buffer size at the remote host) and the
+ * largest size permitted by the IP layer" (RFC 1122)
+ * Setting this to 1 enables code that checks TCP_MSS against the MTU of the
+ * netif used for a connection and limits the MSS if it would be too big otherwise.
+ */
+#ifndef TCP_CALCULATE_EFF_SEND_MSS
+#define TCP_CALCULATE_EFF_SEND_MSS 1
+#endif
+
+
+/**
+ * TCP_SND_BUF: TCP sender buffer space (bytes).
+ */
+#ifndef TCP_SND_BUF
+#define TCP_SND_BUF 256
+#endif
+
+/**
+ * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
+ * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
+ */
+#ifndef TCP_SND_QUEUELEN
+#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
+#endif
+
+/**
+ * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than
+ * TCP_SND_BUF. It is the amount of space which must be available in the
+ * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).
+ */
+#ifndef TCP_SNDLOWAT
+#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
+#endif
+
+/**
+ * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater
+ * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below
+ * this number, select returns writable (combined with TCP_SNDLOWAT).
+ */
+#ifndef TCP_SNDQUEUELOWAT
+#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2)
+#endif
+
+/**
+ * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.
+ */
+#ifndef TCP_LISTEN_BACKLOG
+#define TCP_LISTEN_BACKLOG 0
+#endif
+
+/**
+ * The maximum allowed backlog for TCP listen netconns.
+ * This backlog is used unless another is explicitly specified.
+ * 0xff is the maximum (u8_t).
+ */
+#ifndef TCP_DEFAULT_LISTEN_BACKLOG
+#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
+#endif
+
+/**
+ * TCP_OVERSIZE: The maximum number of bytes that tcp_write may
+ * allocate ahead of time in an attempt to create shorter pbuf chains
+ * for transmission. The meaningful range is 0 to TCP_MSS. Some
+ * suggested values are:
+ *
+ * 0: Disable oversized allocation. Each tcp_write() allocates a new
+ pbuf (old behaviour).
+ * 1: Allocate size-aligned pbufs with minimal excess. Use this if your
+ * scatter-gather DMA requires aligned fragments.
+ * 128: Limit the pbuf/memory overhead to 20%.
+ * TCP_MSS: Try to create unfragmented TCP packets.
+ * TCP_MSS/4: Try to create 4 fragments or less per TCP packet.
+ */
+#ifndef TCP_OVERSIZE
+#define TCP_OVERSIZE TCP_MSS
+#endif
+
+/**
+ * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.
+ */
+#ifndef LWIP_TCP_TIMESTAMPS
+#define LWIP_TCP_TIMESTAMPS 0
+#endif
+
+/**
+ * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an
+ * explicit window update
+ */
+#ifndef TCP_WND_UPDATE_THRESHOLD
+#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4)
+#endif
+
+/**
+ * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.
+ * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
+ * events (accept, sent, etc) that happen in the system.
+ * LWIP_CALLBACK_API==1: The PCB callback function is called directly
+ * for the event.
+ */
+#ifndef LWIP_EVENT_API
+#define LWIP_EVENT_API 0
+#define LWIP_CALLBACK_API 1
+#else
+#define LWIP_EVENT_API 1
+#define LWIP_CALLBACK_API 0
+#endif
+
+
+/*
+ ----------------------------------
+ ---------- 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.
+ */
+#ifndef PBUF_LINK_HLEN
+#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE)
+#endif
+
+/**
+ * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is
+ * designed to accomodate single full size TCP frame in one pbuf, including
+ * TCP_MSS, IP header, and link header.
+ */
+#ifndef PBUF_POOL_BUFSIZE
+#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
+#endif
+
+/*
+ ------------------------------------------------
+ ---------- Network Interfaces options ----------
+ ------------------------------------------------
+*/
+/**
+ * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname
+ * field.
+ */
+#ifndef LWIP_NETIF_HOSTNAME
+#define LWIP_NETIF_HOSTNAME 0
+#endif
+
+/**
+ * LWIP_NETIF_API==1: Support netif api (in netifapi.c)
+ */
+#ifndef LWIP_NETIF_API
+#define LWIP_NETIF_API 0
+#endif
+
+/**
+ * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface
+ * changes its up/down status (i.e., due to DHCP IP acquistion)
+ */
+#ifndef LWIP_NETIF_STATUS_CALLBACK
+#define LWIP_NETIF_STATUS_CALLBACK 0
+#endif
+
+/**
+ * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
+ * whenever the link changes (i.e., link down)
+ */
+#ifndef LWIP_NETIF_LINK_CALLBACK
+#define LWIP_NETIF_LINK_CALLBACK 0
+#endif
+
+/**
+ * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table
+ * indices) in struct netif. TCP and UDP can make use of this to prevent
+ * scanning the ARP table for every sent packet. While this is faster for big
+ * ARP tables or many concurrent connections, it might be counterproductive
+ * if you have a tiny ARP table or if there never are concurrent connections.
+ */
+#ifndef LWIP_NETIF_HWADDRHINT
+#define LWIP_NETIF_HWADDRHINT 0
+#endif
+
+/**
+ * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
+ * address equal to the netif IP address, looping them back up the stack.
+ */
+#ifndef LWIP_NETIF_LOOPBACK
+#define LWIP_NETIF_LOOPBACK 0
+#endif
+
+/**
+ * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback
+ * sending for each netif (0 = disabled)
+ */
+#ifndef LWIP_LOOPBACK_MAX_PBUFS
+#define LWIP_LOOPBACK_MAX_PBUFS 0
+#endif
+
+/**
+ * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in
+ * the system, as netifs must change how they behave depending on this setting
+ * for the LWIP_NETIF_LOOPBACK option to work.
+ * Setting this is needed to avoid reentering non-reentrant functions like
+ * tcp_input().
+ * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a
+ * multithreaded environment like tcpip.c. In this case, netif->input()
+ * is called directly.
+ * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.
+ * The packets are put on a list and netif_poll() must be called in
+ * the main application loop.
+ */
+#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING
+#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS)
+#endif
+
+/**
+ * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data
+ * to be sent into one single pbuf. This is for compatibility with DMA-enabled
+ * MACs that do not support scatter-gather.
+ * Beware that this might involve CPU-memcpy before transmitting that would not
+ * be needed without this flag! Use this only if you need to!
+ *
+ * @todo: TCP and IP-frag do not work with this, yet:
+ */
+#ifndef LWIP_NETIF_TX_SINGLE_PBUF
+#define LWIP_NETIF_TX_SINGLE_PBUF 0
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+
+/*
+ ------------------------------------
+ ---------- LOOPIF options ----------
+ ------------------------------------
+*/
+/**
+ * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c
+ */
+#ifndef LWIP_HAVE_LOOPIF
+#define LWIP_HAVE_LOOPIF 0
+#endif
+
+/*
+ ------------------------------------
+ ---------- SLIPIF options ----------
+ ------------------------------------
+*/
+/**
+ * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c
+ */
+#ifndef LWIP_HAVE_SLIPIF
+#define LWIP_HAVE_SLIPIF 0
+#endif
+
+/*
+ ------------------------------------
+ ---------- Thread options ----------
+ ------------------------------------
+*/
+/**
+ * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.
+ */
+#ifndef TCPIP_THREAD_NAME
+#define TCPIP_THREAD_NAME "tcpip_thread"
+#endif
+
+/**
+ * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.
+ * The stack size value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef TCPIP_THREAD_STACKSIZE
+#define TCPIP_THREAD_STACKSIZE 0
+#endif
+
+/**
+ * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.
+ * The priority value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef TCPIP_THREAD_PRIO
+#define TCPIP_THREAD_PRIO 1
+#endif
+
+/**
+ * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages
+ * The queue size value itself is platform-dependent, but is passed to
+ * sys_mbox_new() when tcpip_init is called.
+ */
+#ifndef TCPIP_MBOX_SIZE
+#define TCPIP_MBOX_SIZE 0
+#endif
+
+/**
+ * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.
+ */
+#ifndef SLIPIF_THREAD_NAME
+#define SLIPIF_THREAD_NAME "slipif_loop"
+#endif
+
+/**
+ * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.
+ * The stack size value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef SLIPIF_THREAD_STACKSIZE
+#define SLIPIF_THREAD_STACKSIZE 0
+#endif
+
+/**
+ * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.
+ * The priority value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef SLIPIF_THREAD_PRIO
+#define SLIPIF_THREAD_PRIO 1
+#endif
+
+/**
+ * PPP_THREAD_NAME: The name assigned to the pppInputThread.
+ */
+#ifndef PPP_THREAD_NAME
+#define PPP_THREAD_NAME "pppInputThread"
+#endif
+
+/**
+ * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread.
+ * The stack size value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef PPP_THREAD_STACKSIZE
+#define PPP_THREAD_STACKSIZE 0
+#endif
+
+/**
+ * PPP_THREAD_PRIO: The priority assigned to the pppInputThread.
+ * The priority value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef PPP_THREAD_PRIO
+#define PPP_THREAD_PRIO 1
+#endif
+
+/**
+ * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.
+ */
+#ifndef DEFAULT_THREAD_NAME
+#define DEFAULT_THREAD_NAME "lwIP"
+#endif
+
+/**
+ * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.
+ * The stack size value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef DEFAULT_THREAD_STACKSIZE
+#define DEFAULT_THREAD_STACKSIZE 0
+#endif
+
+/**
+ * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.
+ * The priority value itself is platform-dependent, but is passed to
+ * sys_thread_new() when the thread is created.
+ */
+#ifndef DEFAULT_THREAD_PRIO
+#define DEFAULT_THREAD_PRIO 1
+#endif
+
+/**
+ * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
+ * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed
+ * to sys_mbox_new() when the recvmbox is created.
+ */
+#ifndef DEFAULT_RAW_RECVMBOX_SIZE
+#define DEFAULT_RAW_RECVMBOX_SIZE 0
+#endif
+
+/**
+ * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
+ * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed
+ * to sys_mbox_new() when the recvmbox is created.
+ */
+#ifndef DEFAULT_UDP_RECVMBOX_SIZE
+#define DEFAULT_UDP_RECVMBOX_SIZE 0
+#endif
+
+/**
+ * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
+ * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed
+ * to sys_mbox_new() when the recvmbox is created.
+ */
+#ifndef DEFAULT_TCP_RECVMBOX_SIZE
+#define DEFAULT_TCP_RECVMBOX_SIZE 0
+#endif
+
+/**
+ * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.
+ * The queue size value itself is platform-dependent, but is passed to
+ * sys_mbox_new() when the acceptmbox is created.
+ */
+#ifndef DEFAULT_ACCEPTMBOX_SIZE
+#define DEFAULT_ACCEPTMBOX_SIZE 0
+#endif
+
+/*
+ ----------------------------------------------
+ ---------- Sequential layer options ----------
+ ----------------------------------------------
+*/
+/**
+ * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)
+ * Don't use it if you're not an active lwIP project member
+ */
+#ifndef LWIP_TCPIP_CORE_LOCKING
+#define LWIP_TCPIP_CORE_LOCKING 0
+#endif
+
+/**
+ * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!)
+ * Don't use it if you're not an active lwIP project member
+ */
+#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT
+#define LWIP_TCPIP_CORE_LOCKING_INPUT 0
+#endif
+
+/**
+ * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
+ */
+#ifndef LWIP_NETCONN
+#define LWIP_NETCONN 1
+#endif
+
+/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create
+ * timers running in tcpip_thread from another thread.
+ */
+#ifndef LWIP_TCPIP_TIMEOUT
+#define LWIP_TCPIP_TIMEOUT 1
+#endif
+
+/*
+ ------------------------------------
+ ---------- Socket options ----------
+ ------------------------------------
+*/
+/**
+ * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
+ */
+#ifndef LWIP_SOCKET
+#define LWIP_SOCKET 1
+#endif
+
+/**
+ * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.
+ * (only used if you use sockets.c)
+ */
+#ifndef LWIP_COMPAT_SOCKETS
+#define LWIP_COMPAT_SOCKETS 1
+#endif
+
+/**
+ * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
+ * Disable this option if you use a POSIX operating system that uses the same
+ * names (read, write & close). (only used if you use sockets.c)
+ */
+#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
+#define LWIP_POSIX_SOCKETS_IO_NAMES 1
+#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
+ * in seconds. (does not require sockets.c, and will affect tcp.c)
+ */
+#ifndef LWIP_TCP_KEEPALIVE
+#define LWIP_TCP_KEEPALIVE 0
+#endif
+
+/**
+ * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.
+ */
+#ifndef LWIP_SO_RCVTIMEO
+#define LWIP_SO_RCVTIMEO 0
+#endif
+
+/**
+ * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
+ */
+#ifndef LWIP_SO_RCVBUF
+#define LWIP_SO_RCVBUF 0
+#endif
+
+/**
+ * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
+ */
+#ifndef RECV_BUFSIZE_DEFAULT
+#define RECV_BUFSIZE_DEFAULT INT_MAX
+#endif
+
+/**
+ * SO_REUSE==1: Enable SO_REUSEADDR option.
+ */
+#ifndef SO_REUSE
+#define SO_REUSE 0
+#endif
+
+/**
+ * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets
+ * to all local matches if SO_REUSEADDR is turned on.
+ * WARNING: Adds a memcpy for every packet if passing to more than one pcb!
+ */
+#ifndef SO_REUSE_RXTOALL
+#define SO_REUSE_RXTOALL 0
+#endif
+
+/*
+ ----------------------------------------
+ ---------- Statistics options ----------
+ ----------------------------------------
+*/
+/**
+ * LWIP_STATS==1: Enable statistics collection in lwip_stats.
+ */
+#ifndef LWIP_STATS
+#define LWIP_STATS 1
+#endif
+
+#if LWIP_STATS
+
+/**
+ * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.
+ */
+#ifndef LWIP_STATS_DISPLAY
+#define LWIP_STATS_DISPLAY 0
+#endif
+
+/**
+ * LINK_STATS==1: Enable link stats.
+ */
+#ifndef LINK_STATS
+#define LINK_STATS 1
+#endif
+
+/**
+ * ETHARP_STATS==1: Enable etharp stats.
+ */
+#ifndef ETHARP_STATS
+#define ETHARP_STATS (LWIP_ARP)
+#endif
+
+/**
+ * IP_STATS==1: Enable IP stats.
+ */
+#ifndef IP_STATS
+#define IP_STATS 1
+#endif
+
+/**
+ * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is
+ * on if using either frag or reass.
+ */
+#ifndef IPFRAG_STATS
+#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG)
+#endif
+
+/**
+ * ICMP_STATS==1: Enable ICMP stats.
+ */
+#ifndef ICMP_STATS
+#define ICMP_STATS 1
+#endif
+
+/**
+ * IGMP_STATS==1: Enable IGMP stats.
+ */
+#ifndef IGMP_STATS
+#define IGMP_STATS (LWIP_IGMP)
+#endif
+
+/**
+ * UDP_STATS==1: Enable UDP stats. Default is on if
+ * UDP enabled, otherwise off.
+ */
+#ifndef UDP_STATS
+#define UDP_STATS (LWIP_UDP)
+#endif
+
+/**
+ * TCP_STATS==1: Enable TCP stats. Default is on if TCP
+ * enabled, otherwise off.
+ */
+#ifndef TCP_STATS
+#define TCP_STATS (LWIP_TCP)
+#endif
+
+/**
+ * MEM_STATS==1: Enable mem.c stats.
+ */
+#ifndef MEM_STATS
+#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))
+#endif
+
+/**
+ * MEMP_STATS==1: Enable memp.c pool stats.
+ */
+#ifndef MEMP_STATS
+#define MEMP_STATS (MEMP_MEM_MALLOC == 0)
+#endif
+
+/**
+ * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).
+ */
+#ifndef SYS_STATS
+#define SYS_STATS (NO_SYS == 0)
+#endif
+
+#else
+
+#define LINK_STATS 0
+#define IP_STATS 0
+#define IPFRAG_STATS 0
+#define ICMP_STATS 0
+#define IGMP_STATS 0
+#define UDP_STATS 0
+#define TCP_STATS 0
+#define MEM_STATS 0
+#define MEMP_STATS 0
+#define SYS_STATS 0
+#define LWIP_STATS_DISPLAY 0
+
+#endif /* LWIP_STATS */
+
+/*
+ ---------------------------------
+ ---------- PPP options ----------
+ ---------------------------------
+*/
+/**
+ * PPP_SUPPORT==1: Enable PPP.
+ */
+#ifndef PPP_SUPPORT
+#define PPP_SUPPORT 0
+#endif
+
+/**
+ * PPPOE_SUPPORT==1: Enable PPP Over Ethernet
+ */
+#ifndef PPPOE_SUPPORT
+#define PPPOE_SUPPORT 0
+#endif
+
+/**
+ * PPPOS_SUPPORT==1: Enable PPP Over Serial
+ */
+#ifndef PPPOS_SUPPORT
+#define PPPOS_SUPPORT PPP_SUPPORT
+#endif
+
+#if PPP_SUPPORT
+
+/**
+ * NUM_PPP: Max PPP sessions.
+ */
+#ifndef NUM_PPP
+#define NUM_PPP 1
+#endif
+
+/**
+ * PAP_SUPPORT==1: Support PAP.
+ */
+#ifndef PAP_SUPPORT
+#define PAP_SUPPORT 0
+#endif
+
+/**
+ * CHAP_SUPPORT==1: Support CHAP.
+ */
+#ifndef CHAP_SUPPORT
+#define CHAP_SUPPORT 0
+#endif
+
+/**
+ * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!
+ */
+#ifndef MSCHAP_SUPPORT
+#define MSCHAP_SUPPORT 0
+#endif
+
+/**
+ * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!
+ */
+#ifndef CBCP_SUPPORT
+#define CBCP_SUPPORT 0
+#endif
+
+/**
+ * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!
+ */
+#ifndef CCP_SUPPORT
+#define CCP_SUPPORT 0
+#endif
+
+/**
+ * VJ_SUPPORT==1: Support VJ header compression.
+ */
+#ifndef VJ_SUPPORT
+#define VJ_SUPPORT 0
+#endif
+
+/**
+ * MD5_SUPPORT==1: Support MD5 (see also CHAP).
+ */
+#ifndef MD5_SUPPORT
+#define MD5_SUPPORT 0
+#endif
+
+/*
+ * Timeouts
+ */
+#ifndef FSM_DEFTIMEOUT
+#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */
+#endif
+
+#ifndef FSM_DEFMAXTERMREQS
+#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#endif
+
+#ifndef FSM_DEFMAXCONFREQS
+#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
+#endif
+
+#ifndef FSM_DEFMAXNAKLOOPS
+#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
+#endif
+
+#ifndef UPAP_DEFTIMEOUT
+#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */
+#endif
+
+#ifndef UPAP_DEFREQTIME
+#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
+#endif
+
+#ifndef CHAP_DEFTIMEOUT
+#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */
+#endif
+
+#ifndef CHAP_DEFTRANSMITS
+#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
+#endif
+
+/* Interval in seconds between keepalive echo requests, 0 to disable. */
+#ifndef LCP_ECHOINTERVAL
+#define LCP_ECHOINTERVAL 0
+#endif
+
+/* Number of unanswered echo requests before failure. */
+#ifndef LCP_MAXECHOFAILS
+#define LCP_MAXECHOFAILS 3
+#endif
+
+/* Max Xmit idle time (in jiffies) before resend flag char. */
+#ifndef PPP_MAXIDLEFLAG
+#define PPP_MAXIDLEFLAG 100
+#endif
+
+/*
+ * Packet sizes
+ *
+ * Note - lcp shouldn't be allowed to negotiate stuff outside these
+ * limits. See lcp.h in the pppd directory.
+ * (XXX - these constants should simply be shared by lcp.c instead
+ * of living in lcp.h)
+ */
+#define PPP_MTU 1500 /* Default MTU (size of Info field) */
+#ifndef PPP_MAXMTU
+/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */
+#define PPP_MAXMTU 1500 /* Largest MTU we allow */
+#endif
+#define PPP_MINMTU 64
+#define PPP_MRU 1500 /* default MRU = max length of info field */
+#define PPP_MAXMRU 1500 /* Largest MRU we allow */
+#ifndef PPP_DEFMRU
+#define PPP_DEFMRU 296 /* Try for this */
+#endif
+#define PPP_MINMRU 128 /* No MRUs below this */
+
+#ifndef MAXNAMELEN
+#define MAXNAMELEN 256 /* max length of hostname or name for auth */
+#endif
+#ifndef MAXSECRETLEN
+#define MAXSECRETLEN 256 /* max length of password or secret */
+#endif
+
+#endif /* PPP_SUPPORT */
+
+/*
+ --------------------------------------
+ ---------- Checksum options ----------
+ --------------------------------------
+*/
+/**
+ * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.
+ */
+#ifndef CHECKSUM_GEN_IP
+#define CHECKSUM_GEN_IP 1
+#endif
+
+/**
+ * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.
+ */
+#ifndef CHECKSUM_GEN_UDP
+#define CHECKSUM_GEN_UDP 1
+#endif
+
+/**
+ * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.
+ */
+#ifndef CHECKSUM_GEN_TCP
+#define CHECKSUM_GEN_TCP 1
+#endif
+
+/**
+ * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.
+ */
+#ifndef CHECKSUM_CHECK_IP
+#define CHECKSUM_CHECK_IP 1
+#endif
+
+/**
+ * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.
+ */
+#ifndef CHECKSUM_CHECK_UDP
+#define CHECKSUM_CHECK_UDP 1
+#endif
+
+/**
+ * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.
+ */
+#ifndef CHECKSUM_CHECK_TCP
+#define CHECKSUM_CHECK_TCP 1
+#endif
+
+/**
+ * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from
+ * application buffers to pbufs.
+ */
+#ifndef LWIP_CHECKSUM_ON_COPY
+#define LWIP_CHECKSUM_ON_COPY 0
+#endif
+
+/*
+ ---------------------------------------
+ ---------- Debugging options ----------
+ ---------------------------------------
+*/
+/**
+ * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is
+ * compared against this value. If it is smaller, then debugging
+ * messages are written.
+ */
+#ifndef LWIP_DBG_MIN_LEVEL
+#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
+#endif
+
+/**
+ * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable
+ * debug messages of certain types.
+ */
+#ifndef LWIP_DBG_TYPES_ON
+#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
+#endif
+
+/**
+ * ETHARP_DEBUG: Enable debugging in etharp.c.
+ */
+#ifndef ETHARP_DEBUG
+#define ETHARP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * NETIF_DEBUG: Enable debugging in netif.c.
+ */
+#ifndef NETIF_DEBUG
+#define NETIF_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * PBUF_DEBUG: Enable debugging in pbuf.c.
+ */
+#ifndef PBUF_DEBUG
+#define PBUF_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * API_LIB_DEBUG: Enable debugging in api_lib.c.
+ */
+#ifndef API_LIB_DEBUG
+#define API_LIB_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * API_MSG_DEBUG: Enable debugging in api_msg.c.
+ */
+#ifndef API_MSG_DEBUG
+#define API_MSG_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * SOCKETS_DEBUG: Enable debugging in sockets.c.
+ */
+#ifndef SOCKETS_DEBUG
+#define SOCKETS_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * ICMP_DEBUG: Enable debugging in icmp.c.
+ */
+#ifndef ICMP_DEBUG
+#define ICMP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * IGMP_DEBUG: Enable debugging in igmp.c.
+ */
+#ifndef IGMP_DEBUG
+#define IGMP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * INET_DEBUG: Enable debugging in inet.c.
+ */
+#ifndef INET_DEBUG
+#define INET_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * IP_DEBUG: Enable debugging for IP.
+ */
+#ifndef IP_DEBUG
+#define IP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.
+ */
+#ifndef IP_REASS_DEBUG
+#define IP_REASS_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * RAW_DEBUG: Enable debugging in raw.c.
+ */
+#ifndef RAW_DEBUG
+#define RAW_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * MEM_DEBUG: Enable debugging in mem.c.
+ */
+#ifndef MEM_DEBUG
+#define MEM_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * MEMP_DEBUG: Enable debugging in memp.c.
+ */
+#ifndef MEMP_DEBUG
+#define MEMP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * SYS_DEBUG: Enable debugging in sys.c.
+ */
+#ifndef SYS_DEBUG
+#define SYS_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TIMERS_DEBUG: Enable debugging in timers.c.
+ */
+#ifndef TIMERS_DEBUG
+#define TIMERS_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_DEBUG: Enable debugging for TCP.
+ */
+#ifndef TCP_DEBUG
+#define TCP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.
+ */
+#ifndef TCP_INPUT_DEBUG
+#define TCP_INPUT_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.
+ */
+#ifndef TCP_FR_DEBUG
+#define TCP_FR_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit
+ * timeout.
+ */
+#ifndef TCP_RTO_DEBUG
+#define TCP_RTO_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.
+ */
+#ifndef TCP_CWND_DEBUG
+#define TCP_CWND_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.
+ */
+#ifndef TCP_WND_DEBUG
+#define TCP_WND_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.
+ */
+#ifndef TCP_OUTPUT_DEBUG
+#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.
+ */
+#ifndef TCP_RST_DEBUG
+#define TCP_RST_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.
+ */
+#ifndef TCP_QLEN_DEBUG
+#define TCP_QLEN_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * UDP_DEBUG: Enable debugging in UDP.
+ */
+#ifndef UDP_DEBUG
+#define UDP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * TCPIP_DEBUG: Enable debugging in tcpip.c.
+ */
+#ifndef TCPIP_DEBUG
+#define TCPIP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * PPP_DEBUG: Enable debugging for PPP.
+ */
+#ifndef PPP_DEBUG
+#define PPP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * SLIP_DEBUG: Enable debugging in slipif.c.
+ */
+#ifndef SLIP_DEBUG
+#define SLIP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * DHCP_DEBUG: Enable debugging in dhcp.c.
+ */
+#ifndef DHCP_DEBUG
+#define DHCP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * AUTOIP_DEBUG: Enable debugging in autoip.c.
+ */
+#ifndef AUTOIP_DEBUG
+#define AUTOIP_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.
+ */
+#ifndef SNMP_MSG_DEBUG
+#define SNMP_MSG_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.
+ */
+#ifndef SNMP_MIB_DEBUG
+#define SNMP_MIB_DEBUG LWIP_DBG_OFF
+#endif
+
+/**
+ * DNS_DEBUG: Enable debugging for DNS.
+ */
+#ifndef DNS_DEBUG
+#define DNS_DEBUG LWIP_DBG_OFF
+#endif
+
+#endif /* __LWIP_OPT_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/pbuf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/pbuf.h
new file mode 100644
index 0000000000..3b1d608b9c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/pbuf.h
@@ -0,0 +1,154 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+#ifndef __LWIP_PBUF_H__
+#define __LWIP_PBUF_H__
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Currently, the pbuf_custom code is only needed for one specific configuration
+ * of IP_FRAG */
+#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
+
+#define PBUF_TRANSPORT_HLEN 20
+#define PBUF_IP_HLEN 20
+
+typedef enum {
+ PBUF_TRANSPORT,
+ PBUF_IP,
+ PBUF_LINK,
+ PBUF_RAW
+} pbuf_layer;
+
+typedef enum {
+ PBUF_RAM, /* pbuf data is stored in RAM */
+ PBUF_ROM, /* pbuf data is stored in ROM */
+ PBUF_REF, /* pbuf comes from the pbuf pool */
+ PBUF_POOL /* pbuf payload refers to RAM */
+} pbuf_type;
+
+
+/** indicates this packet's data should be immediately passed to the application */
+#define PBUF_FLAG_PUSH 0x01U
+/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
+ a pbuf differently */
+#define PBUF_FLAG_IS_CUSTOM 0x02U
+/** indicates this pbuf is UDP multicast to be looped back */
+#define PBUF_FLAG_MCASTLOOP 0x04U
+
+struct pbuf {
+ /** next pbuf in singly linked pbuf chain */
+ struct pbuf *next;
+
+ /** pointer to the actual data in the buffer */
+ void *payload;
+
+ /**
+ * total length of this buffer and all next buffers in chain
+ * belonging to the same packet.
+ *
+ * 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;
+
+ /** length of this buffer */
+ u16_t len;
+
+ /** pbuf_type as u8_t instead of enum to save space */
+ u8_t /*pbuf_type*/ type;
+
+ /** misc flags */
+ u8_t flags;
+
+ /**
+ * the reference count always equals the number of pointers
+ * that refer to this pbuf. This can be pointers from an application,
+ * the stack itself, or pbuf->next pointers from a chain.
+ */
+ u16_t ref;
+};
+
+#if LWIP_SUPPORT_CUSTOM_PBUF
+/** Prototype for a function to free a custom pbuf */
+typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
+
+/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
+struct pbuf_custom {
+ /** The actual pbuf */
+ struct pbuf pbuf;
+ /** This function is called when pbuf_free deallocates this pbuf(_custom) */
+ pbuf_free_custom_fn custom_free_function;
+};
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+
+/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
+#define pbuf_init()
+
+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
+#if LWIP_SUPPORT_CUSTOM_PBUF
+struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
+ struct pbuf_custom *p, void *payload_mem,
+ u16_t payload_mem_len);
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+void pbuf_realloc(struct pbuf *p, u16_t size);
+u8_t pbuf_header(struct pbuf *p, s16_t header_size);
+void pbuf_ref(struct pbuf *p);
+u8_t pbuf_free(struct pbuf *p);
+u8_t pbuf_clen(struct pbuf *p);
+void pbuf_cat(struct pbuf *head, struct pbuf *tail);
+void pbuf_chain(struct pbuf *head, struct pbuf *tail);
+struct pbuf *pbuf_dechain(struct pbuf *p);
+err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
+u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
+err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
+struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
+#if LWIP_CHECKSUM_ON_COPY
+err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
+ u16_t len, u16_t *chksum);
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
+u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
+u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
+u16_t pbuf_strstr(struct pbuf* p, const char* substr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_PBUF_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/raw.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/raw.h
new file mode 100644
index 0000000000..17d0a1c540
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/raw.h
@@ -0,0 +1,98 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_RAW_H__
+#define __LWIP_RAW_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/def.h"
+#include "lwip/ip.h"
+#include "lwip/ip_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct raw_pcb;
+
+/** Function prototype for raw pcb receive callback functions.
+ * @param arg user supplied argument (raw_pcb.recv_arg)
+ * @param pcb the raw_pcb which received data
+ * @param p the packet buffer that was received
+ * @param addr the remote IP address from which the packet was received
+ * @return 1 if the packet was 'eaten' (aka. deleted),
+ * 0 if the packet lives on
+ * If returning 1, the callback is responsible for freeing the pbuf
+ * if it's not used any more.
+ */
+typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+ ip_addr_t *addr);
+
+struct raw_pcb {
+ /* Common members of all PCB types */
+ IP_PCB;
+
+ struct raw_pcb *next;
+
+ u8_t protocol;
+
+ /** receive callback function */
+ raw_recv_fn recv;
+ /* user-supplied argument for the recv callback */
+ void *recv_arg;
+};
+
+/* The following functions is the application layer interface to the
+ RAW code. */
+struct raw_pcb * raw_new (u8_t proto);
+void raw_remove (struct raw_pcb *pcb);
+err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr);
+err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr);
+
+void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
+err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
+err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
+
+/* The following functions are the lower layer interface to RAW. */
+u8_t raw_input (struct pbuf *p, struct netif *inp);
+#define raw_init() /* Compatibility define, not init needed. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_RAW */
+
+#endif /* __LWIP_RAW_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sio.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sio.h
new file mode 100644
index 0000000000..28ae2f225d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sio.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is the interface to the platform specific serial IO module
+ * It needs to be implemented by those platforms which need SLIP or PPP
+ */
+
+#ifndef __SIO_H__
+#define __SIO_H__
+
+#include "lwip/arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If you want to define sio_fd_t elsewhere or differently,
+ define this in your cc.h file. */
+#ifndef __sio_fd_t_defined
+typedef void * sio_fd_t;
+#endif
+
+/* The following functions can be defined to something else in your cc.h file
+ or be implemented in your custom sio.c file. */
+
+#ifndef sio_open
+/**
+ * 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);
+#endif
+
+#ifndef sio_send
+/**
+ * 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);
+#endif
+
+#ifndef sio_recv
+/**
+ * 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);
+#endif
+
+#ifndef sio_read
+/**
+ * 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);
+#endif
+
+#ifndef sio_tryread
+/**
+ * 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);
+#endif
+
+#ifndef sio_write
+/**
+ * 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, u8_t *data, u32_t len);
+#endif
+
+#ifndef sio_read_abort
+/**
+ * Aborts a blocking sio_read() call.
+ *
+ * @param fd serial device handle
+ */
+void sio_read_abort(sio_fd_t fd);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SIO_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp.h
new file mode 100644
index 0000000000..2ed043dd5f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp.h
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2001, 2002 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Leon Woestenberg <leon.woestenberg@axon.tv>
+ *
+ */
+#ifndef __LWIP_SNMP_H__
+#define __LWIP_SNMP_H__
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lwip/ip_addr.h"
+
+struct udp_pcb;
+struct netif;
+
+/**
+ * @see RFC1213, "MIB-II, 6. Definitions"
+ */
+enum snmp_ifType {
+ snmp_ifType_other=1, /* none of the following */
+ snmp_ifType_regular1822,
+ snmp_ifType_hdh1822,
+ snmp_ifType_ddn_x25,
+ snmp_ifType_rfc877_x25,
+ snmp_ifType_ethernet_csmacd,
+ snmp_ifType_iso88023_csmacd,
+ snmp_ifType_iso88024_tokenBus,
+ snmp_ifType_iso88025_tokenRing,
+ snmp_ifType_iso88026_man,
+ snmp_ifType_starLan,
+ snmp_ifType_proteon_10Mbit,
+ snmp_ifType_proteon_80Mbit,
+ snmp_ifType_hyperchannel,
+ snmp_ifType_fddi,
+ snmp_ifType_lapb,
+ snmp_ifType_sdlc,
+ snmp_ifType_ds1, /* T-1 */
+ snmp_ifType_e1, /* european equiv. of T-1 */
+ snmp_ifType_basicISDN,
+ snmp_ifType_primaryISDN, /* proprietary serial */
+ snmp_ifType_propPointToPointSerial,
+ snmp_ifType_ppp,
+ snmp_ifType_softwareLoopback,
+ snmp_ifType_eon, /* CLNP over IP [11] */
+ snmp_ifType_ethernet_3Mbit,
+ snmp_ifType_nsip, /* XNS over IP */
+ snmp_ifType_slip, /* generic SLIP */
+ snmp_ifType_ultra, /* ULTRA technologies */
+ snmp_ifType_ds3, /* T-3 */
+ snmp_ifType_sip, /* SMDS */
+ snmp_ifType_frame_relay
+};
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+/** SNMP "sysuptime" Interval */
+#define SNMP_SYSUPTIME_INTERVAL 10
+
+/** fixed maximum length for object identifier type */
+#define LWIP_SNMP_OBJ_ID_LEN 32
+
+/** internal object identifier representation */
+struct snmp_obj_id
+{
+ u8_t len;
+ s32_t id[LWIP_SNMP_OBJ_ID_LEN];
+};
+
+/* system */
+void snmp_set_sysdesr(u8_t* str, u8_t* len);
+void snmp_set_sysobjid(struct snmp_obj_id *oid);
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);
+void snmp_inc_sysuptime(void);
+void snmp_add_sysuptime(u32_t value);
+void snmp_get_sysuptime(u32_t *value);
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);
+
+/* network interface */
+void snmp_add_ifinoctets(struct netif *ni, u32_t value);
+void snmp_inc_ifinucastpkts(struct netif *ni);
+void snmp_inc_ifinnucastpkts(struct netif *ni);
+void snmp_inc_ifindiscards(struct netif *ni);
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value);
+void snmp_inc_ifoutucastpkts(struct netif *ni);
+void snmp_inc_ifoutnucastpkts(struct netif *ni);
+void snmp_inc_ifoutdiscards(struct netif *ni);
+void snmp_inc_iflist(void);
+void snmp_dec_iflist(void);
+
+/* ARP (for atTable and ipNetToMediaTable) */
+void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);
+void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);
+
+/* IP */
+void snmp_inc_ipinreceives(void);
+void snmp_inc_ipinhdrerrors(void);
+void snmp_inc_ipinaddrerrors(void);
+void snmp_inc_ipforwdatagrams(void);
+void snmp_inc_ipinunknownprotos(void);
+void snmp_inc_ipindiscards(void);
+void snmp_inc_ipindelivers(void);
+void snmp_inc_ipoutrequests(void);
+void snmp_inc_ipoutdiscards(void);
+void snmp_inc_ipoutnoroutes(void);
+void snmp_inc_ipreasmreqds(void);
+void snmp_inc_ipreasmoks(void);
+void snmp_inc_ipreasmfails(void);
+void snmp_inc_ipfragoks(void);
+void snmp_inc_ipfragfails(void);
+void snmp_inc_ipfragcreates(void);
+void snmp_inc_iproutingdiscards(void);
+void snmp_insert_ipaddridx_tree(struct netif *ni);
+void snmp_delete_ipaddridx_tree(struct netif *ni);
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);
+
+/* ICMP */
+void snmp_inc_icmpinmsgs(void);
+void snmp_inc_icmpinerrors(void);
+void snmp_inc_icmpindestunreachs(void);
+void snmp_inc_icmpintimeexcds(void);
+void snmp_inc_icmpinparmprobs(void);
+void snmp_inc_icmpinsrcquenchs(void);
+void snmp_inc_icmpinredirects(void);
+void snmp_inc_icmpinechos(void);
+void snmp_inc_icmpinechoreps(void);
+void snmp_inc_icmpintimestamps(void);
+void snmp_inc_icmpintimestampreps(void);
+void snmp_inc_icmpinaddrmasks(void);
+void snmp_inc_icmpinaddrmaskreps(void);
+void snmp_inc_icmpoutmsgs(void);
+void snmp_inc_icmpouterrors(void);
+void snmp_inc_icmpoutdestunreachs(void);
+void snmp_inc_icmpouttimeexcds(void);
+void snmp_inc_icmpoutparmprobs(void);
+void snmp_inc_icmpoutsrcquenchs(void);
+void snmp_inc_icmpoutredirects(void);
+void snmp_inc_icmpoutechos(void);
+void snmp_inc_icmpoutechoreps(void);
+void snmp_inc_icmpouttimestamps(void);
+void snmp_inc_icmpouttimestampreps(void);
+void snmp_inc_icmpoutaddrmasks(void);
+void snmp_inc_icmpoutaddrmaskreps(void);
+
+/* TCP */
+void snmp_inc_tcpactiveopens(void);
+void snmp_inc_tcppassiveopens(void);
+void snmp_inc_tcpattemptfails(void);
+void snmp_inc_tcpestabresets(void);
+void snmp_inc_tcpinsegs(void);
+void snmp_inc_tcpoutsegs(void);
+void snmp_inc_tcpretranssegs(void);
+void snmp_inc_tcpinerrs(void);
+void snmp_inc_tcpoutrsts(void);
+
+/* UDP */
+void snmp_inc_udpindatagrams(void);
+void snmp_inc_udpnoports(void);
+void snmp_inc_udpinerrors(void);
+void snmp_inc_udpoutdatagrams(void);
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb);
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb);
+
+/* SNMP */
+void snmp_inc_snmpinpkts(void);
+void snmp_inc_snmpoutpkts(void);
+void snmp_inc_snmpinbadversions(void);
+void snmp_inc_snmpinbadcommunitynames(void);
+void snmp_inc_snmpinbadcommunityuses(void);
+void snmp_inc_snmpinasnparseerrs(void);
+void snmp_inc_snmpintoobigs(void);
+void snmp_inc_snmpinnosuchnames(void);
+void snmp_inc_snmpinbadvalues(void);
+void snmp_inc_snmpinreadonlys(void);
+void snmp_inc_snmpingenerrs(void);
+void snmp_add_snmpintotalreqvars(u8_t value);
+void snmp_add_snmpintotalsetvars(u8_t value);
+void snmp_inc_snmpingetrequests(void);
+void snmp_inc_snmpingetnexts(void);
+void snmp_inc_snmpinsetrequests(void);
+void snmp_inc_snmpingetresponses(void);
+void snmp_inc_snmpintraps(void);
+void snmp_inc_snmpouttoobigs(void);
+void snmp_inc_snmpoutnosuchnames(void);
+void snmp_inc_snmpoutbadvalues(void);
+void snmp_inc_snmpoutgenerrs(void);
+void snmp_inc_snmpoutgetrequests(void);
+void snmp_inc_snmpoutgetnexts(void);
+void snmp_inc_snmpoutsetrequests(void);
+void snmp_inc_snmpoutgetresponses(void);
+void snmp_inc_snmpouttraps(void);
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);
+void snmp_set_snmpenableauthentraps(u8_t *value);
+void snmp_get_snmpenableauthentraps(u8_t *value);
+
+/* LWIP_SNMP support not available */
+/* define everything to be empty */
+#else
+
+/* system */
+#define snmp_set_sysdesr(str, len)
+#define snmp_set_sysobjid(oid);
+#define snmp_get_sysobjid_ptr(oid)
+#define snmp_inc_sysuptime()
+#define snmp_add_sysuptime(value)
+#define snmp_get_sysuptime(value)
+#define snmp_set_syscontact(ocstr, ocstrlen);
+#define snmp_set_sysname(ocstr, ocstrlen);
+#define snmp_set_syslocation(ocstr, ocstrlen);
+
+/* network interface */
+#define snmp_add_ifinoctets(ni,value)
+#define snmp_inc_ifinucastpkts(ni)
+#define snmp_inc_ifinnucastpkts(ni)
+#define snmp_inc_ifindiscards(ni)
+#define snmp_add_ifoutoctets(ni,value)
+#define snmp_inc_ifoutucastpkts(ni)
+#define snmp_inc_ifoutnucastpkts(ni)
+#define snmp_inc_ifoutdiscards(ni)
+#define snmp_inc_iflist()
+#define snmp_dec_iflist()
+
+/* ARP */
+#define snmp_insert_arpidx_tree(ni,ip)
+#define snmp_delete_arpidx_tree(ni,ip)
+
+/* IP */
+#define snmp_inc_ipinreceives()
+#define snmp_inc_ipinhdrerrors()
+#define snmp_inc_ipinaddrerrors()
+#define snmp_inc_ipforwdatagrams()
+#define snmp_inc_ipinunknownprotos()
+#define snmp_inc_ipindiscards()
+#define snmp_inc_ipindelivers()
+#define snmp_inc_ipoutrequests()
+#define snmp_inc_ipoutdiscards()
+#define snmp_inc_ipoutnoroutes()
+#define snmp_inc_ipreasmreqds()
+#define snmp_inc_ipreasmoks()
+#define snmp_inc_ipreasmfails()
+#define snmp_inc_ipfragoks()
+#define snmp_inc_ipfragfails()
+#define snmp_inc_ipfragcreates()
+#define snmp_inc_iproutingdiscards()
+#define snmp_insert_ipaddridx_tree(ni)
+#define snmp_delete_ipaddridx_tree(ni)
+#define snmp_insert_iprteidx_tree(dflt, ni)
+#define snmp_delete_iprteidx_tree(dflt, ni)
+
+/* ICMP */
+#define snmp_inc_icmpinmsgs()
+#define snmp_inc_icmpinerrors()
+#define snmp_inc_icmpindestunreachs()
+#define snmp_inc_icmpintimeexcds()
+#define snmp_inc_icmpinparmprobs()
+#define snmp_inc_icmpinsrcquenchs()
+#define snmp_inc_icmpinredirects()
+#define snmp_inc_icmpinechos()
+#define snmp_inc_icmpinechoreps()
+#define snmp_inc_icmpintimestamps()
+#define snmp_inc_icmpintimestampreps()
+#define snmp_inc_icmpinaddrmasks()
+#define snmp_inc_icmpinaddrmaskreps()
+#define snmp_inc_icmpoutmsgs()
+#define snmp_inc_icmpouterrors()
+#define snmp_inc_icmpoutdestunreachs()
+#define snmp_inc_icmpouttimeexcds()
+#define snmp_inc_icmpoutparmprobs()
+#define snmp_inc_icmpoutsrcquenchs()
+#define snmp_inc_icmpoutredirects()
+#define snmp_inc_icmpoutechos()
+#define snmp_inc_icmpoutechoreps()
+#define snmp_inc_icmpouttimestamps()
+#define snmp_inc_icmpouttimestampreps()
+#define snmp_inc_icmpoutaddrmasks()
+#define snmp_inc_icmpoutaddrmaskreps()
+/* TCP */
+#define snmp_inc_tcpactiveopens()
+#define snmp_inc_tcppassiveopens()
+#define snmp_inc_tcpattemptfails()
+#define snmp_inc_tcpestabresets()
+#define snmp_inc_tcpinsegs()
+#define snmp_inc_tcpoutsegs()
+#define snmp_inc_tcpretranssegs()
+#define snmp_inc_tcpinerrs()
+#define snmp_inc_tcpoutrsts()
+
+/* UDP */
+#define snmp_inc_udpindatagrams()
+#define snmp_inc_udpnoports()
+#define snmp_inc_udpinerrors()
+#define snmp_inc_udpoutdatagrams()
+#define snmp_insert_udpidx_tree(pcb)
+#define snmp_delete_udpidx_tree(pcb)
+
+/* SNMP */
+#define snmp_inc_snmpinpkts()
+#define snmp_inc_snmpoutpkts()
+#define snmp_inc_snmpinbadversions()
+#define snmp_inc_snmpinbadcommunitynames()
+#define snmp_inc_snmpinbadcommunityuses()
+#define snmp_inc_snmpinasnparseerrs()
+#define snmp_inc_snmpintoobigs()
+#define snmp_inc_snmpinnosuchnames()
+#define snmp_inc_snmpinbadvalues()
+#define snmp_inc_snmpinreadonlys()
+#define snmp_inc_snmpingenerrs()
+#define snmp_add_snmpintotalreqvars(value)
+#define snmp_add_snmpintotalsetvars(value)
+#define snmp_inc_snmpingetrequests()
+#define snmp_inc_snmpingetnexts()
+#define snmp_inc_snmpinsetrequests()
+#define snmp_inc_snmpingetresponses()
+#define snmp_inc_snmpintraps()
+#define snmp_inc_snmpouttoobigs()
+#define snmp_inc_snmpoutnosuchnames()
+#define snmp_inc_snmpoutbadvalues()
+#define snmp_inc_snmpoutgenerrs()
+#define snmp_inc_snmpoutgetrequests()
+#define snmp_inc_snmpoutgetnexts()
+#define snmp_inc_snmpoutsetrequests()
+#define snmp_inc_snmpoutgetresponses()
+#define snmp_inc_snmpouttraps()
+#define snmp_get_snmpgrpid_ptr(oid)
+#define snmp_set_snmpenableauthentraps(value)
+#define snmp_get_snmpenableauthentraps(value)
+
+#endif /* LWIP_SNMP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_SNMP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_asn1.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_asn1.h
new file mode 100644
index 0000000000..605fa3f16c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_asn1.h
@@ -0,0 +1,101 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) codec.
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#ifndef __LWIP_SNMP_ASN1_H__
+#define __LWIP_SNMP_ASN1_H__
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/pbuf.h"
+#include "lwip/snmp.h"
+
+#if LWIP_SNMP
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
+#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
+#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
+
+#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
+#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
+
+/* universal tags */
+#define SNMP_ASN1_INTEG 2
+#define SNMP_ASN1_OC_STR 4
+#define SNMP_ASN1_NUL 5
+#define SNMP_ASN1_OBJ_ID 6
+#define SNMP_ASN1_SEQ 16
+
+/* application specific (SNMP) tags */
+#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */
+#define SNMP_ASN1_COUNTER 1 /* u32_t */
+#define SNMP_ASN1_GAUGE 2 /* u32_t */
+#define SNMP_ASN1_TIMETICKS 3 /* u32_t */
+#define SNMP_ASN1_OPAQUE 4 /* octet string */
+
+/* context specific (SNMP) tags */
+#define SNMP_ASN1_PDU_GET_REQ 0
+#define SNMP_ASN1_PDU_GET_NEXT_REQ 1
+#define SNMP_ASN1_PDU_GET_RESP 2
+#define SNMP_ASN1_PDU_SET_REQ 3
+#define SNMP_ASN1_PDU_TRAP 4
+
+err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);
+err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);
+err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);
+err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);
+err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);
+err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);
+
+void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
+void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
+void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
+void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
+err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
+err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
+err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
+err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
+err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
+err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_SNMP */
+
+#endif /* __LWIP_SNMP_ASN1_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_msg.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_msg.h
new file mode 100644
index 0000000000..1183e3a95b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_msg.h
@@ -0,0 +1,315 @@
+/**
+ * @file
+ * SNMP Agent message handling structures.
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#ifndef __LWIP_SNMP_MSG_H__
+#define __LWIP_SNMP_MSG_H__
+
+#include "lwip/opt.h"
+#include "lwip/snmp.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/ip_addr.h"
+#include "lwip/err.h"
+
+#if LWIP_SNMP
+
+#if SNMP_PRIVATE_MIB
+/* When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB. */
+#include "private_mib.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The listen port of the SNMP agent. Clients have to make their requests to
+ this port. Most standard clients won't work if you change this! */
+#ifndef SNMP_IN_PORT
+#define SNMP_IN_PORT 161
+#endif
+/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
+ work if you change this! */
+#ifndef SNMP_TRAP_PORT
+#define SNMP_TRAP_PORT 162
+#endif
+
+#define SNMP_ES_NOERROR 0
+#define SNMP_ES_TOOBIG 1
+#define SNMP_ES_NOSUCHNAME 2
+#define SNMP_ES_BADVALUE 3
+#define SNMP_ES_READONLY 4
+#define SNMP_ES_GENERROR 5
+
+#define SNMP_GENTRAP_COLDSTART 0
+#define SNMP_GENTRAP_WARMSTART 1
+#define SNMP_GENTRAP_AUTHFAIL 4
+#define SNMP_GENTRAP_ENTERPRISESPC 6
+
+struct snmp_varbind
+{
+ /* next pointer, NULL for last in list */
+ struct snmp_varbind *next;
+ /* previous pointer, NULL for first in list */
+ struct snmp_varbind *prev;
+
+ /* object identifier length (in s32_t) */
+ u8_t ident_len;
+ /* object identifier array */
+ s32_t *ident;
+
+ /* object value ASN1 type */
+ u8_t value_type;
+ /* object value length (in u8_t) */
+ u8_t value_len;
+ /* object value */
+ void *value;
+
+ /* encoding varbind seq length length */
+ u8_t seqlenlen;
+ /* encoding object identifier length length */
+ u8_t olenlen;
+ /* encoding object value length length */
+ u8_t vlenlen;
+ /* encoding varbind seq length */
+ u16_t seqlen;
+ /* encoding object identifier length */
+ u16_t olen;
+ /* encoding object value length */
+ u16_t vlen;
+};
+
+struct snmp_varbind_root
+{
+ struct snmp_varbind *head;
+ struct snmp_varbind *tail;
+ /* number of variable bindings in list */
+ u8_t count;
+ /* encoding varbind-list seq length length */
+ u8_t seqlenlen;
+ /* encoding varbind-list seq length */
+ u16_t seqlen;
+};
+
+/** output response message header length fields */
+struct snmp_resp_header_lengths
+{
+ /* encoding error-index length length */
+ u8_t erridxlenlen;
+ /* encoding error-status length length */
+ u8_t errstatlenlen;
+ /* encoding request id length length */
+ u8_t ridlenlen;
+ /* encoding pdu length length */
+ u8_t pdulenlen;
+ /* encoding community length length */
+ u8_t comlenlen;
+ /* encoding version length length */
+ u8_t verlenlen;
+ /* encoding sequence length length */
+ u8_t seqlenlen;
+
+ /* encoding error-index length */
+ u16_t erridxlen;
+ /* encoding error-status length */
+ u16_t errstatlen;
+ /* encoding request id length */
+ u16_t ridlen;
+ /* encoding pdu length */
+ u16_t pdulen;
+ /* encoding community length */
+ u16_t comlen;
+ /* encoding version length */
+ u16_t verlen;
+ /* encoding sequence length */
+ u16_t seqlen;
+};
+
+/** output response message header length fields */
+struct snmp_trap_header_lengths
+{
+ /* encoding timestamp length length */
+ u8_t tslenlen;
+ /* encoding specific-trap length length */
+ u8_t strplenlen;
+ /* encoding generic-trap length length */
+ u8_t gtrplenlen;
+ /* encoding agent-addr length length */
+ u8_t aaddrlenlen;
+ /* encoding enterprise-id length length */
+ u8_t eidlenlen;
+ /* encoding pdu length length */
+ u8_t pdulenlen;
+ /* encoding community length length */
+ u8_t comlenlen;
+ /* encoding version length length */
+ u8_t verlenlen;
+ /* encoding sequence length length */
+ u8_t seqlenlen;
+
+ /* encoding timestamp length */
+ u16_t tslen;
+ /* encoding specific-trap length */
+ u16_t strplen;
+ /* encoding generic-trap length */
+ u16_t gtrplen;
+ /* encoding agent-addr length */
+ u16_t aaddrlen;
+ /* encoding enterprise-id length */
+ u16_t eidlen;
+ /* encoding pdu length */
+ u16_t pdulen;
+ /* encoding community length */
+ u16_t comlen;
+ /* encoding version length */
+ u16_t verlen;
+ /* encoding sequence length */
+ u16_t seqlen;
+};
+
+/* Accepting new SNMP messages. */
+#define SNMP_MSG_EMPTY 0
+/* Search for matching object for variable binding. */
+#define SNMP_MSG_SEARCH_OBJ 1
+/* Perform SNMP operation on in-memory object.
+ Pass-through states, for symmetry only. */
+#define SNMP_MSG_INTERNAL_GET_OBJDEF 2
+#define SNMP_MSG_INTERNAL_GET_VALUE 3
+#define SNMP_MSG_INTERNAL_SET_TEST 4
+#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5
+#define SNMP_MSG_INTERNAL_SET_VALUE 6
+/* Perform SNMP operation on object located externally.
+ In theory this could be used for building a proxy agent.
+ Practical use is for an enterprise spc. app. gateway. */
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7
+#define SNMP_MSG_EXTERNAL_GET_VALUE 8
+#define SNMP_MSG_EXTERNAL_SET_TEST 9
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10
+#define SNMP_MSG_EXTERNAL_SET_VALUE 11
+
+#define SNMP_COMMUNITY_STR_LEN 64
+struct snmp_msg_pstat
+{
+ /* lwIP local port (161) binding */
+ struct udp_pcb *pcb;
+ /* source IP address */
+ ip_addr_t sip;
+ /* source UDP port */
+ u16_t sp;
+ /* request type */
+ u8_t rt;
+ /* request ID */
+ s32_t rid;
+ /* error status */
+ s32_t error_status;
+ /* error index */
+ s32_t error_index;
+ /* community name (zero terminated) */
+ u8_t community[SNMP_COMMUNITY_STR_LEN + 1];
+ /* community string length (exclusive zero term) */
+ u8_t com_strlen;
+ /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */
+ u8_t state;
+ /* saved arguments for MSG_EXTERNAL_x */
+ struct mib_external_node *ext_mib_node;
+ struct snmp_name_ptr ext_name_ptr;
+ struct obj_def ext_object_def;
+ struct snmp_obj_id ext_oid;
+ /* index into input variable binding list */
+ u8_t vb_idx;
+ /* ptr into input variable binding list */
+ struct snmp_varbind *vb_ptr;
+ /* list of variable bindings from input */
+ struct snmp_varbind_root invb;
+ /* list of variable bindings to output */
+ struct snmp_varbind_root outvb;
+ /* output response lengths used in ASN encoding */
+ struct snmp_resp_header_lengths rhl;
+};
+
+struct snmp_msg_trap
+{
+ /* lwIP local port (161) binding */
+ struct udp_pcb *pcb;
+ /* destination IP address in network order */
+ ip_addr_t dip;
+
+ /* source enterprise ID (sysObjectID) */
+ struct snmp_obj_id *enterprise;
+ /* source IP address, raw network order format */
+ u8_t sip_raw[4];
+ /* generic trap code */
+ u32_t gen_trap;
+ /* specific trap code */
+ u32_t spc_trap;
+ /* timestamp */
+ u32_t ts;
+ /* list of variable bindings to output */
+ struct snmp_varbind_root outvb;
+ /* output trap lengths used in ASN encoding */
+ struct snmp_trap_header_lengths thl;
+};
+
+/** Agent Version constant, 0 = v1 oddity */
+extern const s32_t snmp_version;
+/** Agent default "public" community string */
+extern const char snmp_publiccommunity[7];
+
+extern struct snmp_msg_trap trap_msg;
+
+/** Agent setup, start listening to port 161. */
+void snmp_init(void);
+void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
+void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);
+
+/** Varbind-list functions. */
+struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
+void snmp_varbind_free(struct snmp_varbind *vb);
+void snmp_varbind_list_free(struct snmp_varbind_root *root);
+void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);
+struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);
+
+/** Handle an internal (recv) or external (private response) event. */
+void snmp_msg_event(u8_t request_id);
+err_t snmp_send_response(struct snmp_msg_pstat *m_stat);
+err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);
+void snmp_coldstart_trap(void);
+void snmp_authfail_trap(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_SNMP */
+
+#endif /* __LWIP_SNMP_MSG_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_structs.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_structs.h
new file mode 100644
index 0000000000..0d3b46a928
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/snmp_structs.h
@@ -0,0 +1,268 @@
+/**
+ * @file
+ * Generic MIB tree structures.
+ *
+ * @todo namespace prefixes
+ */
+
+/*
+ * 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 <christiaan.simons@axon.tv>
+ */
+
+#ifndef __LWIP_SNMP_STRUCTS_H__
+#define __LWIP_SNMP_STRUCTS_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp.h"
+
+#if SNMP_PRIVATE_MIB
+/* When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB. */
+#include "private_mib.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MIB object instance */
+#define MIB_OBJECT_NONE 0
+#define MIB_OBJECT_SCALAR 1
+#define MIB_OBJECT_TAB 2
+
+/* MIB access types */
+#define MIB_ACCESS_READ 1
+#define MIB_ACCESS_WRITE 2
+
+/* MIB object access */
+#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
+#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
+#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
+#define MIB_OBJECT_NOT_ACCESSIBLE 0
+
+/** object definition returned by (get_object_def)() */
+struct obj_def
+{
+ /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */
+ u8_t instance;
+ /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */
+ u8_t access;
+ /* ASN type for this object */
+ u8_t asn_type;
+ /* value length (host length) */
+ u16_t v_len;
+ /* length of instance part of supplied object identifier */
+ u8_t id_inst_len;
+ /* instance part of supplied object identifier */
+ s32_t *id_inst_ptr;
+};
+
+struct snmp_name_ptr
+{
+ u8_t ident_len;
+ s32_t *ident;
+};
+
+/** MIB const scalar (.0) node */
+#define MIB_NODE_SC 0x01
+/** MIB const array node */
+#define MIB_NODE_AR 0x02
+/** MIB array node (mem_malloced from RAM) */
+#define MIB_NODE_RA 0x03
+/** MIB list root node (mem_malloced from RAM) */
+#define MIB_NODE_LR 0x04
+/** MIB node for external objects */
+#define MIB_NODE_EX 0x05
+
+/** node "base class" layout, the mandatory fields for a node */
+struct mib_node
+{
+ /** returns struct obj_def for the given object identifier */
+ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+ /** returns object value for the given object identifier,
+ @note the caller must allocate at least len bytes for the value */
+ void (*get_value)(struct obj_def *od, u16_t len, void *value);
+ /** tests length and/or range BEFORE setting */
+ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+ /** sets object value, only to be called when set_test() */
+ void (*set_value)(struct obj_def *od, u16_t len, void *value);
+ /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
+ u8_t node_type;
+ /* array or max list length */
+ u16_t maxlength;
+};
+
+/** derived node for scalars .0 index */
+typedef struct mib_node mib_scalar_node;
+
+/** derived node, points to a fixed size const array
+ of sub-identifiers plus a 'child' pointer */
+struct mib_array_node
+{
+ /* inherited "base class" members */
+ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+ void (*get_value)(struct obj_def *od, u16_t len, void *value);
+ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+ void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+ u8_t node_type;
+ u16_t maxlength;
+
+ /* additional struct members */
+ const s32_t *objid;
+ struct mib_node* const *nptr;
+};
+
+/** derived node, points to a fixed size mem_malloced array
+ of sub-identifiers plus a 'child' pointer */
+struct mib_ram_array_node
+{
+ /* inherited "base class" members */
+ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+ void (*get_value)(struct obj_def *od, u16_t len, void *value);
+ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+ void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+ u8_t node_type;
+ u16_t maxlength;
+
+ /* aditional struct members */
+ s32_t *objid;
+ struct mib_node **nptr;
+};
+
+struct mib_list_node
+{
+ struct mib_list_node *prev;
+ struct mib_list_node *next;
+ s32_t objid;
+ struct mib_node *nptr;
+};
+
+/** derived node, points to a doubly linked list
+ of sub-identifiers plus a 'child' pointer */
+struct mib_list_rootnode
+{
+ /* inherited "base class" members */
+ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+ void (*get_value)(struct obj_def *od, u16_t len, void *value);
+ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+ void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+ u8_t node_type;
+ u16_t maxlength;
+
+ /* additional struct members */
+ struct mib_list_node *head;
+ struct mib_list_node *tail;
+ /* counts list nodes in list */
+ u16_t count;
+};
+
+/** derived node, has access functions for mib object in external memory or device
+ using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */
+struct mib_external_node
+{
+ /* inherited "base class" members */
+ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
+ void (*get_value)(struct obj_def *od, u16_t len, void *value);
+ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
+ void (*set_value)(struct obj_def *od, u16_t len, void *value);
+
+ u8_t node_type;
+ u16_t maxlength;
+
+ /* additional struct members */
+ /** points to an external (in memory) record of some sort of addressing
+ information, passed to and interpreted by the funtions below */
+ void* addr_inf;
+ /** tree levels under this node */
+ u8_t tree_levels;
+ /** number of objects at this level */
+ u16_t (*level_length)(void* addr_inf, u8_t level);
+ /** compares object sub identifier with external id
+ return zero when equal, nonzero when unequal */
+ s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);
+ void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);
+
+ /** async Questions */
+ void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);
+ void (*get_value_q)(u8_t rid, struct obj_def *od);
+ void (*set_test_q)(u8_t rid, struct obj_def *od);
+ void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+ /** async Answers */
+ void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);
+ void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+ u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+ void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
+ /** async Panic Close (agent returns error reply,
+ e.g. used for external transaction cleanup) */
+ void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);
+ void (*get_value_pc)(u8_t rid, struct obj_def *od);
+ void (*set_test_pc)(u8_t rid, struct obj_def *od);
+ void (*set_value_pc)(u8_t rid, struct obj_def *od);
+};
+
+/** export MIB tree from mib2.c */
+extern const struct mib_array_node internet;
+
+/** dummy function pointers for non-leaf MIB nodes from mib2.c */
+void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
+u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
+void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
+
+void snmp_oidtoip(s32_t *ident, ip_addr_t *ip);
+void snmp_iptooid(ip_addr_t *ip, s32_t *ident);
+void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
+void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);
+
+struct mib_list_node* snmp_mib_ln_alloc(s32_t id);
+void snmp_mib_ln_free(struct mib_list_node *ln);
+struct mib_list_rootnode* snmp_mib_lrn_alloc(void);
+void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);
+
+s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);
+s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);
+struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);
+
+struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);
+struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
+u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);
+u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_SNMP */
+
+#endif /* __LWIP_SNMP_STRUCTS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sockets.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sockets.h
new file mode 100644
index 0000000000..3c8fed24e6
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sockets.h
@@ -0,0 +1,376 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+
+
+#ifndef __LWIP_SOCKETS_H__
+#define __LWIP_SOCKETS_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
+
+#include <stddef.h> /* for size_t */
+
+#include "lwip/ip_addr.h"
+#include "lwip/inet.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* members are in network byte order */
+struct sockaddr_in {
+ u8_t sin_len;
+ u8_t sin_family;
+ u16_t sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+};
+
+struct sockaddr {
+ u8_t sa_len;
+ u8_t sa_family;
+ char sa_data[14];
+};
+
+#ifndef socklen_t
+# define socklen_t u32_t
+#endif
+
+/* Socket protocol types (TCP/UDP/RAW) */
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+
+/*
+ * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
+ */
+#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
+#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
+#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */
+
+#define SO_DONTLINGER ((int)(~SO_LINGER))
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */
+#define SO_NO_CHECK 0x100a /* don't create UDP checksum */
+
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * 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
+#define PF_INET AF_INET
+#define PF_UNSPEC AF_UNSPEC
+
+#define IPPROTO_IP 0
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+#define IPPROTO_UDPLITE 136
+
+/* Flags we can use with send and recv. */
+#define MSG_PEEK 0x01 /* Peeks at an incoming message */
+#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
+#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */
+#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */
+#define MSG_MORE 0x10 /* Sender will send more */
+
+
+/*
+ * Options for level IPPROTO_IP
+ */
+#define IP_TOS 1
+#define IP_TTL 2
+
+#if LWIP_TCP
+/*
+ * Options for level IPPROTO_TCP
+ */
+#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 /* LWIP_TCP */
+
+#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 LWIP_IGMP
+/*
+ * Options and types for UDP multicast traffic handling
+ */
+#define IP_ADD_MEMBERSHIP 3
+#define IP_DROP_MEMBERSHIP 4
+#define IP_MULTICAST_TTL 5
+#define IP_MULTICAST_IF 6
+#define IP_MULTICAST_LOOP 7
+
+typedef struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+} ip_mreq;
+#endif /* LWIP_IGMP */
+
+/*
+ * The Type of Service provides an indication of the abstract
+ * parameters of the quality of service desired. These parameters are
+ * to be used to guide the selection of the actual service parameters
+ * when transmitting a datagram through a particular network. Several
+ * networks offer service precedence, which somehow treats high
+ * precedence traffic as more important than other traffic (generally
+ * by accepting only traffic above a certain precedence at time of high
+ * load). The major choice is a three way tradeoff between low-delay,
+ * high-reliability, and high-throughput.
+ * The use of the Delay, Throughput, and Reliability indications may
+ * increase the cost (in some sense) of the service. In many networks
+ * better performance for one of these parameters is coupled with worse
+ * performance on another. Except for very unusual cases at most two
+ * of these three indications should be set.
+ */
+#define IPTOS_TOS_MASK 0x1E
+#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_LOWCOST 0x02
+#define IPTOS_MINCOST IPTOS_LOWCOST
+
+/*
+ * The Network Control precedence designation is intended to be used
+ * within a network only. The actual use and control of that
+ * designation is up to each network. The Internetwork Control
+ * designation is intended for use by gateway control originators only.
+ * If the actual use of these precedence designations is of concern to
+ * a particular network, it is the responsibility of that network to
+ * control the access to, and use of, those precedence designations.
+ */
+#define IPTOS_PREC_MASK 0xe0
+#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL 0xe0
+#define IPTOS_PREC_INTERNETCONTROL 0xc0
+#define IPTOS_PREC_CRITIC_ECP 0xa0
+#define IPTOS_PREC_FLASHOVERRIDE 0x80
+#define IPTOS_PREC_FLASH 0x60
+#define IPTOS_PREC_IMMEDIATE 0x40
+#define IPTOS_PREC_PRIORITY 0x20
+#define IPTOS_PREC_ROUTINE 0x00
+
+
+/*
+ * Commands for ioctlsocket(), taken from the BSD file fcntl.h.
+ * lwip_ioctl only supports FIONREAD and FIONBIO, for now
+ *
+ * Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word. The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+#if !defined(FIONREAD) || !defined(FIONBIO)
+#define IOCPARM_MASK 0x7fU /* 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 */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+ /* 0x20000000 distinguishes new &
+ old ioctl's */
+#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
+
+#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+#endif /* !defined(FIONREAD) || !defined(FIONBIO) */
+
+#ifndef FIONREAD
+#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */
+#endif
+#ifndef FIONBIO
+#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */
+#endif
+
+/* Socket I/O Controls: unimplemented */
+#ifndef SIOCSHIWAT
+#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */
+#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */
+#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */
+#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */
+#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */
+#endif
+
+/* commands for fnctl */
+#ifndef F_GETFL
+#define F_GETFL 3
+#endif
+#ifndef F_SETFL
+#define F_SETFL 4
+#endif
+
+/* File status flags and file access modes for fnctl,
+ these are bits in an int. */
+#ifndef O_NONBLOCK
+#define O_NONBLOCK 1 /* nonblocking I/O */
+#endif
+#ifndef O_NDELAY
+#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */
+#endif
+
+#ifndef SHUT_RD
+ #define SHUT_RD 0
+ #define SHUT_WR 1
+ #define SHUT_RDWR 2
+#endif
+
+/* FD_SET used for lwip_select */
+#ifndef FD_SET
+ #undef FD_SETSIZE
+ /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */
+ #define FD_SETSIZE MEMP_NUM_NETCONN
+ #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7)))
+ #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))
+ #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7)))
+ #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p)))
+
+ typedef struct fd_set {
+ unsigned char fd_bits [(FD_SETSIZE+7)/8];
+ } fd_set;
+
+#endif /* FD_SET */
+
+/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided
+ * by your system, set this to 0 and include <sys/time.h> in cc.h */
+#ifndef LWIP_TIMEVAL_PRIVATE
+#define LWIP_TIMEVAL_PRIVATE 1
+#endif
+
+#if LWIP_TIMEVAL_PRIVATE
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* LWIP_TIMEVAL_PRIVATE */
+
+void lwip_socket_init(void);
+
+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);
+int lwip_recv(int s, void *mem, size_t len, int flags);
+int lwip_read(int s, void *mem, size_t len);
+int lwip_recvfrom(int s, void *mem, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen);
+int lwip_send(int s, const void *dataptr, size_t size, int flags);
+int 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);
+int lwip_write(int s, const void *dataptr, size_t size);
+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
+ struct timeval *timeout);
+int lwip_ioctl(int s, long cmd, void *argp);
+int lwip_fcntl(int s, int cmd, int val);
+
+#if LWIP_COMPAT_SOCKETS
+#define accept(a,b,c) lwip_accept(a,b,c)
+#define bind(a,b,c) lwip_bind(a,b,c)
+#define shutdown(a,b) lwip_shutdown(a,b)
+#define closesocket(s) lwip_close(s)
+#define connect(a,b,c) lwip_connect(a,b,c)
+#define getsockname(a,b,c) lwip_getsockname(a,b,c)
+#define getpeername(a,b,c) lwip_getpeername(a,b,c)
+#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
+#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
+#define listen(a,b) lwip_listen(a,b)
+#define recv(a,b,c,d) lwip_recv(a,b,c,d)
+#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
+#define send(a,b,c,d) lwip_send(a,b,c,d)
+#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f)
+#define socket(a,b,c) lwip_socket(a,b,c)
+#define select(a,b,c,d,e) lwip_select(a,b,c,d,e)
+#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c)
+
+#if LWIP_POSIX_SOCKETS_IO_NAMES
+#define read(a,b,c) lwip_read(a,b,c)
+#define write(a,b,c) lwip_write(a,b,c)
+#define close(s) lwip_close(s)
+#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */
+
+#endif /* LWIP_COMPAT_SOCKETS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_SOCKET */
+
+#endif /* __LWIP_SOCKETS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/stats.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/stats.h
new file mode 100644
index 0000000000..015b7ce79d
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/stats.h
@@ -0,0 +1,292 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_STATS_H__
+#define __LWIP_STATS_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if LWIP_STATS
+
+#ifndef LWIP_STATS_LARGE
+#define LWIP_STATS_LARGE 0
+#endif
+
+#if LWIP_STATS_LARGE
+#define STAT_COUNTER u32_t
+#define STAT_COUNTER_F U32_F
+#else
+#define STAT_COUNTER u16_t
+#define STAT_COUNTER_F U16_F
+#endif
+
+struct stats_proto {
+ STAT_COUNTER xmit; /* Transmitted packets. */
+ STAT_COUNTER recv; /* Received packets. */
+ STAT_COUNTER fw; /* Forwarded packets. */
+ STAT_COUNTER drop; /* Dropped packets. */
+ STAT_COUNTER chkerr; /* Checksum error. */
+ STAT_COUNTER lenerr; /* Invalid length error. */
+ STAT_COUNTER memerr; /* Out of memory error. */
+ STAT_COUNTER rterr; /* Routing error. */
+ STAT_COUNTER proterr; /* Protocol error. */
+ STAT_COUNTER opterr; /* Error in options. */
+ STAT_COUNTER err; /* Misc error. */
+ STAT_COUNTER cachehit;
+};
+
+struct stats_igmp {
+ STAT_COUNTER xmit; /* Transmitted packets. */
+ STAT_COUNTER recv; /* Received packets. */
+ STAT_COUNTER drop; /* Dropped packets. */
+ STAT_COUNTER chkerr; /* Checksum error. */
+ STAT_COUNTER lenerr; /* Invalid length error. */
+ STAT_COUNTER memerr; /* Out of memory error. */
+ STAT_COUNTER proterr; /* Protocol error. */
+ STAT_COUNTER rx_v1; /* Received v1 frames. */
+ STAT_COUNTER rx_group; /* Received group-specific queries. */
+ STAT_COUNTER rx_general; /* Received general queries. */
+ STAT_COUNTER rx_report; /* Received reports. */
+ STAT_COUNTER tx_join; /* Sent joins. */
+ STAT_COUNTER tx_leave; /* Sent leaves. */
+ STAT_COUNTER tx_report; /* Sent reports. */
+};
+
+struct stats_mem {
+#ifdef LWIP_DEBUG
+ const char *name;
+#endif /* LWIP_DEBUG */
+ mem_size_t avail;
+ mem_size_t used;
+ mem_size_t max;
+ STAT_COUNTER err;
+ STAT_COUNTER illegal;
+};
+
+struct stats_syselem {
+ STAT_COUNTER used;
+ STAT_COUNTER max;
+ STAT_COUNTER err;
+};
+
+struct stats_sys {
+ struct stats_syselem sem;
+ struct stats_syselem mutex;
+ struct stats_syselem mbox;
+};
+
+struct stats_ {
+#if LINK_STATS
+ struct stats_proto link;
+#endif
+#if ETHARP_STATS
+ struct stats_proto etharp;
+#endif
+#if IPFRAG_STATS
+ struct stats_proto ip_frag;
+#endif
+#if IP_STATS
+ struct stats_proto ip;
+#endif
+#if ICMP_STATS
+ struct stats_proto icmp;
+#endif
+#if IGMP_STATS
+ struct stats_igmp igmp;
+#endif
+#if UDP_STATS
+ struct stats_proto udp;
+#endif
+#if TCP_STATS
+ struct stats_proto tcp;
+#endif
+#if MEM_STATS
+ struct stats_mem mem;
+#endif
+#if MEMP_STATS
+ struct stats_mem memp[MEMP_MAX];
+#endif
+#if SYS_STATS
+ struct stats_sys sys;
+#endif
+};
+
+extern struct stats_ lwip_stats;
+
+void stats_init(void);
+
+#define STATS_INC(x) ++lwip_stats.x
+#define STATS_DEC(x) --lwip_stats.x
+#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \
+ if (lwip_stats.x.max < lwip_stats.x.used) { \
+ lwip_stats.x.max = lwip_stats.x.used; \
+ } \
+ } while(0)
+#else /* LWIP_STATS */
+#define stats_init()
+#define STATS_INC(x)
+#define STATS_DEC(x)
+#define STATS_INC_USED(x)
+#endif /* LWIP_STATS */
+
+#if TCP_STATS
+#define TCP_STATS_INC(x) STATS_INC(x)
+#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP")
+#else
+#define TCP_STATS_INC(x)
+#define TCP_STATS_DISPLAY()
+#endif
+
+#if UDP_STATS
+#define UDP_STATS_INC(x) STATS_INC(x)
+#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP")
+#else
+#define UDP_STATS_INC(x)
+#define UDP_STATS_DISPLAY()
+#endif
+
+#if ICMP_STATS
+#define ICMP_STATS_INC(x) STATS_INC(x)
+#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP")
+#else
+#define ICMP_STATS_INC(x)
+#define ICMP_STATS_DISPLAY()
+#endif
+
+#if IGMP_STATS
+#define IGMP_STATS_INC(x) STATS_INC(x)
+#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
+#else
+#define IGMP_STATS_INC(x)
+#define IGMP_STATS_DISPLAY()
+#endif
+
+#if IP_STATS
+#define IP_STATS_INC(x) STATS_INC(x)
+#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP")
+#else
+#define IP_STATS_INC(x)
+#define IP_STATS_DISPLAY()
+#endif
+
+#if IPFRAG_STATS
+#define IPFRAG_STATS_INC(x) STATS_INC(x)
+#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG")
+#else
+#define IPFRAG_STATS_INC(x)
+#define IPFRAG_STATS_DISPLAY()
+#endif
+
+#if ETHARP_STATS
+#define ETHARP_STATS_INC(x) STATS_INC(x)
+#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP")
+#else
+#define ETHARP_STATS_INC(x)
+#define ETHARP_STATS_DISPLAY()
+#endif
+
+#if LINK_STATS
+#define LINK_STATS_INC(x) STATS_INC(x)
+#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK")
+#else
+#define LINK_STATS_INC(x)
+#define LINK_STATS_DISPLAY()
+#endif
+
+#if MEM_STATS
+#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y
+#define MEM_STATS_INC(x) STATS_INC(mem.x)
+#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)
+#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y
+#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP")
+#else
+#define MEM_STATS_AVAIL(x, y)
+#define MEM_STATS_INC(x)
+#define MEM_STATS_INC_USED(x, y)
+#define MEM_STATS_DEC_USED(x, y)
+#define MEM_STATS_DISPLAY()
+#endif
+
+#if MEMP_STATS
+#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y
+#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x)
+#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)
+#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1)
+#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)
+#else
+#define MEMP_STATS_AVAIL(x, i, y)
+#define MEMP_STATS_INC(x, i)
+#define MEMP_STATS_DEC(x, i)
+#define MEMP_STATS_INC_USED(x, i)
+#define MEMP_STATS_DISPLAY(i)
+#endif
+
+#if SYS_STATS
+#define SYS_STATS_INC(x) STATS_INC(sys.x)
+#define SYS_STATS_DEC(x) STATS_DEC(sys.x)
+#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1)
+#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)
+#else
+#define SYS_STATS_INC(x)
+#define SYS_STATS_DEC(x)
+#define SYS_STATS_INC_USED(x)
+#define SYS_STATS_DISPLAY()
+#endif
+
+/* Display of statistics */
+#if LWIP_STATS_DISPLAY
+void stats_display(void);
+void stats_display_proto(struct stats_proto *proto, char *name);
+void stats_display_igmp(struct stats_igmp *igmp);
+void stats_display_mem(struct stats_mem *mem, char *name);
+void stats_display_memp(struct stats_mem *mem, int index);
+void stats_display_sys(struct stats_sys *sys);
+#else /* LWIP_STATS_DISPLAY */
+#define stats_display()
+#define stats_display_proto(proto, name)
+#define stats_display_igmp(igmp)
+#define stats_display_mem(mem, name)
+#define stats_display_memp(mem, index)
+#define stats_display_sys(sys)
+#endif /* LWIP_STATS_DISPLAY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_STATS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sys.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sys.h
new file mode 100644
index 0000000000..9f62c7540e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/sys.h
@@ -0,0 +1,331 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_SYS_H__
+#define __LWIP_SYS_H__
+
+#include "lwip/opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if NO_SYS
+
+/* For a totally minimal and standalone system, we provide null
+ definitions of the sys_ functions. */
+typedef u8_t sys_sem_t;
+typedef u8_t sys_mutex_t;
+typedef u8_t sys_mbox_t;
+
+#define sys_sem_new(s, c) ERR_OK
+#define sys_sem_signal(s)
+#define sys_sem_wait(s)
+#define sys_arch_sem_wait(s,t)
+#define sys_sem_free(s)
+#define sys_mutex_new(mu) ERR_OK
+#define sys_mutex_lock(mu)
+#define sys_mutex_unlock(mu)
+#define sys_mutex_free(mu)
+#define sys_mbox_new(m, s) ERR_OK
+#define sys_mbox_fetch(m,d)
+#define sys_mbox_tryfetch(m,d)
+#define sys_mbox_post(m,d)
+#define sys_mbox_trypost(m,d)
+#define sys_mbox_free(m)
+
+#define sys_thread_new(n,t,a,s,p)
+
+#define sys_msleep(t)
+
+#else /* NO_SYS */
+
+/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
+#define SYS_ARCH_TIMEOUT 0xffffffffUL
+
+/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate.
+ * For now we use the same magic value, but we allow this to change in future.
+ */
+#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT
+
+#include "lwip/err.h"
+#include "arch/sys_arch.h"
+
+/** Function prototype for thread functions */
+typedef void (*lwip_thread_fn)(void *arg);
+
+/* Function prototypes for functions to be implemented by platform ports
+ (in sys_arch.c) */
+
+/* Mutex functions: */
+
+/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores
+ should be used instead */
+#if LWIP_COMPAT_MUTEX
+/* for old ports that don't have mutexes: define them to binary semaphores */
+#define sys_mutex_t sys_sem_t
+#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
+#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
+#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
+#define sys_mutex_free(mutex) sys_sem_free(mutex)
+#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
+#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)
+
+#else /* LWIP_COMPAT_MUTEX */
+
+/** Create a new mutex
+ * @param mutex pointer to the mutex to create
+ * @return a new mutex */
+err_t sys_mutex_new(sys_mutex_t *mutex);
+/** Lock a mutex
+ * @param mutex the mutex to lock */
+void sys_mutex_lock(sys_mutex_t *mutex);
+/** Unlock a mutex
+ * @param mutex the mutex to unlock */
+void sys_mutex_unlock(sys_mutex_t *mutex);
+/** Delete a semaphore
+ * @param mutex the mutex to delete */
+void sys_mutex_free(sys_mutex_t *mutex);
+#ifndef sys_mutex_valid
+/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mutex_valid(sys_mutex_t *mutex);
+#endif
+#ifndef sys_mutex_set_invalid
+/** Set a mutex invalid so that sys_mutex_valid returns 0 */
+void sys_mutex_set_invalid(sys_mutex_t *mutex);
+#endif
+#endif /* LWIP_COMPAT_MUTEX */
+
+/* Semaphore functions: */
+
+/** Create a new semaphore
+ * @param sem pointer to the semaphore to create
+ * @param count initial count of the semaphore
+ * @return ERR_OK if successful, another err_t otherwise */
+err_t sys_sem_new(sys_sem_t *sem, u8_t count);
+/** Signals a semaphore
+ * @param sem the semaphore to signal */
+void sys_sem_signal(sys_sem_t *sem);
+/** Wait for a semaphore for the specified timeout
+ * @param sem the semaphore to wait for
+ * @param timeout timeout in milliseconds to wait (0 = wait forever)
+ * @return time (in milliseconds) waited for the semaphore
+ * or SYS_ARCH_TIMEOUT on timeout */
+u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout);
+/** Delete a semaphore
+ * @param sem semaphore to delete */
+void sys_sem_free(sys_sem_t *sem);
+/** Wait for a semaphore - forever/no timeout */
+#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0)
+#ifndef sys_sem_valid
+/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_sem_valid(sys_sem_t *sem);
+#endif
+#ifndef sys_sem_set_invalid
+/** Set a semaphore invalid so that sys_sem_valid returns 0 */
+void sys_sem_set_invalid(sys_sem_t *sem);
+#endif
+
+/* Time functions. */
+#ifndef sys_msleep
+void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
+#endif
+
+/* Mailbox functions. */
+
+/** Create a new mbox of specified size
+ * @param mbox pointer to the mbox to create
+ * @param size (miminum) number of messages in this mbox
+ * @return ERR_OK if successful, another err_t otherwise */
+err_t sys_mbox_new(sys_mbox_t *mbox, int size);
+/** Post a message to an mbox - may not fail
+ * -> blocks if full, only used from tasks not from ISR
+ * @param mbox mbox to posts the message
+ * @param msg message to post (ATTENTION: can be NULL) */
+void sys_mbox_post(sys_mbox_t *mbox, void *msg);
+/** Try to post a message to an mbox - may fail if full or ISR
+ * @param mbox mbox to posts the message
+ * @param msg message to post (ATTENTION: can be NULL) */
+err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg);
+/** Wait for a new message to arrive in the mbox
+ * @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
+ * @return time (in milliseconds) waited for a message, may be 0 if not waited
+ or SYS_ARCH_TIMEOUT on timeout
+ * The returned time has to be accurate to prevent timer jitter! */
+u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout);
+/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */
+#ifndef sys_arch_mbox_tryfetch
+/** Wait for a new message to arrive in the mbox
+ * @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
+ * @return 0 (milliseconds) if a message has been received
+ * or SYS_MBOX_EMPTY if the mailbox is empty */
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg);
+#endif
+/** For now, we map straight to sys_arch implementation. */
+#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
+/** Delete an mbox
+ * @param mbox mbox to delete */
+void sys_mbox_free(sys_mbox_t *mbox);
+#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0)
+#ifndef sys_mbox_valid
+/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mbox_valid(sys_mbox_t *mbox);
+#endif
+#ifndef sys_mbox_set_invalid
+/** Set an mbox invalid so that sys_mbox_valid returns 0 */
+void sys_mbox_set_invalid(sys_mbox_t *mbox);
+#endif
+
+/** The only thread function:
+ * Creates a new thread
+ * @param name human-readable name for the thread (used for debugging purposes)
+ * @param thread thread-function
+ * @param arg parameter passed to 'thread'
+ * @param stacksize stack size in bytes for the new thread (may be ignored by ports)
+ * @param prio priority of the new thread (may be ignored by ports) */
+sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio);
+
+#endif /* NO_SYS */
+
+/* sys_init() must be called before anthing else. */
+void sys_init(void);
+
+#ifndef sys_jiffies
+/** Ticks/jiffies since power up. */
+u32_t sys_jiffies(void);
+#endif
+
+/** Returns the current time in milliseconds,
+ * may be the same as sys_jiffies or at least based on it. */
+u32_t sys_now(void);
+
+/* Critical Region Protection */
+/* These functions must be implemented in the sys_arch.c file.
+ In some implementations they can provide a more light-weight protection
+ mechanism than using semaphores. Otherwise semaphores can be used for
+ implementation */
+#ifndef SYS_ARCH_PROTECT
+/** 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.
+ */
+#if SYS_LIGHTWEIGHT_PROT
+
+/** SYS_ARCH_DECL_PROTECT
+ * declare a protection variable. This macro will default to defining a variable of
+ * type sys_prot_t. If a particular port needs a different implementation, then
+ * this macro may be defined in sys_arch.h.
+ */
+#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
+/** SYS_ARCH_PROTECT
+ * Perform a "fast" protect. This could be implemented by
+ * disabling interrupts for an embedded system or by using a semaphore or
+ * mutex. The implementation should allow calling SYS_ARCH_PROTECT when
+ * already protected. The old protection level is returned in the variable
+ * "lev". This macro will default to calling the sys_arch_protect() function
+ * which should be implemented in sys_arch.c. If a particular port needs a
+ * different implementation, then this macro may be defined in sys_arch.h
+ */
+#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
+/** SYS_ARCH_UNPROTECT
+ * Perform a "fast" set of the protection level to "lev". This could be
+ * implemented by setting the interrupt level to "lev" within the MACRO or by
+ * using a semaphore or mutex. This macro will default to calling the
+ * sys_arch_unprotect() function which should be implemented in
+ * sys_arch.c. If a particular port needs a different implementation, then
+ * this macro may be defined in sys_arch.h
+ */
+#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
+sys_prot_t sys_arch_protect(void);
+void sys_arch_unprotect(sys_prot_t pval);
+
+#else
+
+#define SYS_ARCH_DECL_PROTECT(lev)
+#define SYS_ARCH_PROTECT(lev)
+#define SYS_ARCH_UNPROTECT(lev)
+
+#endif /* SYS_LIGHTWEIGHT_PROT */
+
+#endif /* SYS_ARCH_PROTECT */
+
+/*
+ * Macros to set/get and increase/decrease variables in a thread-safe way.
+ * Use these for accessing variable that are used from more than one thread.
+ */
+
+#ifndef SYS_ARCH_INC
+#define SYS_ARCH_INC(var, val) do { \
+ SYS_ARCH_DECL_PROTECT(old_level); \
+ SYS_ARCH_PROTECT(old_level); \
+ var += val; \
+ SYS_ARCH_UNPROTECT(old_level); \
+ } while(0)
+#endif /* SYS_ARCH_INC */
+
+#ifndef SYS_ARCH_DEC
+#define SYS_ARCH_DEC(var, val) do { \
+ SYS_ARCH_DECL_PROTECT(old_level); \
+ SYS_ARCH_PROTECT(old_level); \
+ var -= val; \
+ SYS_ARCH_UNPROTECT(old_level); \
+ } while(0)
+#endif /* SYS_ARCH_DEC */
+
+#ifndef SYS_ARCH_GET
+#define SYS_ARCH_GET(var, ret) do { \
+ SYS_ARCH_DECL_PROTECT(old_level); \
+ SYS_ARCH_PROTECT(old_level); \
+ ret = var; \
+ SYS_ARCH_UNPROTECT(old_level); \
+ } while(0)
+#endif /* SYS_ARCH_GET */
+
+#ifndef SYS_ARCH_SET
+#define SYS_ARCH_SET(var, val) do { \
+ SYS_ARCH_DECL_PROTECT(old_level); \
+ SYS_ARCH_PROTECT(old_level); \
+ var = val; \
+ SYS_ARCH_UNPROTECT(old_level); \
+ } while(0)
+#endif /* SYS_ARCH_SET */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_SYS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp.h
new file mode 100644
index 0000000000..07dcd10e78
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp.h
@@ -0,0 +1,377 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_TCP_H__
+#define __LWIP_TCP_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip.h"
+#include "lwip/icmp.h"
+#include "lwip/err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tcp_pcb;
+
+/** Function prototype for tcp accept callback functions. Called when a new
+ * connection can be accepted on a listening pcb.
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param newpcb The new connection pcb
+ * @param err An error code if there has been an error accepting.
+ * Only return ERR_ABRT if you have called tcp_abort from within the
+ * callback function!
+ */
+typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);
+
+/** Function prototype for tcp receive callback functions. Called when data has
+ * been received.
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param tpcb The connection pcb which received data
+ * @param p The received data (or NULL when the connection has been closed!)
+ * @param err An error code if there has been an error receiving
+ * Only return ERR_ABRT if you have called tcp_abort from within the
+ * callback function!
+ */
+typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb,
+ struct pbuf *p, err_t err);
+
+/** Function prototype for tcp sent callback functions. Called when sent data has
+ * been acknowledged by the remote side. Use it to free corresponding resources.
+ * This also means that the pcb has now space available to send new data.
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param tpcb The connection pcb for which data has been acknowledged
+ * @param len The amount of bytes acknowledged
+ * @return ERR_OK: try to send some data by calling tcp_output
+ * Only return ERR_ABRT if you have called tcp_abort from within the
+ * callback function!
+ */
+typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb,
+ u16_t len);
+
+/** Function prototype for tcp poll callback functions. Called periodically as
+ * specified by @see tcp_poll.
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param tpcb tcp pcb
+ * @return ERR_OK: try to send some data by calling tcp_output
+ * Only return ERR_ABRT if you have called tcp_abort from within the
+ * callback function!
+ */
+typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb);
+
+/** Function prototype for tcp error callback functions. Called when the pcb
+ * receives a RST or is unexpectedly closed for any other reason.
+ *
+ * @note The corresponding pcb is already freed when this callback is called!
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param err Error code to indicate why the pcb has been closed
+ * ERR_ABRT: aborted through tcp_abort or by a TCP timer
+ * ERR_RST: the connection was reset by the remote host
+ */
+typedef void (*tcp_err_fn)(void *arg, err_t err);
+
+/** Function prototype for tcp connected callback functions. Called when a pcb
+ * is connected to the remote side after initiating a connection attempt by
+ * calling tcp_connect().
+ *
+ * @param arg Additional argument to pass to the callback function (@see tcp_arg())
+ * @param tpcb The connection pcb which is connected
+ * @param err An unused error code, always ERR_OK currently ;-) TODO!
+ * Only return ERR_ABRT if you have called tcp_abort from within the
+ * callback function!
+ *
+ * @note When a connection attempt fails, the error callback is currently called!
+ */
+typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
+
+enum tcp_state {
+ CLOSED = 0,
+ LISTEN = 1,
+ SYN_SENT = 2,
+ SYN_RCVD = 3,
+ ESTABLISHED = 4,
+ FIN_WAIT_1 = 5,
+ FIN_WAIT_2 = 6,
+ CLOSE_WAIT = 7,
+ CLOSING = 8,
+ LAST_ACK = 9,
+ TIME_WAIT = 10
+};
+
+#if LWIP_CALLBACK_API
+ /* Function to call when a listener has been connected.
+ * @param arg user-supplied argument (tcp_pcb.callback_arg)
+ * @param pcb a new tcp_pcb that now is connected
+ * @param err an error argument (TODO: that is current always ERR_OK?)
+ * @return ERR_OK: accept the new connection,
+ * any other err_t abortsthe new connection
+ */
+#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept;
+#else /* LWIP_CALLBACK_API */
+#define DEF_ACCEPT_CALLBACK
+#endif /* LWIP_CALLBACK_API */
+
+/**
+ * members common to struct tcp_pcb and struct tcp_listen_pcb
+ */
+#define TCP_PCB_COMMON(type) \
+ type *next; /* for the linked list */ \
+ enum tcp_state state; /* TCP state */ \
+ u8_t prio; \
+ void *callback_arg; \
+ /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
+ DEF_ACCEPT_CALLBACK \
+ /* ports are in host byte order */ \
+ u16_t local_port
+
+
+/* the TCP protocol control block */
+struct tcp_pcb {
+/** common PCB members */
+ IP_PCB;
+/** protocol specific PCB members */
+ TCP_PCB_COMMON(struct tcp_pcb);
+
+ /* ports are in host byte order */
+ u16_t remote_port;
+
+ u8_t flags;
+#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */
+#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */
+#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */
+#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */
+#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */
+#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */
+#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */
+#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
+
+ /* the rest of the fields are in host byte order
+ as we have to do some math with them */
+ /* receiver variables */
+ u32_t rcv_nxt; /* next seqno expected */
+ u16_t rcv_wnd; /* receiver window available */
+ u16_t rcv_ann_wnd; /* receiver window to announce */
+ u32_t rcv_ann_right_edge; /* announced right edge of window */
+
+ /* Timers */
+ u32_t tmr;
+ u8_t polltmr, pollinterval;
+
+ /* Retransmission timer. */
+ s16_t rtime;
+
+ u16_t mss; /* maximum segment size */
+
+ /* RTT (round trip time) estimation variables */
+ u32_t rttest; /* RTT estimate in 500ms ticks */
+ u32_t rtseq; /* sequence number being timed */
+ s16_t sa, sv; /* @todo document this */
+
+ s16_t rto; /* retransmission time-out */
+ u8_t nrtx; /* number of retransmissions */
+
+ /* fast retransmit/recovery */
+ u32_t lastack; /* Highest acknowledged seqno. */
+ u8_t dupacks;
+
+ /* congestion avoidance/control variables */
+ u16_t cwnd;
+ u16_t ssthresh;
+
+ /* sender variables */
+ u32_t snd_nxt; /* next new seqno to be sent */
+ u16_t snd_wnd; /* sender window */
+ u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
+ window update. */
+ u32_t snd_lbb; /* Sequence number of next byte to be buffered. */
+
+ u16_t acked;
+
+ u16_t snd_buf; /* Available buffer space for sending (in bytes). */
+#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
+ u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
+
+#if TCP_OVERSIZE
+ /* Extra bytes available at the end of the last pbuf in unsent. */
+ u16_t unsent_oversize;
+#endif /* TCP_OVERSIZE */
+
+ /* These are ordered by sequence number: */
+ struct tcp_seg *unsent; /* Unsent (queued) segments. */
+ struct tcp_seg *unacked; /* Sent but unacknowledged segments. */
+#if TCP_QUEUE_OOSEQ
+ struct tcp_seg *ooseq; /* Received out of sequence segments. */
+#endif /* TCP_QUEUE_OOSEQ */
+
+ struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */
+
+#if LWIP_CALLBACK_API
+ /* Function to be called when more send buffer space is available. */
+ tcp_sent_fn sent;
+ /* Function to be called when (in-sequence) data has arrived. */
+ tcp_recv_fn recv;
+ /* Function to be called when a connection has been set up. */
+ tcp_connected_fn connected;
+ /* Function which is called periodically. */
+ tcp_poll_fn poll;
+ /* Function to be called whenever a fatal error occurs. */
+ tcp_err_fn errf;
+#endif /* LWIP_CALLBACK_API */
+
+#if LWIP_TCP_TIMESTAMPS
+ u32_t ts_lastacksent;
+ u32_t ts_recent;
+#endif /* LWIP_TCP_TIMESTAMPS */
+
+ /* idle time before KEEPALIVE is sent */
+ u32_t keep_idle;
+#if LWIP_TCP_KEEPALIVE
+ u32_t keep_intvl;
+ u32_t keep_cnt;
+#endif /* LWIP_TCP_KEEPALIVE */
+
+ /* Persist timer counter */
+ u32_t persist_cnt;
+ /* Persist timer back-off */
+ u8_t persist_backoff;
+
+ /* KEEPALIVE counter */
+ u8_t keep_cnt_sent;
+};
+
+struct tcp_pcb_listen {
+/* Common members of all PCB types */
+ IP_PCB;
+/* Protocol specific PCB members */
+ TCP_PCB_COMMON(struct tcp_pcb_listen);
+
+#if TCP_LISTEN_BACKLOG
+ u8_t backlog;
+ u8_t accepts_pending;
+#endif /* TCP_LISTEN_BACKLOG */
+};
+
+#if LWIP_EVENT_API
+
+enum lwip_event {
+ LWIP_EVENT_ACCEPT,
+ LWIP_EVENT_SENT,
+ LWIP_EVENT_RECV,
+ LWIP_EVENT_CONNECTED,
+ LWIP_EVENT_POLL,
+ LWIP_EVENT_ERR
+};
+
+err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
+ enum lwip_event,
+ struct pbuf *p,
+ u16_t size,
+ err_t err);
+
+#endif /* LWIP_EVENT_API */
+
+/* Application program's interface: */
+struct tcp_pcb * tcp_new (void);
+
+void tcp_arg (struct tcp_pcb *pcb, void *arg);
+void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept);
+void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv);
+void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent);
+void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval);
+void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
+
+#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss)
+#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
+#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen)
+#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY)
+#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
+#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
+
+#if TCP_LISTEN_BACKLOG
+#define tcp_accepted(pcb) do { \
+ LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \
+ (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
+#else /* TCP_LISTEN_BACKLOG */
+#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
+ pcb->state == LISTEN)
+#endif /* TCP_LISTEN_BACKLOG */
+
+void tcp_recved (struct tcp_pcb *pcb, u16_t len);
+err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
+ u16_t port);
+err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
+ u16_t port, tcp_connected_fn connected);
+
+struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
+#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
+
+void tcp_abort (struct tcp_pcb *pcb);
+err_t tcp_close (struct tcp_pcb *pcb);
+err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx);
+
+/* Flags for "apiflags" parameter in tcp_write */
+#define TCP_WRITE_FLAG_COPY 0x01
+#define TCP_WRITE_FLAG_MORE 0x02
+
+err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
+ u8_t apiflags);
+
+void tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
+
+#define TCP_PRIO_MIN 1
+#define TCP_PRIO_NORMAL 64
+#define TCP_PRIO_MAX 127
+
+err_t tcp_output (struct tcp_pcb *pcb);
+
+
+const char* tcp_debug_state_str(enum tcp_state s);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_TCP */
+
+#endif /* __LWIP_TCP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp_impl.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp_impl.h
new file mode 100644
index 0000000000..b4feec0da1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcp_impl.h
@@ -0,0 +1,471 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_TCP_IMPL_H__
+#define __LWIP_TCP_IMPL_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/tcp.h"
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip.h"
+#include "lwip/icmp.h"
+#include "lwip/err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions for interfacing with TCP: */
+
+/* Lower layer interface to TCP: */
+#define tcp_init() /* Compatibility define, no init needed. */
+void tcp_tmr (void); /* Must be called every
+ TCP_TMR_INTERVAL
+ ms. (Typically 250 ms). */
+/* It is also possible to call these two functions at the right
+ intervals (instead of calling tcp_tmr()). */
+void tcp_slowtmr (void);
+void tcp_fasttmr (void);
+
+
+/* Only used by IP to pass a TCP segment to TCP: */
+void tcp_input (struct pbuf *p, struct netif *inp);
+/* Used within the TCP code only: */
+struct tcp_pcb * tcp_alloc (u8_t prio);
+void tcp_abandon (struct tcp_pcb *pcb, int reset);
+err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
+void tcp_rexmit (struct tcp_pcb *pcb);
+void tcp_rexmit_rto (struct tcp_pcb *pcb);
+void tcp_rexmit_fast (struct tcp_pcb *pcb);
+u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
+
+/**
+ * This is the Nagle algorithm: try to combine user data to send as few TCP
+ * segments as possible. Only send if
+ * - no previously transmitted data on the connection remains unacknowledged or
+ * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
+ * - the only unsent segment is at least pcb->mss bytes long (or there is more
+ * than one unsent segment - with lwIP, this can happen although unsent->len < mss)
+ * - or if we are in fast-retransmit (TF_INFR)
+ */
+#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
+ ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
+ (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
+ ((tpcb)->unsent->len >= (tpcb)->mss))) \
+ ) ? 1 : 0)
+#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
+
+
+#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
+#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
+#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
+#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
+/* 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))
+#define TCP_FIN 0x01U
+#define TCP_SYN 0x02U
+#define TCP_RST 0x04U
+#define TCP_PSH 0x08U
+#define TCP_ACK 0x10U
+#define TCP_URG 0x20U
+#define TCP_ECE 0x40U
+#define TCP_CWR 0x80U
+
+#define TCP_FLAGS 0x3fU
+
+/* Length of the TCP header, excluding options. */
+#define TCP_HLEN 20
+
+#ifndef TCP_TMR_INTERVAL
+#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */
+#endif /* TCP_TMR_INTERVAL */
+
+#ifndef TCP_FAST_INTERVAL
+#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */
+#endif /* TCP_FAST_INTERVAL */
+
+#ifndef TCP_SLOW_INTERVAL
+#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */
+#endif /* TCP_SLOW_INTERVAL */
+
+#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
+#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
+
+#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
+
+#ifndef TCP_MSL
+#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
+#endif
+
+/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
+#ifndef TCP_KEEPIDLE_DEFAULT
+#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */
+#endif
+
+#ifndef TCP_KEEPINTVL_DEFAULT
+#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */
+#endif
+
+#ifndef TCP_KEEPCNT_DEFAULT
+#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */
+#endif
+
+#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
+
+/* Fields are (of course) in network byte order.
+ * Some fields are converted to host byte order in tcp_input().
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct tcp_hdr {
+ PACK_STRUCT_FIELD(u16_t src);
+ PACK_STRUCT_FIELD(u16_t dest);
+ PACK_STRUCT_FIELD(u32_t seqno);
+ PACK_STRUCT_FIELD(u32_t ackno);
+ PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
+ PACK_STRUCT_FIELD(u16_t wnd);
+ PACK_STRUCT_FIELD(u16_t chksum);
+ PACK_STRUCT_FIELD(u16_t urgp);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
+#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
+#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
+
+#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
+#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
+#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
+#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags))
+
+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))
+#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
+
+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
+
+/** Flags used on input processing, not on pcb->flags
+*/
+#define TF_RESET (u8_t)0x08U /* Connection was reset. */
+#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
+#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
+
+
+#if LWIP_EVENT_API
+
+#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_ACCEPT, NULL, 0, err)
+#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_SENT, NULL, space, ERR_OK)
+#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_RECV, (p), 0, (err))
+#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_RECV, NULL, 0, ERR_OK)
+#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_CONNECTED, NULL, 0, (err))
+#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
+ LWIP_EVENT_POLL, NULL, 0, ERR_OK)
+#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
+ LWIP_EVENT_ERR, NULL, 0, (err))
+
+#else /* LWIP_EVENT_API */
+
+#define TCP_EVENT_ACCEPT(pcb,err,ret) \
+ do { \
+ if((pcb)->accept != NULL) \
+ (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
+ else (ret) = ERR_ARG; \
+ } while (0)
+
+#define TCP_EVENT_SENT(pcb,space,ret) \
+ do { \
+ if((pcb)->sent != NULL) \
+ (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
+ else (ret) = ERR_OK; \
+ } while (0)
+
+#define TCP_EVENT_RECV(pcb,p,err,ret) \
+ do { \
+ if((pcb)->recv != NULL) { \
+ (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\
+ } else { \
+ (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \
+ } \
+ } while (0)
+
+#define TCP_EVENT_CLOSED(pcb,ret) \
+ do { \
+ if(((pcb)->recv != NULL)) { \
+ (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\
+ } else { \
+ (ret) = ERR_OK; \
+ } \
+ } while (0)
+
+#define TCP_EVENT_CONNECTED(pcb,err,ret) \
+ do { \
+ if((pcb)->connected != NULL) \
+ (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \
+ else (ret) = ERR_OK; \
+ } while (0)
+
+#define TCP_EVENT_POLL(pcb,ret) \
+ do { \
+ if((pcb)->poll != NULL) \
+ (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \
+ else (ret) = ERR_OK; \
+ } while (0)
+
+#define TCP_EVENT_ERR(errf,arg,err) \
+ do { \
+ if((errf) != NULL) \
+ (errf)((arg),(err)); \
+ } while (0)
+
+#endif /* LWIP_EVENT_API */
+
+/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */
+#if TCP_OVERSIZE && defined(LWIP_DEBUG)
+#define TCP_OVERSIZE_DBGCHECK 1
+#else
+#define TCP_OVERSIZE_DBGCHECK 0
+#endif
+
+/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */
+#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP)
+
+/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */
+struct tcp_seg {
+ struct tcp_seg *next; /* used when putting segements on a queue */
+ struct pbuf *p; /* buffer containing data + TCP header */
+ u16_t len; /* the TCP length of this segment */
+#if TCP_OVERSIZE_DBGCHECK
+ u16_t oversize_left; /* Extra bytes available at the end of the last
+ pbuf in unsent (used for asserting vs.
+ tcp_pcb.unsent_oversized only) */
+#endif /* TCP_OVERSIZE_DBGCHECK */
+#if TCP_CHECKSUM_ON_COPY
+ u16_t chksum;
+ u8_t chksum_swapped;
+#endif /* TCP_CHECKSUM_ON_COPY */
+ u8_t flags;
+#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
+#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
+#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
+ checksummed into 'chksum' */
+ struct tcp_hdr *tcphdr; /* the TCP header */
+};
+
+#define LWIP_TCP_OPT_LENGTH(flags) \
+ (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \
+ (flags & TF_SEG_OPTS_TS ? 12 : 0)
+
+/** This returns a TCP header option for MSS in an u32_t */
+#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \
+ ((u32_t)4 << 16) | \
+ (((u32_t)TCP_MSS / 256) << 8) | \
+ (TCP_MSS & 255))
+
+/* Global variables: */
+extern struct tcp_pcb *tcp_input_pcb;
+extern u32_t tcp_ticks;
+
+/* 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
+ state in which they accept or send
+ data. */
+extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
+
+extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
+
+/* Axioms about the above lists:
+ 1) Every TCP PCB that is not CLOSED is in one of the lists.
+ 2) A PCB is only in one of the lists.
+ 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
+ 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
+*/
+/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
+ with a PCB list or removes a PCB from a list, respectively. */
+#ifndef TCP_DEBUG_PCB_LISTS
+#define TCP_DEBUG_PCB_LISTS 0
+#endif
+#if TCP_DEBUG_PCB_LISTS
+#define TCP_REG(pcbs, npcb) do {\
+ 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)); \
+ (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 { \
+ 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; \
+ } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
+ if(tcp_tmp_pcb->next == (npcb)) { \
+ tcp_tmp_pcb->next = (npcb)->next; \
+ break; \
+ } \
+ } \
+ (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 /* LWIP_DEBUG */
+
+#define TCP_REG(pcbs, npcb) \
+ do { \
+ (npcb)->next = *pcbs; \
+ *(pcbs) = (npcb); \
+ tcp_timer_needed(); \
+ } while (0)
+
+#define TCP_RMV(pcbs, npcb) \
+ do { \
+ if(*(pcbs) == (npcb)) { \
+ (*(pcbs)) = (*pcbs)->next; \
+ } \
+ else { \
+ for(tcp_tmp_pcb = *pcbs; \
+ tcp_tmp_pcb != NULL; \
+ tcp_tmp_pcb = tcp_tmp_pcb->next) { \
+ if(tcp_tmp_pcb->next == (npcb)) { \
+ tcp_tmp_pcb->next = (npcb)->next; \
+ break; \
+ } \
+ } \
+ } \
+ (npcb)->next = NULL; \
+ } while(0)
+
+#endif /* LWIP_DEBUG */
+
+
+/* Internal functions: */
+struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
+void tcp_pcb_purge(struct tcp_pcb *pcb);
+void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
+
+void tcp_segs_free(struct tcp_seg *seg);
+void tcp_seg_free(struct tcp_seg *seg);
+struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
+
+#define tcp_ack(pcb) \
+ do { \
+ if((pcb)->flags & TF_ACK_DELAY) { \
+ (pcb)->flags &= ~TF_ACK_DELAY; \
+ (pcb)->flags |= TF_ACK_NOW; \
+ } \
+ else { \
+ (pcb)->flags |= TF_ACK_DELAY; \
+ } \
+ } while (0)
+
+#define tcp_ack_now(pcb) \
+ do { \
+ (pcb)->flags |= TF_ACK_NOW; \
+ } while (0)
+
+err_t tcp_send_fin(struct tcp_pcb *pcb);
+err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags);
+
+void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
+
+void tcp_rst(u32_t seqno, u32_t ackno,
+ ip_addr_t *local_ip, ip_addr_t *remote_ip,
+ u16_t local_port, u16_t remote_port);
+
+u32_t tcp_next_iss(void);
+
+void tcp_keepalive(struct tcp_pcb *pcb);
+void tcp_zero_window_probe(struct tcp_pcb *pcb);
+
+#if TCP_CALCULATE_EFF_SEND_MSS
+u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr);
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */
+
+#if LWIP_CALLBACK_API
+err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
+#endif /* LWIP_CALLBACK_API */
+
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
+void tcp_debug_print(struct tcp_hdr *tcphdr);
+void tcp_debug_print_flags(u8_t flags);
+void tcp_debug_print_state(enum tcp_state s);
+void tcp_debug_print_pcbs(void);
+s16_t tcp_pcbs_sane(void);
+#else
+# define tcp_debug_print(tcphdr)
+# define tcp_debug_print_flags(flags)
+# define tcp_debug_print_state(s)
+# define tcp_debug_print_pcbs()
+# define tcp_pcbs_sane() 1
+#endif /* TCP_DEBUG */
+
+/** External function (implemented in timers.c), called when TCP detects
+ * that a timer is needed (i.e. active- or time-wait-pcb found). */
+void tcp_timer_needed(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_TCP */
+
+#endif /* __LWIP_TCP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcpip.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcpip.h
new file mode 100644
index 0000000000..995ba8ad00
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/tcpip.h
@@ -0,0 +1,159 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_TCPIP_H__
+#define __LWIP_TCPIP_H__
+
+#include "lwip/opt.h"
+
+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/api_msg.h"
+#include "lwip/netifapi.h"
+#include "lwip/pbuf.h"
+#include "lwip/api.h"
+#include "lwip/sys.h"
+#include "lwip/timers.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Define this to something that triggers a watchdog. This is called from
+ * tcpip_thread after processing a message. */
+#ifndef LWIP_TCPIP_THREAD_ALIVE
+#define LWIP_TCPIP_THREAD_ALIVE()
+#endif
+
+#if LWIP_TCPIP_CORE_LOCKING
+/** The global semaphore to lock the stack. */
+extern sys_mutex_t lock_tcpip_core;
+#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core)
+#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core)
+#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m)
+#define TCPIP_APIMSG_ACK(m)
+#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m)
+#define TCPIP_NETIFAPI_ACK(m)
+#else /* LWIP_TCPIP_CORE_LOCKING */
+#define LOCK_TCPIP_CORE()
+#define UNLOCK_TCPIP_CORE()
+#define TCPIP_APIMSG(m) tcpip_apimsg(m)
+#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed)
+#define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
+#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
+/** Function prototype for the init_done function passed to tcpip_init */
+typedef void (*tcpip_init_done_fn)(void *arg);
+/** Function prototype for functions passed to tcpip_callback() */
+typedef void (*tcpip_callback_fn)(void *ctx);
+
+void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
+
+#if LWIP_NETCONN
+err_t tcpip_apimsg(struct api_msg *apimsg);
+#if LWIP_TCPIP_CORE_LOCKING
+err_t tcpip_apimsg_lock(struct api_msg *apimsg);
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+#endif /* LWIP_NETCONN */
+
+err_t tcpip_input(struct pbuf *p, struct netif *inp);
+
+#if LWIP_NETIF_API
+err_t tcpip_netifapi(struct netifapi_msg *netifapimsg);
+#if LWIP_TCPIP_CORE_LOCKING
+err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+#endif /* LWIP_NETIF_API */
+
+err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
+#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
+
+/* free pbufs or heap memory from another context without blocking */
+err_t pbuf_free_callback(struct pbuf *p);
+err_t mem_free_callback(void *m);
+
+#if LWIP_TCPIP_TIMEOUT
+err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
+err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
+#endif /* LWIP_TCPIP_TIMEOUT */
+
+enum tcpip_msg_type {
+#if LWIP_NETCONN
+ TCPIP_MSG_API,
+#endif /* LWIP_NETCONN */
+ TCPIP_MSG_INPKT,
+#if LWIP_NETIF_API
+ TCPIP_MSG_NETIFAPI,
+#endif /* LWIP_NETIF_API */
+#if LWIP_TCPIP_TIMEOUT
+ TCPIP_MSG_TIMEOUT,
+ TCPIP_MSG_UNTIMEOUT,
+#endif /* LWIP_TCPIP_TIMEOUT */
+ TCPIP_MSG_CALLBACK
+};
+
+struct tcpip_msg {
+ enum tcpip_msg_type type;
+ sys_sem_t *sem;
+ union {
+#if LWIP_NETCONN
+ struct api_msg *apimsg;
+#endif /* LWIP_NETCONN */
+#if LWIP_NETIF_API
+ struct netifapi_msg *netifapimsg;
+#endif /* LWIP_NETIF_API */
+ struct {
+ struct pbuf *p;
+ struct netif *netif;
+ } inp;
+ struct {
+ tcpip_callback_fn function;
+ void *ctx;
+ } cb;
+#if LWIP_TCPIP_TIMEOUT
+ struct {
+ u32_t msecs;
+ sys_timeout_handler h;
+ void *arg;
+ } tmo;
+#endif /* LWIP_TCPIP_TIMEOUT */
+ } msg;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !NO_SYS */
+
+#endif /* __LWIP_TCPIP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/timers.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/timers.h
new file mode 100644
index 0000000000..fb92b4b47c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/timers.h
@@ -0,0 +1,98 @@
+/*
+ * 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 <adam@sics.se>
+ * Simon Goldschmidt
+ *
+ */
+#ifndef __LWIP_TIMERS_H__
+#define __LWIP_TIMERS_H__
+
+#include "lwip/opt.h"
+
+/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
+#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
+
+#if LWIP_TIMERS
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef LWIP_DEBUG_TIMERNAMES
+#ifdef LWIP_DEBUG
+#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG
+#else /* LWIP_DEBUG */
+#define LWIP_DEBUG_TIMERNAMES 0
+#endif /* LWIP_DEBUG*/
+#endif
+
+/** Function prototype for a timeout callback function. Register such a function
+ * using sys_timeout().
+ *
+ * @param arg Additional argument to pass to the function - set up by sys_timeout()
+ */
+typedef void (* sys_timeout_handler)(void *arg);
+
+struct sys_timeo {
+ struct sys_timeo *next;
+ u32_t time;
+ sys_timeout_handler h;
+ void *arg;
+#if LWIP_DEBUG_TIMERNAMES
+ const char* handler_name;
+#endif /* LWIP_DEBUG_TIMERNAMES */
+};
+
+void sys_timeouts_init(void);
+
+#if LWIP_DEBUG_TIMERNAMES
+void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name);
+#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler)
+#else /* LWIP_DEBUG_TIMERNAMES */
+void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
+#endif /* LWIP_DEBUG_TIMERNAMES */
+
+void sys_untimeout(sys_timeout_handler handler, void *arg);
+#if NO_SYS
+void sys_check_timeouts(void);
+void sys_restart_timeouts(void);
+#else /* NO_SYS */
+void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
+#endif /* NO_SYS */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_TIMERS */
+#endif /* __LWIP_TIMERS_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/udp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/udp.h
new file mode 100644
index 0000000000..c98c1b3ec1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/lwip/udp.h
@@ -0,0 +1,171 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_UDP_H__
+#define __LWIP_UDP_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/ip_addr.h"
+#include "lwip/ip.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UDP_HLEN 8
+
+/* Fields are (of course) in network byte order. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct udp_hdr {
+ PACK_STRUCT_FIELD(u16_t src);
+ PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */
+ PACK_STRUCT_FIELD(u16_t len);
+ PACK_STRUCT_FIELD(u16_t chksum);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define UDP_FLAGS_NOCHKSUM 0x01U
+#define UDP_FLAGS_UDPLITE 0x02U
+#define UDP_FLAGS_CONNECTED 0x04U
+#define UDP_FLAGS_MULTICAST_LOOP 0x08U
+
+struct udp_pcb;
+
+/** Function prototype for udp pcb receive callback functions
+ * addr and port are in same byte order as in the pcb
+ * The callback is responsible for freeing the pbuf
+ * if it's not used any more.
+ *
+ * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
+ * makes 'addr' invalid, too.
+ *
+ * @param arg user supplied argument (udp_pcb.recv_arg)
+ * @param pcb the udp_pcb which received data
+ * @param p the packet buffer that was received
+ * @param addr the remote IP address from which the packet was received
+ * @param port the remote port from which the packet was received
+ */
+typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *addr, u16_t port);
+
+
+struct udp_pcb {
+/* Common members of all PCB types */
+ IP_PCB;
+
+/* Protocol specific PCB members */
+
+ struct udp_pcb *next;
+
+ u8_t flags;
+ /** ports are in host byte order */
+ u16_t local_port, remote_port;
+
+#if LWIP_IGMP
+ /** outgoing network interface for multicast packets */
+ ip_addr_t multicast_ip;
+#endif /* LWIP_IGMP */
+
+#if LWIP_UDPLITE
+ /** used for UDP_LITE only */
+ u16_t chksum_len_rx, chksum_len_tx;
+#endif /* LWIP_UDPLITE */
+
+ /** receive callback function */
+ udp_recv_fn recv;
+ /** user-supplied argument for the recv callback */
+ void *recv_arg;
+};
+/* udp_pcbs export for exernal reference (e.g. SNMP agent) */
+extern struct udp_pcb *udp_pcbs;
+
+/* The following functions is the application layer interface to the
+ UDP code. */
+struct udp_pcb * udp_new (void);
+void udp_remove (struct udp_pcb *pcb);
+err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr,
+ u16_t port);
+err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr,
+ u16_t port);
+void udp_disconnect (struct udp_pcb *pcb);
+void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv,
+ void *recv_arg);
+err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port,
+ struct netif *netif);
+err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port);
+err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);
+
+#if LWIP_CHECKSUM_ON_COPY
+err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port,
+ struct netif *netif, u8_t have_chksum,
+ u16_t chksum);
+err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p,
+ ip_addr_t *dst_ip, u16_t dst_port,
+ u8_t have_chksum, u16_t chksum);
+err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
+ u8_t have_chksum, u16_t chksum);
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+#define udp_flags(pcb) ((pcb)->flags)
+#define udp_setflags(pcb, f) ((pcb)->flags = (f))
+
+/* The following functions are the lower layer interface to UDP. */
+void udp_input (struct pbuf *p, struct netif *inp);
+
+#define udp_init() /* Compatibility define, not init needed. */
+
+#if UDP_DEBUG
+void udp_debug_print(struct udp_hdr *udphdr);
+#else
+#define udp_debug_print(udphdr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_UDP */
+
+#endif /* __LWIP_UDP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/etharp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/etharp.h
new file mode 100644
index 0000000000..82c9f20dd9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/etharp.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2003-2004 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __NETIF_ETHARP_H__
+#define __NETIF_ETHARP_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ETHARP_HWADDR_LEN
+#define ETHARP_HWADDR_LEN 6
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_addr {
+ PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** Ethernet header */
+struct eth_hdr {
+#if ETH_PAD_SIZE
+ PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
+#endif
+ PACK_STRUCT_FIELD(struct eth_addr dest);
+ PACK_STRUCT_FIELD(struct eth_addr src);
+ PACK_STRUCT_FIELD(u16_t type);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
+
+#if ETHARP_SUPPORT_VLAN
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** VLAN header inserted between ethernet header and payload
+ * if 'type' in ethernet header is ETHTYPE_VLAN.
+ * See IEEE802.Q */
+struct eth_vlan_hdr {
+ PACK_STRUCT_FIELD(u16_t prio_vid);
+ PACK_STRUCT_FIELD(u16_t tpid);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define SIZEOF_VLAN_HDR 4
+#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
+
+#endif /* ETHARP_SUPPORT_VLAN */
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** the ARP message, see RFC 826 ("Packet format") */
+struct etharp_hdr {
+ PACK_STRUCT_FIELD(u16_t hwtype);
+ PACK_STRUCT_FIELD(u16_t proto);
+ PACK_STRUCT_FIELD(u8_t hwlen);
+ PACK_STRUCT_FIELD(u8_t protolen);
+ PACK_STRUCT_FIELD(u16_t opcode);
+ PACK_STRUCT_FIELD(struct eth_addr shwaddr);
+ PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
+ PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
+ PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define SIZEOF_ETHARP_HDR 28
+#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
+
+/** 5 seconds period */
+#define ARP_TMR_INTERVAL 5000
+
+#define ETHTYPE_ARP 0x0806U
+#define ETHTYPE_IP 0x0800U
+#define ETHTYPE_VLAN 0x8100U
+#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
+#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
+
+/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
+ * or known to be 32-bit aligned within the protocol header. */
+#ifndef ETHADDR32_COPY
+#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
+#endif
+
+/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local
+ * variables and known to be 16-bit aligned within the protocol header. */
+#ifndef ETHADDR16_COPY
+#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
+#endif
+
+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
+
+/** ARP message types (opcodes) */
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)
+ * to a filter function that returns the correct netif when using multiple
+ * netifs on one hardware interface where the netif's low-level receive
+ * routine cannot decide for the correct netif (e.g. when mapping multiple
+ * IP addresses to one hardware interface).
+ */
+#ifndef LWIP_ARP_FILTER_NETIF
+#define LWIP_ARP_FILTER_NETIF 0
+#endif
+
+#if ARP_QUEUEING
+/** struct for queueing outgoing packets for unknown address
+ * defined here to be accessed by memp.h
+ */
+struct etharp_q_entry {
+ struct etharp_q_entry *next;
+ struct pbuf *p;
+};
+#endif /* ARP_QUEUEING */
+
+#define etharp_init() /* Compatibility define, not init needed. */
+void etharp_tmr(void);
+s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
+ struct eth_addr **eth_ret, ip_addr_t **ip_ret);
+err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
+err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q);
+err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
+/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
+ * this is an ARP packet sent by a node in order to spontaneously cause other
+ * nodes to update an entry in their ARP cache.
+ * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
+#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
+
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);
+err_t etharp_remove_static_entry(ip_addr_t *ipaddr);
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+
+#if LWIP_AUTOIP
+err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
+ const struct eth_addr *ethdst_addr,
+ const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
+ const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
+ const u16_t opcode);
+#endif /* LWIP_AUTOIP */
+
+#endif /* LWIP_ARP */
+
+err_t ethernet_input(struct pbuf *p, struct netif *netif);
+
+#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)
+
+extern const struct eth_addr ethbroadcast, ethzero;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_ARP || LWIP_ETHERNET */
+
+#endif /* __NETIF_ARP_H__ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/ppp_oe.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/ppp_oe.h
new file mode 100644
index 0000000000..e1cdfa5199
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/ppp_oe.h
@@ -0,0 +1,190 @@
+/*****************************************************************************
+* ppp_oe.h - PPP Over Ethernet implementation for lwIP.
+*
+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 06-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+*****************************************************************************/
+
+
+
+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Martin Husemann <martin@NetBSD.org>.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 PPP_OE_H
+#define PPP_OE_H
+
+#include "lwip/opt.h"
+
+#if PPPOE_SUPPORT > 0
+
+#include "netif/etharp.h"
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct pppoehdr {
+ PACK_STRUCT_FIELD(u8_t vertype);
+ PACK_STRUCT_FIELD(u8_t code);
+ PACK_STRUCT_FIELD(u16_t session);
+ PACK_STRUCT_FIELD(u16_t plen);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct pppoetag {
+ PACK_STRUCT_FIELD(u16_t tag);
+ PACK_STRUCT_FIELD(u16_t len);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+
+#define PPPOE_STATE_INITIAL 0
+#define PPPOE_STATE_PADI_SENT 1
+#define PPPOE_STATE_PADR_SENT 2
+#define PPPOE_STATE_SESSION 3
+#define PPPOE_STATE_CLOSING 4
+/* passive */
+#define PPPOE_STATE_PADO_SENT 1
+
+#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
+#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
+
+#define PPPOE_TAG_EOL 0x0000 /* end of list */
+#define PPPOE_TAG_SNAME 0x0101 /* service name */
+#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
+#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
+#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
+#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
+#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_CODE_PADI 0x09 /* Active Discovery Initiation */
+#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
+#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
+#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
+#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
+
+#ifndef ETHERMTU
+#define ETHERMTU 1500
+#endif
+
+/* two byte PPP protocol discriminator, then IP data */
+#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
+
+#ifndef PPPOE_MAX_AC_COOKIE_LEN
+#define PPPOE_MAX_AC_COOKIE_LEN 64
+#endif
+
+struct pppoe_softc {
+ struct pppoe_softc *next;
+ struct netif *sc_ethif; /* ethernet interface we are using */
+ int sc_pd; /* ppp unit number */
+ void (*sc_linkStatusCB)(int pd, int up);
+
+ int sc_state; /* discovery phase or session connected */
+ struct eth_addr sc_dest; /* hardware address of concentrator */
+ u16_t sc_session; /* PPPoE session id */
+
+#ifdef PPPOE_TODO
+ char *sc_service_name; /* if != NULL: requested name of service */
+ char *sc_concentrator_name; /* if != NULL: requested concentrator id */
+#endif /* PPPOE_TODO */
+ u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
+ size_t sc_ac_cookie_len; /* length of cookie data */
+#ifdef PPPOE_SERVER
+ u8_t *sc_hunique; /* content of host unique we must echo back */
+ size_t sc_hunique_len; /* length of host unique */
+#endif
+ int sc_padi_retried; /* number of PADI retries already done */
+ int sc_padr_retried; /* number of PADR retries already done */
+};
+
+
+#define pppoe_init() /* compatibility define, no initialization needed */
+
+err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);
+err_t pppoe_destroy(struct netif *ifp);
+
+int pppoe_connect(struct pppoe_softc *sc);
+void pppoe_disconnect(struct pppoe_softc *sc);
+
+void pppoe_disc_input(struct netif *netif, struct pbuf *p);
+void pppoe_data_input(struct netif *netif, struct pbuf *p);
+
+err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
+
+/** used in ppp.c */
+#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)
+
+#endif /* PPPOE_SUPPORT */
+
+#endif /* PPP_OE_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/slipif.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/slipif.h
new file mode 100644
index 0000000000..ccd03c8a16
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/include/netif/slipif.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <adam@sics.se>
+ *
+ */
+#ifndef __NETIF_SLIPIF_H__
+#define __NETIF_SLIPIF_H__
+
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+err_t slipif_init(struct netif * netif);
+void slipif_poll(struct netif *netif);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/lwipopts.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/lwipopts.h
new file mode 100644
index 0000000000..1d68e59937
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/lwipopts.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LWIPOPTS_H
+#define LWIPOPTS_H
+
+#include "lwipopts_conf.h"
+
+// Operating System
+#define NO_SYS 0
+
+#if NO_SYS == 0
+#include "cmsis_os.h"
+
+#define SYS_LIGHTWEIGHT_PROT 1
+
+#define LWIP_RAW 0
+
+#define TCPIP_MBOX_SIZE 8
+#define DEFAULT_TCP_RECVMBOX_SIZE 8
+#define DEFAULT_UDP_RECVMBOX_SIZE 8
+#define DEFAULT_RAW_RECVMBOX_SIZE 8
+#define DEFAULT_ACCEPTMBOX_SIZE 8
+
+#define TCPIP_THREAD_STACKSIZE 1024
+#define TCPIP_THREAD_PRIO (osPriorityNormal)
+
+#define DEFAULT_THREAD_STACKSIZE 512
+
+#define MEMP_NUM_SYS_TIMEOUT 16
+#endif
+
+// 32-bit alignment
+#define MEM_ALIGNMENT 4
+
+#define PBUF_POOL_SIZE 5
+#define MEMP_NUM_TCP_PCB_LISTEN 4
+#define MEMP_NUM_TCP_PCB 4
+#define MEMP_NUM_PBUF 8
+
+#define TCP_QUEUE_OOSEQ 0
+#define TCP_OVERSIZE 0
+
+#define LWIP_DHCP 1
+#define LWIP_DNS 1
+
+// Support Multicast
+#include "stdlib.h"
+#define LWIP_IGMP 1
+#define LWIP_RAND() rand()
+
+#define LWIP_COMPAT_SOCKETS 0
+#define LWIP_POSIX_SOCKETS_IO_NAMES 0
+#define LWIP_SO_RCVTIMEO 1
+#define LWIP_TCP_KEEPALIVE 1
+
+// Debug Options
+// #define LWIP_DEBUG
+#define UDP_LPC_EMAC LWIP_DBG_OFF
+#define SYS_DEBUG LWIP_DBG_OFF
+#define PPP_DEBUG LWIP_DBG_OFF
+#define IP_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 SOCKETS_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 ETHARP_DEBUG LWIP_DBG_OFF
+#define NETIF_DEBUG LWIP_DBG_OFF
+#define DHCP_DEBUG LWIP_DBG_OFF
+
+#ifdef LWIP_DEBUG
+#define MEMP_OVERFLOW_CHECK 1
+#define MEMP_SANITY_CHECK 1
+#else
+#define LWIP_NOASSERT 1
+#define LWIP_STATS 0
+#endif
+
+#define LWIP_PLATFORM_BYTESWAP 1
+
+#if LWIP_TRANSPORT_ETHERNET
+
+/* MSS should match the hardware packet size */
+#define TCP_MSS 1460
+#define TCP_SND_BUF (2 * TCP_MSS)
+#define TCP_WND (2 * TCP_MSS)
+#define TCP_SND_QUEUELEN (2 * TCP_SND_BUF/TCP_MSS)
+
+// Broadcast
+#define IP_SOF_BROADCAST 1
+#define IP_SOF_BROADCAST_RECV 1
+
+#define LWIP_BROADCAST_PING 1
+
+#define LWIP_CHECKSUM_ON_COPY 1
+
+#define LWIP_NETIF_HOSTNAME 1
+#define LWIP_NETIF_STATUS_CALLBACK 1
+#define LWIP_NETIF_LINK_CALLBACK 1
+
+#elif LWIP_TRANSPORT_PPP
+
+#define TCP_SND_BUF (3 * 536)
+#define TCP_WND (2 * 536)
+
+#define LWIP_ARP 0
+
+#define PPP_SUPPORT 1
+#define CHAP_SUPPORT 1
+#define PAP_SUPPORT 1
+#define PPP_THREAD_STACKSIZE 4*192
+#define PPP_THREAD_PRIO 0
+
+#define MAXNAMELEN 64 /* max length of hostname or name for auth */
+#define MAXSECRETLEN 64
+
+#else
+#error A transport mechanism (Ethernet or PPP) must be defined
+#endif
+
+#endif /* LWIPOPTS_H_ */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/etharp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/etharp.c
new file mode 100644
index 0000000000..b60dadd024
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/etharp.c
@@ -0,0 +1,1318 @@
+/**
+ * @file
+ * Address Resolution Protocol module for IP over Ethernet
+ *
+ * Functionally, ARP is divided into two parts. The first maps an IP address
+ * to a physical address when sending a packet, and the second part answers
+ * 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
+ * if an interface calls etharp_gratuitous(our_netif) upon address change.
+ */
+
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
+ * Copyright (c) 2003-2004 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_ARP || LWIP_ETHERNET
+
+#include "lwip/ip_addr.h"
+#include "lwip/def.h"
+#include "lwip/ip.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "netif/etharp.h"
+
+#if PPPOE_SUPPORT
+#include "netif/ppp_oe.h"
+#endif /* PPPOE_SUPPORT */
+
+#include <string.h>
+
+const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
+const struct eth_addr ethzero = {{0,0,0,0,0,0}};
+
+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
+
+/** the time an ARP entry stays valid after its last update,
+ * for ARP_TMR_INTERVAL = 5000, this is
+ * (240 * 5) seconds = 20 minutes.
+ */
+#define ARP_MAXAGE 240
+/** the time an ARP entry stays pending after first request,
+ * for ARP_TMR_INTERVAL = 5000, this is
+ * (2 * 5) seconds = 10 seconds.
+ *
+ * @internal Keep this number at least 2, otherwise it might
+ * run out instantly if the timeout occurs directly after a request.
+ */
+#define ARP_MAXPENDING 2
+
+#define HWTYPE_ETHERNET 1
+
+enum etharp_state {
+ ETHARP_STATE_EMPTY = 0,
+ ETHARP_STATE_PENDING,
+ ETHARP_STATE_STABLE
+};
+
+struct etharp_entry {
+#if ARP_QUEUEING
+ /** Pointer to queue of pending outgoing packets on this ARP entry. */
+ struct etharp_q_entry *q;
+#else /* ARP_QUEUEING */
+ /** Pointer to a single pending outgoing packet on this ARP entry. */
+ struct pbuf *q;
+#endif /* ARP_QUEUEING */
+ ip_addr_t ipaddr;
+ struct eth_addr ethaddr;
+#if LWIP_SNMP
+ struct netif *netif;
+#endif /* LWIP_SNMP */
+ u8_t state;
+ u8_t ctime;
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+ u8_t static_entry;
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+};
+
+static struct etharp_entry arp_table[ARP_TABLE_SIZE];
+
+#if !LWIP_NETIF_HWADDRHINT
+static u8_t etharp_cached_entry;
+#endif /* !LWIP_NETIF_HWADDRHINT */
+
+/** Try hard to create a new entry - we want the IP address to appear in
+ the cache (even if this means removing an active entry or so). */
+#define ETHARP_FLAG_TRY_HARD 1
+#define ETHARP_FLAG_FIND_ONLY 2
+#define ETHARP_FLAG_STATIC_ENTRY 4
+
+#if LWIP_NETIF_HWADDRHINT
+#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
+ *((netif)->addr_hint) = (hint);
+#else /* LWIP_NETIF_HWADDRHINT */
+#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
+#endif /* LWIP_NETIF_HWADDRHINT */
+
+static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
+
+
+/* Some checks, instead of etharp_init(): */
+#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
+ #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h"
+#endif
+
+
+#if ARP_QUEUEING
+/**
+ * Free a complete queue of etharp entries
+ *
+ * @param q a qeueue of etharp_q_entry's to free
+ */
+static void
+free_etharp_q(struct etharp_q_entry *q)
+{
+ struct etharp_q_entry *r;
+ LWIP_ASSERT("q != NULL", q != NULL);
+ LWIP_ASSERT("q->p != NULL", q->p != NULL);
+ while (q) {
+ r = q;
+ q = q->next;
+ LWIP_ASSERT("r->p != NULL", (r->p != NULL));
+ pbuf_free(r->p);
+ memp_free(MEMP_ARP_QUEUE, r);
+ }
+}
+#else /* ARP_QUEUEING */
+
+/** Compatibility define: free the queued pbuf */
+#define free_etharp_q(q) pbuf_free(q)
+
+#endif /* ARP_QUEUEING */
+
+/** Clean up ARP table entries */
+static void
+free_entry(int i)
+{
+ /* remove from SNMP ARP index tree */
+ snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
+ /* and empty packet queue */
+ if (arp_table[i].q != NULL) {
+ /* remove all queued packets */
+ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
+ free_etharp_q(arp_table[i].q);
+ arp_table[i].q = NULL;
+ }
+ /* recycle entry for re-use */
+ arp_table[i].state = ETHARP_STATE_EMPTY;
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+ arp_table[i].static_entry = 0;
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+#ifdef LWIP_DEBUG
+ /* for debugging, clean out the complete entry */
+ arp_table[i].ctime = 0;
+#if LWIP_SNMP
+ arp_table[i].netif = NULL;
+#endif /* LWIP_SNMP */
+ ip_addr_set_zero(&arp_table[i].ipaddr);
+ arp_table[i].ethaddr = ethzero;
+#endif /* LWIP_DEBUG */
+}
+
+/**
+ * Clears expired entries in the ARP table.
+ *
+ * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),
+ * in order to expire entries in the ARP table.
+ */
+void
+etharp_tmr(void)
+{
+ u8_t i;
+
+ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
+ /* remove expired entries from the ARP table */
+ 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
+ && (arp_table[i].static_entry == 0)
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+ ) {
+ arp_table[i].ctime++;
+ if ((arp_table[i].ctime >= ARP_MAXAGE) ||
+ ((arp_table[i].state == ETHARP_STATE_PENDING) &&
+ (arp_table[i].ctime >= ARP_MAXPENDING))) {
+ /* pending or stable entry has become old! */
+ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
+ arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
+ /* clean up entries that have just been expired */
+ free_entry(i);
+ }
+#if ARP_QUEUEING
+ /* still pending entry? (not expired) */
+ if (arp_table[i].state == ETHARP_STATE_PENDING) {
+ /* resend an ARP query here? */
+ }
+#endif /* ARP_QUEUEING */
+ }
+ }
+}
+
+/**
+ * Search the ARP table for a matching or new entry.
+ *
+ * If an IP address is given, return a pending or stable ARP entry that matches
+ * the address. If no match is found, create a new entry with this address set,
+ * but in state ETHARP_EMPTY. The caller must check and possibly change the
+ * state of the returned entry.
+ *
+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
+ *
+ * In all cases, attempt to create new entries from an empty entry. If no
+ * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle
+ * old entries. Heuristic choose the least important entry for recycling.
+ *
+ * @param ipaddr IP address to find in ARP cache, or to add if not found.
+ * @param flags @see definition of ETHARP_FLAG_*
+ * @param netif netif related to this address (used for NETIF_HWADDRHINT)
+ *
+ * @return The ARP entry index that matched or is created, ERR_MEM if no
+ * entry is found or could be recycled.
+ */
+static s8_t
+find_entry(ip_addr_t *ipaddr, u8_t flags)
+{
+ s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
+ s8_t empty = ARP_TABLE_SIZE;
+ u8_t i = 0, age_pending = 0, age_stable = 0;
+ /* oldest entry with packets on queue */
+ s8_t old_queue = ARP_TABLE_SIZE;
+ /* its age */
+ u8_t age_queue = 0;
+
+ /**
+ * a) do a search through the cache, remember candidates
+ * b) select candidate entry
+ * c) create new entry
+ */
+
+ /* a) in a single search sweep, do all of this
+ * 1) remember the first empty entry (if any)
+ * 2) remember the oldest stable entry (if any)
+ * 3) remember the oldest pending entry without queued packets (if any)
+ * 4) remember the oldest pending entry with queued packets (if any)
+ * 5) search for a matching IP entry, either pending or stable
+ * until 5 matches, or all entries are searched for.
+ */
+
+ for (i = 0; i < ARP_TABLE_SIZE; ++i) {
+ u8_t state = arp_table[i].state;
+ /* no empty entry found yet and now we do find one? */
+ if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
+ LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
+ /* remember first empty entry */
+ empty = i;
+ } else if (state != ETHARP_STATE_EMPTY) {
+ 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 && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
+ /* found exact IP address match, simply bail out */
+ return i;
+ }
+ /* pending entry? */
+ if (state == ETHARP_STATE_PENDING) {
+ /* pending with queued packets? */
+ if (arp_table[i].q != NULL) {
+ if (arp_table[i].ctime >= age_queue) {
+ old_queue = i;
+ age_queue = arp_table[i].ctime;
+ }
+ } else
+ /* pending without queued packets? */
+ {
+ if (arp_table[i].ctime >= age_pending) {
+ old_pending = i;
+ age_pending = arp_table[i].ctime;
+ }
+ }
+ /* stable entry? */
+ } else if (state == ETHARP_STATE_STABLE) {
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+ /* don't record old_stable for static entries since they never expire */
+ if (arp_table[i].static_entry == 0)
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+ {
+ /* remember entry with oldest stable entry in oldest, its age in maxtime */
+ if (arp_table[i].ctime >= age_stable) {
+ old_stable = i;
+ age_stable = arp_table[i].ctime;
+ }
+ }
+ }
+ }
+ }
+ /* { we have no match } => try to create a new entry */
+
+ /* don't create new entry, only search? */
+ if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
+ /* or no empty entry found and not allowed to recycle? */
+ ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
+ return (s8_t)ERR_MEM;
+ }
+
+ /* b) choose the least destructive entry to recycle:
+ * 1) empty entry
+ * 2) oldest stable entry
+ * 3) oldest pending entry without queued packets
+ * 4) oldest pending entry with queued packets
+ *
+ * { ETHARP_FLAG_TRY_HARD is set at this point }
+ */
+
+ /* 1) empty entry available? */
+ if (empty < ARP_TABLE_SIZE) {
+ i = empty;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
+ } else {
+ /* 2) found recyclable stable entry? */
+ if (old_stable < ARP_TABLE_SIZE) {
+ /* recycle oldest stable*/
+ i = old_stable;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
+ /* no queued packets should exist on stable entries */
+ LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
+ /* 3) found recyclable pending entry without queued packets? */
+ } else if (old_pending < ARP_TABLE_SIZE) {
+ /* recycle oldest pending */
+ i = old_pending;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
+ /* 4) found recyclable pending entry with queued packets? */
+ } else if (old_queue < ARP_TABLE_SIZE) {
+ /* recycle oldest pending (queued packets are free in free_entry) */
+ i = old_queue;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
+ /* no empty or recyclable entries found */
+ } else {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
+ return (s8_t)ERR_MEM;
+ }
+
+ /* { empty or recyclable entry found } */
+ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
+ free_entry(i);
+ }
+
+ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
+ LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
+ arp_table[i].state == ETHARP_STATE_EMPTY);
+
+ /* IP address given? */
+ if (ipaddr != NULL) {
+ /* set IP address */
+ ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
+ }
+ arp_table[i].ctime = 0;
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+ arp_table[i].static_entry = 0;
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+ return (err_t)i;
+}
+
+/**
+ * Send an IP packet on the network using netif->linkoutput
+ * The ethernet header is filled in before sending.
+ *
+ * @params netif the lwIP network interface on which to send the packet
+ * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
+ * @params src the source MAC address to be copied into the ethernet header
+ * @params dst the destination MAC address to be copied into the ethernet header
+ * @return ERR_OK if the packet was sent, any other err_t on failure
+ */
+static err_t
+etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
+{
+ struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
+
+ LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
+ (netif->hwaddr_len == ETHARP_HWADDR_LEN));
+ ETHADDR32_COPY(&ethhdr->dest, dst);
+ ETHADDR16_COPY(&ethhdr->src, src);
+ ethhdr->type = PP_HTONS(ETHTYPE_IP);
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));
+ /* send the packet */
+ return netif->linkoutput(netif, p);
+}
+
+/**
+ * Update (or insert) a IP/MAC address pair in the ARP cache.
+ *
+ * If a pending entry is resolved, any queued packets will be sent
+ * at this point.
+ *
+ * @param netif netif related to this entry (used for NETIF_ADDRHINT)
+ * @param ipaddr IP address of the inserted ARP entry.
+ * @param ethaddr Ethernet address of the inserted ARP entry.
+ * @param flags @see definition of ETHARP_FLAG_*
+ *
+ * @return
+ * - ERR_OK Succesfully updated ARP cache.
+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set.
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
+ *
+ * @see pbuf_free()
+ */
+static err_t
+update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
+{
+ s8_t i;
+ LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
+ ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
+ ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
+ ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
+ /* non-unicast address? */
+ if (ip_addr_isany(ipaddr) ||
+ ip_addr_isbroadcast(ipaddr, netif) ||
+ ip_addr_ismulticast(ipaddr)) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
+ return ERR_ARG;
+ }
+ /* find or create ARP entry */
+ i = find_entry(ipaddr, flags);
+ /* bail out if no entry could be found */
+ if (i < 0) {
+ return (err_t)i;
+ }
+
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+ if (flags & ETHARP_FLAG_STATIC_ENTRY) {
+ /* record static type */
+ arp_table[i].static_entry = 1;
+ }
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+
+ /* mark it stable */
+ arp_table[i].state = ETHARP_STATE_STABLE;
+
+#if LWIP_SNMP
+ /* record network interface */
+ arp_table[i].netif = netif;
+#endif /* LWIP_SNMP */
+ /* insert in SNMP ARP index tree */
+ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
+
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
+ /* update address */
+ ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
+ /* reset time stamp */
+ arp_table[i].ctime = 0;
+ /* this is where we will send out queued packets! */
+#if ARP_QUEUEING
+ while (arp_table[i].q != NULL) {
+ struct pbuf *p;
+ /* remember remainder of queue */
+ struct etharp_q_entry *q = arp_table[i].q;
+ /* pop first item off the queue */
+ arp_table[i].q = q->next;
+ /* get the packet pointer */
+ p = q->p;
+ /* now queue entry can be freed */
+ memp_free(MEMP_ARP_QUEUE, q);
+#else /* ARP_QUEUEING */
+ if (arp_table[i].q != NULL) {
+ struct pbuf *p = arp_table[i].q;
+ arp_table[i].q = NULL;
+#endif /* ARP_QUEUEING */
+ /* send the queued IP packet */
+ etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
+ /* free the queued IP packet */
+ pbuf_free(p);
+ }
+ return ERR_OK;
+}
+
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+/** Add a new static entry to the ARP table. If an entry exists for the
+ * specified IP address, this entry is overwritten.
+ * If packets are queued for the specified IP address, they are sent out.
+ *
+ * @param ipaddr IP address for the new static entry
+ * @param ethaddr ethernet address for the new static entry
+ * @return @see return values of etharp_add_static_entry
+ */
+err_t
+etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
+{
+ struct netif *netif;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
+ ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
+ ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
+ ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
+
+ netif = ip_route(ipaddr);
+ if (netif == NULL) {
+ return ERR_RTE;
+ }
+
+ return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
+}
+
+/** Remove a static entry from the ARP table previously added with a call to
+ * etharp_add_static_entry.
+ *
+ * @param ipaddr IP address of the static entry to remove
+ * @return ERR_OK: entry removed
+ * ERR_MEM: entry wasn't found
+ * ERR_ARG: entry wasn't a static entry but a dynamic one
+ */
+err_t
+etharp_remove_static_entry(ip_addr_t *ipaddr)
+{
+ s8_t i;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+ ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+
+ /* find or create ARP entry */
+ i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+ /* bail out if no entry could be found */
+ if (i < 0) {
+ return (err_t)i;
+ }
+
+ if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
+ (arp_table[i].static_entry == 0)) {
+ /* entry wasn't a static entry, cannot remove it */
+ return ERR_ARG;
+ }
+ /* entry found, free it */
+ free_entry(i);
+ return ERR_OK;
+}
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
+
+/**
+ * Finds (stable) ethernet/IP address pair from ARP table
+ * using interface and IP address index.
+ * @note the addresses in the ARP table are in network order!
+ *
+ * @param netif points to interface index
+ * @param ipaddr points to the (network order) IP address index
+ * @param eth_ret points to return pointer
+ * @param ip_ret points to return pointer
+ * @return table index if found, -1 otherwise
+ */
+s8_t
+etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
+ struct eth_addr **eth_ret, ip_addr_t **ip_ret)
+{
+ s8_t i;
+
+ LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
+ eth_ret != NULL && ip_ret != NULL);
+
+ LWIP_UNUSED_ARG(netif);
+
+ i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+ if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
+ *eth_ret = &arp_table[i].ethaddr;
+ *ip_ret = &arp_table[i].ipaddr;
+ return i;
+ }
+ return -1;
+}
+
+#if ETHARP_TRUST_IP_MAC
+/**
+ * Updates the ARP table using the given IP packet.
+ *
+ * Uses the incoming IP packet's source address to update the
+ * ARP cache for the local network. The function does not alter
+ * or free the packet. This function must be called before the
+ * packet p is passed to the IP layer.
+ *
+ * @param netif The lwIP network interface on which the IP packet pbuf arrived.
+ * @param p The IP packet that arrived on netif.
+ *
+ * @return NULL
+ *
+ * @see pbuf_free()
+ */
+static void
+etharp_ip_input(struct netif *netif, struct pbuf *p)
+{
+ struct eth_hdr *ethhdr;
+ struct ip_hdr *iphdr;
+ ip_addr_t iphdr_src;
+ LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+
+ /* Only insert an entry if the source IP address of the
+ incoming IP packet comes from a host on the local network. */
+ ethhdr = (struct eth_hdr *)p->payload;
+ iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
+#if ETHARP_SUPPORT_VLAN
+ if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
+ iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
+ }
+#endif /* ETHARP_SUPPORT_VLAN */
+
+ ip_addr_copy(iphdr_src, iphdr->src);
+
+ /* source is not on the local network? */
+ if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) {
+ /* do nothing */
+ return;
+ }
+
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
+ /* update the source IP address in the cache, if present */
+ /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
+ * back soon (for example, if the destination IP address is ours. */
+ update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
+}
+#endif /* ETHARP_TRUST_IP_MAC */
+
+/**
+ * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
+ * send out queued IP packets. Updates cache with snooped address pairs.
+ *
+ * Should be called for incoming ARP packets. The pbuf in the argument
+ * is freed by this function.
+ *
+ * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
+ * @param ethaddr Ethernet address of netif.
+ * @param p The ARP packet that arrived on netif. Is freed by this function.
+ *
+ * @return NULL
+ *
+ * @see pbuf_free()
+ */
+static void
+etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
+{
+ struct etharp_hdr *hdr;
+ struct eth_hdr *ethhdr;
+ /* these are aligned properly, whereas the ARP header fields might not be */
+ ip_addr_t sipaddr, dipaddr;
+ u8_t for_us;
+#if LWIP_AUTOIP
+ const u8_t * ethdst_hwaddr;
+#endif /* LWIP_AUTOIP */
+
+ LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+
+ /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
+ since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
+ if (p->len < SIZEOF_ETHARP_PACKET) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+ ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
+ (s16_t)SIZEOF_ETHARP_PACKET));
+ ETHARP_STATS_INC(etharp.lenerr);
+ ETHARP_STATS_INC(etharp.drop);
+ pbuf_free(p);
+ return;
+ }
+
+ ethhdr = (struct eth_hdr *)p->payload;
+ hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
+#if ETHARP_SUPPORT_VLAN
+ if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
+ hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
+ }
+#endif /* ETHARP_SUPPORT_VLAN */
+
+ /* RFC 826 "Packet Reception": */
+ if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
+ (hdr->hwlen != ETHARP_HWADDR_LEN) ||
+ (hdr->protolen != sizeof(ip_addr_t)) ||
+ (hdr->proto != PP_HTONS(ETHTYPE_IP))) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+ ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
+ hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
+ ETHARP_STATS_INC(etharp.proterr);
+ ETHARP_STATS_INC(etharp.drop);
+ pbuf_free(p);
+ return;
+ }
+ 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 continously check if there is
+ * a host with this IP-address so we can detect collisions */
+ autoip_arp_reply(netif, hdr);
+#endif /* LWIP_AUTOIP */
+
+ /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
+ * structure packing (not using structure copy which breaks strict-aliasing rules). */
+ IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
+ IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
+
+ /* this interface is not configured? */
+ if (ip_addr_isany(&netif->ip_addr)) {
+ for_us = 0;
+ } else {
+ /* ARP packet directed to us? */
+ for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
+ }
+
+ /* ARP message directed to us?
+ -> add IP address in ARP cache; assume requester wants to talk to us,
+ can result in directly sending the queued packets for this host.
+ ARP message not directed to us?
+ -> update the source IP address in the cache, if present */
+ update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
+ for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
+
+ /* now act on the message itself */
+ switch (hdr->opcode) {
+ /* ARP request? */
+ case PP_HTONS(ARP_REQUEST):
+ /* ARP request. If it asked for our address, we send out a
+ * reply. In any case, we time-stamp any existing ARP entry,
+ * and possiby send out an IP packet that was queued on it. */
+
+ LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
+ /* ARP request for our address? */
+ if (for_us) {
+
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
+ /* Re-use pbuf to send ARP reply.
+ Since we are re-using an existing pbuf, we can't call etharp_raw since
+ that would allocate a new pbuf. */
+ hdr->opcode = htons(ARP_REPLY);
+
+ IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
+ IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);
+
+ LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
+ (netif->hwaddr_len == ETHARP_HWADDR_LEN));
+#if LWIP_AUTOIP
+ /* If we are using Link-Local, all ARP packets that contain a Link-Local
+ * 'sender IP address' MUST be sent using link-layer broadcast instead of
+ * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
+ ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;
+#endif /* LWIP_AUTOIP */
+
+ ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
+#if LWIP_AUTOIP
+ ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
+#else /* LWIP_AUTOIP */
+ ETHADDR16_COPY(&ethhdr->dest, &hdr->shwaddr);
+#endif /* LWIP_AUTOIP */
+ ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
+ ETHADDR16_COPY(&ethhdr->src, ethaddr);
+
+ /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
+ are already correct, we tested that before */
+
+ /* return ARP reply */
+ netif->linkoutput(netif, p);
+ /* we are not configured? */
+ } else if (ip_addr_isany(&netif->ip_addr)) {
+ /* { for_us == 0 and netif->ip_addr.addr == 0 } */
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
+ /* request was not directed to us */
+ } else {
+ /* { for_us == 0 and netif->ip_addr.addr != 0 } */
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
+ }
+ break;
+ case PP_HTONS(ARP_REPLY):
+ /* ARP reply. We already updated the ARP cache earlier. */
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_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_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
+ ETHARP_STATS_INC(etharp.err);
+ break;
+ }
+ /* free ARP packet */
+ pbuf_free(p);
+}
+
+/**
+ * Resolve and fill-in Ethernet address header for outgoing IP packet.
+ *
+ * For IP multicast and broadcast, corresponding Ethernet addresses
+ * are selected and the packet is transmitted on the link.
+ *
+ * For unicast addresses, the packet is submitted to etharp_query(). In
+ * case the IP address is outside the local network, the IP address of
+ * the gateway is used.
+ *
+ * @param netif The lwIP network interface which the IP packet will be sent on.
+ * @param q The pbuf(s) containing the IP packet to be sent.
+ * @param ipaddr The IP address of the packet destination.
+ *
+ * @return
+ * - ERR_RTE No route to destination (no gateway to external networks),
+ * or the return type of either etharp_query() or etharp_send_ip().
+ */
+err_t
+etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
+{
+ struct eth_addr *dest, mcastaddr;
+
+ /* make room for Ethernet header - should not fail */
+ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
+ /* bail out */
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("etharp_output: could not allocate room for header.\n"));
+ LINK_STATS_INC(link.lenerr);
+ return ERR_BUF;
+ }
+
+ /* assume unresolved Ethernet address */
+ dest = NULL;
+ /* Determine on destination hardware address. Broadcasts and multicasts
+ * are special, other IP addresses are looked up in the ARP table. */
+
+ /* broadcast destination IP address? */
+ if (ip_addr_isbroadcast(ipaddr, netif)) {
+ /* broadcast on Ethernet also */
+ dest = (struct eth_addr *)&ethbroadcast;
+ /* multicast destination IP address? */
+ } else if (ip_addr_ismulticast(ipaddr)) {
+ /* Hash IP multicast address to MAC address.*/
+ mcastaddr.addr[0] = 0x01;
+ mcastaddr.addr[1] = 0x00;
+ mcastaddr.addr[2] = 0x5e;
+ mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
+ mcastaddr.addr[4] = ip4_addr3(ipaddr);
+ mcastaddr.addr[5] = ip4_addr4(ipaddr);
+ /* destination Ethernet address is multicast */
+ dest = &mcastaddr;
+ /* unicast destination IP address? */
+ } else {
+ /* outside local network? */
+ if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
+ !ip_addr_islinklocal(ipaddr)) {
+#if LWIP_AUTOIP
+ struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
+ sizeof(struct eth_hdr));
+ /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
+ a link-local source address must always be "directly to its destination
+ on the same physical link. The host MUST NOT send the packet to any
+ router for forwarding". */
+ if (!ip_addr_islinklocal(&iphdr->src))
+#endif /* LWIP_AUTOIP */
+ {
+ /* interface has default gateway? */
+ if (!ip_addr_isany(&netif->gw)) {
+ /* send to hardware address of default gateway IP address */
+ ipaddr = &(netif->gw);
+ /* no default gateway available */
+ } else {
+ /* no route to destination error (default gateway missing) */
+ return ERR_RTE;
+ }
+ }
+ }
+#if LWIP_NETIF_HWADDRHINT
+ if (netif->addr_hint != NULL) {
+ /* per-pcb cached entry was given */
+ u8_t etharp_cached_entry = *(netif->addr_hint);
+ if (etharp_cached_entry < ARP_TABLE_SIZE) {
+#endif /* LWIP_NETIF_HWADDRHINT */
+ if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
+ (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
+ /* the per-pcb-cached entry is stable and the right one! */
+ ETHARP_STATS_INC(etharp.cachehit);
+ return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
+ &arp_table[etharp_cached_entry].ethaddr);
+ }
+#if LWIP_NETIF_HWADDRHINT
+ }
+ }
+#endif /* LWIP_NETIF_HWADDRHINT */
+ /* queue on destination Ethernet address belonging to ipaddr */
+ return etharp_query(netif, ipaddr, q);
+ }
+
+ /* continuation for multicast/broadcast destinations */
+ /* obtain source Ethernet address of the given interface */
+ /* send packet directly on the link */
+ return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
+}
+
+/**
+ * Send an ARP request for the given IP address and/or queue a packet.
+ *
+ * If the IP address was not yet in the cache, a pending ARP cache entry
+ * is added and an ARP request is sent for the given address. The packet
+ * is queued on this entry.
+ *
+ * If the IP address was already pending in the cache, a new ARP request
+ * is sent for the given address. The packet is queued on this entry.
+ *
+ * If the IP address was already stable in the cache, and a packet is
+ * given, it is directly sent and no ARP request is sent out.
+ *
+ * If the IP address was already stable in the cache, and no packet is
+ * given, an ARP request is sent out.
+ *
+ * @param netif The lwIP network interface on which ipaddr
+ * must be queried for.
+ * @param ipaddr The IP address to be resolved.
+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.
+ * q is not freed by this function.
+ *
+ * @note q must only be ONE packet, not a packet queue!
+ *
+ * @return
+ * - ERR_BUF Could not make room for Ethernet header.
+ * - ERR_MEM Hardware address unknown, and no more ARP entries available
+ * to query for address or queue the packet.
+ * - ERR_MEM Could not queue packet due to memory shortage.
+ * - ERR_RTE No route to destination (no gateway to external networks).
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
+ *
+ */
+err_t
+etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
+{
+ struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
+ err_t result = ERR_MEM;
+ s8_t i; /* ARP entry index */
+
+ /* non-unicast address? */
+ if (ip_addr_isbroadcast(ipaddr, netif) ||
+ ip_addr_ismulticast(ipaddr) ||
+ ip_addr_isany(ipaddr)) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
+ return ERR_ARG;
+ }
+
+ /* find entry in ARP cache, ask to create entry if queueing packet */
+ i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
+
+ /* could not find or create entry? */
+ if (i < 0) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
+ if (q) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));
+ ETHARP_STATS_INC(etharp.memerr);
+ }
+ return (err_t)i;
+ }
+
+ /* mark a fresh entry as pending (we just sent a request) */
+ if (arp_table[i].state == ETHARP_STATE_EMPTY) {
+ arp_table[i].state = ETHARP_STATE_PENDING;
+ }
+
+ /* { i is either a STABLE or (new or existing) PENDING entry } */
+ LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
+ ((arp_table[i].state == ETHARP_STATE_PENDING) ||
+ (arp_table[i].state == ETHARP_STATE_STABLE)));
+
+ /* do we have a pending entry? or an implicit query request? */
+ if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
+ /* try to resolve it; send out ARP request */
+ result = etharp_request(netif, ipaddr);
+ if (result != ERR_OK) {
+ /* ARP request couldn't be sent */
+ /* We don't re-send arp request in etharp_tmr, but we still queue packets,
+ since this failure could be temporary, and the next packet calling
+ etharp_query again could lead to sending the queued packets. */
+ }
+ if (q == NULL) {
+ return result;
+ }
+ }
+
+ /* packet given? */
+ LWIP_ASSERT("q != NULL", q != NULL);
+ /* stable entry? */
+ if (arp_table[i].state == ETHARP_STATE_STABLE) {
+ /* we have a valid IP->Ethernet address mapping */
+ ETHARP_SET_HINT(netif, i);
+ /* send the packet */
+ result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
+ /* pending entry? (either just created or already pending */
+ } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+ /* entry is still pending, queue the given packet 'q' */
+ struct pbuf *p;
+ int copy_needed = 0;
+ /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
+ * to copy the whole queue into a new PBUF_RAM (see bug #11400)
+ * PBUF_ROMs can be left as they are, since ROM must not get changed. */
+ p = q;
+ while (p) {
+ LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
+ if(p->type != PBUF_ROM) {
+ copy_needed = 1;
+ break;
+ }
+ p = p->next;
+ }
+ if(copy_needed) {
+ /* copy the whole packet into new pbufs */
+ p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+ if(p != NULL) {
+ if (pbuf_copy(p, q) != ERR_OK) {
+ pbuf_free(p);
+ p = NULL;
+ }
+ }
+ } else {
+ /* referencing the old pbuf is enough */
+ p = q;
+ pbuf_ref(p);
+ }
+ /* packet could be taken over? */
+ if (p != NULL) {
+ /* queue packet ... */
+#if ARP_QUEUEING
+ struct etharp_q_entry *new_entry;
+ /* allocate a new arp queue entry */
+ new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
+ if (new_entry != NULL) {
+ new_entry->next = 0;
+ new_entry->p = p;
+ if(arp_table[i].q != NULL) {
+ /* queue was already existent, append the new entry to the end */
+ struct etharp_q_entry *r;
+ r = arp_table[i].q;
+ while (r->next != NULL) {
+ r = r->next;
+ }
+ r->next = new_entry;
+ } else {
+ /* queue did not exist, first item in queue */
+ arp_table[i].q = new_entry;
+ }
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+ result = ERR_OK;
+ } else {
+ /* the pool MEMP_ARP_QUEUE is empty */
+ pbuf_free(p);
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
+ result = ERR_MEM;
+ }
+#else /* ARP_QUEUEING */
+ /* always queue one packet per ARP request only, freeing a previously queued packet */
+ if (arp_table[i].q != NULL) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+ pbuf_free(arp_table[i].q);
+ }
+ arp_table[i].q = p;
+ result = ERR_OK;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+#endif /* ARP_QUEUEING */
+ } else {
+ ETHARP_STATS_INC(etharp.memerr);
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
+ result = ERR_MEM;
+ }
+ }
+ return result;
+}
+
+/**
+ * Send a raw ARP packet (opcode and all addresses can be modified)
+ *
+ * @param netif the lwip network interface on which to send the ARP packet
+ * @param ethsrc_addr the source MAC address for the ethernet header
+ * @param ethdst_addr the destination MAC address for the ethernet header
+ * @param hwsrc_addr the source MAC address for the ARP protocol header
+ * @param ipsrc_addr the source IP address for the ARP protocol header
+ * @param hwdst_addr the destination MAC address for the ARP protocol header
+ * @param ipdst_addr the destination IP address for the ARP protocol header
+ * @param opcode the type of the ARP packet
+ * @return ERR_OK if the ARP packet has been sent
+ * ERR_MEM if the ARP packet couldn't be allocated
+ * any other err_t on failure
+ */
+#if !LWIP_AUTOIP
+static
+#endif /* LWIP_AUTOIP */
+err_t
+etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
+ const struct eth_addr *ethdst_addr,
+ const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
+ const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
+ const u16_t opcode)
+{
+ struct pbuf *p;
+ err_t result = ERR_OK;
+ struct eth_hdr *ethhdr;
+ struct etharp_hdr *hdr;
+#if LWIP_AUTOIP
+ const u8_t * ethdst_hwaddr;
+#endif /* LWIP_AUTOIP */
+
+ /* allocate a pbuf for the outgoing ARP request packet */
+ p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
+ /* could allocate a pbuf for an ARP request? */
+ if (p == NULL) {
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+ ("etharp_raw: could not allocate pbuf for ARP request.\n"));
+ ETHARP_STATS_INC(etharp.memerr);
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
+ (p->len >= SIZEOF_ETHARP_PACKET));
+
+ ethhdr = (struct eth_hdr *)p->payload;
+ hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
+ hdr->opcode = htons(opcode);
+
+ LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
+ (netif->hwaddr_len == ETHARP_HWADDR_LEN));
+#if LWIP_AUTOIP
+ /* If we are using Link-Local, all ARP packets that contain a Link-Local
+ * 'sender IP address' MUST be sent using link-layer broadcast instead of
+ * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
+ ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;
+#endif /* LWIP_AUTOIP */
+ /* Write the ARP MAC-Addresses */
+ ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
+ ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
+ /* Write the Ethernet MAC-Addresses */
+#if LWIP_AUTOIP
+ ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
+#else /* LWIP_AUTOIP */
+ ETHADDR16_COPY(&ethhdr->dest, ethdst_addr);
+#endif /* LWIP_AUTOIP */
+ ETHADDR16_COPY(&ethhdr->src, ethsrc_addr);
+ /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
+ * structure packing. */
+ IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);
+ IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);
+
+ hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);
+ hdr->proto = PP_HTONS(ETHTYPE_IP);
+ /* set hwlen and protolen */
+ hdr->hwlen = ETHARP_HWADDR_LEN;
+ hdr->protolen = sizeof(ip_addr_t);
+
+ ethhdr->type = PP_HTONS(ETHTYPE_ARP);
+ /* send ARP query */
+ result = netif->linkoutput(netif, p);
+ ETHARP_STATS_INC(etharp.xmit);
+ /* free ARP query packet */
+ pbuf_free(p);
+ p = NULL;
+ /* could not allocate pbuf for ARP request */
+
+ return result;
+}
+
+/**
+ * Send an ARP request packet asking for ipaddr.
+ *
+ * @param netif the lwip network interface on which to send the request
+ * @param ipaddr the IP address for which to ask
+ * @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_request(struct netif *netif, ip_addr_t *ipaddr)
+{
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));
+ return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+ (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,
+ ipaddr, ARP_REQUEST);
+}
+#endif /* LWIP_ARP */
+
+/**
+ * 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.
+ *
+ * @param p the recevied packet, p->payload pointing to the ethernet header
+ * @param netif the network interface on which the packet was received
+ */
+err_t
+ethernet_input(struct pbuf *p, struct netif *netif)
+{
+ struct eth_hdr* ethhdr;
+ u16_t type;
+ s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
+
+ if (p->len <= SIZEOF_ETH_HDR) {
+ /* a packet with only an ethernet header (or less) is not valid for us */
+ ETHARP_STATS_INC(etharp.proterr);
+ ETHARP_STATS_INC(etharp.drop);
+ goto free_and_return;
+ }
+
+ /* points to packet payload, which starts with an Ethernet header */
+ ethhdr = (struct eth_hdr *)p->payload;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
+ ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
+ (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
+ (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
+ (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],
+ (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
+ (unsigned)htons(ethhdr->type)));
+
+ type = ethhdr->type;
+#if ETHARP_SUPPORT_VLAN
+ if (type == PP_HTONS(ETHTYPE_VLAN)) {
+ struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
+ if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
+ /* a packet with only an ethernet/vlan header (or less) is not valid for us */
+ ETHARP_STATS_INC(etharp.proterr);
+ ETHARP_STATS_INC(etharp.drop);
+ goto free_and_return;
+ }
+#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
+ if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
+ /* silently ignore this packet: not for our VLAN */
+ pbuf_free(p);
+ return ERR_OK;
+ }
+#endif /* ETHARP_VLAN_CHECK */
+ type = vlan->tpid;
+ ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
+ }
+#endif /* ETHARP_SUPPORT_VLAN */
+
+#if LWIP_ARP_FILTER_NETIF
+ netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
+#endif /* LWIP_ARP_FILTER_NETIF*/
+
+ switch (type) {
+#if LWIP_ARP
+ /* IP packet? */
+ case PP_HTONS(ETHTYPE_IP):
+ if (!(netif->flags & NETIF_FLAG_ETHARP)) {
+ goto free_and_return;
+ }
+#if ETHARP_TRUST_IP_MAC
+ /* update ARP table */
+ etharp_ip_input(netif, p);
+#endif /* ETHARP_TRUST_IP_MAC */
+ /* skip Ethernet header */
+ if(pbuf_header(p, -ip_hdr_offset)) {
+ LWIP_ASSERT("Can't move over header in packet", 0);
+ goto free_and_return;
+ } else {
+ /* pass to IP layer */
+ ip_input(p, netif);
+ }
+ break;
+
+ case PP_HTONS(ETHTYPE_ARP):
+ if (!(netif->flags & NETIF_FLAG_ETHARP)) {
+ goto free_and_return;
+ }
+ /* pass p to ARP module */
+ etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
+ break;
+#endif /* LWIP_ARP */
+#if PPPOE_SUPPORT
+ case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
+ pppoe_disc_input(netif, p);
+ break;
+
+ case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
+ pppoe_data_input(netif, p);
+ break;
+#endif /* PPPOE_SUPPORT */
+
+ default:
+ ETHARP_STATS_INC(etharp.proterr);
+ ETHARP_STATS_INC(etharp.drop);
+ goto free_and_return;
+ }
+
+ /* This means the pbuf is freed or consumed,
+ so the caller doesn't have to free it again */
+ return ERR_OK;
+
+free_and_return:
+ pbuf_free(p);
+ return ERR_OK;
+}
+#endif /* LWIP_ARP || LWIP_ETHERNET */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ethernetif.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ethernetif.c
new file mode 100644
index 0000000000..a5b7d990b1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ethernetif.c
@@ -0,0 +1,318 @@
+/**
+ * @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 <adam@sics.se>
+ *
+ */
+
+/*
+ * 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/sys.h"
+#include <lwip/stats.h>
+#include <lwip/snmp.h>
+#include "netif/etharp.h"
+#include "netif/ppp_oe.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;
+
+ /* 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 availale 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_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();
+
+#if ETH_PAD_SIZE
+ pbuf_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_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();
+
+#if ETH_PAD_SIZE
+ pbuf_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);
+ }
+
+ 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);
+ /* no packet could be read, silently ignore this */
+ if (p == NULL) return;
+ /* points to packet payload, which starts with an Ethernet header */
+ ethhdr = p->payload;
+
+ switch (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);
+ p = NULL;
+ break;
+ }
+}
+
+/**
+ * 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.
+ */
+ NETIF_INIT_SNMP(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...) */
+ netif->output = etharp_output;
+ 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/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.c
new file mode 100644
index 0000000000..c3c49d22a2
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.c
@@ -0,0 +1,1334 @@
+/*****************************************************************************
+* auth.c - Network Authentication and Phase Control program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Ported from public pppd code.
+*****************************************************************************/
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived 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.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "fsm.h"
+#include "lcp.h"
+#include "pap.h"
+#include "chap.h"
+#include "auth.h"
+#include "ipcp.h"
+
+#if CBCP_SUPPORT
+#include "cbcp.h"
+#endif /* CBCP_SUPPORT */
+
+#include "lwip/inet.h"
+
+#include <string.h>
+
+#if 0 /* UNUSED */
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER 1
+#define NONWILD_CLIENT 2
+
+#define ISWILD(word) (word[0] == '*' && word[1] == 0)
+#endif /* UNUSED */
+
+#if PAP_SUPPORT || CHAP_SUPPORT
+/* The name by which the peer authenticated itself to us. */
+static char peer_authname[MAXNAMELEN];
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called plogin() */
+static int logged_in;
+
+/* Set if we have run the /etc/ppp/auth-up script. */
+static int did_authup; /* @todo, we don't need this in lwip*/
+
+/* List of addresses which the peer may use. */
+static struct wordlist *addresses[NUM_PPP];
+
+#if 0 /* UNUSED */
+/* Wordlist giving addresses which the peer may use
+ without authenticating itself. */
+static struct wordlist *noauth_addrs;
+
+/* Extra options to apply, from the secrets file entry for the peer. */
+static struct wordlist *extra_options;
+#endif /* UNUSED */
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+#if PAP_SUPPORT || CHAP_SUPPORT
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */
+
+#if 0 /* UNUSED */
+/* Set if we require authentication only because we have a default route. */
+static bool default_auth;
+
+/* Hook to enable a plugin to control the idle time limit */
+int (*idle_time_hook) __P((struct ppp_idle *)) = NULL;
+
+/* Hook for a plugin to say whether we can possibly authenticate any peer */
+int (*pap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to check the PAP user and password */
+int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
+ struct wordlist **paddrs,
+ struct wordlist **popts)) = NULL;
+
+/* Hook for a plugin to know about the PAP user logout */
+void (*pap_logout_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the PAP password for authenticating us */
+int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/*
+ * This is used to ensure that we don't start an auth-up/down
+ * script while one is already running.
+ */
+enum script_state {
+ s_down,
+ s_up
+};
+
+static enum script_state auth_state = s_down;
+static enum script_state auth_script_state = s_down;
+static pid_t auth_script_pid = 0;
+
+/*
+ * Option variables.
+ * lwip: some of these are present in the ppp_settings structure
+ */
+bool uselogin = 0; /* Use /etc/passwd for checking PAP */
+bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
+bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
+bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
+bool usehostname = 0; /* Use hostname for our_name */
+bool auth_required = 0; /* Always require authentication from peer */
+bool allow_any_ip = 0; /* Allow peer to use any IP address */
+bool explicit_remote = 0; /* User specified explicit remote name */
+char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+
+#endif /* UNUSED */
+
+/* Bits in auth_pending[] */
+#define PAP_WITHPEER 1
+#define PAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+/* @todo, move this somewhere */
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char word[1];
+};
+
+
+extern char *crypt (const char *, const char *);
+
+/* Prototypes for procedures local to this file. */
+
+static void network_phase (int);
+static void check_idle (void *);
+static void connect_time_expired (void *);
+#if 0
+static int plogin (char *, char *, char **, int *);
+#endif
+static void plogout (void);
+static int null_login (int);
+static int get_pap_passwd (int, char *, char *);
+static int have_pap_secret (void);
+static int have_chap_secret (char *, char *, u32_t);
+static int ip_addr_check (u32_t, struct wordlist *);
+
+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */
+static int scan_authfile (FILE *, char *, char *, char *,
+ struct wordlist **, struct wordlist **,
+ char *);
+static void free_wordlist (struct wordlist *);
+static void auth_script (char *);
+static void auth_script_done (void *);
+static void set_allowed_addrs (int unit, struct wordlist *addrs);
+static int some_ip_ok (struct wordlist *);
+static int setupapfile (char **);
+static int privgroup (char **);
+static int set_noauth_addr (char **);
+static void check_access (FILE *, char *);
+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */
+
+#if 0 /* UNUSED */
+/*
+ * Authentication-related options.
+ */
+option_t auth_options[] = {
+ { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer", 1, &auth_required },
+ { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer", 1, &auth_required },
+ { "refuse-pap", o_bool, &refuse_pap,
+ "Don't agree to auth to peer with PAP", 1 },
+ { "-pap", o_bool, &refuse_pap,
+ "Don't allow PAP authentication with peer", 1 },
+ { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ "Require CHAP authentication from peer", 1, &auth_required },
+ { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ "Require CHAP authentication from peer", 1, &auth_required },
+ { "refuse-chap", o_bool, &refuse_chap,
+ "Don't agree to auth to peer with CHAP", 1 },
+ { "-chap", o_bool, &refuse_chap,
+ "Don't allow CHAP authentication with peer", 1 },
+ { "name", o_string, our_name,
+ "Set local name for authentication",
+ OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN },
+ { "user", o_string, user,
+ "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN },
+ { "usehostname", o_bool, &usehostname,
+ "Must use hostname for authentication", 1 },
+ { "remotename", o_string, remote_name,
+ "Set remote name for authentication", OPT_STATIC,
+ &explicit_remote, MAXNAMELEN },
+ { "auth", o_bool, &auth_required,
+ "Require authentication from peer", 1 },
+ { "noauth", o_bool, &auth_required,
+ "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip },
+ { "login", o_bool, &uselogin,
+ "Use system password database for PAP", 1 },
+ { "papcrypt", o_bool, &cryptpap,
+ "PAP passwords are encrypted", 1 },
+ { "+ua", o_special, (void *)setupapfile,
+ "Get PAP user and password from file" },
+ { "password", o_string, passwd,
+ "Password for authenticating us to the peer", OPT_STATIC,
+ NULL, MAXSECRETLEN },
+ { "privgroup", o_special, (void *)privgroup,
+ "Allow group members to use privileged options", OPT_PRIV },
+ { "allow-ip", o_special, (void *)set_noauth_addr,
+ "Set IP address(es) which can be used without authentication",
+ OPT_PRIV },
+ { NULL }
+};
+#endif /* UNUSED */
+#if 0 /* UNUSED */
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(char **argv)
+{
+ FILE * ufile;
+ int l;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ seteuid(getuid());
+ ufile = fopen(*argv, "r");
+ seteuid(0);
+ if (ufile == NULL) {
+ option_error("unable to open user login data file %s", *argv);
+ return 0;
+ }
+ check_access(ufile, *argv);
+
+ /* get username */
+ if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
+ || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
+ option_error("unable to read user login data file %s", *argv);
+ return 0;
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(user);
+ if (l > 0 && user[l-1] == '\n')
+ user[l-1] = 0;
+ l = strlen(passwd);
+ if (l > 0 && passwd[l-1] == '\n')
+ passwd[l-1] = 0;
+
+ return (1);
+}
+#endif /* UNUSED */
+
+#if 0 /* UNUSED */
+/*
+ * privgroup - allow members of the group to have privileged access.
+ */
+static int
+privgroup(char **argv)
+{
+ struct group *g;
+ int i;
+
+ g = getgrnam(*argv);
+ if (g == 0) {
+ option_error("group %s is unknown", *argv);
+ return 0;
+ }
+ for (i = 0; i < ngroups; ++i) {
+ if (groups[i] == g->gr_gid) {
+ privileged = 1;
+ break;
+ }
+ }
+ return 1;
+}
+#endif
+
+#if 0 /* UNUSED */
+/*
+ * set_noauth_addr - set address(es) that can be used without authentication.
+ * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets.
+ */
+static int
+set_noauth_addr(char **argv)
+{
+ char *addr = *argv;
+ int l = strlen(addr);
+ struct wordlist *wp;
+
+ wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1);
+ if (wp == NULL)
+ novm("allow-ip argument");
+ wp->word = (char *) (wp + 1);
+ wp->next = noauth_addrs;
+ BCOPY(addr, wp->word, l);
+ noauth_addrs = wp;
+ return 1;
+}
+#endif /* UNUSED */
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(int unit)
+{
+ LWIP_UNUSED_ARG(unit);
+
+ AUTHDEBUG(LOG_INFO, ("link_required: %d\n", unit));
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(int unit)
+{
+ AUTHDEBUG(LOG_INFO, ("link_terminated: %d\n", unit));
+ if (lcp_phase[unit] == PHASE_DEAD) {
+ return;
+ }
+ if (logged_in) {
+ plogout();
+ }
+ lcp_phase[unit] = PHASE_DEAD;
+ AUTHDEBUG(LOG_NOTICE, ("Connection terminated.\n"));
+ pppLinkTerminated(unit);
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void
+link_down(int unit)
+{
+ int i;
+ struct protent *protp;
+
+ AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit));
+
+ if (did_authup) {
+ /* XXX Do link down processing. */
+ did_authup = 0;
+ }
+ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+ if (!protp->enabled_flag) {
+ continue;
+ }
+ if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) {
+ (*protp->lowerdown)(unit);
+ }
+ if (protp->protocol < 0xC000 && protp->close != NULL) {
+ (*protp->close)(unit, "LCP down");
+ }
+ }
+ num_np_open = 0; /* number of network protocols we have opened */
+ num_np_up = 0; /* Number of network protocols which have come up */
+
+ if (lcp_phase[unit] != PHASE_DEAD) {
+ lcp_phase[unit] = PHASE_TERMINATE;
+ }
+ pppLinkDown(unit);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(int unit)
+{
+ int auth;
+ int i;
+ struct protent *protp;
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+#if PAP_SUPPORT || CHAP_SUPPORT
+ lcp_options *ho = &lcp_hisoptions[unit];
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */
+
+ AUTHDEBUG(LOG_INFO, ("link_established: unit %d; Lowering up all protocols...\n", unit));
+ /*
+ * Tell higher-level protocols that LCP is up.
+ */
+ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+ if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) {
+ (*protp->lowerup)(unit);
+ }
+ }
+ if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {
+ /*
+ * We wanted the peer to authenticate itself, and it refused:
+ * treat it as though it authenticated with PAP using a username
+ * of "" and a password of "". If that's not OK, boot it out.
+ */
+ if (!wo->neg_upap || !null_login(unit)) {
+ AUTHDEBUG(LOG_WARNING, ("peer refused to authenticate\n"));
+ lcp_close(unit, "peer refused to authenticate");
+ return;
+ }
+ }
+
+ lcp_phase[unit] = PHASE_AUTHENTICATE;
+ auth = 0;
+#if CHAP_SUPPORT
+ if (go->neg_chap) {
+ ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);
+ auth |= CHAP_PEER;
+ }
+#endif /* CHAP_SUPPORT */
+#if PAP_SUPPORT && CHAP_SUPPORT
+ else
+#endif /* PAP_SUPPORT && CHAP_SUPPORT */
+#if PAP_SUPPORT
+ if (go->neg_upap) {
+ upap_authpeer(unit);
+ auth |= PAP_PEER;
+ }
+#endif /* PAP_SUPPORT */
+#if CHAP_SUPPORT
+ if (ho->neg_chap) {
+ ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);
+ auth |= CHAP_WITHPEER;
+ }
+#endif /* CHAP_SUPPORT */
+#if PAP_SUPPORT && CHAP_SUPPORT
+ else
+#endif /* PAP_SUPPORT && CHAP_SUPPORT */
+#if PAP_SUPPORT
+ if (ho->neg_upap) {
+ if (ppp_settings.passwd[0] == 0) {
+ passwd_from_file = 1;
+ if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) {
+ AUTHDEBUG(LOG_ERR, ("No secret found for PAP login\n"));
+ }
+ }
+ upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);
+ auth |= PAP_WITHPEER;
+ }
+#endif /* PAP_SUPPORT */
+ auth_pending[unit] = auth;
+
+ if (!auth) {
+ network_phase(unit);
+ }
+}
+
+/*
+ * Proceed to the network phase.
+ */
+static void
+network_phase(int unit)
+{
+ int i;
+ struct protent *protp;
+ lcp_options *go = &lcp_gotoptions[unit];
+
+ /*
+ * If the peer had to authenticate, run the auth-up script now.
+ */
+ if ((go->neg_chap || go->neg_upap) && !did_authup) {
+ /* XXX Do setup for peer authentication. */
+ did_authup = 1;
+ }
+
+#if CBCP_SUPPORT
+ /*
+ * If we negotiated callback, do it now.
+ */
+ if (go->neg_cbcp) {
+ lcp_phase[unit] = PHASE_CALLBACK;
+ (*cbcp_protent.open)(unit);
+ return;
+ }
+#endif /* CBCP_SUPPORT */
+
+ lcp_phase[unit] = PHASE_NETWORK;
+ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+ if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) {
+ (*protp->open)(unit);
+ if (protp->protocol != PPP_CCP) {
+ ++num_np_open;
+ }
+ }
+ }
+
+ if (num_np_open == 0) {
+ /* nothing to do */
+ lcp_close(0, "No network protocols running");
+ }
+}
+/* @todo: add void start_networks(void) here (pppd 2.3.11) */
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(int unit, u16_t protocol)
+{
+ LWIP_UNUSED_ARG(protocol);
+
+ AUTHDEBUG(LOG_INFO, ("auth_peer_fail: %d proto=%X\n", unit, protocol));
+ /*
+ * Authentication failure: take the link down
+ */
+ lcp_close(unit, "Authentication failed");
+}
+
+
+#if PAP_SUPPORT || CHAP_SUPPORT
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(int unit, u16_t protocol, char *name, int namelen)
+{
+ int pbit;
+
+ AUTHDEBUG(LOG_INFO, ("auth_peer_success: %d proto=%X\n", unit, protocol));
+ switch (protocol) {
+ case PPP_CHAP:
+ pbit = CHAP_PEER;
+ break;
+ case PPP_PAP:
+ pbit = PAP_PEER;
+ break;
+ default:
+ AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol));
+ return;
+ }
+
+ /*
+ * Save the authenticated name of the peer for later.
+ */
+ if (namelen > (int)sizeof(peer_authname) - 1) {
+ namelen = sizeof(peer_authname) - 1;
+ }
+ BCOPY(name, peer_authname, namelen);
+ peer_authname[namelen] = 0;
+
+ /*
+ * If there is no more authentication still to be done,
+ * proceed to the network (or callback) phase.
+ */
+ if ((auth_pending[unit] &= ~pbit) == 0) {
+ network_phase(unit);
+ }
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(int unit, u16_t protocol)
+{
+ int errCode = PPPERR_AUTHFAIL;
+
+ LWIP_UNUSED_ARG(protocol);
+
+ AUTHDEBUG(LOG_INFO, ("auth_withpeer_fail: %d proto=%X\n", unit, protocol));
+ if (passwd_from_file) {
+ BZERO(ppp_settings.passwd, MAXSECRETLEN);
+ }
+
+ /*
+ * We've failed to authenticate ourselves to our peer.
+ * He'll probably take the link down, and there's not much
+ * we can do except wait for that.
+ */
+ pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);
+ lcp_close(unit, "Failed to authenticate ourselves to peer");
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(int unit, u16_t protocol)
+{
+ int pbit;
+
+ AUTHDEBUG(LOG_INFO, ("auth_withpeer_success: %d proto=%X\n", unit, protocol));
+ switch (protocol) {
+ case PPP_CHAP:
+ pbit = CHAP_WITHPEER;
+ break;
+ case PPP_PAP:
+ if (passwd_from_file) {
+ BZERO(ppp_settings.passwd, MAXSECRETLEN);
+ }
+ pbit = PAP_WITHPEER;
+ break;
+ default:
+ AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol));
+ pbit = 0;
+ }
+
+ /*
+ * If there is no more authentication still being done,
+ * proceed to the network (or callback) phase.
+ */
+ if ((auth_pending[unit] &= ~pbit) == 0) {
+ network_phase(unit);
+ }
+}
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */
+
+
+/*
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(int unit, u16_t proto)
+{
+ LWIP_UNUSED_ARG(unit);
+ LWIP_UNUSED_ARG(proto);
+
+ AUTHDEBUG(LOG_INFO, ("np_up: %d proto=%X\n", unit, proto));
+ if (num_np_up == 0) {
+ AUTHDEBUG(LOG_INFO, ("np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));
+ /*
+ * At this point we consider that the link has come up successfully.
+ */
+ if (ppp_settings.idle_time_limit > 0) {
+ TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);
+ }
+
+ /*
+ * Set a timeout to close the connection once the maximum
+ * connect time has expired.
+ */
+ if (ppp_settings.maxconnect > 0) {
+ TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);
+ }
+ }
+ ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(int unit, u16_t proto)
+{
+ LWIP_UNUSED_ARG(unit);
+ LWIP_UNUSED_ARG(proto);
+
+ AUTHDEBUG(LOG_INFO, ("np_down: %d proto=%X\n", unit, proto));
+ if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {
+ UNTIMEOUT(check_idle, NULL);
+ }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(int unit, u16_t proto)
+{
+ LWIP_UNUSED_ARG(unit);
+ LWIP_UNUSED_ARG(proto);
+
+ AUTHDEBUG(LOG_INFO, ("np_finished: %d proto=%X\n", unit, proto));
+ if (--num_np_open <= 0) {
+ /* no further use for the link: shut up shop. */
+ lcp_close(0, "No network protocols running");
+ }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(void *arg)
+{
+ struct ppp_idle idle;
+ u_short itime;
+
+ LWIP_UNUSED_ARG(arg);
+ if (!get_idle_time(0, &idle)) {
+ return;
+ }
+ itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);
+ if (itime >= ppp_settings.idle_time_limit) {
+ /* link is idle: shut it down. */
+ AUTHDEBUG(LOG_INFO, ("Terminating connection due to lack of activity.\n"));
+ lcp_close(0, "Link inactive");
+ } else {
+ TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);
+ }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+
+ AUTHDEBUG(LOG_INFO, ("Connect time expired\n"));
+ lcp_close(0, "Connect time expired"); /* Close connection */
+}
+
+#if 0 /* UNUSED */
+/*
+ * auth_check_options - called to check authentication options.
+ */
+void
+auth_check_options(void)
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ int can_auth;
+ ipcp_options *ipwo = &ipcp_wantoptions[0];
+ u32_t remote;
+
+ /* Default our_name to hostname, and user to our_name */
+ if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) {
+ strcpy(ppp_settings.our_name, ppp_settings.hostname);
+ }
+
+ if (ppp_settings.user[0] == 0) {
+ strcpy(ppp_settings.user, ppp_settings.our_name);
+ }
+
+ /* If authentication is required, ask peer for CHAP or PAP. */
+ if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {
+ wo->neg_chap = 1;
+ wo->neg_upap = 1;
+ }
+
+ /*
+ * Check whether we have appropriate secrets to use
+ * to authenticate the peer.
+ */
+ can_auth = wo->neg_upap && have_pap_secret();
+ if (!can_auth && wo->neg_chap) {
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);
+ }
+
+ if (ppp_settings.auth_required && !can_auth) {
+ ppp_panic("No auth secret");
+ }
+}
+#endif /* UNUSED */
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void
+auth_reset(int unit)
+{
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[0];
+ ipcp_options *ipwo = &ipcp_wantoptions[0];
+ u32_t remote;
+
+ AUTHDEBUG(LOG_INFO, ("auth_reset: %d\n", unit));
+ ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));
+ ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/;
+
+ if (go->neg_upap && !have_pap_secret()) {
+ go->neg_upap = 0;
+ }
+ if (go->neg_chap) {
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) {
+ go->neg_chap = 0;
+ }
+ }
+}
+
+#if PAP_SUPPORT
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file. If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Authentication failed.
+ * UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+u_char
+check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen)
+{
+#if 1 /* XXX Assume all entries OK. */
+ LWIP_UNUSED_ARG(unit);
+ LWIP_UNUSED_ARG(auser);
+ LWIP_UNUSED_ARG(userlen);
+ LWIP_UNUSED_ARG(apasswd);
+ LWIP_UNUSED_ARG(passwdlen);
+ LWIP_UNUSED_ARG(msglen);
+ *msg = (char *) 0;
+ return UPAP_AUTHACK; /* XXX Assume all entries OK. */
+#else
+ u_char ret = 0;
+ struct wordlist *addrs = NULL;
+ char passwd[256], user[256];
+ char secret[MAXWORDLEN];
+ static u_short attempts = 0;
+
+ /*
+ * Make copies of apasswd and auser, then null-terminate them.
+ */
+ BCOPY(apasswd, passwd, passwdlen);
+ passwd[passwdlen] = '\0';
+ BCOPY(auser, user, userlen);
+ user[userlen] = '\0';
+ *msg = (char *) 0;
+
+ /* XXX Validate user name and password. */
+ ret = UPAP_AUTHACK; /* XXX Assume all entries OK. */
+
+ if (ret == UPAP_AUTHNAK) {
+ if (*msg == (char *) 0) {
+ *msg = "Login incorrect";
+ }
+ *msglen = strlen(*msg);
+ /*
+ * Frustrate passwd stealer programs.
+ * Allow 10 tries, but start backing off after 3 (stolen from login).
+ * On 10'th, drop the connection.
+ */
+ if (attempts++ >= 10) {
+ AUTHDEBUG(LOG_WARNING, ("%d LOGIN FAILURES BY %s\n", attempts, user));
+ /*ppp_panic("Excess Bad Logins");*/
+ }
+ if (attempts > 3) {
+ /* @todo: this was sleep(), i.e. seconds, not milliseconds
+ * I don't think we really need this in lwIP - we would block tcpip_thread!
+ */
+ /*sys_msleep((attempts - 3) * 5);*/
+ }
+ if (addrs != NULL) {
+ free_wordlist(addrs);
+ }
+ } else {
+ attempts = 0; /* Reset count */
+ if (*msg == (char *) 0) {
+ *msg = "Login ok";
+ }
+ *msglen = strlen(*msg);
+ set_allowed_addrs(unit, addrs);
+ }
+
+ BZERO(passwd, sizeof(passwd));
+ BZERO(secret, sizeof(secret));
+
+ return ret;
+#endif
+}
+#endif /* PAP_SUPPORT */
+
+#if 0 /* UNUSED */
+/*
+ * This function is needed for PAM.
+ */
+
+#ifdef USE_PAM
+
+/* lwip does not support PAM*/
+
+#endif /* USE_PAM */
+
+#endif /* UNUSED */
+
+
+#if 0 /* UNUSED */
+/*
+ * plogin - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+static int
+plogin(char *user, char *passwd, char **msg, int *msglen)
+{
+
+ LWIP_UNUSED_ARG(user);
+ LWIP_UNUSED_ARG(passwd);
+ LWIP_UNUSED_ARG(msg);
+ LWIP_UNUSED_ARG(msglen);
+
+
+ /* The new lines are here align the file when
+ * compared against the pppd 2.3.11 code */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /* XXX Fail until we decide that we want to support logins. */
+ return (UPAP_AUTHNAK);
+}
+#endif
+
+
+
+/*
+ * plogout - Logout the user.
+ */
+static void
+plogout(void)
+{
+ logged_in = 0;
+}
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int
+null_login(int unit)
+{
+ LWIP_UNUSED_ARG(unit);
+ /* XXX Fail until we decide that we want to support logins. */
+ return 0;
+}
+
+
+/*
+ * get_pap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP. Returns 1 on success, 0 if no suitable password
+ * could be found.
+ */
+static int
+get_pap_passwd(int unit, char *user, char *passwd)
+{
+ LWIP_UNUSED_ARG(unit);
+/* normally we would reject PAP if no password is provided,
+ but this causes problems with some providers (like CHT in Taiwan)
+ who incorrectly request PAP and expect a bogus/empty password, so
+ always provide a default user/passwd of "none"/"none"
+
+ @todo: This should be configured by the user, instead of being hardcoded here!
+*/
+ if(user) {
+ strcpy(user, "none");
+ }
+ if(passwd) {
+ strcpy(passwd, "none");
+ }
+ return 1;
+}
+
+/*
+ * have_pap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_pap_secret(void)
+{
+ /* XXX Fail until we set up our passwords. */
+ return 0;
+}
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'. Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(char *client, char *server, u32_t remote)
+{
+ LWIP_UNUSED_ARG(client);
+ LWIP_UNUSED_ARG(server);
+ LWIP_UNUSED_ARG(remote);
+
+ /* XXX Fail until we set up our passwords. */
+ return 0;
+}
+#if CHAP_SUPPORT
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs)
+{
+#if 1
+ int len;
+ struct wordlist *addrs;
+
+ LWIP_UNUSED_ARG(unit);
+ LWIP_UNUSED_ARG(server);
+ LWIP_UNUSED_ARG(save_addrs);
+
+ addrs = NULL;
+
+ if(!client || !client[0] || strcmp(client, ppp_settings.user)) {
+ return 0;
+ }
+
+ len = (int)strlen(ppp_settings.passwd);
+ if (len > MAXSECRETLEN) {
+ AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server));
+ len = MAXSECRETLEN;
+ }
+
+ BCOPY(ppp_settings.passwd, secret, len);
+ *secret_len = len;
+
+ return 1;
+#else
+ int ret = 0, len;
+ struct wordlist *addrs;
+ char secbuf[MAXWORDLEN];
+
+ addrs = NULL;
+ secbuf[0] = 0;
+
+ /* XXX Find secret. */
+ if (ret < 0) {
+ return 0;
+ }
+
+ if (save_addrs) {
+ set_allowed_addrs(unit, addrs);
+ }
+
+ len = strlen(secbuf);
+ if (len > MAXSECRETLEN) {
+ AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server));
+ len = MAXSECRETLEN;
+ }
+
+ BCOPY(secbuf, secret, len);
+ BZERO(secbuf, sizeof(secbuf));
+ *secret_len = len;
+
+ return 1;
+#endif
+}
+#endif /* CHAP_SUPPORT */
+
+
+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ */
+static void
+set_allowed_addrs(int unit, struct wordlist *addrs)
+{
+ if (addresses[unit] != NULL) {
+ free_wordlist(addresses[unit]);
+ }
+ addresses[unit] = addrs;
+
+#if 0
+ /*
+ * If there's only one authorized address we might as well
+ * ask our peer for that one right away
+ */
+ if (addrs != NULL && addrs->next == NULL) {
+ char *p = addrs->word;
+ struct ipcp_options *wo = &ipcp_wantoptions[unit];
+ u32_t a;
+ struct hostent *hp;
+
+ if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) {
+ hp = gethostbyname(p);
+ if (hp != NULL && hp->h_addrtype == AF_INET) {
+ a = *(u32_t *)hp->h_addr;
+ } else {
+ a = inet_addr(p);
+ }
+ if (a != (u32_t) -1) {
+ wo->hisaddr = a;
+ }
+ }
+ }
+#endif
+}
+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address. Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(int unit, u32_t addr)
+{
+ return ip_addr_check(addr, addresses[unit]);
+}
+
+static int /* @todo: integrate this funtion into auth_ip_addr()*/
+ip_addr_check(u32_t addr, struct wordlist *addrs)
+{
+ /* don't allow loopback or multicast address */
+ if (bad_ip_adrs(addr)) {
+ return 0;
+ }
+
+ if (addrs == NULL) {
+ return !ppp_settings.auth_required; /* no addresses authorized */
+ }
+
+ /* XXX All other addresses allowed. */
+ return 1;
+}
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int
+bad_ip_adrs(u32_t addr)
+{
+ addr = ntohl(addr);
+ return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+ || IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+#if 0 /* UNUSED */ /* PAP_SUPPORT || CHAP_SUPPORT */
+/*
+ * some_ip_ok - check a wordlist to see if it authorizes any
+ * IP address(es).
+ */
+static int
+some_ip_ok(struct wordlist *addrs)
+{
+ for (; addrs != 0; addrs = addrs->next) {
+ if (addrs->word[0] == '-')
+ break;
+ if (addrs->word[0] != '!')
+ return 1; /* some IP address is allowed */
+ }
+ return 0;
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+static void
+check_access(FILE *f, char *filename)
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(f), &sbuf) < 0) {
+ warn("cannot stat secret file %s: %m", filename);
+ } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ warn("Warning - secret file %s has world and/or group access",
+ filename);
+ }
+}
+
+
+/*
+ * scan_authfile - Scan an authorization file for a secret suitable
+ * for authenticating `client' on `server'. The return value is -1
+ * if no secret is found, otherwise >= 0. The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line up to a "--" (i.e. address authorization
+ * info) are placed in a wordlist and returned in *addrs. Any
+ * following words (extra options) are placed in a wordlist and
+ * returned in *opts.
+ * We assume secret is NULL or points to MAXWORDLEN bytes of space.
+ */
+static int
+scan_authfile(FILE *f, char *client, char *server, char *secret, struct wordlist **addrs, struct wordlist **opts, char *filename)
+{
+ /* We do not (currently) need this in lwip */
+ return 0; /* dummy */
+}
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(struct wordlist *wp)
+{
+ struct wordlist *next;
+
+ while (wp != NULL) {
+ next = wp->next;
+ free(wp);
+ wp = next;
+ }
+}
+
+/*
+ * auth_script_done - called when the auth-up or auth-down script
+ * has finished.
+ */
+static void
+auth_script_done(void *arg)
+{
+ auth_script_pid = 0;
+ switch (auth_script_state) {
+ case s_up:
+ if (auth_state == s_down) {
+ auth_script_state = s_down;
+ auth_script(_PATH_AUTHDOWN);
+ }
+ break;
+ case s_down:
+ if (auth_state == s_up) {
+ auth_script_state = s_up;
+ auth_script(_PATH_AUTHUP);
+ }
+ break;
+ }
+}
+
+/*
+ * auth_script - execute a script with arguments
+ * interface-name peer-name real-user tty speed
+ */
+static void
+auth_script(char *script)
+{
+ char strspeed[32];
+ struct passwd *pw;
+ char struid[32];
+ char *user_name;
+ char *argv[8];
+
+ if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL)
+ user_name = pw->pw_name;
+ else {
+ slprintf(struid, sizeof(struid), "%d", getuid());
+ user_name = struid;
+ }
+ slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = peer_authname;
+ argv[3] = user_name;
+ argv[4] = devnam;
+ argv[5] = strspeed;
+ argv[6] = NULL;
+
+ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL);
+}
+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.h
new file mode 100644
index 0000000000..a8069ec464
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/auth.h
@@ -0,0 +1,111 @@
+/*****************************************************************************
+* auth.h - PPP Authentication and phase control header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original derived from BSD pppd.h.
+*****************************************************************************/
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ */
+
+#ifndef AUTH_H
+#define AUTH_H
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+/* we are starting to use the link */
+void link_required (int);
+
+/* we are finished with the link */
+void link_terminated (int);
+
+/* the LCP layer has left the Opened state */
+void link_down (int);
+
+/* the link is up; authenticate now */
+void link_established (int);
+
+/* a network protocol has come up */
+void np_up (int, u16_t);
+
+/* a network protocol has gone down */
+void np_down (int, u16_t);
+
+/* a network protocol no longer needs link */
+void np_finished (int, u16_t);
+
+/* peer failed to authenticate itself */
+void auth_peer_fail (int, u16_t);
+
+/* peer successfully authenticated itself */
+void auth_peer_success (int, u16_t, char *, int);
+
+/* we failed to authenticate ourselves */
+void auth_withpeer_fail (int, u16_t);
+
+/* we successfully authenticated ourselves */
+void auth_withpeer_success (int, u16_t);
+
+/* check authentication options supplied */
+void auth_check_options (void);
+
+/* check what secrets we have */
+void auth_reset (int);
+
+/* Check peer-supplied username/password */
+u_char check_passwd (int, char *, int, char *, int, char **, int *);
+
+/* get "secret" for chap */
+int get_secret (int, char *, char *, char *, int *, int);
+
+/* check if IP address is authorized */
+int auth_ip_addr (int, u32_t);
+
+/* check if IP address is unreasonable */
+int bad_ip_adrs (u32_t);
+
+#endif /* AUTH_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.c
new file mode 100644
index 0000000000..3a49ff8a5e
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.c
@@ -0,0 +1,908 @@
+/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
+/*****************************************************************************
+* chap.c - Network Challenge Handshake Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original based on BSD chap.c.
+*****************************************************************************/
+/*
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived 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.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "magic.h"
+#include "randm.h"
+#include "auth.h"
+#include "md5.h"
+#include "chap.h"
+#include "chpms.h"
+
+#include <string.h>
+
+#if 0 /* UNUSED */
+/*
+ * Command-line options.
+ */
+static option_t chap_option_list[] = {
+ { "chap-restart", o_int, &chap[0].timeouttime,
+ "Set timeout for CHAP" },
+ { "chap-max-challenge", o_int, &chap[0].max_transmits,
+ "Set max #xmits for challenge" },
+ { "chap-interval", o_int, &chap[0].chal_interval,
+ "Set interval for rechallenge" },
+#ifdef MSLANMAN
+ { "ms-lanman", o_bool, &ms_lanman,
+ "Use LanMan passwd when using MS-CHAP", 1 },
+#endif
+ { NULL }
+};
+#endif /* UNUSED */
+
+/*
+ * Protocol entry points.
+ */
+static void ChapInit (int);
+static void ChapLowerUp (int);
+static void ChapLowerDown (int);
+static void ChapInput (int, u_char *, int);
+static void ChapProtocolReject (int);
+#if PPP_ADDITIONAL_CALLBACKS
+static int ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
+#endif
+
+struct protent chap_protent = {
+ PPP_CHAP,
+ ChapInit,
+ ChapInput,
+ ChapProtocolReject,
+ ChapLowerUp,
+ ChapLowerDown,
+ NULL,
+ NULL,
+#if PPP_ADDITIONAL_CALLBACKS
+ ChapPrintPkt,
+ NULL,
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+ 1,
+ "CHAP",
+#if PPP_ADDITIONAL_CALLBACKS
+ NULL,
+ NULL,
+ NULL
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+};
+
+chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout (void *);
+static void ChapResponseTimeout (void *);
+static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int);
+static void ChapRechallenge (void *);
+static void ChapReceiveResponse (chap_state *, u_char *, int, int);
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
+static void ChapSendStatus (chap_state *, int);
+static void ChapSendChallenge (chap_state *);
+static void ChapSendResponse (chap_state *);
+static void ChapGenChallenge (chap_state *);
+
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+static void
+ChapInit(int unit)
+{
+ chap_state *cstate = &chap[unit];
+
+ BZERO(cstate, sizeof(*cstate));
+ cstate->unit = unit;
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+ cstate->timeouttime = CHAP_DEFTIMEOUT;
+ cstate->max_transmits = CHAP_DEFTRANSMITS;
+ /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void
+ChapAuthWithPeer(int unit, char *our_name, u_char digest)
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->resp_name = our_name;
+ cstate->resp_type = digest;
+
+ if (cstate->clientstate == CHAPCS_INITIAL ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->clientstate = CHAPCS_PENDING;
+ return;
+ }
+
+ /*
+ * We get here as a result of LCP coming up.
+ * So even if CHAP was open before, we will
+ * have to re-authenticate ourselves.
+ */
+ cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void
+ChapAuthPeer(int unit, char *our_name, u_char digest)
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->chal_name = our_name;
+ cstate->chal_type = digest;
+
+ if (cstate->serverstate == CHAPSS_INITIAL ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->serverstate = CHAPSS_PENDING;
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate); /* crank it up dude! */
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void
+ChapChallengeTimeout(void *arg)
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending challenges, don't worry. then again we */
+ /* probably shouldn't be here either */
+ if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+ cstate->serverstate != CHAPSS_RECHALLENGE) {
+ return;
+ }
+
+ if (cstate->chal_transmits >= cstate->max_transmits) {
+ /* give up on peer */
+ CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n"));
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ return;
+ }
+
+ ChapSendChallenge(cstate); /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(void *arg)
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ return;
+ }
+
+ ChapSendResponse(cstate); /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(void *arg)
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->serverstate != CHAPSS_OPEN) {
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+static void
+ChapLowerUp(int unit)
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->clientstate == CHAPCS_INITIAL) {
+ cstate->clientstate = CHAPCS_CLOSED;
+ } else if (cstate->clientstate == CHAPCS_PENDING) {
+ cstate->clientstate = CHAPCS_LISTEN;
+ }
+
+ if (cstate->serverstate == CHAPSS_INITIAL) {
+ cstate->serverstate = CHAPSS_CLOSED;
+ } else if (cstate->serverstate == CHAPSS_PENDING) {
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+ }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+ChapLowerDown(int unit)
+{
+ chap_state *cstate = &chap[unit];
+
+ /* Timeout(s) pending? Cancel if so. */
+ if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+ cstate->serverstate == CHAPSS_RECHALLENGE) {
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
+ } else if (cstate->serverstate == CHAPSS_OPEN
+ && cstate->chal_interval != 0) {
+ UNTIMEOUT(ChapRechallenge, cstate);
+ }
+ if (cstate->clientstate == CHAPCS_RESPONSE) {
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+ }
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void
+ChapProtocolReject(int unit)
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->serverstate != CHAPSS_INITIAL &&
+ cstate->serverstate != CHAPSS_CLOSED) {
+ auth_peer_fail(unit, PPP_CHAP);
+ }
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED) {
+ auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
+ }
+ ChapLowerDown(unit); /* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+static void
+ChapInput(int unit, u_char *inpacket, int packet_len)
+{
+ chap_state *cstate = &chap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (packet_len < CHAP_HEADERLEN) {
+ CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n"));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < CHAP_HEADERLEN) {
+ CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n"));
+ return;
+ }
+ if (len > packet_len) {
+ CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n"));
+ return;
+ }
+ len -= CHAP_HEADERLEN;
+
+ /*
+ * Action depends on code (as in fact it usually does :-).
+ */
+ switch (code) {
+ case CHAP_CHALLENGE:
+ ChapReceiveChallenge(cstate, inp, id, len);
+ break;
+
+ case CHAP_RESPONSE:
+ ChapReceiveResponse(cstate, inp, id, len);
+ break;
+
+ case CHAP_FAILURE:
+ ChapReceiveFailure(cstate, inp, id, len);
+ break;
+
+ case CHAP_SUCCESS:
+ ChapReceiveSuccess(cstate, inp, id, len);
+ break;
+
+ default: /* Need code reject? */
+ CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code));
+ break;
+ }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void
+ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
+{
+ int rchallenge_len;
+ u_char *rchallenge;
+ int secret_len;
+ char secret[MAXSECRETLEN];
+ char rhostname[256];
+ MD5_CTX mdContext;
+ u_char hash[MD5_SIGNATURE_SIZE];
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
+ if (cstate->clientstate == CHAPCS_CLOSED ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
+ return;
+ }
+
+ GETCHAR(rchallenge_len, inp);
+ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
+ if (len < 0) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
+ return;
+ }
+ rchallenge = inp;
+ INCPTR(rchallenge_len, inp);
+
+ if (len >= (int)sizeof(rhostname)) {
+ len = sizeof(rhostname) - 1;
+ }
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n",
+ rhostname));
+
+ /* Microsoft doesn't send their name back in the PPP packet */
+ if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
+ strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
+ rhostname[sizeof(rhostname) - 1] = 0;
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n",
+ rhostname));
+ }
+
+ /* get secret for authenticating ourselves with the specified host */
+ if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+ secret, &secret_len, 0)) {
+ secret_len = 0; /* assume null secret if can't find one */
+ CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n",
+ rhostname));
+ }
+
+ /* cancel response send timeout if necessary */
+ if (cstate->clientstate == CHAPCS_RESPONSE) {
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+ }
+
+ cstate->resp_id = id;
+ cstate->resp_transmits = 0;
+
+ /* generate MD based on negotiated type */
+ switch (cstate->resp_type) {
+
+ case CHAP_DIGEST_MD5:
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->resp_id, 1);
+ MD5Update(&mdContext, (u_char*)secret, secret_len);
+ MD5Update(&mdContext, rchallenge, rchallenge_len);
+ MD5Final(hash, &mdContext);
+ BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+ cstate->resp_length = MD5_SIGNATURE_SIZE;
+ break;
+
+#if MSCHAP_SUPPORT
+ case CHAP_MICROSOFT:
+ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+ break;
+#endif
+
+ default:
+ CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type));
+ return;
+ }
+
+ BZERO(secret, sizeof(secret));
+ ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
+{
+ u_char *remmd, remmd_len;
+ int secret_len, old_state;
+ int code;
+ char rhostname[256];
+ MD5_CTX mdContext;
+ char secret[MAXSECRETLEN];
+ u_char hash[MD5_SIGNATURE_SIZE];
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
+
+ if (cstate->serverstate == CHAPSS_CLOSED ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n",
+ cstate->serverstate));
+ return;
+ }
+
+ if (id != cstate->chal_id) {
+ return; /* doesn't match ID of last challenge */
+ }
+
+ /*
+ * If we have received a duplicate or bogus Response,
+ * we have to send the same answer (Success/Failure)
+ * as we did for the first Response we saw.
+ */
+ if (cstate->serverstate == CHAPSS_OPEN) {
+ ChapSendStatus(cstate, CHAP_SUCCESS);
+ return;
+ }
+ if (cstate->serverstate == CHAPSS_BADAUTH) {
+ ChapSendStatus(cstate, CHAP_FAILURE);
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
+ return;
+ }
+ GETCHAR(remmd_len, inp); /* get length of MD */
+ remmd = inp; /* get pointer to MD */
+ INCPTR(remmd_len, inp);
+
+ len -= sizeof (u_char) + remmd_len;
+ if (len < 0) {
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
+ return;
+ }
+
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
+
+ if (len >= (int)sizeof(rhostname)) {
+ len = sizeof(rhostname) - 1;
+ }
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n",
+ rhostname));
+
+ /*
+ * Get secret for authenticating them with us,
+ * do the hash ourselves, and compare the result.
+ */
+ code = CHAP_FAILURE;
+ if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+ secret, &secret_len, 1)) {
+ CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
+ rhostname));
+ } else {
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE) {
+ break; /* it's not even the right length */
+ }
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, (u_char*)secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(hash, &mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {
+ code = CHAP_SUCCESS; /* they are the same! */
+ }
+ break;
+
+ default:
+ CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type));
+ }
+ }
+
+ BZERO(secret, sizeof(secret));
+ ChapSendStatus(cstate, code);
+
+ if (code == CHAP_SUCCESS) {
+ old_state = cstate->serverstate;
+ cstate->serverstate = CHAPSS_OPEN;
+ if (old_state == CHAPSS_INITIAL_CHAL) {
+ auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+ }
+ if (cstate->chal_interval != 0) {
+ TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+ }
+ } else {
+ CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n"));
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void
+ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
+{
+ LWIP_UNUSED_ARG(id);
+ LWIP_UNUSED_ARG(inp);
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id));
+
+ if (cstate->clientstate == CHAPCS_OPEN) {
+ /* presumably an answer to a duplicate response */
+ return;
+ }
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0) {
+ PRINTMSG(inp, len);
+ }
+
+ cstate->clientstate = CHAPCS_OPEN;
+
+ auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void
+ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
+{
+ LWIP_UNUSED_ARG(id);
+ LWIP_UNUSED_ARG(inp);
+
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id));
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0) {
+ PRINTMSG(inp, len);
+ }
+
+ CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n"));
+ auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void
+ChapSendChallenge(chap_state *cstate)
+{
+ u_char *outp;
+ int chal_len, name_len;
+ int outlen;
+
+ chal_len = cstate->chal_len;
+ name_len = (int)strlen(cstate->chal_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+ outp = outpacket_buf[cstate->unit];
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
+
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+
+ PUTCHAR(chal_len, outp); /* put length of challenge */
+ BCOPY(cstate->challenge, outp, chal_len);
+ INCPTR(chal_len, outp);
+
+ BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
+
+ pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+
+ CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
+
+ TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+ ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void
+ChapSendStatus(chap_state *cstate, int code)
+{
+ u_char *outp;
+ int outlen, msglen;
+ char msg[256]; /* @todo: this can be a char*, no strcpy needed */
+
+ if (code == CHAP_SUCCESS) {
+ strcpy(msg, "Welcome!");
+ } else {
+ strcpy(msg, "I don't like you. Go 'way.");
+ }
+ msglen = (int)strlen(msg);
+
+ outlen = CHAP_HEADERLEN + msglen;
+ outp = outpacket_buf[cstate->unit];
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
+
+ PUTCHAR(code, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+ BCOPY(msg, outp, msglen);
+ pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+
+ CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
+ cstate->chal_id));
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len. The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void
+ChapGenChallenge(chap_state *cstate)
+{
+ int chal_len;
+ u_char *ptr = cstate->challenge;
+ int i;
+
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
+ chal_len = (unsigned)
+ ((((magic() >> 16) *
+ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
+ + MIN_CHALLENGE_LENGTH);
+ LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff);
+ cstate->chal_len = (u_char)chal_len;
+ cstate->chal_id = ++cstate->id;
+ cstate->chal_transmits = 0;
+
+ /* generate a random string */
+ for (i = 0; i < chal_len; i++ ) {
+ *ptr++ = (char) (magic() & 0xff);
+ }
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void
+ChapSendResponse(chap_state *cstate)
+{
+ u_char *outp;
+ int outlen, md_len, name_len;
+
+ md_len = cstate->resp_length;
+ name_len = (int)strlen(cstate->resp_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+ outp = outpacket_buf[cstate->unit];
+
+ MAKEHEADER(outp, PPP_CHAP);
+
+ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
+ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+ PUTSHORT(outlen, outp); /* packet length */
+
+ PUTCHAR(md_len, outp); /* length of MD */
+ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
+ INCPTR(md_len, outp);
+
+ BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+ /* send the packet */
+ pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
+
+ cstate->clientstate = CHAPCS_RESPONSE;
+ TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+ ++cstate->resp_transmits;
+}
+
+#if PPP_ADDITIONAL_CALLBACKS
+static char *ChapCodenames[] = {
+ "Challenge", "Response", "Success", "Failure"
+};
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static int
+ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
+{
+ int code, id, len;
+ int clen, nlen;
+ u_char x;
+
+ if (plen < CHAP_HEADERLEN) {
+ return 0;
+ }
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < CHAP_HEADERLEN || len > plen) {
+ return 0;
+ }
+
+ if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
+ printer(arg, " %s", ChapCodenames[code-1]);
+ } else {
+ printer(arg, " code=0x%x", code);
+ }
+ printer(arg, " id=0x%x", id);
+ len -= CHAP_HEADERLEN;
+ switch (code) {
+ case CHAP_CHALLENGE:
+ case CHAP_RESPONSE:
+ if (len < 1) {
+ break;
+ }
+ clen = p[0];
+ if (len < clen + 1) {
+ break;
+ }
+ ++p;
+ nlen = len - clen - 1;
+ printer(arg, " <");
+ for (; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, "%.2x", x);
+ }
+ printer(arg, ">, name = %.*Z", nlen, p);
+ break;
+ case CHAP_FAILURE:
+ case CHAP_SUCCESS:
+ printer(arg, " %.*Z", len, p);
+ break;
+ default:
+ for (clen = len; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, " %.2x", x);
+ }
+ }
+
+ return len + CHAP_HEADERLEN;
+}
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+
+#endif /* CHAP_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.h
new file mode 100644
index 0000000000..fedcab8da1
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chap.h
@@ -0,0 +1,150 @@
+/*****************************************************************************
+* chap.h - Network Challenge Handshake Authentication Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original built from BSD network code.
+******************************************************************************/
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived 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.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * 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.
+ *
+ * $Id: chap.h,v 1.6 2010/01/24 13:19:34 goldsimon Exp $
+ */
+
+#ifndef CHAP_H
+#define CHAP_H
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN 4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+
+/*
+ * Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH 32
+#define MAX_CHALLENGE_LENGTH 64
+#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+ int unit; /* Interface unit number */
+ int clientstate; /* Client state */
+ int serverstate; /* Server state */
+ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+ u_char chal_len; /* challenge length */
+ u_char chal_id; /* ID of last challenge */
+ u_char chal_type; /* hash algorithm for challenges */
+ u_char id; /* Current id */
+ char *chal_name; /* Our name to use with challenge */
+ int chal_interval; /* Time until we challenge peer again */
+ int timeouttime; /* Timeout time in seconds */
+ int max_transmits; /* Maximum # of challenge transmissions */
+ int chal_transmits; /* Number of transmissions of challenge */
+ int resp_transmits; /* Number of transmissions of response */
+ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
+ u_char resp_length; /* length of response */
+ u_char resp_id; /* ID for response messages */
+ u_char resp_type; /* hash algorithm for responses */
+ char *resp_name; /* Our name to send with response */
+} chap_state;
+
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN 3 /* Listening for a challenge */
+#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
+#define CHAPCS_OPEN 5 /* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPSS_PENDING 2 /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
+#define CHAPSS_OPEN 4 /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
+#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
+
+extern chap_state chap[];
+
+void ChapAuthWithPeer (int, char *, u_char);
+void ChapAuthPeer (int, char *, u_char);
+
+extern struct protent chap_protent;
+
+#endif /* CHAP_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.c
new file mode 100644
index 0000000000..83acefcec6
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.c
@@ -0,0 +1,396 @@
+/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
+/*** The original PPPD code is written in a way to require either the UNIX DES
+ encryption functions encrypt(3) and setkey(3) or the DES library libdes.
+ Since both is not included in lwIP, MSCHAP currently does not work! */
+/*****************************************************************************
+* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original based on BSD chap_ms.c.
+*****************************************************************************/
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ * 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.
+ * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#define USE_CRYPT
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "md4.h"
+#ifndef USE_CRYPT
+#include "des.h"
+#endif
+#include "chap.h"
+#include "chpms.h"
+
+#include <string.h>
+
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+typedef struct {
+ u_char LANManResp[24];
+ u_char NTResp[24];
+ u_char UseNT; /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+ in case this struct gets padded. */
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+
+/* XXX Don't know what to do with these. */
+extern void setkey(const char *);
+extern void encrypt(char *, int);
+
+static void DesEncrypt (u_char *, u_char *, u_char *);
+static void MakeKey (u_char *, u_char *);
+
+#ifdef USE_CRYPT
+static void Expand (u_char *, u_char *);
+static void Collapse (u_char *, u_char *);
+#endif
+
+static void ChallengeResponse(
+ u_char *challenge, /* IN 8 octets */
+ u_char *pwHash, /* IN 16 octets */
+ u_char *response /* OUT 24 octets */
+);
+static void ChapMS_NT(
+ char *rchallenge,
+ int rchallenge_len,
+ char *secret,
+ int secret_len,
+ MS_ChapResponse *response
+);
+static u_char Get7Bits(
+ u_char *input,
+ int startBit
+);
+
+static void
+ChallengeResponse( u_char *challenge, /* IN 8 octets */
+ u_char *pwHash, /* IN 16 octets */
+ u_char *response /* OUT 24 octets */)
+{
+ u_char ZPasswordHash[21];
+
+ BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+ BCOPY(pwHash, ZPasswordHash, 16);
+
+#if 0
+ log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
+#endif
+
+ DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
+ DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
+ DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+ log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void
+DesEncrypt( u_char *clear, /* IN 8 octets */
+ u_char *key, /* IN 7 octets */
+ u_char *cipher /* OUT 8 octets */)
+{
+ u_char des_key[8];
+ u_char crypt_key[66];
+ u_char des_input[66];
+
+ MakeKey(key, des_key);
+
+ Expand(des_key, crypt_key);
+ setkey((char*)crypt_key);
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+ Expand(clear, des_input);
+ encrypt((char*)des_input, 0);
+ Collapse(des_input, cipher);
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void
+DesEncrypt( u_char *clear, /* IN 8 octets */
+ u_char *key, /* IN 7 octets */
+ u_char *cipher /* OUT 8 octets */)
+{
+ des_cblock des_key;
+ des_key_schedule key_schedule;
+
+ MakeKey(key, des_key);
+
+ des_set_key(&des_key, key_schedule);
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+ des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char
+Get7Bits( u_char *input, int startBit)
+{
+ register unsigned int word;
+
+ word = (unsigned)input[startBit / 8] << 8;
+ word |= (unsigned)input[startBit / 8 + 1];
+
+ word >>= 15 - (startBit % 8 + 7);
+
+ return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void
+Expand(u_char *in, u_char *out)
+{
+ int j, c;
+ int i;
+
+ for(i = 0; i < 64; in++){
+ c = *in;
+ for(j = 7; j >= 0; j--) {
+ *out++ = (c >> j) & 01;
+ }
+ i += 8;
+ }
+}
+
+/* The inverse of Expand
+ */
+static void
+Collapse(u_char *in, u_char *out)
+{
+ int j;
+ int i;
+ unsigned int c;
+
+ for (i = 0; i < 64; i += 8, out++) {
+ c = 0;
+ for (j = 7; j >= 0; j--, in++) {
+ c |= *in << j;
+ }
+ *out = c & 0xff;
+ }
+}
+#endif
+
+static void
+MakeKey( u_char *key, /* IN 56 bit DES key missing parity bits */
+ u_char *des_key /* OUT 64 bit DES key with parity bits added */)
+{
+ des_key[0] = Get7Bits(key, 0);
+ des_key[1] = Get7Bits(key, 7);
+ des_key[2] = Get7Bits(key, 14);
+ des_key[3] = Get7Bits(key, 21);
+ des_key[4] = Get7Bits(key, 28);
+ des_key[5] = Get7Bits(key, 35);
+ des_key[6] = Get7Bits(key, 42);
+ des_key[7] = Get7Bits(key, 49);
+
+#ifndef USE_CRYPT
+ des_set_odd_parity((des_cblock *)des_key);
+#endif
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
+ key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
+ CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
+#endif
+}
+
+static void
+ChapMS_NT( char *rchallenge,
+ int rchallenge_len,
+ char *secret,
+ int secret_len,
+ MS_ChapResponse *response)
+{
+ int i;
+ MDstruct md4Context;
+ u_char unicodePassword[MAX_NT_PASSWORD * 2];
+ static int low_byte_first = -1;
+
+ LWIP_UNUSED_ARG(rchallenge_len);
+
+ /* Initialize the Unicode version of the secret (== password). */
+ /* This implicitly supports 8-bit ISO8859/1 characters. */
+ BZERO(unicodePassword, sizeof(unicodePassword));
+ for (i = 0; i < secret_len; i++) {
+ unicodePassword[i * 2] = (u_char)secret[i];
+ }
+ MDbegin(&md4Context);
+ MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
+
+ if (low_byte_first == -1) {
+ low_byte_first = (PP_HTONS((unsigned short int)1) != 1);
+ }
+ if (low_byte_first == 0) {
+ /* @todo: arg type - u_long* or u_int* ? */
+ MDreverse((unsigned int*)&md4Context); /* sfb 961105 */
+ }
+
+ MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
+
+ ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static void
+ChapMS_LANMan( char *rchallenge,
+ int rchallenge_len,
+ char *secret,
+ int secret_len,
+ MS_ChapResponse *response)
+{
+ int i;
+ u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+ u_char PasswordHash[16];
+
+ /* LANMan password is case insensitive */
+ BZERO(UcasePassword, sizeof(UcasePassword));
+ for (i = 0; i < secret_len; i++) {
+ UcasePassword[i] = (u_char)toupper(secret[i]);
+ }
+ DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+ DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+ ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+void
+ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
+{
+ MS_ChapResponse response;
+#ifdef MSLANMAN
+ extern int ms_lanman;
+#endif
+
+#if 0
+ CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret));
+#endif
+ BZERO(&response, sizeof(response));
+
+ /* Calculate both always */
+ ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+ ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+ /* prefered method is set by option */
+ response.UseNT = !ms_lanman;
+#else
+ response.UseNT = 1;
+#endif
+
+ BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+ cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+#endif /* MSCHAP_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.h
new file mode 100644
index 0000000000..df070fb356
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/chpms.h
@@ -0,0 +1,64 @@
+/*****************************************************************************
+* chpms.h - Network Microsoft Challenge Handshake Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original built from BSD network code.
+******************************************************************************/
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $
+ */
+
+#ifndef CHPMS_H
+#define CHPMS_H
+
+#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS (chap_state *, char *, int, char *, int);
+
+#endif /* CHPMS_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.c
new file mode 100644
index 0000000000..2e73c5af8f
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.c
@@ -0,0 +1,890 @@
+/*****************************************************************************
+* fsm.c - Network Control Protocol Finite State Machine program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original based on BSD fsm.c.
+*****************************************************************************/
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "fsm.h"
+
+#include <string.h>
+
+#if PPP_DEBUG
+static const char *ppperr_strerr[] = {
+ "LS_INITIAL", /* LS_INITIAL 0 */
+ "LS_STARTING", /* LS_STARTING 1 */
+ "LS_CLOSED", /* LS_CLOSED 2 */
+ "LS_STOPPED", /* LS_STOPPED 3 */
+ "LS_CLOSING", /* LS_CLOSING 4 */
+ "LS_STOPPING", /* LS_STOPPING 5 */
+ "LS_REQSENT", /* LS_REQSENT 6 */
+ "LS_ACKRCVD", /* LS_ACKRCVD 7 */
+ "LS_ACKSENT", /* LS_ACKSENT 8 */
+ "LS_OPENED" /* LS_OPENED 9 */
+};
+#endif /* PPP_DEBUG */
+
+static void fsm_timeout (void *);
+static void fsm_rconfreq (fsm *, u_char, u_char *, int);
+static void fsm_rconfack (fsm *, int, u_char *, int);
+static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
+static void fsm_rtermreq (fsm *, int, u_char *, int);
+static void fsm_rtermack (fsm *);
+static void fsm_rcoderej (fsm *, u_char *, int);
+static void fsm_sconfreq (fsm *, int);
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(fsm *f)
+{
+ f->state = LS_INITIAL;
+ f->flags = 0;
+ f->id = 0; /* XXX Start with random id? */
+ f->timeouttime = FSM_DEFTIMEOUT;
+ f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
+ f->maxtermtransmits = FSM_DEFMAXTERMREQS;
+ f->maxnakloops = FSM_DEFMAXNAKLOOPS;
+ f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(fsm *f)
+{
+ int oldState = f->state;
+
+ LWIP_UNUSED_ARG(oldState);
+
+ switch( f->state ) {
+ case LS_INITIAL:
+ f->state = LS_CLOSED;
+ break;
+
+ case LS_STARTING:
+ if( f->flags & OPT_SILENT ) {
+ f->state = LS_STOPPED;
+ } else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = LS_REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ }
+
+ FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
+ PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(fsm *f)
+{
+ int oldState = f->state;
+
+ LWIP_UNUSED_ARG(oldState);
+
+ switch( f->state ) {
+ case LS_CLOSED:
+ f->state = LS_INITIAL;
+ break;
+
+ case LS_STOPPED:
+ f->state = LS_STARTING;
+ if( f->callbacks->starting ) {
+ (*f->callbacks->starting)(f);
+ }
+ break;
+
+ case LS_CLOSING:
+ f->state = LS_INITIAL;
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ break;
+
+ case LS_STOPPING:
+ case LS_REQSENT:
+ case LS_ACKRCVD:
+ case LS_ACKSENT:
+ f->state = LS_STARTING;
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ break;
+
+ case LS_OPENED:
+ if( f->callbacks->down ) {
+ (*f->callbacks->down)(f);
+ }
+ f->state = LS_STARTING;
+ break;
+
+ default:
+ FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ }
+
+ FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
+ PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(fsm *f)
+{
+ int oldState = f->state;
+
+ LWIP_UNUSED_ARG(oldState);
+
+ switch( f->state ) {
+ case LS_INITIAL:
+ f->state = LS_STARTING;
+ if( f->callbacks->starting ) {
+ (*f->callbacks->starting)(f);
+ }
+ break;
+
+ case LS_CLOSED:
+ if( f->flags & OPT_SILENT ) {
+ f->state = LS_STOPPED;
+ } else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = LS_REQSENT;
+ }
+ break;
+
+ case LS_CLOSING:
+ f->state = LS_STOPPING;
+ /* fall through */
+ case LS_STOPPED:
+ case LS_OPENED:
+ if( f->flags & OPT_RESTART ) {
+ fsm_lowerdown(f);
+ fsm_lowerup(f);
+ }
+ break;
+ }
+
+ FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
+ PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
+}
+
+#if 0 /* backport pppd 2.4.4b1; */
+/*
+ * terminate_layer - Start process of shutting down the FSM
+ *
+ * Cancel any timeout running, notify upper layers we're done, and
+ * send a terminate-request message as configured.
+ */
+static void
+terminate_layer(fsm *f, int nextstate)
+{
+ /* @todo */
+}
+#endif
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the LS_CLOSED state.
+ */
+void
+fsm_close(fsm *f, char *reason)
+{
+ int oldState = f->state;
+
+ LWIP_UNUSED_ARG(oldState);
+
+ f->term_reason = reason;
+ f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
+ switch( f->state ) {
+ case LS_STARTING:
+ f->state = LS_INITIAL;
+ break;
+ case LS_STOPPED:
+ f->state = LS_CLOSED;
+ break;
+ case LS_STOPPING:
+ f->state = LS_CLOSING;
+ break;
+
+ case LS_REQSENT:
+ case LS_ACKRCVD:
+ case LS_ACKSENT:
+ case LS_OPENED:
+ if( f->state != LS_OPENED ) {
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ } else if( f->callbacks->down ) {
+ (*f->callbacks->down)(f); /* Inform upper layers we're down */
+ }
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = LS_CLOSING;
+ break;
+ }
+
+ FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
+ PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(void *arg)
+{
+ fsm *f = (fsm *) arg;
+
+ switch (f->state) {
+ case LS_CLOSING:
+ case LS_STOPPING:
+ if( f->retransmits <= 0 ) {
+ FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ /*
+ * We've waited for an ack long enough. Peer probably heard us.
+ */
+ f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
+ if( f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ } else {
+ FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ /* Send Terminate-Request */
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+ }
+ break;
+
+ case LS_REQSENT:
+ case LS_ACKRCVD:
+ case LS_ACKSENT:
+ if (f->retransmits <= 0) {
+ FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ f->state = LS_STOPPED;
+ if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ } else {
+ FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ /* Retransmit the configure-request */
+ if (f->callbacks->retransmit) {
+ (*f->callbacks->retransmit)(f);
+ }
+ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
+ if( f->state == LS_ACKRCVD ) {
+ f->state = LS_REQSENT;
+ }
+ }
+ break;
+
+ default:
+ FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ }
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void
+fsm_input(fsm *f, u_char *inpacket, int l)
+{
+ u_char *inp = inpacket;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ if (l < HEADERLEN) {
+ FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
+ f->protocol));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < HEADERLEN) {
+ FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
+ f->protocol));
+ return;
+ }
+ if (len > l) {
+ FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
+ f->protocol));
+ return;
+ }
+ len -= HEADERLEN; /* subtract header length */
+
+ if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
+ FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
+ f->protocol, f->state, ppperr_strerr[f->state]));
+ return;
+ }
+ FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case CONFREQ:
+ fsm_rconfreq(f, id, inp, len);
+ break;
+
+ case CONFACK:
+ fsm_rconfack(f, id, inp, len);
+ break;
+
+ case CONFNAK:
+ case CONFREJ:
+ fsm_rconfnakrej(f, code, id, inp, len);
+ break;
+
+ case TERMREQ:
+ fsm_rtermreq(f, id, inp, len);
+ break;
+
+ case TERMACK:
+ fsm_rtermack(f);
+ break;
+
+ case CODEREJ:
+ fsm_rcoderej(f, inp, len);
+ break;
+
+ default:
+ FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
+ if( !f->callbacks->extcode ||
+ !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
+ fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+ }
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void
+fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
+{
+ int code, reject_if_disagree;
+
+ FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
+ PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
+ switch( f->state ) {
+ case LS_CLOSED:
+ /* Go away, we're closed */
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ return;
+ case LS_CLOSING:
+ case LS_STOPPING:
+ return;
+
+ case LS_OPENED:
+ /* Go down and restart negotiation */
+ if( f->callbacks->down ) {
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ }
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ break;
+
+ case LS_STOPPED:
+ /* Negotiation started by our peer */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = LS_REQSENT;
+ break;
+ }
+
+ /*
+ * Pass the requested configuration options
+ * to protocol-specific code for checking.
+ */
+ if (f->callbacks->reqci) { /* Check CI */
+ reject_if_disagree = (f->nakloops >= f->maxnakloops);
+ code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+ } else if (len) {
+ code = CONFREJ; /* Reject all CI */
+ } else {
+ code = CONFACK;
+ }
+
+ /* send the Ack, Nak or Rej to the peer */
+ fsm_sdata(f, (u_char)code, id, inp, len);
+
+ if (code == CONFACK) {
+ if (f->state == LS_ACKRCVD) {
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ f->state = LS_OPENED;
+ if (f->callbacks->up) {
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ }
+ } else {
+ f->state = LS_ACKSENT;
+ }
+ f->nakloops = 0;
+ } else {
+ /* we sent CONFACK or CONFREJ */
+ if (f->state != LS_ACKRCVD) {
+ f->state = LS_REQSENT;
+ }
+ if( code == CONFNAK ) {
+ ++f->nakloops;
+ }
+ }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void
+fsm_rconfack(fsm *f, int id, u_char *inp, int len)
+{
+ FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
+ PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
+
+ if (id != f->reqid || f->seen_ack) { /* Expected id? */
+ return; /* Nope, toss... */
+ }
+ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
+ /* Ack is bad - ignore it */
+ FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
+ PROTO_NAME(f), len));
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case LS_CLOSED:
+ case LS_STOPPED:
+ fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+ break;
+
+ case LS_REQSENT:
+ f->state = LS_ACKRCVD;
+ f->retransmits = f->maxconfreqtransmits;
+ break;
+
+ case LS_ACKRCVD:
+ /* Huh? an extra valid Ack? oh well... */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = LS_REQSENT;
+ break;
+
+ case LS_ACKSENT:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ f->state = LS_OPENED;
+ f->retransmits = f->maxconfreqtransmits;
+ if (f->callbacks->up) {
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ }
+ break;
+
+ case LS_OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down) {
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ }
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = LS_REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void
+fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
+{
+ int (*proc) (fsm *, u_char *, int);
+ int ret;
+
+ FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
+ PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
+
+ if (id != f->reqid || f->seen_ack) { /* Expected id? */
+ return; /* Nope, toss... */
+ }
+ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+ if (!proc || !((ret = proc(f, inp, len)))) {
+ /* Nak/reject is bad - ignore it */
+ FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
+ PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case LS_CLOSED:
+ case LS_STOPPED:
+ fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+ break;
+
+ case LS_REQSENT:
+ case LS_ACKSENT:
+ /* They didn't agree to what we wanted - try another request */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ if (ret < 0) {
+ f->state = LS_STOPPED; /* kludge for stopping CCP */
+ } else {
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
+ }
+ break;
+
+ case LS_ACKRCVD:
+ /* Got a Nak/reject when we had already had an Ack?? oh well... */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = LS_REQSENT;
+ break;
+
+ case LS_OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down) {
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ }
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = LS_REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void
+fsm_rtermreq(fsm *f, int id, u_char *p, int len)
+{
+ LWIP_UNUSED_ARG(p);
+
+ FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
+ PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
+
+ switch (f->state) {
+ case LS_ACKRCVD:
+ case LS_ACKSENT:
+ f->state = LS_REQSENT; /* Start over but keep trying */
+ break;
+
+ case LS_OPENED:
+ if (len > 0) {
+ FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
+ } else {
+ FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
+ }
+ if (f->callbacks->down) {
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ }
+ f->retransmits = 0;
+ f->state = LS_STOPPING;
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ break;
+ }
+
+ fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(fsm *f)
+{
+ FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+
+ switch (f->state) {
+ case LS_CLOSING:
+ UNTIMEOUT(fsm_timeout, f);
+ f->state = LS_CLOSED;
+ if( f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ break;
+
+ case LS_STOPPING:
+ UNTIMEOUT(fsm_timeout, f);
+ f->state = LS_STOPPED;
+ if( f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ break;
+
+ case LS_ACKRCVD:
+ f->state = LS_REQSENT;
+ break;
+
+ case LS_OPENED:
+ if (f->callbacks->down) {
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ }
+ fsm_sconfreq(f, 0);
+ break;
+ default:
+ FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void
+fsm_rcoderej(fsm *f, u_char *inp, int len)
+{
+ u_char code, id;
+
+ FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+
+ if (len < HEADERLEN) {
+ FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
+ PROTO_NAME(f), code, id));
+
+ if( f->state == LS_ACKRCVD ) {
+ f->state = LS_REQSENT;
+ }
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void
+fsm_protreject(fsm *f)
+{
+ switch( f->state ) {
+ case LS_CLOSING:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ /* fall through */
+ case LS_CLOSED:
+ f->state = LS_CLOSED;
+ if( f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ break;
+
+ case LS_STOPPING:
+ case LS_REQSENT:
+ case LS_ACKRCVD:
+ case LS_ACKSENT:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ /* fall through */
+ case LS_STOPPED:
+ f->state = LS_STOPPED;
+ if( f->callbacks->finished ) {
+ (*f->callbacks->finished)(f);
+ }
+ break;
+
+ case LS_OPENED:
+ if( f->callbacks->down ) {
+ (*f->callbacks->down)(f);
+ }
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = LS_STOPPING;
+ break;
+
+ default:
+ FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
+ PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
+ }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(fsm *f, int retransmit)
+{
+ u_char *outp;
+ int cilen;
+
+ if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
+ /* Not currently negotiating - reset options */
+ if( f->callbacks->resetci ) {
+ (*f->callbacks->resetci)(f);
+ }
+ f->nakloops = 0;
+ }
+
+ if( !retransmit ) {
+ /* New request - reset retransmission counter, use new ID */
+ f->retransmits = f->maxconfreqtransmits;
+ f->reqid = ++f->id;
+ }
+
+ f->seen_ack = 0;
+
+ /*
+ * Make up the request packet
+ */
+ outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
+ if( f->callbacks->cilen && f->callbacks->addci ) {
+ cilen = (*f->callbacks->cilen)(f);
+ if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
+ cilen = peer_mru[f->unit] - HEADERLEN;
+ }
+ if (f->callbacks->addci) {
+ (*f->callbacks->addci)(f, outp, &cilen);
+ }
+ } else {
+ cilen = 0;
+ }
+
+ /* send the request to our peer */
+ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+ /* start the retransmit timer */
+ --f->retransmits;
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+
+ FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
+ PROTO_NAME(f), f->reqid));
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void
+fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
+{
+ u_char *outp;
+ int outlen;
+
+ /* Adjust length to be smaller than MTU */
+ outp = outpacket_buf[f->unit];
+ if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
+ datalen = peer_mru[f->unit] - HEADERLEN;
+ }
+ if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
+ BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+ }
+ outlen = datalen + HEADERLEN;
+ MAKEHEADER(outp, f->protocol);
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
+ FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
+ PROTO_NAME(f), code, id, outlen));
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.h
new file mode 100644
index 0000000000..8d41b5f511
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/fsm.h
@@ -0,0 +1,157 @@
+/*****************************************************************************
+* fsm.h - Network Control Protocol Finite State Machine header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original based on BSD code.
+*****************************************************************************/
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * $Id: fsm.h,v 1.5 2009/12/31 17:08:08 goldsimon Exp $
+ */
+
+#ifndef FSM_H
+#define FSM_H
+
+/*
+ * LCP Packet header = Code, id, length.
+ */
+#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ * CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ 1 /* Configuration Request */
+#define CONFACK 2 /* Configuration Ack */
+#define CONFNAK 3 /* Configuration Nak */
+#define CONFREJ 4 /* Configuration Reject */
+#define TERMREQ 5 /* Termination Request */
+#define TERMACK 6 /* Termination Ack */
+#define CODEREJ 7 /* Code Reject */
+
+
+/*
+ * Each FSM is described by an fsm structure and fsm callbacks.
+ */
+typedef struct fsm {
+ int unit; /* Interface unit number */
+ u_short protocol; /* Data Link Layer Protocol field value */
+ int state; /* State */
+ int flags; /* Contains option bits */
+ u_char id; /* Current id */
+ u_char reqid; /* Current request id */
+ u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */
+ int timeouttime; /* Timeout time in milliseconds */
+ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
+ int retransmits; /* Number of retransmissions left */
+ int maxtermtransmits; /* Maximum Terminate-Request transmissions */
+ int nakloops; /* Number of nak loops since last ack */
+ int maxnakloops; /* Maximum number of nak loops tolerated */
+ struct fsm_callbacks* callbacks; /* Callback routines */
+ char* term_reason; /* Reason for closing protocol */
+ int term_reason_len; /* Length of term_reason */
+} fsm;
+
+
+typedef struct fsm_callbacks {
+ void (*resetci)(fsm*); /* Reset our Configuration Information */
+ int (*cilen)(fsm*); /* Length of our Configuration Information */
+ void (*addci)(fsm*, u_char*, int*); /* Add our Configuration Information */
+ int (*ackci)(fsm*, u_char*, int); /* ACK our Configuration Information */
+ int (*nakci)(fsm*, u_char*, int); /* NAK our Configuration Information */
+ int (*rejci)(fsm*, u_char*, int); /* Reject our Configuration Information */
+ int (*reqci)(fsm*, u_char*, int*, int); /* Request peer's Configuration Information */
+ void (*up)(fsm*); /* Called when fsm reaches LS_OPENED state */
+ void (*down)(fsm*); /* Called when fsm leaves LS_OPENED state */
+ void (*starting)(fsm*); /* Called when we want the lower layer */
+ void (*finished)(fsm*); /* Called when we don't want the lower layer */
+ void (*protreject)(int); /* Called when Protocol-Reject received */
+ void (*retransmit)(fsm*); /* Retransmission is necessary */
+ int (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */
+ char *proto_name; /* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+/*
+ * Link states.
+ */
+#define LS_INITIAL 0 /* Down, hasn't been opened */
+#define LS_STARTING 1 /* Down, been opened */
+#define LS_CLOSED 2 /* Up, hasn't been opened */
+#define LS_STOPPED 3 /* Open, waiting for down event */
+#define LS_CLOSING 4 /* Terminating the connection, not open */
+#define LS_STOPPING 5 /* Terminating, but open */
+#define LS_REQSENT 6 /* We've sent a Config Request */
+#define LS_ACKRCVD 7 /* We've received a Config Ack */
+#define LS_ACKSENT 8 /* We've sent a Config Ack */
+#define LS_OPENED 9 /* Connection available */
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT 4 /* Wait for peer to speak first */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init (fsm*);
+void fsm_lowerup (fsm*);
+void fsm_lowerdown (fsm*);
+void fsm_open (fsm*);
+void fsm_close (fsm*, char*);
+void fsm_input (fsm*, u_char*, int);
+void fsm_protreject (fsm*);
+void fsm_sdata (fsm*, u_char, u_char, u_char*, int);
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
+
+#endif /* FSM_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.c
new file mode 100644
index 0000000000..655f949dad
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.c
@@ -0,0 +1,1415 @@
+/** In contrast to pppd 2.3.1, DNS support has been added, proxy-ARP and
+ dial-on-demand has been stripped. */
+/*****************************************************************************
+* ipcp.c - Network PPP IP Control Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original.
+*****************************************************************************/
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "auth.h"
+#include "fsm.h"
+#include "vj.h"
+#include "ipcp.h"
+
+#include "lwip/inet.h"
+
+#include <string.h>
+
+/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+/* local vars */
+static int default_route_set[NUM_PPP]; /* Have set up a default route */
+static int cis_received[NUM_PPP]; /* # Conf-Reqs received */
+
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipcp_resetci (fsm *); /* Reset our CI */
+static int ipcp_cilen (fsm *); /* Return length of our CI */
+static void ipcp_addci (fsm *, u_char *, int *); /* Add our CI */
+static int ipcp_ackci (fsm *, u_char *, int); /* Peer ack'd our CI */
+static int ipcp_nakci (fsm *, u_char *, int); /* Peer nak'd our CI */
+static int ipcp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */
+static int ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
+static void ipcp_up (fsm *); /* We're UP */
+static void ipcp_down (fsm *); /* We're DOWN */
+#if PPP_ADDITIONAL_CALLBACKS
+static void ipcp_script (fsm *, char *); /* Run an up/down script */
+#endif
+static void ipcp_finished (fsm *); /* Don't need lower layer */
+
+
+fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
+
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+ ipcp_resetci, /* Reset our Configuration Information */
+ ipcp_cilen, /* Length of our Configuration Information */
+ ipcp_addci, /* Add our Configuration Information */
+ ipcp_ackci, /* ACK our Configuration Information */
+ ipcp_nakci, /* NAK our Configuration Information */
+ ipcp_rejci, /* Reject our Configuration Information */
+ ipcp_reqci, /* Request peer's Configuration Information */
+ ipcp_up, /* Called when fsm reaches LS_OPENED state */
+ ipcp_down, /* Called when fsm leaves LS_OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ ipcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPCP" /* String name of protocol */
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init (int);
+static void ipcp_open (int);
+static void ipcp_close (int, char *);
+static void ipcp_lowerup (int);
+static void ipcp_lowerdown (int);
+static void ipcp_input (int, u_char *, int);
+static void ipcp_protrej (int);
+
+
+struct protent ipcp_protent = {
+ PPP_IPCP,
+ ipcp_init,
+ ipcp_input,
+ ipcp_protrej,
+ ipcp_lowerup,
+ ipcp_lowerdown,
+ ipcp_open,
+ ipcp_close,
+#if PPP_ADDITIONAL_CALLBACKS
+ ipcp_printpkt,
+ NULL,
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+ 1,
+ "IPCP",
+#if PPP_ADDITIONAL_CALLBACKS
+ ip_check_options,
+ NULL,
+ ip_active_pkt
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+};
+
+static void ipcp_clear_addrs (int);
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
+#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR 6 /* new-style single address option */
+#define CILEN_ADDRS 10 /* old-style dual address option */
+
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+static void
+ipcp_init(int unit)
+{
+ fsm *f = &ipcp_fsm[unit];
+ ipcp_options *wo = &ipcp_wantoptions[unit];
+ ipcp_options *ao = &ipcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPCP;
+ f->callbacks = &ipcp_callbacks;
+ fsm_init(&ipcp_fsm[unit]);
+
+ memset(wo, 0, sizeof(*wo));
+ memset(ao, 0, sizeof(*ao));
+
+ wo->neg_addr = 1;
+ wo->ouraddr = 0;
+#if VJ_SUPPORT
+ wo->neg_vj = 1;
+#else /* VJ_SUPPORT */
+ wo->neg_vj = 0;
+#endif /* VJ_SUPPORT */
+ wo->vj_protocol = IPCP_VJ_COMP;
+ wo->maxslotindex = MAX_SLOTS - 1;
+ wo->cflag = 0;
+ wo->default_route = 1;
+
+ ao->neg_addr = 1;
+#if VJ_SUPPORT
+ ao->neg_vj = 1;
+#else /* VJ_SUPPORT */
+ ao->neg_vj = 0;
+#endif /* VJ_SUPPORT */
+ ao->maxslotindex = MAX_SLOTS - 1;
+ ao->cflag = 1;
+ ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void
+ipcp_open(int unit)
+{
+ fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void
+ipcp_close(int unit, char *reason)
+{
+ fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void
+ipcp_lowerup(int unit)
+{
+ fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void
+ipcp_lowerdown(int unit)
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void
+ipcp_input(int unit, u_char *p, int len)
+{
+ fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipcp_protrej(int unit)
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ */
+static void
+ipcp_resetci(fsm *f)
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+ if (wo->ouraddr == 0) {
+ wo->accept_local = 1;
+ }
+ if (wo->hisaddr == 0) {
+ wo->accept_remote = 1;
+ }
+ /* Request DNS addresses from the peer */
+ wo->req_dns1 = ppp_settings.usepeerdns;
+ wo->req_dns2 = ppp_settings.usepeerdns;
+ ipcp_gotoptions[f->unit] = *wo;
+ cis_received[f->unit] = 0;
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ */
+static int
+ipcp_cilen(fsm *f)
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+
+#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0)
+
+ /*
+ * First see if we want to change our options to the old
+ * forms because we have received old forms from the peer.
+ */
+ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+ /* use the old style of address negotiation */
+ go->neg_addr = 1;
+ go->old_addrs = 1;
+ }
+ if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+ /* try an older style of VJ negotiation */
+ if (cis_received[f->unit] == 0) {
+ /* keep trying the new style until we see some CI from the peer */
+ go->neg_vj = 1;
+ } else {
+ /* use the old style only if the peer did */
+ if (ho->neg_vj && ho->old_vj) {
+ go->neg_vj = 1;
+ go->old_vj = 1;
+ go->vj_protocol = ho->vj_protocol;
+ }
+ }
+ }
+
+ return (LENCIADDR(go->neg_addr, go->old_addrs) +
+ LENCIVJ(go->neg_vj, go->old_vj) +
+ LENCIDNS(go->req_dns1) +
+ LENCIDNS(go->req_dns2));
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipcp_addci(fsm *f, u_char *ucp, int *lenp)
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ if (!old) { \
+ PUTCHAR(maxslotindex, ucp); \
+ PUTCHAR(cflag, ucp); \
+ } \
+ len -= vjlen; \
+ } else { \
+ neg = 0; \
+ } \
+ }
+
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ if (len >= addrlen) { \
+ u32_t l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(addrlen, ucp); \
+ l = ntohl(val1); \
+ PUTLONG(l, ucp); \
+ if (old) { \
+ l = ntohl(val2); \
+ PUTLONG(l, ucp); \
+ } \
+ len -= addrlen; \
+ } else { \
+ neg = 0; \
+ } \
+ }
+
+#define ADDCIDNS(opt, neg, addr) \
+ if (neg) { \
+ if (len >= CILEN_ADDR) { \
+ u32_t l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_ADDR, ucp); \
+ l = ntohl(addr); \
+ PUTLONG(l, ucp); \
+ len -= CILEN_ADDR; \
+ } else { \
+ neg = 0; \
+ } \
+ }
+
+ ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+ ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+ *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipcp_ackci(fsm *f, u_char *p, int len)
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_short cilen, citype, cishort;
+ u32_t cilong;
+ u_char cimaxslotindex, cicflag;
+
+ /*
+ * CIs must be in exactly the same order that we sent...
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if ((len -= vjlen) < 0) { \
+ goto bad; \
+ } \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != vjlen || \
+ citype != opt) { \
+ goto bad; \
+ } \
+ GETSHORT(cishort, p); \
+ if (cishort != val) { \
+ goto bad; \
+ } \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslotindex) { \
+ goto bad; \
+ } \
+ GETCHAR(cicflag, p); \
+ if (cicflag != cflag) { \
+ goto bad; \
+ } \
+ } \
+ }
+
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ u32_t l; \
+ if ((len -= addrlen) < 0) { \
+ goto bad; \
+ } \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != addrlen || \
+ citype != opt) { \
+ goto bad; \
+ } \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val1 != cilong) { \
+ goto bad; \
+ } \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val2 != cilong) { \
+ goto bad; \
+ } \
+ } \
+ }
+
+#define ACKCIDNS(opt, neg, addr) \
+ if (neg) { \
+ u32_t l; \
+ if ((len -= CILEN_ADDR) < 0) { \
+ goto bad; \
+ } \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_ADDR || \
+ citype != opt) { \
+ goto bad; \
+ } \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (addr != cilong) { \
+ goto bad; \
+ } \
+ }
+
+ ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+ ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0) {
+ goto bad;
+ }
+ return (1);
+
+bad:
+ IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n"));
+ return (0);
+}
+
+/*
+ * 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 LS_OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+ipcp_nakci(fsm *f, u_char *p, int len)
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
+ u_short cishort;
+ u32_t ciaddr1, ciaddr2, l, cidnsaddr;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIADDR(opt, neg, old, code) \
+ if (go->neg && \
+ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ ciaddr1 = htonl(l); \
+ if (old) { \
+ GETLONG(l, p); \
+ ciaddr2 = htonl(l); \
+ no.old_addrs = 1; \
+ } else { \
+ ciaddr2 = 0; \
+ } \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIDNS(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_ADDR) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cidnsaddr = htonl(l); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
+ */
+ NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+ if (go->accept_local && ciaddr1) { /* Do we know our address? */
+ try.ouraddr = ciaddr1;
+ IPCPDEBUG(LOG_INFO, ("local IP address %s\n",
+ inet_ntoa(ciaddr1)));
+ }
+ if (go->accept_remote && ciaddr2) { /* Does he know his? */
+ try.hisaddr = ciaddr2;
+ IPCPDEBUG(LOG_INFO, ("remote IP address %s\n",
+ inet_ntoa(ciaddr2)));
+ }
+ );
+
+ /*
+ * Accept the peer's value of maxslotindex provided that it
+ * is less than what we asked for. Turn off slot-ID compression
+ * if the peer wants. Send old-style compress-type option if
+ * the peer wants.
+ */
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ if (cilen == CILEN_VJ) {
+ GETCHAR(cimaxslotindex, p);
+ GETCHAR(cicflag, p);
+ if (cishort == IPCP_VJ_COMP) {
+ try.old_vj = 0;
+ if (cimaxslotindex < go->maxslotindex) {
+ try.maxslotindex = cimaxslotindex;
+ }
+ if (!cicflag) {
+ try.cflag = 0;
+ }
+ } else {
+ try.neg_vj = 0;
+ }
+ } else {
+ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+ try.old_vj = 1;
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+
+ NAKCIDNS(CI_MS_DNS1, req_dns1,
+ try.dnsaddr[0] = cidnsaddr;
+ IPCPDEBUG(LOG_INFO, ("primary DNS address %s\n", inet_ntoa(cidnsaddr)));
+ );
+
+ NAKCIDNS(CI_MS_DNS2, req_dns2,
+ try.dnsaddr[1] = cidnsaddr;
+ IPCPDEBUG(LOG_INFO, ("secondary DNS address %s\n", inet_ntoa(cidnsaddr)));
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about IP addresses, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 ) {
+ goto bad;
+ }
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+ goto bad;
+ }
+ no.neg_vj = 1;
+ break;
+ case CI_ADDRS:
+ if ((go->neg_addr && go->old_addrs) || no.old_addrs
+ || cilen != CILEN_ADDRS) {
+ goto bad;
+ }
+ try.neg_addr = 1;
+ try.old_addrs = 1;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local) {
+ try.ouraddr = ciaddr1;
+ }
+ GETLONG(l, p);
+ ciaddr2 = htonl(l);
+ if (ciaddr2 && go->accept_remote) {
+ try.hisaddr = ciaddr2;
+ }
+ no.old_addrs = 1;
+ break;
+ case CI_ADDR:
+ if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {
+ goto bad;
+ }
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local) {
+ try.ouraddr = ciaddr1;
+ }
+ if (try.ouraddr != 0) {
+ try.neg_addr = 1;
+ }
+ no.neg_addr = 1;
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0) {
+ goto bad;
+ }
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != LS_OPENED) {
+ *go = try;
+ }
+
+ return 1;
+
+bad:
+ IPCPDEBUG(LOG_INFO, ("ipcp_nakci: received bad Nak!\n"));
+ return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ */
+static int
+ipcp_rejci(fsm *f, u_char *p, int len)
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, ciflag, cilen;
+ u_short cishort;
+ u32_t cilong;
+ ipcp_options try; /* options to request next time */
+
+ try = *go;
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+ if (go->neg && \
+ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ u32_t l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val1) { \
+ goto bad; \
+ } \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val2) { \
+ goto bad; \
+ } \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+ if (go->neg && \
+ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+ len >= p[1] && \
+ p[0] == opt) { \
+ len -= p[1]; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) { \
+ goto bad; \
+ } \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslot) { \
+ goto bad; \
+ } \
+ GETCHAR(ciflag, p); \
+ if (ciflag != cflag) { \
+ goto bad; \
+ } \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIDNS(opt, neg, dnsaddr) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_ADDR) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ u32_t l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != dnsaddr) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+ REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
+
+ REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0) {
+ goto bad;
+ }
+ /*
+ * Now we can update state.
+ */
+ if (f->state != LS_OPENED) {
+ *go = try;
+ }
+ return 1;
+
+bad:
+ IPCPDEBUG(LOG_INFO, ("ipcp_rejci: received bad Reject!\n"));
+ return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *ao = &ipcp_allowoptions[f->unit];
+#ifdef OLD_CI_ADDRS
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+#endif
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort; /* Parsed short value */
+ u32_t tl, ciaddr1; /* Parsed address values */
+#ifdef OLD_CI_ADDRS
+ u32_t ciaddr2; /* Parsed address values */
+#endif
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+ u_char maxslotindex, cflag;
+ int d;
+
+ cis_received[f->unit] = 1;
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining 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? */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: bad CI length!\n"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = (u_short)l;/* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+#ifdef OLD_CI_ADDRS /* Need to save space... */
+ case CI_ADDRS:
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received ADDRS\n"));
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDRS) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ IPCPDEBUG(LOG_INFO, ("his addr %s\n", inet_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * If neither we nor he knows his address, reject the option.
+ */
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ /*
+ * 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) */
+ ciaddr2 = htonl(tl);
+ IPCPDEBUG(LOG_INFO, ("our addr %s\n", inet_ntoa(ciaddr2)));
+ if (ciaddr2 != wo->ouraddr) {
+ if (ciaddr2 == 0 || !wo->accept_local) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u32_t), p);
+ tl = ntohl(wo->ouraddr);
+ PUTLONG(tl, p);
+ }
+ } else {
+ go->ouraddr = ciaddr2; /* accept peer's idea */
+ }
+ }
+
+ ho->neg_addr = 1;
+ ho->old_addrs = 1;
+ ho->hisaddr = ciaddr1;
+ ho->ouraddr = ciaddr2;
+ break;
+#endif
+
+ case CI_ADDR:
+ if (!ao->neg_addr) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR not allowed\n"));
+ orc = CONFREJ; /* Reject CI */
+ break;
+ } else if (cilen != CILEN_ADDR) { /* Check CI length */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR bad len\n"));
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * Don't ACK an address of 0.0.0.0 - reject it instead.
+ */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ ho->neg_addr = 1;
+ ho->hisaddr = ciaddr1;
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));
+ break;
+
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ /* Microsoft primary or secondary DNS request */
+ d = citype == CI_MS_DNS2;
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->dnsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting DNS%d Request\n", d+1));
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->dnsaddr[d]) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking DNS%d Request %s\n",
+ d+1, inet_ntoa(tl)));
+ DECPTR(sizeof(u32_t), p);
+ tl = ntohl(ao->dnsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received DNS%d Request\n", d+1));
+ break;
+
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ /* Microsoft primary or secondary WINS request */
+ d = citype == CI_MS_WINS2;
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received WINS%d Request\n", d+1));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->winsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->winsaddr[d]) {
+ DECPTR(sizeof(u32_t), p);
+ tl = ntohl(ao->winsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+
+ case CI_COMPRESSTYPE:
+ if (!ao->neg_vj) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));
+ orc = CONFREJ;
+ break;
+ } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+
+ if (!(cishort == IPCP_VJ_COMP ||
+ (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ if (cilen == CILEN_VJ) {
+ GETCHAR(maxslotindex, p);
+ if (maxslotindex > ao->maxslotindex) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(1, p);
+ PUTCHAR(ao->maxslotindex, p);
+ }
+ }
+ GETCHAR(cflag, p);
+ if (cflag && !ao->cflag) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ cflag %d\n", cflag));
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(1, p);
+ PUTCHAR(wo->cflag, p);
+ }
+ }
+ ho->maxslotindex = maxslotindex;
+ ho->cflag = cflag;
+ } else {
+ ho->old_vj = 1;
+ ho->maxslotindex = MAX_SLOTS - 1;
+ ho->cflag = 1;
+ }
+ IPCPDEBUG(LOG_INFO, (
+ "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",
+ ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));
+ break;
+
+ default:
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting unknown CI type %d\n", citype));
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) { /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+ }
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) { /* Getting fed up with sending NAKs? */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting too many naks\n"));
+ orc = CONFREJ; /* Get tough if so */
+ } else {
+ if (rc == CONFREJ) { /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ }
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip) {
+ BCOPY(cip, ucp, cilen); /* Move it */
+ }
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a CI_ADDR option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+ if (rc != CONFREJ && !ho->neg_addr &&
+ wo->req_addr && !reject_if_disagree) {
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Requesting peer address\n"));
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_addr = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_ADDR, ucp);
+ PUTCHAR(CILEN_ADDR, ucp);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, ucp);
+ }
+
+ *len = (int)(ucp - inp); /* Compute output length */
+ IPCPDEBUG(LOG_INFO, ("ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+#if 0
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ip_check_options(u_long localAddr)
+{
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * Load our default IP address but allow the remote host to give us
+ * a new address.
+ */
+ if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {
+ wo->accept_local = 1; /* don't insist on this default value */
+ wo->ouraddr = htonl(localAddr);
+ }
+}
+#endif
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+ipcp_up(fsm *f)
+{
+ u32_t mask;
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ np_up(f->unit, PPP_IP);
+ IPCPDEBUG(LOG_INFO, ("ipcp: up\n"));
+
+ /*
+ * We must have a non-zero IP address for both ends of the link.
+ */
+ if (!ho->neg_addr) {
+ ho->hisaddr = wo->hisaddr;
+ }
+
+ if (ho->hisaddr == 0) {
+#if 0
+ IPCPDEBUG(LOG_ERR, ("Could not determine remote IP address\n"));
+ ipcp_close(f->unit, "Could not determine remote IP address");
+ return;
+#else //Kludge
+ ho->hisaddr = 0; //Set remote IP to 0.0.0.0, this is needed as most 3g providers do not advertise the remote IP to the user
+#endif
+ }
+ if (go->ouraddr == 0) {
+ IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n"));
+ ipcp_close(f->unit, "Could not determine local IP address");
+ return;
+ }
+
+ if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
+ /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/
+ }
+
+ /*
+ * Check that the peer is allowed to use the IP address it wants.
+ */
+ if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+ IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n",
+ inet_ntoa(ho->hisaddr)));
+ ipcp_close(f->unit, "Unauthorized remote IP address");
+ return;
+ }
+
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {
+ IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ IPCPDEBUG(LOG_WARNING, ("sifup failed\n"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+
+ sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route) {
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {
+ default_route_set[f->unit] = 1;
+ }
+ }
+
+ IPCPDEBUG(LOG_NOTICE, ("local IP address %s\n", inet_ntoa(go->ouraddr)));
+ IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr)));
+ if (go->dnsaddr[0]) {
+ IPCPDEBUG(LOG_NOTICE, ("primary DNS address %s\n", inet_ntoa(go->dnsaddr[0])));
+ }
+ if (go->dnsaddr[1]) {
+ IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));
+ }
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipcp_down(fsm *f)
+{
+ IPCPDEBUG(LOG_INFO, ("ipcp: down\n"));
+ np_down(f->unit, PPP_IP);
+ sifvjcomp(f->unit, 0, 0, 0);
+
+ sifdown(f->unit);
+ ipcp_clear_addrs(f->unit);
+}
+
+
+/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes, etc.
+ */
+static void
+ipcp_clear_addrs(int unit)
+{
+ u32_t ouraddr, hisaddr;
+
+ ouraddr = ipcp_gotoptions[unit].ouraddr;
+ hisaddr = ipcp_hisoptions[unit].hisaddr;
+ if (default_route_set[unit]) {
+ cifdefaultroute(unit, ouraddr, hisaddr);
+ default_route_set[unit] = 0;
+ }
+ cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(fsm *f)
+{
+ np_finished(f->unit, PPP_IP);
+}
+
+#if PPP_ADDITIONAL_CALLBACKS
+static int
+ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
+{
+ LWIP_UNUSED_ARG(p);
+ LWIP_UNUSED_ARG(plen);
+ LWIP_UNUSED_ARG(printer);
+ LWIP_UNUSED_ARG(arg);
+ return 0;
+}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN 20 /* bytes */
+#define IP_OFFMASK 0x1fff
+#define IPPROTO_TCP 6
+#define TCP_HDRLEN 20
+#define TH_FIN 0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x) (((x)[0] << 8) + (x)[1])
+#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x) (((unsigned char *)(x))[9])
+#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x) (((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(u_char *pkt, int len)
+{
+ u_char *tcp;
+ int hlen;
+
+ len -= PPP_HDRLEN;
+ pkt += PPP_HDRLEN;
+ if (len < IP_HDRLEN) {
+ return 0;
+ }
+ if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {
+ return 0;
+ }
+ if (get_ipproto(pkt) != IPPROTO_TCP) {
+ return 1;
+ }
+ hlen = get_iphl(pkt) * 4;
+ if (len < hlen + TCP_HDRLEN) {
+ return 0;
+ }
+ tcp = pkt + hlen;
+ if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {
+ return 0;
+ }
+ return 1;
+}
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.h
new file mode 100644
index 0000000000..de03f460ec
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ipcp.h
@@ -0,0 +1,106 @@
+/*****************************************************************************
+* ipcp.h - PPP IP NCP: Internet Protocol Network Control Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * $Id: ipcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $
+ */
+
+#ifndef IPCP_H
+#define IPCP_H
+
+/*
+ * Options.
+ */
+#define CI_ADDRS 1 /* IP Addresses */
+#define CI_COMPRESSTYPE 2 /* Compression Type */
+#define CI_ADDR 3
+
+#define CI_MS_DNS1 129 /* Primary DNS value */
+#define CI_MS_WINS1 128 /* Primary WINS value */
+#define CI_MS_DNS2 131 /* Secondary DNS value */
+#define CI_MS_WINS2 130 /* Secondary WINS value */
+
+#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
+ /* maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option */
+#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
+ /* compression option */
+
+typedef struct ipcp_options {
+ u_int neg_addr : 1; /* Negotiate IP Address? */
+ u_int old_addrs : 1; /* Use old (IP-Addresses) option? */
+ u_int req_addr : 1; /* Ask peer to send IP address? */
+ u_int default_route : 1; /* Assign default route through interface? */
+ u_int proxy_arp : 1; /* Make proxy ARP entry for peer? */
+ u_int neg_vj : 1; /* Van Jacobson Compression? */
+ u_int old_vj : 1; /* use old (short) form of VJ option? */
+ u_int accept_local : 1; /* accept peer's value for ouraddr */
+ u_int accept_remote : 1; /* accept peer's value for hisaddr */
+ u_int req_dns1 : 1; /* Ask peer to send primary DNS address? */
+ u_int req_dns2 : 1; /* Ask peer to send secondary DNS address? */
+ u_short vj_protocol; /* protocol value to use in VJ option */
+ u_char maxslotindex; /* VJ slots - 1. */
+ u_char cflag; /* VJ slot compression flag. */
+ u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+ u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */
+ u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */
+} ipcp_options;
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+extern struct protent ipcp_protent;
+
+#endif /* IPCP_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.c
new file mode 100644
index 0000000000..95d54849b9
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.c
@@ -0,0 +1,2066 @@
+/*****************************************************************************
+* lcp.c - Network Link Control Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original.
+*****************************************************************************/
+
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "fsm.h"
+#include "chap.h"
+#include "magic.h"
+#include "auth.h"
+#include "lcp.h"
+
+#include <string.h>
+
+#if PPPOE_SUPPORT
+#include "netif/ppp_oe.h"
+#else
+#define PPPOE_MAXMTU PPP_MAXMRU
+#endif
+
+#if 0 /* UNUSED */
+/*
+ * LCP-related command-line options.
+ */
+int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
+int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
+bool lax_recv = 0; /* accept control chars in asyncmap */
+
+static int setescape (char **);
+
+static option_t lcp_option_list[] = {
+ /* LCP options */
+ /* list stripped for simplicity */
+ {NULL}
+};
+#endif /* UNUSED */
+
+/* options */
+LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */
+static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
+static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */
+
+/* global vars */
+static fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+ext_accm xmit_accm[NUM_PPP]; /* extended transmit ACCM */
+
+static u32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */
+static u32_t lcp_echo_number = 0; /* ID number of next echo frame */
+static u32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */
+
+/* @todo: do we really need such a large buffer? The typical 1500 bytes seem too much. */
+static u_char nak_buffer[PPP_MRU] __attribute((section("AHBSRAM1"))); /* where we construct a nak packet */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci (fsm*); /* Reset our CI */
+static int lcp_cilen (fsm*); /* Return length of our CI */
+static void lcp_addci (fsm*, u_char*, int*); /* Add our CI to pkt */
+static int lcp_ackci (fsm*, u_char*, int); /* Peer ack'd our CI */
+static int lcp_nakci (fsm*, u_char*, int); /* Peer nak'd our CI */
+static int lcp_rejci (fsm*, u_char*, int); /* Peer rej'd our CI */
+static int lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */
+static void lcp_up (fsm*); /* We're UP */
+static void lcp_down (fsm*); /* We're DOWN */
+static void lcp_starting (fsm*); /* We need lower layer up */
+static void lcp_finished (fsm*); /* We need lower layer down */
+static int lcp_extcode (fsm*, int, u_char, u_char*, int);
+static void lcp_rprotrej (fsm*, u_char*, int);
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup (int);
+static void lcp_echo_lowerdown (int);
+static void LcpEchoTimeout (void*);
+static void lcp_received_echo_reply (fsm*, int, u_char*, int);
+static void LcpSendEchoRequest (fsm*);
+static void LcpLinkFailure (fsm*);
+static void LcpEchoCheck (fsm*);
+
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
+ lcp_resetci, /* Reset our Configuration Information */
+ lcp_cilen, /* Length of our Configuration Information */
+ lcp_addci, /* Add our Configuration Information */
+ lcp_ackci, /* ACK our Configuration Information */
+ lcp_nakci, /* NAK our Configuration Information */
+ lcp_rejci, /* Reject our Configuration Information */
+ lcp_reqci, /* Request peer's Configuration Information */
+ lcp_up, /* Called when fsm reaches LS_OPENED state */
+ lcp_down, /* Called when fsm leaves LS_OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
+};
+
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+
+static void lcp_input (int, u_char *, int);
+static void lcp_protrej (int);
+
+struct protent lcp_protent = {
+ PPP_LCP,
+ lcp_init,
+ lcp_input,
+ lcp_protrej,
+ lcp_lowerup,
+ lcp_lowerdown,
+ lcp_open,
+ lcp_close,
+#if PPP_ADDITIONAL_CALLBACKS
+ lcp_printpkt,
+ NULL,
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+ 1,
+ "LCP",
+#if PPP_ADDITIONAL_CALLBACKS
+ NULL,
+ NULL,
+ NULL
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#define CILEN_CHAR 3
+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
+#define CILEN_CBCP 3
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ")
+
+#if 0 /* UNUSED */
+/*
+ * setescape - add chars to the set we escape on transmission.
+ */
+static int
+setescape(argv)
+ char **argv;
+{
+ int n, ret;
+ char *p, *endp;
+
+ p = *argv;
+ ret = 1;
+ while (*p) {
+ n = strtol(p, &endp, 16);
+ if (p == endp) {
+ option_error("escape parameter contains invalid hex number '%s'", p);
+ return 0;
+ }
+ p = endp;
+ if (n < 0 || n == 0x5E || n > 0xFF) {
+ option_error("can't escape character 0x%x", n);
+ ret = 0;
+ } else
+ xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
+ while (*p == ',' || *p == ' ')
+ ++p;
+ }
+ return ret;
+}
+#endif /* UNUSED */
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+void
+lcp_init(int unit)
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_LCP;
+ f->callbacks = &lcp_callbacks;
+
+ fsm_init(f);
+
+ wo->passive = 0;
+ wo->silent = 0;
+ wo->restart = 0; /* Set to 1 in kernels or multi-line implementations */
+ wo->neg_mru = 1;
+ wo->mru = PPP_DEFMRU;
+ wo->neg_asyncmap = 1;
+ wo->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */
+ wo->neg_chap = 0; /* Set to 1 on server */
+ wo->neg_upap = 0; /* Set to 1 on server */
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+ wo->neg_lqr = 0; /* no LQR implementation yet */
+ wo->neg_cbcp = 0;
+
+ ao->neg_mru = 1;
+ ao->mru = PPP_MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */
+ ao->neg_chap = (CHAP_SUPPORT != 0);
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = (PAP_SUPPORT != 0);
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+ ao->neg_lqr = 0; /* no LQR implementation yet */
+ ao->neg_cbcp = (CBCP_SUPPORT != 0);
+
+ /*
+ * Set transmit escape for the flag and escape characters plus anything
+ * set for the allowable options.
+ */
+ memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+ xmit_accm[unit][15] = 0x60;
+ xmit_accm[unit][0] = (u_char)((ao->asyncmap & 0xFF));
+ xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF);
+ xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF);
+ xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF);
+ LCPDEBUG(LOG_INFO, ("lcp_init: xmit_accm=%X %X %X %X\n",
+ xmit_accm[unit][0],
+ xmit_accm[unit][1],
+ xmit_accm[unit][2],
+ xmit_accm[unit][3]));
+
+ lcp_phase[unit] = PHASE_INITIALIZE;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(int unit)
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags = 0;
+ if (wo->passive) {
+ f->flags |= OPT_PASSIVE;
+ }
+ if (wo->silent) {
+ f->flags |= OPT_SILENT;
+ }
+ fsm_open(f);
+
+ lcp_phase[unit] = PHASE_ESTABLISH;
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(int unit, char *reason)
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (lcp_phase[unit] != PHASE_DEAD) {
+ lcp_phase[unit] = PHASE_TERMINATE;
+ }
+ if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+ /*
+ * This action is not strictly according to the FSM in RFC1548,
+ * but it does mean that the program terminates if you do an
+ * lcp_close() in passive/silent mode when a connection hasn't
+ * been established.
+ */
+ f->state = LS_CLOSED;
+ lcp_finished(f);
+ } else {
+ fsm_close(f, reason);
+ }
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(int unit)
+{
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ /*
+ * Don't use A/C or protocol compression on transmission,
+ * but accept A/C and protocol compressed packets
+ * if we are going to ask for A/C and protocol compression.
+ */
+ ppp_set_xaccm(unit, &xmit_accm[unit]);
+ ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);
+ ppp_recv_config(unit, PPP_MRU, 0x00000000l,
+ wo->neg_pcompression, wo->neg_accompression);
+ peer_mru[unit] = PPP_MRU;
+ lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0]
+ | ((u_long)xmit_accm[unit][1] << 8)
+ | ((u_long)xmit_accm[unit][2] << 16)
+ | ((u_long)xmit_accm[unit][3] << 24);
+ LCPDEBUG(LOG_INFO, ("lcp_lowerup: asyncmap=%X %X %X %X\n",
+ xmit_accm[unit][3],
+ xmit_accm[unit][2],
+ xmit_accm[unit][1],
+ xmit_accm[unit][0]));
+
+ fsm_lowerup(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void
+lcp_lowerdown(int unit)
+{
+ fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_input - Input LCP packet.
+ */
+static void
+lcp_input(int unit, u_char *p, int len)
+{
+ fsm *f = &lcp_fsm[unit];
+
+ fsm_input(f, p, len);
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)
+{
+ u_char *magp;
+
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if (f->state != LS_OPENED) {
+ break;
+ }
+ LCPDEBUG(LOG_INFO, ("lcp: Echo-Request, Rcvd id %d\n", id));
+ magp = inp;
+ PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ lcp_received_echo_reply(f, id, inp, len);
+ break;
+
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(fsm *f, u_char *inp, int len)
+{
+ int i;
+ struct protent *protp;
+ u_short prot;
+
+ if (len < (int)sizeof (u_short)) {
+ LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot));
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * LS_OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != LS_OPENED ) {
+ LCPDEBUG(LOG_INFO, ("Protocol-Reject discarded: LCP in state %d\n", f->state));
+ return;
+ }
+
+ /*
+ * Upcall the proper Protocol-Reject routine.
+ */
+ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+ if (protp->protocol == prot && protp->enabled_flag) {
+ (*protp->protrej)(f->unit);
+ return;
+ }
+ }
+
+ LCPDEBUG(LOG_WARNING, ("Protocol-Reject for unsupported protocol 0x%x\n", prot));
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+static void
+lcp_protrej(int unit)
+{
+ LWIP_UNUSED_ARG(unit);
+ /*
+ * Can't reject LCP!
+ */
+ LCPDEBUG(LOG_WARNING, ("lcp_protrej: Received Protocol-Reject for LCP!\n"));
+ fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void
+lcp_sprotrej(int unit, u_char *p, int len)
+{
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the LS_OPENED state.
+ */
+
+ fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void
+lcp_resetci(fsm *f)
+{
+ lcp_wantoptions[f->unit].magicnumber = magic();
+ lcp_wantoptions[f->unit].numloops = 0;
+ lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+ peer_mru[f->unit] = PPP_MRU;
+ auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(fsm *f)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
+ /*
+ * NB: we only ask for one of CHAP and UPAP, even if we will
+ * accept either.
+ */
+ return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
+ LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +
+ LENCICHAP(go->neg_chap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
+ LENCICBCP(go->neg_cbcp) +
+ LENCILONG(go->neg_magicnumber) +
+ LENCIVOID(go->neg_pcompression) +
+ LENCIVOID(go->neg_accompression));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void
+lcp_addci(fsm *f, u_char *ucp, int *lenp)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
+
+#define ADDCIVOID(opt, neg) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: opt=%d\n", opt)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
+ }
+#define ADDCISHORT(opt, neg, val) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: INT opt=%d %X\n", opt, val)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
+ PUTSHORT(val, ucp); \
+ }
+#define ADDCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: CHAP opt=%d %X\n", opt, val)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
+ PUTSHORT(val, ucp); \
+ PUTCHAR(digest, ucp); \
+ }
+#define ADDCILONG(opt, neg, val) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: L opt=%d %lX\n", opt, val)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: LQR opt=%d %lX\n", opt, val)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(PPP_LQR, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCICHAR(opt, neg, val) \
+ if (neg) { \
+ LCPDEBUG(LOG_INFO, ("lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAR, ucp); \
+ PUTCHAR(val, ucp); \
+ }
+
+ ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ LCPDEBUG(LOG_ERR, ("Bug in lcp_addci: wrong length\n"));
+ }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+lcp_ackci(fsm *f, u_char *p, int len)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cilen, citype, cichar;
+ u_short cishort;
+ u32_t cilong;
+
+ /*
+ * CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define ACKCIVOID(opt, neg) \
+ if (neg) { \
+ if ((len -= CILEN_VOID) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || citype != opt) \
+ goto bad; \
+ }
+#define ACKCISHORT(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_SHORT) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_SHORT || citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ }
+#define ACKCICHAR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_CHAR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAR || citype != opt) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != val) \
+ goto bad; \
+ }
+#define ACKCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ if ((len -= CILEN_CHAP) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAP || citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != digest) \
+ goto bad; \
+ }
+#define ACKCILONG(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LONG) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LONG || citype != opt) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != PPP_LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+
+ ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0) {
+ goto bad;
+ }
+ LCPDEBUG(LOG_INFO, ("lcp_acki: Ack\n"));
+ return (1);
+bad:
+ LCPDEBUG(LOG_WARNING, ("lcp_acki: received bad Ack!\n"));
+ return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the LS_OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+lcp_nakci(fsm *f, u_char *p, int len)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char citype, cichar, *next;
+ u_short cishort;
+ u32_t cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+ int cilen;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIVOID(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCICHAR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAR && \
+ p[1] == CILEN_CHAR && \
+ p[0] == opt) { \
+ len -= CILEN_CHAR; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCISHORT(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILONG(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * We don't care if they want to send us smaller packets than
+ * we want. Therefore, accept any MRU less than what we asked for,
+ * but then ignore the new value when setting the MRU in the kernel.
+ * If they send us a bigger MRU than what we asked, accept it, up to
+ * the limit of the default MRU we'd get if we didn't negotiate.
+ */
+ if (go->neg_mru && go->mru != PPP_DEFMRU) {
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort < PPP_DEFMRU) {
+ try.mru = cishort;
+ }
+ );
+ }
+
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ }
+
+ /*
+ * If they've nak'd our authentication-protocol, check whether
+ * they are proposing a different protocol, or a different
+ * hash algorithm for CHAP.
+ */
+ if ((go->neg_chap || go->neg_upap)
+ && len >= CILEN_SHORT
+ && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+ cilen = p[1];
+ len -= cilen;
+ no.neg_chap = go->neg_chap;
+ no.neg_upap = go->neg_upap;
+ INCPTR(2, p);
+ GETSHORT(cishort, p);
+ if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+ /*
+ * If we were asking for CHAP, they obviously don't want to do it.
+ * If we weren't asking for CHAP, then we were asking for PAP,
+ * in which case this Nak is bad.
+ */
+ if (!go->neg_chap) {
+ goto bad;
+ }
+ try.neg_chap = 0;
+
+ } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+ GETCHAR(cichar, p);
+ if (go->neg_chap) {
+ /*
+ * We were asking for CHAP/MD5; they must want a different
+ * algorithm. If they can't do MD5, we'll have to stop
+ * asking for CHAP.
+ */
+ if (cichar != go->chap_mdtype) {
+ try.neg_chap = 0;
+ }
+ } else {
+ /*
+ * Stop asking for PAP if we were asking for it.
+ */
+ try.neg_upap = 0;
+ }
+
+ } else {
+ /*
+ * We don't recognize what they're suggesting.
+ * Stop asking for what we were asking for.
+ */
+ if (go->neg_chap) {
+ try.neg_chap = 0;
+ } else {
+ try.neg_upap = 0;
+ }
+ p += cilen - CILEN_SHORT;
+ }
+ }
+
+ /*
+ * If they can't cope with our link quality protocol, we'll have
+ * to stop asking for LQR. We haven't got any other protocol.
+ * If they Nak the reporting period, take their value XXX ?
+ */
+ NAKCILQR(CI_QUALITY, neg_lqr,
+ if (cishort != PPP_LQR) {
+ try.neg_lqr = 0;
+ } else {
+ try.lqr_period = cilong;
+ }
+ );
+
+ /*
+ * Only implementing CBCP...not the rest of the callback options
+ */
+ NAKCICHAR(CI_CALLBACK, neg_cbcp,
+ try.neg_cbcp = 0;
+ );
+
+ /*
+ * Check for a looped-back line.
+ */
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ looped_back = 1;
+ );
+
+ /*
+ * Peer shouldn't send Nak for protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+ try.neg_pcompression = 0;
+ );
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+ try.neg_accompression = 0;
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
+ * An option we don't recognize represents the peer asking to
+ * negotiate some option we don't support, so ignore it.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if (cilen < CILEN_VOID || (len -= cilen) < 0) {
+ goto bad;
+ }
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if ((go->neg_mru && go->mru != PPP_DEFMRU)
+ || no.neg_mru || cilen != CILEN_SHORT) {
+ goto bad;
+ }
+ GETSHORT(cishort, p);
+ if (cishort < PPP_DEFMRU) {
+ try.mru = cishort;
+ }
+ break;
+ case CI_ASYNCMAP:
+ if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)
+ || no.neg_asyncmap || cilen != CILEN_LONG) {
+ goto bad;
+ }
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) {
+ goto bad;
+ }
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG) {
+ goto bad;
+ }
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID) {
+ goto bad;
+ }
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID) {
+ goto bad;
+ }
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) {
+ goto bad;
+ }
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0) {
+ goto bad;
+ }
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != LS_OPENED) {
+ if (looped_back) {
+ if (++try.numloops >= lcp_loopbackfail) {
+ LCPDEBUG(LOG_NOTICE, ("Serial line is looped back.\n"));
+ lcp_close(f->unit, "Loopback detected");
+ }
+ } else {
+ try.numloops = 0;
+ }
+ *go = try;
+ }
+
+ return 1;
+
+bad:
+ LCPDEBUG(LOG_WARNING, ("lcp_nakci: received bad Nak!\n"));
+ return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the LS_OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
+ */
+static int
+lcp_rejci(fsm *f, u_char *p, int len)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
+ u_short cishort;
+ u32_t cilong;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIVOID(opt, neg) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: void opt %d rejected\n", opt)); \
+ }
+#define REJCISHORT(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: short opt %d rejected\n", opt)); \
+ }
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cishort != val || cichar != digest) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ try.neg_upap = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: chap opt %d rejected\n", opt)); \
+ }
+#define REJCILONG(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cilong != val) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: long opt %d rejected\n", opt)); \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != PPP_LQR || cilong != val) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: LQR opt %d rejected\n", opt)); \
+ }
+#define REJCICBCP(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_CBCP && \
+ p[1] == CILEN_CBCP && \
+ p[0] == opt) { \
+ len -= CILEN_CBCP; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cichar != val) { \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ LCPDEBUG(LOG_INFO, ("lcp_rejci: Callback opt %d rejected\n", opt)); \
+ }
+
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0) {
+ goto bad;
+ }
+ /*
+ * Now we can update state.
+ */
+ if (f->state != LS_OPENED) {
+ *go = try;
+ }
+ return 1;
+
+bad:
+ LCPDEBUG(LOG_WARNING, ("lcp_rejci: received bad Reject!\n"));
+ return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+lcp_reqci(fsm *f,
+ u_char *inp, /* Requested CIs */
+ int *lenp, /* Length of requested CIs */
+ int reject_if_disagree)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ int cilen, citype; /* Parsed len, type */
+ u_char cichar; /* Parsed char value */
+ u_short cishort; /* Parsed short value */
+ u32_t cilong; /* Parse long value */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *rejp; /* Pointer to next char in reject frame */
+ u_char *nakp; /* Pointer to next char in Nak frame */
+ int l = *lenp; /* Length left */
+#if TRACELCP > 0
+ char traceBuf[80];
+ size_t traceNdx = 0;
+#endif
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ nakp = nak_buffer;
+ rejp = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining 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? */
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: bad CI length!\n"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ citype = 0;
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_MRU:
+ if (!ao->neg_mru) { /* Allow option? */
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - not allowed\n"));
+ orc = CONFREJ; /* Reject CI */
+ break;
+ } else if (cilen != CILEN_SHORT) { /* Check CI length */
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - bad length\n"));
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETSHORT(cishort, p); /* Parse MRU */
+
+ /*
+ * He must be able to receive at least our minimum.
+ * No need to check a maximum. If he sends a large number,
+ * we'll just ignore it.
+ */
+ if (cishort < PPP_MINMRU) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak - MRU too small\n"));
+ orc = CONFNAK; /* Nak CI */
+ PUTCHAR(CI_MRU, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_MINMRU, nakp); /* Give him a hint */
+ break;
+ }
+ ho->neg_mru = 1; /* Remember he sent MRU */
+ ho->mru = cishort; /* And remember value */
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);
+ traceNdx = strlen(traceBuf);
+#endif
+ break;
+
+ case CI_ASYNCMAP:
+ if (!ao->neg_asyncmap) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP not allowed\n"));
+ orc = CONFREJ;
+ break;
+ } else if (cilen != CILEN_LONG) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP bad length\n"));
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+
+ /*
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
+ */
+ if ((ao->asyncmap & ~cilong) != 0) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak ASYNCMAP %lX missing %lX\n",
+ cilong, ao->asyncmap));
+ orc = CONFNAK;
+ PUTCHAR(CI_ASYNCMAP, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(ao->asyncmap | cilong, nakp);
+ break;
+ }
+ ho->neg_asyncmap = 1;
+ ho->asyncmap = cilong;
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);
+ traceNdx = strlen(traceBuf);
+#endif
+ break;
+
+ case CI_AUTHTYPE:
+ if (cilen < CILEN_SHORT) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE missing arg\n"));
+ orc = CONFREJ;
+ break;
+ } else if (!(ao->neg_upap || ao->neg_chap)) {
+ /*
+ * Reject the option if we're not willing to authenticate.
+ */
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE not allowed\n"));
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+
+ /*
+ * Authtype must be UPAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
+ */
+
+ if (cishort == PPP_PAP) {
+ if (ho->neg_chap) { /* we've already accepted CHAP */
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));
+ orc = CONFREJ;
+ break;
+ } else if (cilen != CILEN_SHORT) {
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP bad len\n"));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_upap) { /* we don't want to do PAP */
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));
+ orc = CONFNAK; /* NAK it and suggest CHAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ break;
+ }
+ ho->neg_upap = 1;
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);
+ traceNdx = strlen(traceBuf);
+#endif
+ break;
+ }
+ if (cishort == PPP_CHAP) {
+ if (ho->neg_upap) { /* we've already accepted PAP */
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));
+ orc = CONFREJ;
+ break;
+ } else if (cilen != CILEN_CHAP) {
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_chap) { /* we don't want to do CHAP */
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));
+ orc = CONFNAK; /* NAK it and suggest PAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != CHAP_DIGEST_MD5
+#if MSCHAP_SUPPORT
+ && cichar != CHAP_MICROSOFT
+#endif
+ ) {
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", (int)cichar));
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ break;
+ }
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, (int)cichar);
+ traceNdx = strlen(traceBuf);
+#endif
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
+ break;
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Nak it with something we're willing to do.
+ * (At this point we know ao->neg_upap || ao->neg_chap.)
+ */
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ if (ao->neg_chap) {
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ } else {
+ LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ }
+ break;
+
+ case CI_QUALITY:
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);
+ traceNdx = strlen(traceBuf);
+#endif
+
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
+ break;
+ }
+
+ /*
+ * Check the protocol and the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ if (cishort != PPP_LQR) {
+ orc = CONFNAK;
+ PUTCHAR(CI_QUALITY, nakp);
+ PUTCHAR(CILEN_LQR, nakp);
+ PUTSHORT(PPP_LQR, nakp);
+ PUTLONG(ao->lqr_period, nakp);
+ break;
+ }
+ break;
+
+ case CI_MAGICNUMBER:
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);
+ traceNdx = strlen(traceBuf);
+#endif
+
+ /*
+ * He must have a different magic number.
+ */
+ if (go->neg_magicnumber &&
+ cilong == go->magicnumber) {
+ cilong = magic(); /* Don't put magic() inside macro! */
+ orc = CONFNAK;
+ PUTCHAR(CI_MAGICNUMBER, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(cilong, nakp);
+ break;
+ }
+ ho->neg_magicnumber = 1;
+ ho->magicnumber = cilong;
+ break;
+
+
+ case CI_PCOMPRESSION:
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");
+ traceNdx = strlen(traceBuf);
+#endif
+ if (!ao->neg_pcompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_pcompression = 1;
+ break;
+
+ case CI_ACCOMPRESSION:
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");
+ traceNdx = strlen(traceBuf);
+#endif
+ if (!ao->neg_accompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_accompression = 1;
+ break;
+
+ case CI_MRRU:
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");
+ traceNdx = strlen(traceBuf);
+#endif
+ orc = CONFREJ;
+ break;
+
+ case CI_SSNHF:
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");
+ traceNdx = strlen(traceBuf);
+#endif
+ orc = CONFREJ;
+ break;
+
+ case CI_EPDISC:
+#if TRACELCP > 0
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");
+ traceNdx = strlen(traceBuf);
+#endif
+ orc = CONFREJ;
+ break;
+
+ default:
+#if TRACELCP
+ snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);
+ traceNdx = strlen(traceBuf);
+#endif
+ orc = CONFREJ;
+ break;
+ }
+
+ endswitch:
+#if TRACELCP
+ if (traceNdx >= 80 - 32) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: rcvd%s\n", traceBuf));
+ traceNdx = 0;
+ }
+#endif
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) { /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+ }
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree /* Getting fed up with sending NAKs? */
+ && citype != CI_MAGICNUMBER) {
+ orc = CONFREJ; /* Get tough if so */
+ } else {
+ if (rc == CONFREJ) { /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ }
+ rc = CONFNAK;
+ }
+ }
+ if (orc == CONFREJ) { /* Reject this CI */
+ rc = CONFREJ;
+ if (cip != rejp) { /* Need to move rejected CI? */
+ BCOPY(cip, rejp, cilen); /* Move it */
+ }
+ INCPTR(cilen, rejp); /* Update output pointer */
+ }
+ }
+
+ /*
+ * If we wanted to send additional NAKs (for unsent CIs), the
+ * code would go here. The extra NAKs would go at *nakp.
+ * At present there are no cases where we want to ask the
+ * peer to negotiate an option.
+ */
+
+ switch (rc) {
+ case CONFACK:
+ *lenp = (int)(next - inp);
+ break;
+ case CONFNAK:
+ /*
+ * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+ */
+ *lenp = (int)(nakp - nak_buffer);
+ BCOPY(nak_buffer, inp, *lenp);
+ break;
+ case CONFREJ:
+ *lenp = (int)(rejp - inp);
+ break;
+ }
+
+#if TRACELCP > 0
+ if (traceNdx > 0) {
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: %s\n", traceBuf));
+ }
+#endif
+ LCPDEBUG(LOG_INFO, ("lcp_reqci: returning CONF%s.\n", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void
+lcp_up(fsm *f)
+{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ if (!go->neg_magicnumber) {
+ go->magicnumber = 0;
+ }
+ if (!ho->neg_magicnumber) {
+ ho->magicnumber = 0;
+ }
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ */
+ ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),
+ ho->neg_pcompression, ho->neg_accompression);
+ /*
+ * If the asyncmap hasn't been negotiated, we really should
+ * set the receive asyncmap to ffffffff, but we set it to 0
+ * for backwards contemptibility.
+ */
+ ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),
+ (go->neg_asyncmap? go->asyncmap: 0x00000000),
+ go->neg_pcompression, go->neg_accompression);
+
+ if (ho->neg_mru) {
+ peer_mru[f->unit] = ho->mru;
+ }
+
+ lcp_echo_lowerup(f->unit); /* Enable echo messages */
+
+ link_established(f->unit); /* The link is up; authenticate now */
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(fsm *f)
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+ lcp_echo_lowerdown(f->unit);
+
+ link_down(f->unit);
+
+ ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);
+ ppp_recv_config(f->unit, PPP_MRU,
+ (go->neg_asyncmap? go->asyncmap: 0x00000000),
+ go->neg_pcompression, go->neg_accompression);
+ peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(fsm *f)
+{
+ link_required(f->unit); /* lwip: currently does nothing */
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(fsm *f)
+{
+ link_terminated(f->unit); /* we are finished with the link */
+}
+
+
+#if PPP_ADDITIONAL_CALLBACKS
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+static void
+print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg)
+{
+ int c;
+
+ printer(arg, "\"");
+ for (; len > 0; --len) {
+ c = *p++;
+ if (' ' <= c && c <= '~') {
+ if (c == '\\' || c == '"') {
+ printer(arg, "\\");
+ }
+ printer(arg, "%c", c);
+ } else {
+ switch (c) {
+ case '\n':
+ printer(arg, "\\n");
+ break;
+ case '\r':
+ printer(arg, "\\r");
+ break;
+ case '\t':
+ printer(arg, "\\t");
+ break;
+ default:
+ printer(arg, "\\%.3o", c);
+ }
+ }
+ }
+ printer(arg, "\"");
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej", "ProtRej",
+ "EchoReq", "EchoRep", "DiscReq"
+};
+
+static int
+lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u32_t cilong;
+
+ if (plen < HEADERLEN) {
+ return 0;
+ }
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen) {
+ return 0;
+ }
+
+ if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) {
+ printer(arg, " %s", lcp_codenames[code-1]);
+ } else {
+ printer(arg, " code=0x%x", code);
+ }
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_MRU:
+ if (olen == CILEN_SHORT) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "mru %d", cishort);
+ }
+ break;
+ case CI_ASYNCMAP:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "asyncmap 0x%lx", cilong);
+ }
+ break;
+ case CI_AUTHTYPE:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "auth ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_PAP:
+ printer(arg, "pap");
+ break;
+ case PPP_CHAP:
+ printer(arg, "chap");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_QUALITY:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "quality ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_LQR:
+ printer(arg, "lqr");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_CALLBACK:
+ if (olen >= CILEN_CHAR) {
+ p += 2;
+ printer(arg, "callback ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case CBCP_OPT:
+ printer(arg, "CBCP");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_MAGICNUMBER:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "magic 0x%x", cilong);
+ }
+ break;
+ case CI_PCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "pcomp");
+ }
+ break;
+ case CI_ACCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "accomp");
+ }
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string((char*)p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+
+ case ECHOREQ:
+ case ECHOREP:
+ case DISCREQ:
+ if (len >= 4) {
+ GETLONG(cilong, p);
+ printer(arg, " magic=0x%x", cilong);
+ p += 4;
+ len -= 4;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return (int)(p - pstart);
+}
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+static void
+LcpLinkFailure (fsm *f)
+{
+ if (f->state == LS_OPENED) {
+ LCPDEBUG(LOG_INFO, ("No response to %d echo-requests\n", lcp_echos_pending));
+ LCPDEBUG(LOG_NOTICE, ("Serial link appears to be disconnected.\n"));
+ lcp_close(f->unit, "Peer not responding");
+ }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+static void
+LcpEchoCheck (fsm *f)
+{
+ LcpSendEchoRequest (f);
+
+ /*
+ * Start the timer for the next interval.
+ */
+ LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);
+
+ TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
+ lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+static void
+LcpEchoTimeout (void *arg)
+{
+ if (lcp_echo_timer_running != 0) {
+ lcp_echo_timer_running = 0;
+ LcpEchoCheck ((fsm *) arg);
+ }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+static void
+lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)
+{
+ u32_t magic;
+
+ LWIP_UNUSED_ARG(id);
+
+ /* Check the magic number - don't count replies from ourselves. */
+ if (len < 4) {
+ LCPDEBUG(LOG_WARNING, ("lcp: received short Echo-Reply, length %d\n", len));
+ return;
+ }
+ GETLONG(magic, inp);
+ if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) {
+ LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n"));
+ return;
+ }
+
+ /* Reset the number of outstanding echo frames */
+ lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+static void
+LcpSendEchoRequest (fsm *f)
+{
+ u32_t lcp_magic;
+ u_char pkt[4], *pktp;
+
+ /*
+ * Detect the failure of the peer at this point.
+ */
+ if (lcp_echo_fails != 0) {
+ if (lcp_echos_pending >= lcp_echo_fails) {
+ LcpLinkFailure(f);
+ lcp_echos_pending = 0;
+ }
+ }
+
+ /*
+ * Make and send the echo request frame.
+ */
+ if (f->state == LS_OPENED) {
+ lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+ pktp = pkt;
+ PUTLONG(lcp_magic, pktp);
+ fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));
+ ++lcp_echos_pending;
+ }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerup (int unit)
+{
+ fsm *f = &lcp_fsm[unit];
+
+ /* Clear the parameters for generating echo frames */
+ lcp_echos_pending = 0;
+ lcp_echo_number = 0;
+ lcp_echo_timer_running = 0;
+
+ /* If a timeout interval is specified then start the timer */
+ if (lcp_echo_interval != 0) {
+ LcpEchoCheck (f);
+ }
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerdown (int unit)
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (lcp_echo_timer_running != 0) {
+ UNTIMEOUT (LcpEchoTimeout, f);
+ lcp_echo_timer_running = 0;
+ }
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.h
new file mode 100644
index 0000000000..b9201eeb50
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/lcp.h
@@ -0,0 +1,151 @@
+/*****************************************************************************
+* lcp.h - Network Link Control Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * $Id: lcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $
+ */
+
+#ifndef LCP_H
+#define LCP_H
+/*
+ * Options.
+ */
+#define CI_MRU 1 /* Maximum Receive Unit */
+#define CI_ASYNCMAP 2 /* Async Control Character Map */
+#define CI_AUTHTYPE 3 /* Authentication Type */
+#define CI_QUALITY 4 /* Quality Protocol */
+#define CI_MAGICNUMBER 5 /* Magic Number */
+#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
+#define CI_CALLBACK 13 /* callback */
+#define CI_MRRU 17 /* max reconstructed receive unit; multilink */
+#define CI_SSNHF 18 /* short sequence numbers for multilink */
+#define CI_EPDISC 19 /* endpoint discriminator */
+
+/*
+ * LCP-specific packet types (code numbers).
+ */
+#define PROTREJ 8 /* Protocol Reject */
+#define ECHOREQ 9 /* Echo Request */
+#define ECHOREP 10 /* Echo Reply */
+#define DISCREQ 11 /* Discard Request */
+#define CBCP_OPT 6 /* Use callback control protocol */
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+ u_int passive : 1; /* Don't die if we don't get a response */
+ u_int silent : 1; /* Wait for the other end to start first */
+ u_int restart : 1; /* Restart vs. exit after close */
+ u_int neg_mru : 1; /* Negotiate the MRU? */
+ u_int neg_asyncmap : 1; /* Negotiate the async map? */
+ u_int neg_upap : 1; /* Ask for UPAP authentication? */
+ u_int neg_chap : 1; /* Ask for CHAP authentication? */
+ u_int neg_magicnumber : 1; /* Ask for magic number? */
+ u_int neg_pcompression : 1; /* HDLC Protocol Field Compression? */
+ u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */
+ u_int neg_lqr : 1; /* Negotiate use of Link Quality Reports */
+ u_int neg_cbcp : 1; /* Negotiate use of CBCP */
+#ifdef PPP_MULTILINK
+ u_int neg_mrru : 1; /* Negotiate multilink MRRU */
+ u_int neg_ssnhf : 1; /* Negotiate short sequence numbers */
+ u_int neg_endpoint : 1; /* Negotiate endpoint discriminator */
+#endif
+ u_short mru; /* Value of MRU */
+#ifdef PPP_MULTILINK
+ u_short mrru; /* Value of MRRU, and multilink enable */
+#endif
+ u_char chap_mdtype; /* which MD type (hashing algorithm) */
+ u32_t asyncmap; /* Value of async map */
+ u32_t magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u32_t lqr_period; /* Reporting period for LQR 1/100ths second */
+#ifdef PPP_MULTILINK
+ struct epdisc endpoint; /* endpoint discriminator */
+#endif
+} lcp_options;
+
+/*
+ * Values for phase from BSD pppd.h based on RFC 1661.
+ */
+typedef enum {
+ PHASE_DEAD = 0,
+ PHASE_INITIALIZE,
+ PHASE_ESTABLISH,
+ PHASE_AUTHENTICATE,
+ PHASE_CALLBACK,
+ PHASE_NETWORK,
+ PHASE_TERMINATE
+} LinkPhase;
+
+
+
+extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+extern ext_accm xmit_accm[];
+
+
+void lcp_init (int);
+void lcp_open (int);
+void lcp_close (int, char *);
+void lcp_lowerup (int);
+void lcp_lowerdown(int);
+void lcp_sprotrej (int, u_char *, int); /* send protocol reject */
+
+extern struct protent lcp_protent;
+
+/* Default number of times we receive our magic number from the peer
+ before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL 10
+
+#endif /* LCP_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.c
new file mode 100644
index 0000000000..3901330895
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.c
@@ -0,0 +1,80 @@
+/*****************************************************************************
+* magic.c - Network Random Number Generator program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original based on BSD magic.c.
+*****************************************************************************/
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT
+
+#include "ppp.h"
+#include "randm.h"
+#include "magic.h"
+
+
+/*
+ * magicInit - Initialize the magic number generator.
+ *
+ * Since we use another random number generator that has its own
+ * initialization, we do nothing here.
+ */
+void magicInit()
+{
+ return;
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+u32_t magic()
+{
+ return avRandom();
+}
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.h
new file mode 100644
index 0000000000..eba70d20b0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/magic.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+* magic.h - Network Random Number Generator header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * $Id: magic.h,v 1.3 2010/01/18 20:49:43 goldsimon Exp $
+ */
+
+#ifndef MAGIC_H
+#define MAGIC_H
+
+/* Initialize the magic number generator */
+void magicInit(void);
+
+/* Returns the next magic number */
+u32_t magic(void);
+
+#endif /* MAGIC_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.c
new file mode 100644
index 0000000000..3cb69e2b06
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.c
@@ -0,0 +1,320 @@
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#if CHAP_SUPPORT || MD5_SUPPORT
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "md5.h"
+
+#include <string.h>
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform (u32_t *buf, u32_t *in);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##UL
+#else
+#ifdef WIN32
+#define UL(x) x##UL
+#else
+#define UL(x) x
+#endif
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void
+MD5Init (MD5_CTX *mdContext)
+{
+ mdContext->i[0] = mdContext->i[1] = (u32_t)0;
+
+ /* Load magic initialization constants. */
+ mdContext->buf[0] = (u32_t)0x67452301UL;
+ mdContext->buf[1] = (u32_t)0xefcdab89UL;
+ mdContext->buf[2] = (u32_t)0x98badcfeUL;
+ mdContext->buf[3] = (u32_t)0x10325476UL;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void
+MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
+{
+ u32_t in[16];
+ int mdi;
+ unsigned int i, ii;
+
+#if 0
+ PPPDEBUG(LOG_INFO, ("MD5Update: %u:%.*H\n", inLen, LWIP_MIN(inLen, 20) * 2, inBuf));
+ PPPDEBUG(LOG_INFO, ("MD5Update: %u:%s\n", inLen, inBuf));
+#endif
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) {
+ mdContext->i[1]++;
+ }
+ mdContext->i[0] += ((u32_t)inLen << 3);
+ mdContext->i[1] += ((u32_t)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4) {
+ in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
+ (((u32_t)mdContext->in[ii+2]) << 16) |
+ (((u32_t)mdContext->in[ii+1]) << 8) |
+ ((u32_t)mdContext->in[ii]);
+ }
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void
+MD5Final (unsigned char hash[], MD5_CTX *mdContext)
+{
+ u32_t in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4) {
+ in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
+ (((u32_t)mdContext->in[ii+2]) << 16) |
+ (((u32_t)mdContext->in[ii+1]) << 8) |
+ ((u32_t)mdContext->in[ii]);
+ }
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ SMEMCPY(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void
+Transform (u32_t *buf, u32_t *in)
+{
+ u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif /* CHAP_SUPPORT || MD5_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.h
new file mode 100644
index 0000000000..e129533f38
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/md5.h
@@ -0,0 +1,55 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ u32_t i[2]; /* number of _bits_ handled mod 2^64 */
+ u32_t buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init ( MD5_CTX *mdContext);
+void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
+void MD5Final ( unsigned char hash[], MD5_CTX *mdContext);
+
+#endif /* MD5_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.c
new file mode 100644
index 0000000000..ac44e6464c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.c
@@ -0,0 +1,628 @@
+/*****************************************************************************
+* pap.c - Network Password Authentication Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original.
+*****************************************************************************/
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "auth.h"
+#include "pap.h"
+
+#include <string.h>
+
+#if 0 /* UNUSED */
+static bool hide_password = 1;
+
+/*
+ * Command-line options.
+ */
+static option_t pap_option_list[] = {
+ { "hide-password", o_bool, &hide_password,
+ "Don't output passwords to log", 1 },
+ { "show-password", o_bool, &hide_password,
+ "Show password string in debug log messages", 0 },
+ { "pap-restart", o_int, &upap[0].us_timeouttime,
+ "Set retransmit timeout for PAP" },
+ { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
+ "Set max number of transmissions for auth-reqs" },
+ { "pap-timeout", o_int, &upap[0].us_reqtimeout,
+ "Set time limit for peer PAP authentication" },
+ { NULL }
+};
+#endif
+
+/*
+ * Protocol entry points.
+ */
+static void upap_init (int);
+static void upap_lowerup (int);
+static void upap_lowerdown (int);
+static void upap_input (int, u_char *, int);
+static void upap_protrej (int);
+#if PPP_ADDITIONAL_CALLBACKS
+static int upap_printpkt (u_char *, int, void (*)(void *, char *, ...), void *);
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+
+struct protent pap_protent = {
+ PPP_PAP,
+ upap_init,
+ upap_input,
+ upap_protrej,
+ upap_lowerup,
+ upap_lowerdown,
+ NULL,
+ NULL,
+#if PPP_ADDITIONAL_CALLBACKS
+ upap_printpkt,
+ NULL,
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+ 1,
+ "PAP",
+#if PPP_ADDITIONAL_CALLBACKS
+ NULL,
+ NULL,
+ NULL
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+};
+
+upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
+
+static void upap_timeout (void *);
+static void upap_reqtimeout(void *);
+static void upap_rauthreq (upap_state *, u_char *, u_char, int);
+static void upap_rauthack (upap_state *, u_char *, int, int);
+static void upap_rauthnak (upap_state *, u_char *, int, int);
+static void upap_sauthreq (upap_state *);
+static void upap_sresp (upap_state *, u_char, u_char, char *, int);
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void
+upap_init(int unit)
+{
+ upap_state *u = &upap[unit];
+
+ UPAPDEBUG(LOG_INFO, ("upap_init: %d\n", unit));
+ u->us_unit = unit;
+ u->us_user = NULL;
+ u->us_userlen = 0;
+ u->us_passwd = NULL;
+ u->us_passwdlen = 0;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+ u->us_id = 0;
+ u->us_timeouttime = UPAP_DEFTIMEOUT;
+ u->us_maxtransmits = 10;
+ u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void
+upap_authwithpeer(int unit, char *user, char *password)
+{
+ upap_state *u = &upap[unit];
+
+ UPAPDEBUG(LOG_INFO, ("upap_authwithpeer: %d user=%s password=%s s=%d\n",
+ unit, user, password, u->us_clientstate));
+
+ /* Save the username and password we're given */
+ u->us_user = user;
+ u->us_userlen = (int)strlen(user);
+ u->us_passwd = password;
+ u->us_passwdlen = (int)strlen(password);
+
+ u->us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (u->us_clientstate == UPAPCS_INITIAL ||
+ u->us_clientstate == UPAPCS_PENDING) {
+ u->us_clientstate = UPAPCS_PENDING;
+ return;
+ }
+
+ upap_sauthreq(u); /* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void
+upap_authpeer(int unit)
+{
+ upap_state *u = &upap[unit];
+
+ /* Lower layer up yet? */
+ if (u->us_serverstate == UPAPSS_INITIAL ||
+ u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_PENDING;
+ return;
+ }
+
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0) {
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+ }
+}
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void
+upap_timeout(void *arg)
+{
+ upap_state *u = (upap_state *) arg;
+
+ UPAPDEBUG(LOG_INFO, ("upap_timeout: %d timeout %d expired s=%d\n",
+ u->us_unit, u->us_timeouttime, u->us_clientstate));
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ) {
+ UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
+ return;
+ }
+
+ if (u->us_transmits >= u->us_maxtransmits) {
+ /* give up in disgust */
+ UPAPDEBUG(LOG_ERR, ("No response to PAP authenticate-requests\n"));
+ u->us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+ return;
+ }
+
+ upap_sauthreq(u); /* Send Authenticate-Request and set upap timeout*/
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void
+upap_reqtimeout(void *arg)
+{
+ upap_state *u = (upap_state *) arg;
+
+ if (u->us_serverstate != UPAPSS_LISTEN) {
+ return; /* huh?? */
+ }
+
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void
+upap_lowerup(int unit)
+{
+ upap_state *u = &upap[unit];
+
+ UPAPDEBUG(LOG_INFO, ("upap_lowerup: init %d clientstate s=%d\n", unit, u->us_clientstate));
+
+ if (u->us_clientstate == UPAPCS_INITIAL) {
+ u->us_clientstate = UPAPCS_CLOSED;
+ } else if (u->us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(u); /* send an auth-request */
+ /* now client state is UPAPCS__AUTHREQ */
+ }
+
+ if (u->us_serverstate == UPAPSS_INITIAL) {
+ u->us_serverstate = UPAPSS_CLOSED;
+ } else if (u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0) {
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+ }
+ }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+upap_lowerdown(int unit)
+{
+ upap_state *u = &upap[unit];
+
+ UPAPDEBUG(LOG_INFO, ("upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */
+ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) {
+ UNTIMEOUT(upap_reqtimeout, u);
+ }
+
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen. In any case, pretend lower layer went down.
+ */
+static void
+upap_protrej(int unit)
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) {
+ UPAPDEBUG(LOG_ERR, ("PAP authentication failed due to protocol-reject\n"));
+ auth_withpeer_fail(unit, PPP_PAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ UPAPDEBUG(LOG_ERR, ("PAP authentication of peer failed (protocol-reject)\n"));
+ auth_peer_fail(unit, PPP_PAP);
+ }
+ upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void
+upap_input(int unit, u_char *inpacket, int l)
+{
+ upap_state *u = &upap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < (int)UPAP_HEADERLEN) {
+ UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short header.\n"));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < (int)UPAP_HEADERLEN) {
+ UPAPDEBUG(LOG_INFO, ("pap_input: rcvd illegal length.\n"));
+ return;
+ }
+ if (len > l) {
+ UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short packet.\n"));
+ return;
+ }
+ len -= UPAP_HEADERLEN;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case UPAP_AUTHREQ:
+ upap_rauthreq(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHACK:
+ upap_rauthack(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHNAK:
+ upap_rauthnak(u, inp, id, len);
+ break;
+
+ default: /* XXX Need code reject */
+ UPAPDEBUG(LOG_INFO, ("pap_input: UNHANDLED default: code: %d, id: %d, len: %d.\n", code, id, len));
+ break;
+ }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void
+upap_rauthreq(upap_state *u, u_char *inp, u_char id, int len)
+{
+ u_char ruserlen, rpasswdlen;
+ char *ruser, *rpasswd;
+ u_char retcode;
+ char *msg;
+ int msglen;
+
+ UPAPDEBUG(LOG_INFO, ("pap_rauth: Rcvd id %d.\n", id));
+
+ if (u->us_serverstate < UPAPSS_LISTEN) {
+ return;
+ }
+
+ /*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (u->us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (u->us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
+ * Parse user/passwd.
+ */
+ if (len < (int)sizeof (u_char)) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
+ return;
+ }
+ GETCHAR(ruserlen, inp);
+ len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+ if (len < 0) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
+ return;
+ }
+ ruser = (char *) inp;
+ INCPTR(ruserlen, inp);
+ GETCHAR(rpasswdlen, inp);
+ if (len < rpasswdlen) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
+ return;
+ }
+ rpasswd = (char *) inp;
+
+ /*
+ * Check the username and password given.
+ */
+ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen);
+ /* lwip: currently retcode is always UPAP_AUTHACK */
+ BZERO(rpasswd, rpasswdlen);
+
+ upap_sresp(u, retcode, id, msg, msglen);
+
+ if (retcode == UPAP_AUTHACK) {
+ u->us_serverstate = UPAPSS_OPEN;
+ auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ }
+
+ if (u->us_reqtimeout > 0) {
+ UNTIMEOUT(upap_reqtimeout, u);
+ }
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void
+upap_rauthack(upap_state *u, u_char *inp, int id, int len)
+{
+ u_char msglen;
+ char *msg;
+
+ LWIP_UNUSED_ARG(id);
+
+ UPAPDEBUG(LOG_INFO, ("pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */
+ UPAPDEBUG(LOG_INFO, ("pap_rauthack: us_clientstate != UPAPCS_AUTHREQ\n"));
+ return;
+ }
+
+ /*
+ * Parse message.
+ */
+ if (len < (int)sizeof (u_char)) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauthack: ignoring missing msg-length.\n"));
+ } else {
+ GETCHAR(msglen, inp);
+ if (msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauthack: rcvd short packet.\n"));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
+ u->us_clientstate = UPAPCS_OPEN;
+
+ auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nak.
+ */
+static void
+upap_rauthnak(upap_state *u, u_char *inp, int id, int len)
+{
+ u_char msglen;
+ char *msg;
+
+ LWIP_UNUSED_ARG(id);
+
+ UPAPDEBUG(LOG_INFO, ("pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */
+ return;
+ }
+
+ /*
+ * Parse message.
+ */
+ if (len < sizeof (u_char)) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauthnak: ignoring missing msg-length.\n"));
+ } else {
+ GETCHAR(msglen, inp);
+ if(msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(LOG_INFO, ("pap_rauthnak: rcvd short packet.\n"));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+
+ u->us_clientstate = UPAPCS_BADAUTH;
+
+ UPAPDEBUG(LOG_ERR, ("PAP authentication failed\n"));
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void
+upap_sauthreq(upap_state *u)
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)
+ + u->us_userlen + u->us_passwdlen;
+ outp = outpacket_buf[u->us_unit];
+
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(UPAP_AUTHREQ, outp);
+ PUTCHAR(++u->us_id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(u->us_userlen, outp);
+ BCOPY(u->us_user, outp, u->us_userlen);
+ INCPTR(u->us_userlen, outp);
+ PUTCHAR(u->us_passwdlen, outp);
+ BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+ pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
+
+ UPAPDEBUG(LOG_INFO, ("pap_sauth: Sent id %d\n", u->us_id));
+
+ TIMEOUT(upap_timeout, u, u->us_timeouttime);
+ ++u->us_transmits;
+ u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void
+upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen)
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+ outp = outpacket_buf[u->us_unit];
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(msglen, outp);
+ BCOPY(msg, outp, msglen);
+ pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
+
+ UPAPDEBUG(LOG_INFO, ("pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate));
+}
+
+#if PPP_ADDITIONAL_CALLBACKS
+static char *upap_codenames[] = {
+ "AuthReq", "AuthAck", "AuthNak"
+};
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static int upap_printpkt(
+ u_char *p,
+ int plen,
+ void (*printer) (void *, char *, ...),
+ void *arg
+)
+{
+ LWIP_UNUSED_ARG(p);
+ LWIP_UNUSED_ARG(plen);
+ LWIP_UNUSED_ARG(printer);
+ LWIP_UNUSED_ARG(arg);
+ return 0;
+}
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+
+#endif /* PAP_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.h
new file mode 100644
index 0000000000..c99a204019
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pap.h
@@ -0,0 +1,118 @@
+/*****************************************************************************
+* pap.h - PPP Password Authentication Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original derived from BSD codes.
+*****************************************************************************/
+/*
+ * upap.h - User/Password Authentication Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ */
+
+#ifndef PAP_H
+#define PAP_H
+
+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ * UPAP codes.
+ */
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
+
+/*
+ * Each interface is described by upap structure.
+ */
+typedef struct upap_state {
+ int us_unit; /* Interface unit number */
+ const char *us_user; /* User */
+ int us_userlen; /* User length */
+ const char *us_passwd; /* Password */
+ int us_passwdlen; /* Password length */
+ int us_clientstate; /* Client state */
+ int us_serverstate; /* Server state */
+ u_char us_id; /* Current id */
+ int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
+ int us_reqtimeout; /* Time to wait for auth-req from peer */
+} upap_state;
+
+/*
+ * Client states.
+ */
+#define UPAPCS_INITIAL 0 /* Connection down */
+#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN 4 /* We've received an Ack */
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */
+
+/*
+ * Server states.
+ */
+#define UPAPSS_INITIAL 0 /* Connection down */
+#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
+#define UPAPSS_OPEN 4 /* We've sent an Ack */
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
+
+
+extern upap_state upap[];
+
+void upap_authwithpeer (int, char *, char *);
+void upap_authpeer (int);
+
+extern struct protent pap_protent;
+
+#endif /* PAP_SUPPORT */
+
+#endif /* PAP_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.c
new file mode 100644
index 0000000000..fd35689734
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.c
@@ -0,0 +1,2030 @@
+/*****************************************************************************
+* ppp.c - Network Point to Point Protocol program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original.
+*****************************************************************************/
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/ip.h" /* for ip_input() */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "randm.h"
+#include "fsm.h"
+#if PAP_SUPPORT
+#include "pap.h"
+#endif /* PAP_SUPPORT */
+#if CHAP_SUPPORT
+#include "chap.h"
+#endif /* CHAP_SUPPORT */
+#include "ipcp.h"
+#include "lcp.h"
+#include "magic.h"
+#include "auth.h"
+#if VJ_SUPPORT
+#include "vj.h"
+#endif /* VJ_SUPPORT */
+#if PPPOE_SUPPORT
+#include "netif/ppp_oe.h"
+#endif /* PPPOE_SUPPORT */
+
+#include "lwip/tcpip.h"
+#include "lwip/api.h"
+#include "lwip/snmp.h"
+
+#include <string.h>
+
+/*************************/
+/*** LOCAL DEFINITIONS ***/
+/*************************/
+
+/** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
+ * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
+ * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
+ */
+#ifndef PPP_INPROC_MULTITHREADED
+#define PPP_INPROC_MULTITHREADED (NO_SYS==0)
+#endif
+
+/** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
+ * Default is 0: call pppos_input() for received raw characters, charcater
+ * reception is up to the port */
+#ifndef PPP_INPROC_OWNTHREAD
+#define PPP_INPROC_OWNTHREAD PPP_INPROC_MULTITHREADED
+#endif
+
+#if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
+ #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
+#endif
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_ADDRESS(p) (((u_char *)(p))[0])
+#define PPP_CONTROL(p) (((u_char *)(p))[1])
+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/* PPP packet parser states. Current state indicates operation yet to be
+ * completed. */
+typedef enum {
+ PDIDLE = 0, /* Idle state - waiting. */
+ PDSTART, /* Process start flag. */
+ PDADDRESS, /* Process address field. */
+ PDCONTROL, /* Process control field. */
+ PDPROTOCOL1, /* Process protocol field 1. */
+ PDPROTOCOL2, /* Process protocol field 2. */
+ PDDATA /* Process data byte. */
+} PPPDevStates;
+
+#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
+
+/************************/
+/*** LOCAL DATA TYPES ***/
+/************************/
+
+/** RX buffer size: this may be configured smaller! */
+#ifndef PPPOS_RX_BUFSIZE
+#define PPPOS_RX_BUFSIZE (PPP_MRU + PPP_HDRLEN)
+#endif
+
+typedef struct PPPControlRx_s {
+ /** unit number / ppp descriptor */
+ int pd;
+ /** the rx file descriptor */
+ sio_fd_t fd;
+ /** receive buffer - encoded data is stored here */
+ u_char rxbuf[PPPOS_RX_BUFSIZE];
+
+ /* The input packet. */
+ struct pbuf *inHead, *inTail;
+
+#if PPPOS_SUPPORT
+ u16_t inProtocol; /* The input protocol code. */
+ u16_t inFCS; /* Input Frame Check Sequence value. */
+#endif /* PPPOS_SUPPORT */
+ PPPDevStates inState; /* The input process state. */
+ char inEscaped; /* Escape next character. */
+ ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
+} PPPControlRx;
+
+/*
+ * PPP interface control block.
+ */
+typedef struct PPPControl_s {
+ PPPControlRx rx;
+ char openFlag; /* True when in use. */
+#if PPPOE_SUPPORT
+ struct netif *ethif;
+ struct pppoe_softc *pppoe_sc;
+#endif /* PPPOE_SUPPORT */
+ int if_up; /* True when the interface is up. */
+ int errCode; /* Code indicating why interface is down. */
+#if PPPOS_SUPPORT
+ sio_fd_t fd; /* File device ID of port. */
+#endif /* PPPOS_SUPPORT */
+ u16_t mtu; /* Peer's mru */
+ int pcomp; /* Does peer accept protocol compression? */
+ int accomp; /* Does peer accept addr/ctl compression? */
+ u_long lastXMit; /* Time of last transmission. */
+ ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
+#if PPPOS_SUPPORT && VJ_SUPPORT
+ int vjEnabled; /* Flag indicating VJ compression enabled. */
+ struct vjcompress vjComp; /* Van Jacobson compression header. */
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
+
+ struct netif netif;
+
+ struct ppp_addrs addrs;
+
+ void (*linkStatusCB)(void *ctx, int errCode, void *arg);
+ void *linkStatusCtx;
+
+} PPPControl;
+
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+ int protocol; /* PPP procotol, e.g. PPP_IP */
+ enum NPmode mode;
+};
+
+
+
+/***********************************/
+/*** LOCAL FUNCTION DECLARATIONS ***/
+/***********************************/
+#if PPPOS_SUPPORT
+#if PPP_INPROC_OWNTHREAD
+static void pppInputThread(void *arg);
+#endif /* PPP_INPROC_OWNTHREAD */
+static void pppDrop(PPPControlRx *pcrx);
+static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
+#endif /* PPPOS_SUPPORT */
+
+
+/******************************/
+/*** PUBLIC DATA STRUCTURES ***/
+/******************************/
+u_long subnetMask;
+
+static PPPControl pppControl[NUM_PPP] __attribute((section("AHBSRAM1"))); /* The PPP interface control blocks. */
+
+sys_mbox_t pppMbox; //Used to signal PPP thread that a PPP session begins
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *ppp_protocols[] = {
+ &lcp_protent,
+#if PAP_SUPPORT
+ &pap_protent,
+#endif /* PAP_SUPPORT */
+#if CHAP_SUPPORT
+ &chap_protent,
+#endif /* CHAP_SUPPORT */
+#if CBCP_SUPPORT
+ &cbcp_protent,
+#endif /* CBCP_SUPPORT */
+ &ipcp_protent,
+#if CCP_SUPPORT
+ &ccp_protent,
+#endif /* CCP_SUPPORT */
+ NULL
+};
+
+
+/*
+ * Buffers for outgoing packets. This must be accessed only from the appropriate
+ * PPP task so that it doesn't need to be protected to avoid collisions.
+ */
+u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN] __attribute((section("AHBSRAM1")));
+
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+
+#if PPPOS_SUPPORT
+/*
+ * FCS lookup table as calculated by genfcstab.
+ * @todo: smaller, slower implementation for lower memory footprint?
+ */
+static const u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/* PPP's Asynchronous-Control-Character-Map. The mask array is used
+ * to select the specific bit for a character. */
+static u_char pppACCMMask[] = {
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80
+};
+
+/** Wake up the task blocked in reading from serial line (if any) */
+static void
+pppRecvWakeup(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
+ if (pppControl[pd].openFlag != 0) {
+ sio_read_abort(pppControl[pd].fd);
+ }
+}
+#endif /* PPPOS_SUPPORT */
+
+void
+pppLinkTerminated(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
+
+#if PPPOE_SUPPORT
+ if (pppControl[pd].ethif) {
+ pppoe_disconnect(pppControl[pd].pppoe_sc);
+ } else
+#endif /* PPPOE_SUPPORT */
+ {
+#if PPPOS_SUPPORT
+ PPPControl* pc;
+ pppRecvWakeup(pd);
+ pc = &pppControl[pd];
+
+ PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+ if (pc->linkStatusCB) {
+ pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
+ }
+
+ pc->openFlag = 0;/**/
+#endif /* PPPOS_SUPPORT */
+ }
+ PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
+}
+
+void
+pppLinkDown(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
+
+#if PPPOE_SUPPORT
+ if (pppControl[pd].ethif) {
+ pppoe_disconnect(pppControl[pd].pppoe_sc);
+ } else
+#endif /* PPPOE_SUPPORT */
+ {
+#if PPPOS_SUPPORT
+ pppRecvWakeup(pd);
+#endif /* PPPOS_SUPPORT */
+ }
+}
+
+/** Initiate LCP open request */
+static void
+pppStart(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
+ lcp_lowerup(pd);
+ lcp_open(pd); /* Start protocol */
+ PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
+}
+
+/** LCP close request */
+static void
+pppStop(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
+ lcp_close(pd, "User request");
+}
+
+/** Called when carrier/link is lost */
+static void
+pppHup(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
+ lcp_lowerdown(pd);
+ link_terminated(pd);
+}
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/* Initialize the PPP subsystem. */
+
+struct ppp_settings ppp_settings;
+
+void
+pppInit(void)
+{
+ struct protent *protp;
+ int i, j;
+
+ memset(&ppp_settings, 0, sizeof(ppp_settings));
+ ppp_settings.usepeerdns = 1;
+ pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
+
+ magicInit();
+
+ subnetMask = PP_HTONL(0xffffff00UL);
+
+ for (i = 0; i < NUM_PPP; i++) {
+ /* Initialize each protocol to the standard option set. */
+ for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
+ (*protp->init)(i);
+ }
+ }
+
+ sys_mbox_new(&pppMbox, 1);
+ sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)NULL, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); //Create PPP thread here
+}
+
+void
+pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
+{
+ switch(authType) {
+ case PPPAUTHTYPE_NONE:
+ default:
+#ifdef LWIP_PPP_STRICT_PAP_REJECT
+ ppp_settings.refuse_pap = 1;
+#else /* LWIP_PPP_STRICT_PAP_REJECT */
+ /* some providers request pap and accept an empty login/pw */
+ ppp_settings.refuse_pap = 0;
+#endif /* LWIP_PPP_STRICT_PAP_REJECT */
+ ppp_settings.refuse_chap = 1;
+ break;
+
+ case PPPAUTHTYPE_ANY:
+ /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
+ * RFC 1994 says:
+ *
+ * In practice, within or associated with each PPP server, there is a
+ * database which associates "user" names with authentication
+ * information ("secrets"). It is not anticipated that a particular
+ * named user would be authenticated by multiple methods. This would
+ * make the user vulnerable to attacks which negotiate the least secure
+ * method from among a set (such as PAP rather than CHAP). If the same
+ * secret was used, PAP would reveal the secret to be used later with
+ * CHAP.
+ *
+ * Instead, for each user name there should be an indication of exactly
+ * one method used to authenticate that user name. If a user needs to
+ * make use of different authentication methods under different
+ * circumstances, then distinct user names SHOULD be employed, each of
+ * which identifies exactly one authentication method.
+ *
+ */
+ ppp_settings.refuse_pap = 0;
+ ppp_settings.refuse_chap = 0;
+ break;
+
+ case PPPAUTHTYPE_PAP:
+ ppp_settings.refuse_pap = 0;
+ ppp_settings.refuse_chap = 1;
+ break;
+
+ case PPPAUTHTYPE_CHAP:
+ ppp_settings.refuse_pap = 1;
+ ppp_settings.refuse_chap = 0;
+ break;
+ }
+
+ if(user) {
+ strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
+ ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
+ } else {
+ ppp_settings.user[0] = '\0';
+ }
+
+ if(passwd) {
+ strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
+ ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
+ } else {
+ ppp_settings.passwd[0] = '\0';
+ }
+}
+
+#if PPPOS_SUPPORT
+/** Open a new PPP connection using the given I/O device.
+ * This initializes the PPP control block but does not
+ * attempt to negotiate the LCP session. If this port
+ * connects to a modem, the modem connection must be
+ * established before calling this.
+ * Return a new PPP connection descriptor on success or
+ * an error code (negative) on failure.
+ *
+ * pppOpen() is directly defined to this function.
+ */
+int
+pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
+{
+ PPPControl *pc;
+ int pd;
+
+ if (linkStatusCB == NULL) {
+ /* PPP is single-threaded: without a callback,
+ * there is no way to know when the link is up. */
+ return PPPERR_PARAM;
+ }
+
+ /* Find a free PPP session descriptor. */
+ for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
+
+ if (pd >= NUM_PPP) {
+ pd = PPPERR_OPEN;
+ } else {
+ pc = &pppControl[pd];
+ /* @todo: is this correct or do I overwrite something? */
+ memset(pc, 0, sizeof(PPPControl));
+ pc->rx.pd = pd;
+ pc->rx.fd = fd;
+
+ pc->openFlag = 1;
+ pc->fd = fd;
+
+#if VJ_SUPPORT
+ vj_compress_init(&pc->vjComp);
+#endif /* VJ_SUPPORT */
+
+ /*
+ * Default the in and out accm so that escape and flag characters
+ * are always escaped.
+ */
+ pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
+ pc->outACCM[15] = 0x60;
+
+ pc->linkStatusCB = linkStatusCB;
+ pc->linkStatusCtx = linkStatusCtx;
+
+ /*
+ * Start the connection and handle incoming events (packet or timeout).
+ */
+ PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
+ pppStart(pd);
+#if PPP_INPROC_OWNTHREAD
+ sys_mbox_post(&pppMbox, (void*)&pc->rx);
+#endif
+ }
+
+ return pd;
+}
+#endif /* PPPOS_SUPPORT */
+
+#if PPPOE_SUPPORT
+static void pppOverEthernetLinkStatusCB(int pd, int up);
+
+void
+pppOverEthernetClose(int pd)
+{
+ PPPControl* pc = &pppControl[pd];
+
+ /* *TJL* There's no lcp_deinit */
+ lcp_close(pd, NULL);
+
+ pppoe_destroy(&pc->netif);
+}
+
+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
+{
+ PPPControl *pc;
+ int pd;
+
+ LWIP_UNUSED_ARG(service_name);
+ LWIP_UNUSED_ARG(concentrator_name);
+
+ if (linkStatusCB == NULL) {
+ /* PPP is single-threaded: without a callback,
+ * there is no way to know when the link is up. */
+ return PPPERR_PARAM;
+ }
+
+ /* Find a free PPP session descriptor. Critical region? */
+ for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
+ if (pd >= NUM_PPP) {
+ pd = PPPERR_OPEN;
+ } else {
+ pc = &pppControl[pd];
+ memset(pc, 0, sizeof(PPPControl));
+ pc->openFlag = 1;
+ pc->ethif = ethif;
+
+ pc->linkStatusCB = linkStatusCB;
+ pc->linkStatusCtx = linkStatusCtx;
+
+ lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
+ lcp_wantoptions[pd].neg_asyncmap = 0;
+ lcp_wantoptions[pd].neg_pcompression = 0;
+ lcp_wantoptions[pd].neg_accompression = 0;
+
+ lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
+ lcp_allowoptions[pd].neg_asyncmap = 0;
+ lcp_allowoptions[pd].neg_pcompression = 0;
+ lcp_allowoptions[pd].neg_accompression = 0;
+
+ if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
+ pc->openFlag = 0;
+ return PPPERR_OPEN;
+ }
+
+ pppoe_connect(pc->pppoe_sc);
+ }
+
+ return pd;
+}
+#endif /* PPPOE_SUPPORT */
+
+
+/* Close a PPP connection and release the descriptor.
+ * Any outstanding packets in the queues are dropped.
+ * Return 0 on success, an error code on failure. */
+int
+pppClose(int pd)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 0;
+
+ PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
+
+ /* Disconnect */
+#if PPPOE_SUPPORT
+ if(pc->ethif) {
+ PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
+ pc->errCode = PPPERR_USER;
+ /* This will leave us at PHASE_DEAD. */
+ pppStop(pd);
+ } else
+#endif /* PPPOE_SUPPORT */
+ {
+#if PPPOS_SUPPORT
+ PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
+ pc->errCode = PPPERR_USER;
+ /* This will leave us at PHASE_DEAD. */
+ pppStop(pd);
+ pppRecvWakeup(pd);
+#endif /* PPPOS_SUPPORT */
+ }
+
+ return st;
+}
+
+/* This function is called when carrier is lost on the PPP channel. */
+void
+pppSigHUP(int pd)
+{
+ PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
+ pppHup(pd);
+}
+
+#if PPPOS_SUPPORT
+static void
+nPut(PPPControl *pc, struct pbuf *nb)
+{
+ struct pbuf *b;
+ int c;
+
+ for(b = nb; b != NULL; b = b->next) {
+ if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
+ PPPDEBUG(LOG_WARNING,
+ ("PPP nPut: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pc->fd, b->len, c, c));
+ LINK_STATS_INC(link.err);
+ pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
+ snmp_inc_ifoutdiscards(&pc->netif);
+ pbuf_free(nb);
+ return;
+ }
+ }
+
+ snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
+ snmp_inc_ifoutucastpkts(&pc->netif);
+ pbuf_free(nb);
+ LINK_STATS_INC(link.xmit);
+}
+
+/*
+ * pppAppend - append given character to end of given pbuf. If outACCM
+ * is not NULL and the character needs to be escaped, do so.
+ * If pbuf is full, append another.
+ * Return the current pbuf.
+ */
+static struct pbuf *
+pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
+{
+ struct pbuf *tb = nb;
+
+ /* Make sure there is room for the character and an escape code.
+ * Sure we don't quite fill the buffer if the character doesn't
+ * get escaped but is one character worth complicating this? */
+ /* Note: We assume no packet header. */
+ if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
+ tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ if (tb) {
+ nb->next = tb;
+ } else {
+ LINK_STATS_INC(link.memerr);
+ }
+ nb = tb;
+ }
+
+ if (nb) {
+ if (outACCM && ESCAPE_P(*outACCM, c)) {
+ *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
+ *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
+ } else {
+ *((u_char*)nb->payload + nb->len++) = c;
+ }
+ }
+
+ return tb;
+}
+#endif /* PPPOS_SUPPORT */
+
+#if PPPOE_SUPPORT
+static err_t
+pppifOutputOverEthernet(int pd, struct pbuf *p)
+{
+ PPPControl *pc = &pppControl[pd];
+ struct pbuf *pb;
+ u_short protocol = PPP_IP;
+ int i=0;
+ u16_t tot_len;
+
+ /* @todo: try to use pbuf_header() here! */
+ pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
+ if(!pb) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.proterr);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return ERR_MEM;
+ }
+
+ pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
+
+ pc->lastXMit = sys_jiffies();
+
+ if (!pc->pcomp || protocol > 0xFF) {
+ *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
+ }
+ *((u_char*)pb->payload + i) = protocol & 0xFF;
+
+ pbuf_chain(pb, p);
+ tot_len = pb->tot_len;
+
+ if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
+ LINK_STATS_INC(link.err);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return PPPERR_DEVICE;
+ }
+
+ snmp_add_ifoutoctets(&pc->netif, tot_len);
+ snmp_inc_ifoutucastpkts(&pc->netif);
+ LINK_STATS_INC(link.xmit);
+ return ERR_OK;
+}
+#endif /* PPPOE_SUPPORT */
+
+/* Send a packet on the given connection. */
+static err_t
+pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
+{
+ int pd = (int)(size_t)netif->state;
+ PPPControl *pc = &pppControl[pd];
+#if PPPOS_SUPPORT
+ u_short protocol = PPP_IP;
+ u_int fcsOut = PPP_INITFCS;
+ struct pbuf *headMB = NULL, *tailMB = NULL, *p;
+ u_char c;
+#endif /* PPPOS_SUPPORT */
+
+ LWIP_UNUSED_ARG(ipaddr);
+
+ /* Validate parameters. */
+ /* We let any protocol value go through - it can't hurt us
+ * and the peer will just drop it if it's not accepting it. */
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
+ PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
+ pd, PPP_IP, pb));
+ LINK_STATS_INC(link.opterr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(netif);
+ return ERR_ARG;
+ }
+
+ /* Check that the link is up. */
+ if (lcp_phase[pd] == PHASE_DEAD) {
+ PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
+ LINK_STATS_INC(link.rterr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(netif);
+ return ERR_RTE;
+ }
+
+#if PPPOE_SUPPORT
+ if(pc->ethif) {
+ return pppifOutputOverEthernet(pd, pb);
+ }
+#endif /* PPPOE_SUPPORT */
+
+#if PPPOS_SUPPORT
+ /* Grab an output buffer. */
+ headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ if (headMB == NULL) {
+ PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(netif);
+ return ERR_MEM;
+ }
+
+#if VJ_SUPPORT
+ /*
+ * Attempt Van Jacobson header compression if VJ is configured and
+ * this is an IP packet.
+ */
+ if (protocol == PPP_IP && pc->vjEnabled) {
+ switch (vj_compress_tcp(&pc->vjComp, pb)) {
+ case TYPE_IP:
+ /* No change...
+ protocol = PPP_IP_PROTOCOL; */
+ break;
+ case TYPE_COMPRESSED_TCP:
+ protocol = PPP_VJC_COMP;
+ break;
+ case TYPE_UNCOMPRESSED_TCP:
+ protocol = PPP_VJC_UNCOMP;
+ break;
+ default:
+ PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
+ LINK_STATS_INC(link.proterr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(netif);
+ pbuf_free(headMB);
+ return ERR_VAL;
+ }
+ }
+#endif /* VJ_SUPPORT */
+
+ tailMB = headMB;
+
+ /* Build the PPP header. */
+ if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
+ tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+ }
+
+ pc->lastXMit = sys_jiffies();
+ if (!pc->accomp) {
+ fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
+ tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
+ fcsOut = PPP_FCS(fcsOut, PPP_UI);
+ tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
+ }
+ if (!pc->pcomp || protocol > 0xFF) {
+ c = (protocol >> 8) & 0xFF;
+ fcsOut = PPP_FCS(fcsOut, c);
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ }
+ c = protocol & 0xFF;
+ fcsOut = PPP_FCS(fcsOut, c);
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+
+ /* Load packet. */
+ for(p = pb; p; p = p->next) {
+ int n;
+ u_char *sPtr;
+
+ sPtr = (u_char*)p->payload;
+ n = p->len;
+ while (n-- > 0) {
+ c = *sPtr++;
+
+ /* Update FCS before checking for special characters. */
+ fcsOut = PPP_FCS(fcsOut, c);
+
+ /* Copy to output buffer escaping special characters. */
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ }
+ }
+
+ /* Add FCS and trailing flag. */
+ c = ~fcsOut & 0xFF;
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ c = (~fcsOut >> 8) & 0xFF;
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+
+ /* If we failed to complete the packet, throw it away. */
+ if (!tailMB) {
+ PPPDEBUG(LOG_WARNING,
+ ("pppifOutput[%d]: Alloc err - dropping proto=%d\n",
+ pd, protocol));
+ pbuf_free(headMB);
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifoutdiscards(netif);
+ return ERR_MEM;
+ }
+
+ /* Send it. */
+ PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
+
+ nPut(pc, headMB);
+#endif /* PPPOS_SUPPORT */
+
+ return ERR_OK;
+}
+
+/* Get and set parameters for the given connection.
+ * Return 0 on success, an error code on failure. */
+int
+pppIOCtl(int pd, int cmd, void *arg)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 0;
+
+ if (pd < 0 || pd >= NUM_PPP) {
+ st = PPPERR_PARAM;
+ } else {
+ switch(cmd) {
+ case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
+ if (arg) {
+ *(int *)arg = (int)(pc->if_up);
+ } else {
+ st = PPPERR_PARAM;
+ }
+ break;
+ case PPPCTLS_ERRCODE: /* Set the PPP error code. */
+ if (arg) {
+ pc->errCode = *(int *)arg;
+ } else {
+ st = PPPERR_PARAM;
+ }
+ break;
+ case PPPCTLG_ERRCODE: /* Get the PPP error code. */
+ if (arg) {
+ *(int *)arg = (int)(pc->errCode);
+ } else {
+ st = PPPERR_PARAM;
+ }
+ break;
+#if PPPOS_SUPPORT
+ case PPPCTLG_FD: /* Get the fd associated with the ppp */
+ if (arg) {
+ *(sio_fd_t *)arg = pc->fd;
+ } else {
+ st = PPPERR_PARAM;
+ }
+ break;
+#endif /* PPPOS_SUPPORT */
+ default:
+ st = PPPERR_PARAM;
+ break;
+ }
+ }
+
+ return st;
+}
+
+/*
+ * Return the Maximum Transmission Unit for the given PPP connection.
+ */
+u_short
+pppMTU(int pd)
+{
+ PPPControl *pc = &pppControl[pd];
+ u_short st;
+
+ /* Validate parameters. */
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ } else {
+ st = pc->mtu;
+ }
+
+ return st;
+}
+
+#if PPPOE_SUPPORT
+int
+pppWriteOverEthernet(int pd, const u_char *s, int n)
+{
+ PPPControl *pc = &pppControl[pd];
+ struct pbuf *pb;
+
+ /* skip address & flags */
+ s += 2;
+ n -= 2;
+
+ LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
+ pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
+ if(!pb) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.proterr);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return PPPERR_ALLOC;
+ }
+
+ pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
+
+ pc->lastXMit = sys_jiffies();
+
+ MEMCPY(pb->payload, s, n);
+
+ if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
+ LINK_STATS_INC(link.err);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return PPPERR_DEVICE;
+ }
+
+ snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
+ snmp_inc_ifoutucastpkts(&pc->netif);
+ LINK_STATS_INC(link.xmit);
+ return PPPERR_NONE;
+}
+#endif /* PPPOE_SUPPORT */
+
+/*
+ * Write n characters to a ppp link.
+ * RETURN: >= 0 Number of characters written
+ * -1 Failed to write to device
+ */
+int
+pppWrite(int pd, const u_char *s, int n)
+{
+ PPPControl *pc = &pppControl[pd];
+#if PPPOS_SUPPORT
+ u_char c;
+ u_int fcsOut;
+ struct pbuf *headMB, *tailMB;
+#endif /* PPPOS_SUPPORT */
+
+#if PPPOE_SUPPORT
+ if(pc->ethif) {
+ return pppWriteOverEthernet(pd, s, n);
+ }
+#endif /* PPPOE_SUPPORT */
+
+#if PPPOS_SUPPORT
+ headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ if (headMB == NULL) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.proterr);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return PPPERR_ALLOC;
+ }
+
+ tailMB = headMB;
+
+ /* If the link has been idle, we'll send a fresh flag character to
+ * flush any noise. */
+ if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
+ tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+ }
+ pc->lastXMit = sys_jiffies();
+
+ fcsOut = PPP_INITFCS;
+ /* Load output buffer. */
+ while (n-- > 0) {
+ c = *s++;
+
+ /* Update FCS before checking for special characters. */
+ fcsOut = PPP_FCS(fcsOut, c);
+
+ /* Copy to output buffer escaping special characters. */
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ }
+
+ /* Add FCS and trailing flag. */
+ c = ~fcsOut & 0xFF;
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ c = (~fcsOut >> 8) & 0xFF;
+ tailMB = pppAppend(c, tailMB, &pc->outACCM);
+ tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
+
+ /* If we failed to complete the packet, throw it away.
+ * Otherwise send it. */
+ if (!tailMB) {
+ PPPDEBUG(LOG_WARNING,
+ ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
+ /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
+ pbuf_free(headMB);
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.proterr);
+ snmp_inc_ifoutdiscards(&pc->netif);
+ return PPPERR_ALLOC;
+ }
+
+ PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
+ /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
+ nPut(pc, headMB);
+#endif /* PPPOS_SUPPORT */
+
+ return PPPERR_NONE;
+}
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
+{
+ PPPControl *pc = &pppControl[unit];
+ int i;
+
+ pc->mtu = mtu;
+ pc->pcomp = pcomp;
+ pc->accomp = accomp;
+
+ /* Load the ACCM bits for the 32 control codes. */
+ for (i = 0; i < 32/8; i++) {
+ pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
+ }
+ PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
+ unit,
+ pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
+}
+
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+ppp_set_xaccm(int unit, ext_accm *accm)
+{
+ SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
+ PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
+ unit,
+ pppControl[unit].outACCM[0],
+ pppControl[unit].outACCM[1],
+ pppControl[unit].outACCM[2],
+ pppControl[unit].outACCM[3]));
+}
+
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
+{
+ PPPControl *pc = &pppControl[unit];
+ int i;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ LWIP_UNUSED_ARG(accomp);
+ LWIP_UNUSED_ARG(pcomp);
+ LWIP_UNUSED_ARG(mru);
+
+ /* Load the ACCM bits for the 32 control codes. */
+ SYS_ARCH_PROTECT(lev);
+ for (i = 0; i < 32 / 8; i++) {
+ /* @todo: does this work? ext_accm has been modified from pppd! */
+ pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
+ }
+ SYS_ARCH_UNPROTECT(lev);
+ PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
+ unit,
+ pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
+}
+
+#if 0
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use. Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
+ */
+int
+ccp_test( int unit, int opt_len, int for_transmit, u_char *opt_ptr)
+{
+ return 0; /* XXX Currently no compression. */
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(int unit, int isopen, int isup)
+{
+ /* XXX */
+}
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(int unit)
+{
+ /* XXX */
+ return 0;
+}
+#endif
+
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(int u, struct ppp_idle *ip)
+{
+ /* XXX */
+ LWIP_UNUSED_ARG(u);
+ LWIP_UNUSED_ARG(ip);
+
+ return 0;
+}
+
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u32_t
+GetMask(u32_t addr)
+{
+ u32_t mask, nmask;
+
+ htonl(addr);
+ if (IP_CLASSA(addr)) { /* determine network mask for address class */
+ nmask = IP_CLASSA_NET;
+ } else if (IP_CLASSB(addr)) {
+ nmask = IP_CLASSB_NET;
+ } else {
+ nmask = IP_CLASSC_NET;
+ }
+
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = subnetMask | htonl(nmask);
+
+ /* XXX
+ * Scan through the system's network interfaces.
+ * Get each netmask and OR them into our mask.
+ */
+
+ return mask;
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
+{
+#if PPPOS_SUPPORT && VJ_SUPPORT
+ PPPControl *pc = &pppControl[pd];
+
+ pc->vjEnabled = vjcomp;
+ pc->vjComp.compressSlot = cidcomp;
+ pc->vjComp.maxSlotIndex = maxcid;
+ PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
+ vjcomp, cidcomp, maxcid));
+#else /* PPPOS_SUPPORT && VJ_SUPPORT */
+ LWIP_UNUSED_ARG(pd);
+ LWIP_UNUSED_ARG(vjcomp);
+ LWIP_UNUSED_ARG(cidcomp);
+ LWIP_UNUSED_ARG(maxcid);
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
+
+ return 0;
+}
+
+/*
+ * pppifNetifInit - netif init callback
+ */
+static err_t
+pppifNetifInit(struct netif *netif)
+{
+ netif->name[0] = 'p';
+ netif->name[1] = 'p';
+ netif->output = pppifOutput;
+ netif->mtu = pppMTU((int)(size_t)netif->state);
+ netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
+#if LWIP_NETIF_HOSTNAME
+ /* @todo: Initialize interface hostname */
+ /* netif_set_hostname(netif, "lwip"); */
+#endif /* LWIP_NETIF_HOSTNAME */
+ return ERR_OK;
+}
+
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int
+sifup(int pd)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
+ } else {
+ netif_remove(&pc->netif);
+ if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
+ &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
+ netif_set_up(&pc->netif);
+ pc->if_up = 1;
+ pc->errCode = PPPERR_NONE;
+
+ PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+ if (pc->linkStatusCB) {
+ pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
+ }
+ } else {
+ st = 0;
+ PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
+ }
+ }
+
+ return st;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(int u, int proto, enum NPmode mode)
+{
+ LWIP_UNUSED_ARG(u);
+ LWIP_UNUSED_ARG(proto);
+ LWIP_UNUSED_ARG(mode);
+ return 0;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(int pd)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
+ } else {
+ pc->if_up = 0;
+ /* make sure the netif status callback is called */
+ netif_set_down(&pc->netif);
+ netif_remove(&pc->netif);
+ PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
+ if (pc->linkStatusCB) {
+ pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
+ }
+ }
+ return st;
+}
+
+/**
+ * sifaddr - Config the interface IP addresses and netmask.
+ * @param pd Interface unit ???
+ * @param o Our IP address ???
+ * @param h His IP address ???
+ * @param m IP subnet mask ???
+ * @param ns1 Primary DNS
+ * @param ns2 Secondary DNS
+ */
+int
+sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
+ } else {
+ SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
+ SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
+ SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
+ SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
+ SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
+ }
+ return st;
+}
+
+/**
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ * @param pd Interface unit ???
+ * @param o Our IP address ???
+ * @param h IP broadcast address ???
+ */
+int
+cifaddr( int pd, u32_t o, u32_t h)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ LWIP_UNUSED_ARG(o);
+ LWIP_UNUSED_ARG(h);
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
+ } else {
+ IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
+ IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
+ IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
+ IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
+ IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
+ }
+ return st;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(int pd, u32_t l, u32_t g)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ LWIP_UNUSED_ARG(l);
+ LWIP_UNUSED_ARG(g);
+
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
+ } else {
+ netif_set_default(&pc->netif);
+ }
+
+ /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
+
+ return st;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(int pd, u32_t l, u32_t g)
+{
+ PPPControl *pc = &pppControl[pd];
+ int st = 1;
+
+ LWIP_UNUSED_ARG(l);
+ LWIP_UNUSED_ARG(g);
+
+ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
+ st = 0;
+ PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
+ } else {
+ netif_set_default(NULL);
+ }
+
+ return st;
+}
+
+/**********************************/
+/*** LOCAL FUNCTION DEFINITIONS ***/
+/**********************************/
+
+#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
+/* The main PPP process function. This implements the state machine according
+ * to section 4 of RFC 1661: The Point-To-Point Protocol. */
+static void
+pppInputThread(void *arg)
+{
+ int count;
+ PPPControlRx *pcrx = arg;
+
+ do
+ {
+ sys_arch_mbox_fetch(&pppMbox, (void**)&pcrx, 0); //Wait indefinitely
+
+ while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
+ count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
+ if(count > 0) {
+ pppInProc(pcrx, pcrx->rxbuf, count);
+ } else {
+ /* nothing received, give other tasks a chance to run */
+ sys_msleep(1);
+ }
+ }
+ } while(1); //Never terminates
+}
+#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
+
+#if PPPOE_SUPPORT
+
+void
+pppOverEthernetInitFailed(int pd)
+{
+ PPPControl* pc;
+
+ pppHup(pd);
+ pppStop(pd);
+
+ pc = &pppControl[pd];
+ pppoe_destroy(&pc->netif);
+ pc->openFlag = 0;
+
+ if(pc->linkStatusCB) {
+ pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
+ }
+}
+
+static void
+pppOverEthernetLinkStatusCB(int pd, int up)
+{
+ if(up) {
+ PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
+ pppStart(pd);
+ } else {
+ pppOverEthernetInitFailed(pd);
+ }
+}
+#endif /* PPPOE_SUPPORT */
+
+struct pbuf *
+pppSingleBuf(struct pbuf *p)
+{
+ struct pbuf *q, *b;
+ u_char *pl;
+
+ if(p->tot_len == p->len) {
+ return p;
+ }
+
+ q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+ if(!q) {
+ PPPDEBUG(LOG_ERR,
+ ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
+ return p; /* live dangerously */
+ }
+
+ for(b = p, pl = q->payload; b != NULL; b = b->next) {
+ MEMCPY(pl, b->payload, b->len);
+ pl += b->len;
+ }
+
+ pbuf_free(p);
+
+ return q;
+}
+
+struct pppInputHeader {
+ int unit;
+ u16_t proto;
+};
+
+/*
+ * Pass the processed input packet to the appropriate handler.
+ * This function and all handlers run in the context of the tcpip_thread
+ */
+static void
+pppInput(void *arg)
+{
+ struct pbuf *nb = (struct pbuf *)arg;
+ u16_t protocol;
+ int pd;
+
+ pd = ((struct pppInputHeader *)nb->payload)->unit;
+ protocol = ((struct pppInputHeader *)nb->payload)->proto;
+
+ if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ goto drop;
+ }
+
+ LINK_STATS_INC(link.recv);
+ snmp_inc_ifinucastpkts(&pppControl[pd].netif);
+ snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ * Until we get past the authentication phase, toss all packets
+ * except LCP, LQR and authentication packets.
+ */
+ if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
+ if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
+ (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
+ PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
+ goto drop;
+ }
+ }
+
+ switch(protocol) {
+ case PPP_VJC_COMP: /* VJ compressed TCP */
+#if PPPOS_SUPPORT && VJ_SUPPORT
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
+ /*
+ * Clip off the VJ header and prepend the rebuilt TCP/IP header and
+ * pass the result to IP.
+ */
+ if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
+ pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+ return;
+ }
+ /* Something's wrong so drop it. */
+ PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
+#else /* PPPOS_SUPPORT && VJ_SUPPORT */
+ /* No handler for this protocol so drop the packet. */
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
+ break;
+
+ case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
+#if PPPOS_SUPPORT && VJ_SUPPORT
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
+ /*
+ * Process the TCP/IP header for VJ header compression and then pass
+ * the packet to IP.
+ */
+ if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
+ pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+ return;
+ }
+ /* Something's wrong so drop it. */
+ PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
+#else /* PPPOS_SUPPORT && VJ_SUPPORT */
+ /* No handler for this protocol so drop the packet. */
+ PPPDEBUG(LOG_INFO,
+ ("pppInput[%d]: drop VJ UnComp in %d:.*H\n",
+ pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */
+ break;
+
+ case PPP_IP: /* Internet Protocol */
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
+ if (pppControl[pd].netif.input) {
+ pppControl[pd].netif.input(nb, &pppControl[pd].netif);
+ return;
+ }
+ break;
+
+ default: {
+ struct protent *protp;
+ int i;
+
+ /*
+ * Upcall the proper protocol input routine.
+ */
+ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
+ if (protp->protocol == protocol && protp->enabled_flag) {
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
+ nb = pppSingleBuf(nb);
+ (*protp->input)(pd, nb->payload, nb->len);
+ PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
+ goto out;
+ }
+ }
+
+ /* No handler for this protocol so reject the packet. */
+ PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
+ if (pbuf_header(nb, sizeof(protocol))) {
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ goto drop;
+ }
+#if BYTE_ORDER == LITTLE_ENDIAN
+ protocol = htons(protocol);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ SMEMCPY(nb->payload, &protocol, sizeof(protocol));
+ lcp_sprotrej(pd, nb->payload, nb->len);
+ }
+ break;
+ }
+
+drop:
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifindiscards(&pppControl[pd].netif);
+
+out:
+ pbuf_free(nb);
+ return;
+}
+
+#if PPPOS_SUPPORT
+/*
+ * Drop the input packet.
+ */
+static void
+pppDrop(PPPControlRx *pcrx)
+{
+ if (pcrx->inHead != NULL) {
+#if 0
+ PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
+#endif
+ PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
+ if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
+ pbuf_free(pcrx->inTail);
+ }
+ pbuf_free(pcrx->inHead);
+ pcrx->inHead = NULL;
+ pcrx->inTail = NULL;
+ }
+#if VJ_SUPPORT
+ vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
+#endif /* VJ_SUPPORT */
+
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
+}
+
+/** Pass received raw characters to PPPoS to be decoded. This function is
+ * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
+ *
+ * @param pd PPP descriptor index, returned by pppOpen()
+ * @param data received data
+ * @param len length of received data
+ */
+void
+pppos_input(int pd, u_char* data, int len)
+{
+ pppInProc(&pppControl[pd].rx, data, len);
+}
+
+/**
+ * Process a received octet string.
+ */
+static void
+pppInProc(PPPControlRx *pcrx, u_char *s, int l)
+{
+ struct pbuf *nextNBuf;
+ u_char curChar;
+ u_char escaped;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
+ while (l-- > 0) {
+ curChar = *s++;
+
+ SYS_ARCH_PROTECT(lev);
+ escaped = ESCAPE_P(pcrx->inACCM, curChar);
+ SYS_ARCH_UNPROTECT(lev);
+ /* Handle special characters. */
+ if (escaped) {
+ /* Check for escape sequences. */
+ /* XXX Note that this does not handle an escaped 0x5d character which
+ * would appear as an escape character. Since this is an ASCII ']'
+ * and there is no reason that I know of to escape it, I won't complicate
+ * the code to handle this case. GLL */
+ if (curChar == PPP_ESCAPE) {
+ pcrx->inEscaped = 1;
+ /* Check for the flag character. */
+ } else if (curChar == PPP_FLAG) {
+ /* If this is just an extra flag character, ignore it. */
+ if (pcrx->inState <= PDADDRESS) {
+ /* ignore it */;
+ /* If we haven't received the packet header, drop what has come in. */
+ } else if (pcrx->inState < PDDATA) {
+ PPPDEBUG(LOG_WARNING,
+ ("pppInProc[%d]: Dropping incomplete packet %d\n",
+ pcrx->pd, pcrx->inState));
+ LINK_STATS_INC(link.lenerr);
+ pppDrop(pcrx);
+ /* If the fcs is invalid, drop the packet. */
+ } else if (pcrx->inFCS != PPP_GOODFCS) {
+ PPPDEBUG(LOG_INFO,
+ ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
+ pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
+ /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
+ LINK_STATS_INC(link.chkerr);
+ pppDrop(pcrx);
+ /* Otherwise it's a good packet so pass it on. */
+ } else {
+ struct pbuf *inp;
+ /* Trim off the checksum. */
+ if(pcrx->inTail->len >= 2) {
+ pcrx->inTail->len -= 2;
+
+ pcrx->inTail->tot_len = pcrx->inTail->len;
+ if (pcrx->inTail != pcrx->inHead) {
+ pbuf_cat(pcrx->inHead, pcrx->inTail);
+ }
+ } else {
+ pcrx->inTail->tot_len = pcrx->inTail->len;
+ if (pcrx->inTail != pcrx->inHead) {
+ pbuf_cat(pcrx->inHead, pcrx->inTail);
+ }
+
+ pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
+ }
+
+ /* Dispatch the packet thereby consuming it. */
+ inp = pcrx->inHead;
+ /* Packet consumed, release our references. */
+ pcrx->inHead = NULL;
+ pcrx->inTail = NULL;
+#if PPP_INPROC_MULTITHREADED
+ if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
+ PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
+ pbuf_free(inp);
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
+ }
+#else /* PPP_INPROC_MULTITHREADED */
+ pppInput(inp);
+#endif /* PPP_INPROC_MULTITHREADED */
+ }
+
+ /* Prepare for a new packet. */
+ pcrx->inFCS = PPP_INITFCS;
+ pcrx->inState = PDADDRESS;
+ pcrx->inEscaped = 0;
+ /* Other characters are usually control characters that may have
+ * been inserted by the physical layer so here we just drop them. */
+ } else {
+ PPPDEBUG(LOG_WARNING,
+ ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
+ }
+ /* Process other characters. */
+ } else {
+ /* Unencode escaped characters. */
+ if (pcrx->inEscaped) {
+ pcrx->inEscaped = 0;
+ curChar ^= PPP_TRANS;
+ }
+
+ /* Process character relative to current state. */
+ switch(pcrx->inState) {
+ case PDIDLE: /* Idle state - waiting. */
+ /* Drop the character if it's not 0xff
+ * we would have processed a flag character above. */
+ if (curChar != PPP_ALLSTATIONS) {
+ break;
+ }
+
+ /* Fall through */
+ case PDSTART: /* Process start flag. */
+ /* Prepare for a new packet. */
+ pcrx->inFCS = PPP_INITFCS;
+
+ /* Fall through */
+ case PDADDRESS: /* Process address field. */
+ if (curChar == PPP_ALLSTATIONS) {
+ pcrx->inState = PDCONTROL;
+ break;
+ }
+ /* Else assume compressed address and control fields so
+ * fall through to get the protocol... */
+ case PDCONTROL: /* Process control field. */
+ /* If we don't get a valid control code, restart. */
+ if (curChar == PPP_UI) {
+ pcrx->inState = PDPROTOCOL1;
+ break;
+ }
+#if 0
+ else {
+ PPPDEBUG(LOG_WARNING,
+ ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
+ pcrx->inState = PDSTART;
+ }
+#endif
+ case PDPROTOCOL1: /* Process protocol field 1. */
+ /* If the lower bit is set, this is the end of the protocol
+ * field. */
+ if (curChar & 1) {
+ pcrx->inProtocol = curChar;
+ pcrx->inState = PDDATA;
+ } else {
+ pcrx->inProtocol = (u_int)curChar << 8;
+ pcrx->inState = PDPROTOCOL2;
+ }
+ break;
+ case PDPROTOCOL2: /* Process protocol field 2. */
+ pcrx->inProtocol |= curChar;
+ pcrx->inState = PDDATA;
+ break;
+ case PDDATA: /* Process data byte. */
+ /* Make space to receive processed data. */
+ if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
+ if (pcrx->inTail != NULL) {
+ pcrx->inTail->tot_len = pcrx->inTail->len;
+ if (pcrx->inTail != pcrx->inHead) {
+ pbuf_cat(pcrx->inHead, pcrx->inTail);
+ /* give up the inTail reference now */
+ pcrx->inTail = NULL;
+ }
+ }
+ /* If we haven't started a packet, we need a packet header. */
+ nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ if (nextNBuf == 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. */
+ PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
+ LINK_STATS_INC(link.memerr);
+ pppDrop(pcrx);
+ pcrx->inState = PDSTART; /* Wait for flag sequence. */
+ break;
+ }
+ if (pcrx->inHead == NULL) {
+ struct pppInputHeader *pih = nextNBuf->payload;
+
+ pih->unit = pcrx->pd;
+ pih->proto = pcrx->inProtocol;
+
+ nextNBuf->len += sizeof(*pih);
+
+ pcrx->inHead = nextNBuf;
+ }
+ pcrx->inTail = nextNBuf;
+ }
+ /* Load character into buffer. */
+ ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
+ break;
+ }
+
+ /* update the frame check sequence number. */
+ pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
+ }
+ } /* while (l-- > 0), all bytes processed */
+
+ avRandomize();
+}
+#endif /* PPPOS_SUPPORT */
+
+#if PPPOE_SUPPORT
+void
+pppInProcOverEthernet(int pd, struct pbuf *pb)
+{
+ struct pppInputHeader *pih;
+ u16_t inProtocol;
+
+ if(pb->len < sizeof(inProtocol)) {
+ PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
+ goto drop;
+ }
+
+ inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
+
+ /* make room for pppInputHeader - should not fail */
+ if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
+ PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
+ goto drop;
+ }
+
+ pih = pb->payload;
+
+ pih->unit = pd;
+ pih->proto = inProtocol;
+
+ /* Dispatch the packet thereby consuming it. */
+ pppInput(pb);
+ return;
+
+drop:
+ LINK_STATS_INC(link.drop);
+ snmp_inc_ifindiscards(&pppControl[pd].netif);
+ pbuf_free(pb);
+ return;
+}
+#endif /* PPPOE_SUPPORT */
+
+#if LWIP_NETIF_STATUS_CALLBACK
+/** Set the status callback of a PPP's netif
+ *
+ * @param pd The PPP descriptor returned by pppOpen()
+ * @param status_callback pointer to the status callback function
+ *
+ * @see netif_set_status_callback
+ */
+void
+ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
+{
+ netif_set_status_callback(&pppControl[pd].netif, status_callback);
+}
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+
+#if LWIP_NETIF_LINK_CALLBACK
+/** Set the link callback of a PPP's netif
+ *
+ * @param pd The PPP descriptor returned by pppOpen()
+ * @param link_callback pointer to the link callback function
+ *
+ * @see netif_set_link_callback
+ */
+void
+ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
+{
+ netif_set_link_callback(&pppControl[pd].netif, link_callback);
+}
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.h
new file mode 100644
index 0000000000..a72ac9576b
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.h
@@ -0,0 +1,483 @@
+/*****************************************************************************
+* ppp.h - Network Point to Point Protocol header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1997 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Original derived from BSD codes.
+*****************************************************************************/
+
+#ifndef PPP_H
+#define PPP_H
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/sio.h"
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+#include "lwip/netif.h"
+#include "lwip/sys.h"
+#include "lwip/timers.h"
+
+/** Some defines for code we skip compared to the original pppd.
+ * These are just here to minimise the use of the ugly "#if 0". */
+#define PPP_ADDITIONAL_CALLBACKS 0
+
+/** Some error checks to test for unsupported code */
+#if CBCP_SUPPORT
+#error "CBCP is not supported in lwIP PPP"
+#endif
+#if CCP_SUPPORT
+#error "CCP is not supported in lwIP PPP"
+#endif
+
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ */
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0)
+#define UNTIMEOUT(f, a) sys_untimeout((f), (a))
+
+
+#ifndef __u_char_defined
+
+/* Type definitions for BSD code. */
+typedef unsigned long u_long;
+typedef unsigned int u_int;
+typedef unsigned short u_short;
+typedef unsigned char u_char;
+
+#endif
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981, and numerous additions.
+ */
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN 4 /* octets for standard ppp header */
+#define PPP_FCSLEN 2 /* octets for FCS */
+
+
+/*
+ * Significant octet values.
+ */
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_FLAG 0x7e /* Flag Sequence */
+#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
+#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP 0x21 /* Internet Protocol */
+#define PPP_AT 0x29 /* AppleTalk Protocol */
+#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
+#define PPP_COMP 0xfd /* compressed packet */
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
+#define PPP_CCP 0x80fd /* Compression Control Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Report protocol */
+#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_char ext_accm[32];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+ NPMODE_PASS, /* pass the packet through */
+ NPMODE_DROP, /* silently drop the packet */
+ NPMODE_ERROR, /* return an error */
+ NPMODE_QUEUE /* save it up for later. */
+};
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+ (c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+ *(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+ (s) = *(cp); (cp)++; (s) <<= 8; \
+ (s) |= *(cp); (cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+ *(cp)++ = (u_char) ((s) >> 8); \
+ *(cp)++ = (u_char) (s & 0xff); \
+}
+
+#define GETLONG(l, cp) { \
+ (l) = *(cp); (cp)++; (l) <<= 8; \
+ (l) |= *(cp); (cp)++; (l) <<= 8; \
+ (l) |= *(cp); (cp)++; (l) <<= 8; \
+ (l) |= *(cp); (cp)++; \
+}
+#define PUTLONG(l, cp) { \
+ *(cp)++ = (u_char) ((l) >> 24); \
+ *(cp)++ = (u_char) ((l) >> 16); \
+ *(cp)++ = (u_char) ((l) >> 8); \
+ *(cp)++ = (u_char) (l); \
+}
+
+
+#define INCPTR(n, cp) ((cp) += (n))
+#define DECPTR(n, cp) ((cp) -= (n))
+
+#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l))
+#define BCOPY(s, d, l) MEMCPY((d), (s), (l))
+#define BZERO(s, n) memset(s, 0, n)
+
+#if PPP_DEBUG
+#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); }
+#else /* PPP_DEBUG */
+#define PRINTMSG(m, l)
+#endif /* PPP_DEBUG */
+
+/*
+ * MAKEHEADER - Add PPP Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+ PUTCHAR(PPP_ALLSTATIONS, p); \
+ PUTCHAR(PPP_UI, p); \
+ PUTSHORT(t, p); }
+
+/*************************
+*** PUBLIC DEFINITIONS ***
+*************************/
+
+/* Error codes. */
+#define PPPERR_NONE 0 /* No error. */
+#define PPPERR_PARAM -1 /* Invalid parameter. */
+#define PPPERR_OPEN -2 /* Unable to open PPP session. */
+#define PPPERR_DEVICE -3 /* Invalid I/O device for PPP. */
+#define PPPERR_ALLOC -4 /* Unable to allocate resources. */
+#define PPPERR_USER -5 /* User interrupt. */
+#define PPPERR_CONNECT -6 /* Connection lost. */
+#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */
+#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */
+
+/*
+ * PPP IOCTL commands.
+ */
+/*
+ * Get the up status - 0 for down, non-zero for up. The argument must
+ * point to an int.
+ */
+#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */
+#define PPPCTLS_ERRCODE 101 /* Set the error code */
+#define PPPCTLG_ERRCODE 102 /* Get the error code */
+#define PPPCTLG_FD 103 /* Get the fd associated with the ppp */
+
+/************************
+*** PUBLIC DATA TYPES ***
+************************/
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+ u_short protocol; /* PPP protocol number */
+ /* Initialization procedure */
+ void (*init) (int unit);
+ /* Process a received packet */
+ void (*input) (int unit, u_char *pkt, int len);
+ /* Process a received protocol-reject */
+ void (*protrej) (int unit);
+ /* Lower layer has come up */
+ void (*lowerup) (int unit);
+ /* Lower layer has gone down */
+ void (*lowerdown) (int unit);
+ /* Open the protocol */
+ void (*open) (int unit);
+ /* Close the protocol */
+ void (*close) (int unit, char *reason);
+#if PPP_ADDITIONAL_CALLBACKS
+ /* Print a packet in readable form */
+ int (*printpkt) (u_char *pkt, int len,
+ void (*printer) (void *, char *, ...),
+ void *arg);
+ /* Process a received data packet */
+ void (*datainput) (int unit, u_char *pkt, int len);
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+ int enabled_flag; /* 0 if protocol is disabled */
+ char *name; /* Text name of protocol */
+#if PPP_ADDITIONAL_CALLBACKS
+ /* Check requested options, assign defaults */
+ void (*check_options) (u_long);
+ /* Configure interface for demand-dial */
+ int (*demand_conf) (int unit);
+ /* Say whether to bring up link for this pkt */
+ int (*active_pkt) (u_char *pkt, int len);
+#endif /* PPP_ADDITIONAL_CALLBACKS */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+ u_short xmit_idle; /* seconds since last NP packet sent */
+ u_short recv_idle; /* seconds since last NP packet received */
+};
+
+struct ppp_settings {
+
+ u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */
+ u_int auth_required : 1; /* Peer is required to authenticate */
+ u_int explicit_remote : 1; /* remote_name specified with remotename opt */
+ u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */
+ u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */
+ u_int usehostname : 1; /* Use hostname for our_name */
+ u_int usepeerdns : 1; /* Ask peer for DNS adds */
+
+ u_short idle_time_limit; /* Shut down link if idle for this long */
+ int maxconnect; /* Maximum connect time (seconds) */
+
+ char user [MAXNAMELEN + 1]; /* Username for PAP */
+ char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */
+ char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */
+ char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */
+};
+
+struct ppp_addrs {
+ ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2;
+};
+
+/*****************************
+*** PUBLIC DATA STRUCTURES ***
+*****************************/
+
+/* Buffers for outgoing packets. */
+extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
+
+extern struct ppp_settings ppp_settings;
+
+extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */
+
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+
+/* Initialize the PPP subsystem. */
+void pppInit(void);
+
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
+ * RFC 1994 says:
+ *
+ * In practice, within or associated with each PPP server, there is a
+ * database which associates "user" names with authentication
+ * information ("secrets"). It is not anticipated that a particular
+ * named user would be authenticated by multiple methods. This would
+ * make the user vulnerable to attacks which negotiate the least secure
+ * method from among a set (such as PAP rather than CHAP). If the same
+ * secret was used, PAP would reveal the secret to be used later with
+ * CHAP.
+ *
+ * Instead, for each user name there should be an indication of exactly
+ * one method used to authenticate that user name. If a user needs to
+ * make use of different authentication methods under different
+ * circumstances, then distinct user names SHOULD be employed, each of
+ * which identifies exactly one authentication method.
+ *
+ */
+enum pppAuthType {
+ PPPAUTHTYPE_NONE,
+ PPPAUTHTYPE_ANY,
+ PPPAUTHTYPE_PAP,
+ PPPAUTHTYPE_CHAP
+};
+
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);
+
+/*
+ * Open a new PPP connection using the given serial I/O device.
+ * This initializes the PPP control block but does not
+ * attempt to negotiate the LCP session.
+ * Return a new PPP connection descriptor on success or
+ * an error code (negative) on failure.
+ */
+int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
+
+/*
+ * Open a new PPP Over Ethernet (PPPOE) connection.
+ */
+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
+
+/* for source code compatibility */
+#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls)
+
+/*
+ * Close a PPP connection and release the descriptor.
+ * Any outstanding packets in the queues are dropped.
+ * Return 0 on success, an error code on failure.
+ */
+int pppClose(int pd);
+
+/*
+ * Indicate to the PPP process that the line has disconnected.
+ */
+void pppSigHUP(int pd);
+
+/*
+ * Get and set parameters for the given connection.
+ * Return 0 on success, an error code on failure.
+ */
+int pppIOCtl(int pd, int cmd, void *arg);
+
+/*
+ * Return the Maximum Transmission Unit for the given PPP connection.
+ */
+u_short pppMTU(int pd);
+
+/*
+ * Write n characters to a ppp link.
+ * RETURN: >= 0 Number of characters written, -1 Failed to write to device.
+ */
+int pppWrite(int pd, const u_char *s, int n);
+
+void pppInProcOverEthernet(int pd, struct pbuf *pb);
+
+struct pbuf *pppSingleBuf(struct pbuf *p);
+
+void pppLinkTerminated(int pd);
+
+void pppLinkDown(int pd);
+
+void pppos_input(int pd, u_char* data, int len);
+
+/* Configure i/f transmit parameters */
+void ppp_send_config (int, u16_t, u32_t, int, int);
+/* Set extended transmit ACCM */
+void ppp_set_xaccm (int, ext_accm *);
+/* Configure i/f receive parameters */
+void ppp_recv_config (int, int, u32_t, int, int);
+/* Find out how long link has been idle */
+int get_idle_time (int, struct ppp_idle *);
+
+/* Configure VJ TCP header compression */
+int sifvjcomp (int, int, u8_t, u8_t);
+/* Configure i/f down (for IP) */
+int sifup (int);
+/* Set mode for handling packets for proto */
+int sifnpmode (int u, int proto, enum NPmode mode);
+/* Configure i/f down (for IP) */
+int sifdown (int);
+/* Configure IP addresses for i/f */
+int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);
+/* Reset i/f IP addresses */
+int cifaddr (int, u32_t, u32_t);
+/* Create default route through i/f */
+int sifdefaultroute (int, u32_t, u32_t);
+/* Delete default route through i/f */
+int cifdefaultroute (int, u32_t, u32_t);
+
+/* Get appropriate netmask for address */
+u32_t GetMask (u32_t);
+
+#if LWIP_NETIF_STATUS_CALLBACK
+void ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback);
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+#if LWIP_NETIF_LINK_CALLBACK
+void ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback);
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#endif /* PPP_SUPPORT */
+
+#endif /* PPP_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp_oe.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp_oe.c
new file mode 100644
index 0000000000..040a0bc93c
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp_oe.c
@@ -0,0 +1,1132 @@
+/*****************************************************************************
+* ppp_oe.c - PPP Over Ethernet implementation for lwIP.
+*
+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 06-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+*****************************************************************************/
+
+
+
+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Martin Husemann <martin@NetBSD.org>.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "netif/ppp_oe.h"
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "lwip/timers.h"
+#include "lwip/memp.h"
+
+#include <string.h>
+#include <stdio.h>
+
+
+/* Add a 16 bit unsigned value to a buffer pointed to by PTR */
+#define PPPOE_ADD_16(PTR, VAL) \
+ *(PTR)++ = (u8_t)((VAL) / 256); \
+ *(PTR)++ = (u8_t)((VAL) % 256)
+
+/* Add a complete PPPoE header to the buffer pointed to by PTR */
+#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \
+ *(PTR)++ = PPPOE_VERTYPE; \
+ *(PTR)++ = (CODE); \
+ PPPOE_ADD_16(PTR, SESS); \
+ PPPOE_ADD_16(PTR, LEN)
+
+#define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */
+#define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */
+#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */
+#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */
+
+#ifdef PPPOE_SERVER
+#error "PPPOE_SERVER is not yet supported under lwIP!"
+/* from if_spppsubr.c */
+#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
+#endif
+
+#ifndef PPPOE_ERRORSTRING_LEN
+#define PPPOE_ERRORSTRING_LEN 64
+#endif
+static char pppoe_error_tmp[PPPOE_ERRORSTRING_LEN];
+
+
+/* input routines */
+static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *);
+
+/* management routines */
+static int pppoe_do_disconnect(struct pppoe_softc *);
+static void pppoe_abort_connect(struct pppoe_softc *);
+static void pppoe_clear_softc(struct pppoe_softc *, const char *);
+
+/* internal timeout handling */
+static void pppoe_timeout(void *);
+
+/* sending actual protocol controll packets */
+static err_t pppoe_send_padi(struct pppoe_softc *);
+static err_t pppoe_send_padr(struct pppoe_softc *);
+#ifdef PPPOE_SERVER
+static err_t pppoe_send_pado(struct pppoe_softc *);
+static err_t pppoe_send_pads(struct pppoe_softc *);
+#endif
+static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *);
+
+/* internal helper functions */
+static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *);
+static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *);
+
+/** linked list of created pppoe interfaces */
+static struct pppoe_softc *pppoe_softc_list;
+
+err_t
+pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr)
+{
+ struct pppoe_softc *sc;
+
+ sc = (struct pppoe_softc *)memp_malloc(MEMP_PPPOE_IF);
+ if (sc == NULL) {
+ *scptr = NULL;
+ return ERR_MEM;
+ }
+ memset(sc, 0, sizeof(struct pppoe_softc));
+
+ /* changed to real address later */
+ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
+
+ sc->sc_pd = pd;
+ sc->sc_linkStatusCB = linkStatusCB;
+ sc->sc_ethif = ethif;
+
+ /* put the new interface at the head of the list */
+ sc->next = pppoe_softc_list;
+ pppoe_softc_list = sc;
+
+ *scptr = sc;
+
+ return ERR_OK;
+}
+
+err_t
+pppoe_destroy(struct netif *ifp)
+{
+ struct pppoe_softc *sc, *prev = NULL;
+
+ for (sc = pppoe_softc_list; sc != NULL; prev = sc, sc = sc->next) {
+ if (sc->sc_ethif == ifp) {
+ break;
+ }
+ }
+
+ if(!(sc && (sc->sc_ethif == ifp))) {
+ return ERR_IF;
+ }
+
+ sys_untimeout(pppoe_timeout, sc);
+ if (prev == NULL) {
+ /* remove sc from the head of the list */
+ pppoe_softc_list = sc->next;
+ } else {
+ /* remove sc from the list */
+ prev->next = sc->next;
+ }
+
+#ifdef PPPOE_TODO
+ if (sc->sc_concentrator_name) {
+ mem_free(sc->sc_concentrator_name);
+ }
+ if (sc->sc_service_name) {
+ mem_free(sc->sc_service_name);
+ }
+#endif /* PPPOE_TODO */
+ memp_free(MEMP_PPPOE_IF, sc);
+
+ return ERR_OK;
+}
+
+/*
+ * Find the interface handling the specified session.
+ * Note: O(number of sessions open), this is a client-side only, mean
+ * and lean implementation, so number of open sessions typically should
+ * be 1.
+ */
+static struct pppoe_softc *
+pppoe_find_softc_by_session(u_int session, struct netif *rcvif)
+{
+ struct pppoe_softc *sc;
+
+ if (session == 0) {
+ return NULL;
+ }
+
+ for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) {
+ if (sc->sc_state == PPPOE_STATE_SESSION
+ && sc->sc_session == session) {
+ if (sc->sc_ethif == rcvif) {
+ return sc;
+ } else {
+ return NULL;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Check host unique token passed and return appropriate softc pointer,
+ * or NULL if token is bogus. */
+static struct pppoe_softc *
+pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif)
+{
+ struct pppoe_softc *sc, *t;
+
+ if (pppoe_softc_list == NULL) {
+ return NULL;
+ }
+
+ if (len != sizeof sc) {
+ return NULL;
+ }
+ MEMCPY(&t, token, len);
+
+ for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) {
+ if (sc == t) {
+ break;
+ }
+ }
+
+ if (sc == NULL) {
+ PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n"));
+ return NULL;
+ }
+
+ /* should be safe to access *sc now */
+ if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
+ printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state);
+ return NULL;
+ }
+ if (sc->sc_ethif != rcvif) {
+ printf("%c%c%"U16_F": wrong interface, not accepting host unique\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ return NULL;
+ }
+ return sc;
+}
+
+static void
+pppoe_linkstatus_up(struct pppoe_softc *sc)
+{
+ sc->sc_linkStatusCB(sc->sc_pd, 1);
+}
+
+/* analyze and handle a single received packet while not in session state */
+static void
+pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
+{
+ u16_t tag, len;
+ u16_t session, plen;
+ struct pppoe_softc *sc;
+ const char *err_msg;
+ char devname[6];
+ u8_t *ac_cookie;
+ u16_t ac_cookie_len;
+#ifdef PPPOE_SERVER
+ u8_t *hunique;
+ size_t hunique_len;
+#endif
+ struct pppoehdr *ph;
+ struct pppoetag pt;
+ int off, err, errortag;
+ struct eth_hdr *ethhdr;
+
+ pb = pppSingleBuf(pb);
+
+ strcpy(devname, "pppoe"); /* as long as we don't know which instance */
+ err_msg = NULL;
+ errortag = 0;
+ if (pb->len < sizeof(*ethhdr)) {
+ goto done;
+ }
+ ethhdr = (struct eth_hdr *)pb->payload;
+ off = sizeof(*ethhdr);
+
+ ac_cookie = NULL;
+ ac_cookie_len = 0;
+#ifdef PPPOE_SERVER
+ hunique = NULL;
+ hunique_len = 0;
+#endif
+ session = 0;
+ if (pb->len - off < PPPOE_HEADERLEN) {
+ printf("pppoe: packet too short: %d\n", pb->len);
+ goto done;
+ }
+
+ ph = (struct pppoehdr *) (ethhdr + 1);
+ if (ph->vertype != PPPOE_VERTYPE) {
+ printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype);
+ goto done;
+ }
+ session = ntohs(ph->session);
+ plen = ntohs(ph->plen);
+ off += sizeof(*ph);
+
+ if (plen + off > pb->len) {
+ printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
+ pb->len - off, plen);
+ goto done;
+ }
+ if(pb->tot_len == pb->len) {
+ pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */
+ }
+ tag = 0;
+ len = 0;
+ sc = NULL;
+ while (off + sizeof(pt) <= pb->len) {
+ MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));
+ tag = ntohs(pt.tag);
+ len = ntohs(pt.len);
+ if (off + sizeof(pt) + len > pb->len) {
+ printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len);
+ goto done;
+ }
+ switch (tag) {
+ case PPPOE_TAG_EOL:
+ goto breakbreak;
+ case PPPOE_TAG_SNAME:
+ break; /* ignored */
+ case PPPOE_TAG_ACNAME:
+ break; /* ignored */
+ case PPPOE_TAG_HUNIQUE:
+ if (sc != NULL) {
+ break;
+ }
+#ifdef PPPOE_SERVER
+ hunique = (u8_t*)pb->payload + off + sizeof(pt);
+ hunique_len = len;
+#endif
+ sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);
+ if (sc != NULL) {
+ snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ }
+ break;
+ case PPPOE_TAG_ACCOOKIE:
+ if (ac_cookie == NULL) {
+ ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);
+ ac_cookie_len = len;
+ }
+ break;
+ case PPPOE_TAG_SNAME_ERR:
+ err_msg = "SERVICE NAME ERROR";
+ errortag = 1;
+ break;
+ case PPPOE_TAG_ACSYS_ERR:
+ err_msg = "AC SYSTEM ERROR";
+ errortag = 1;
+ break;
+ case PPPOE_TAG_GENERIC_ERR:
+ err_msg = "GENERIC ERROR";
+ errortag = 1;
+ break;
+ }
+ if (err_msg) {
+ if (errortag && len) {
+ u16_t error_len = LWIP_MIN(len, sizeof(pppoe_error_tmp)-1);
+ strncpy(pppoe_error_tmp, (char*)pb->payload + off + sizeof(pt), error_len);
+ pppoe_error_tmp[error_len-1] = '\0';
+ printf("%s: %s: %s\n", devname, err_msg, pppoe_error_tmp);
+ } else {
+ printf("%s: %s\n", devname, err_msg);
+ }
+ if (errortag) {
+ goto done;
+ }
+ }
+ off += sizeof(pt) + len;
+ }
+
+breakbreak:;
+ switch (ph->code) {
+ case PPPOE_CODE_PADI:
+#ifdef PPPOE_SERVER
+ /*
+ * got service name, concentrator name, and/or host unique.
+ * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
+ */
+ if (LIST_EMPTY(&pppoe_softc_list)) {
+ goto done;
+ }
+ LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {
+ continue;
+ }
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
+ continue;
+ }
+ if (sc->sc_state == PPPOE_STATE_INITIAL) {
+ break;
+ }
+ }
+ if (sc == NULL) {
+ /* printf("pppoe: free passive interface is not found\n"); */
+ goto done;
+ }
+ if (hunique) {
+ if (sc->sc_hunique) {
+ mem_free(sc->sc_hunique);
+ }
+ sc->sc_hunique = mem_malloc(hunique_len);
+ if (sc->sc_hunique == NULL) {
+ goto done;
+ }
+ sc->sc_hunique_len = hunique_len;
+ MEMCPY(sc->sc_hunique, hunique, hunique_len);
+ }
+ MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);
+ sc->sc_state = PPPOE_STATE_PADO_SENT;
+ pppoe_send_pado(sc);
+ break;
+#endif /* PPPOE_SERVER */
+ case PPPOE_CODE_PADR:
+#ifdef PPPOE_SERVER
+ /*
+ * get sc from ac_cookie if IFF_PASSIVE
+ */
+ if (ac_cookie == NULL) {
+ /* be quiet if there is not a single pppoe instance */
+ printf("pppoe: received PADR but not includes ac_cookie\n");
+ goto done;
+ }
+ sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);
+ if (sc == NULL) {
+ /* be quiet if there is not a single pppoe instance */
+ if (!LIST_EMPTY(&pppoe_softc_list)) {
+ printf("pppoe: received PADR but could not find request for it\n");
+ }
+ goto done;
+ }
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
+ printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ goto done;
+ }
+ if (hunique) {
+ if (sc->sc_hunique) {
+ mem_free(sc->sc_hunique);
+ }
+ sc->sc_hunique = mem_malloc(hunique_len);
+ if (sc->sc_hunique == NULL) {
+ goto done;
+ }
+ sc->sc_hunique_len = hunique_len;
+ MEMCPY(sc->sc_hunique, hunique, hunique_len);
+ }
+ pppoe_send_pads(sc);
+ sc->sc_state = PPPOE_STATE_SESSION;
+ pppoe_linkstatus_up(sc); /* notify upper layers */
+ break;
+#else
+ /* ignore, we are no access concentrator */
+ goto done;
+#endif /* PPPOE_SERVER */
+ case PPPOE_CODE_PADO:
+ if (sc == NULL) {
+ /* be quiet if there is not a single pppoe instance */
+ if (pppoe_softc_list != NULL) {
+ printf("pppoe: received PADO but could not find request for it\n");
+ }
+ goto done;
+ }
+ if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
+ printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ goto done;
+ }
+ if (ac_cookie) {
+ sc->sc_ac_cookie_len = ac_cookie_len;
+ MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
+ }
+ MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));
+ sys_untimeout(pppoe_timeout, sc);
+ sc->sc_padr_retried = 0;
+ sc->sc_state = PPPOE_STATE_PADR_SENT;
+ if ((err = pppoe_send_padr(sc)) != 0) {
+ 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));
+ }
+ sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
+ break;
+ case PPPOE_CODE_PADS:
+ if (sc == NULL) {
+ goto done;
+ }
+ sc->sc_session = session;
+ sys_untimeout(pppoe_timeout, sc);
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session));
+ sc->sc_state = PPPOE_STATE_SESSION;
+ pppoe_linkstatus_up(sc); /* notify upper layers */
+ break;
+ case PPPOE_CODE_PADT:
+ if (sc == NULL) {
+ goto done;
+ }
+ pppoe_clear_softc(sc, "received PADT");
+ break;
+ default:
+ if(sc) {
+ printf("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
+ (u16_t)ph->code, session);
+ } else {
+ printf("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session);
+ }
+ break;
+ }
+
+done:
+ pbuf_free(pb);
+ return;
+}
+
+void
+pppoe_disc_input(struct netif *netif, struct pbuf *p)
+{
+ /* avoid error messages if there is not a single pppoe instance */
+ if (pppoe_softc_list != NULL) {
+ pppoe_dispatch_disc_pkt(netif, p);
+ } else {
+ pbuf_free(p);
+ }
+}
+
+void
+pppoe_data_input(struct netif *netif, struct pbuf *pb)
+{
+ u16_t session, plen;
+ struct pppoe_softc *sc;
+ struct pppoehdr *ph;
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
+ u8_t shost[ETHER_ADDR_LEN];
+#endif
+
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
+ MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));
+#endif
+ if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) {
+ /* bail out */
+ PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n"));
+ LINK_STATS_INC(link.lenerr);
+ goto drop;
+ }
+
+ pb = pppSingleBuf (pb);
+
+ if (pb->len <= PPPOE_HEADERLEN) {
+ printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len);
+ goto drop;
+ }
+
+ if (pb->len < sizeof(*ph)) {
+ printf("pppoe_data_input: could not get PPPoE header\n");
+ goto drop;
+ }
+ ph = (struct pppoehdr *)pb->payload;
+
+ if (ph->vertype != PPPOE_VERTYPE) {
+ printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype);
+ goto drop;
+ }
+ if (ph->code != 0) {
+ goto drop;
+ }
+
+ session = ntohs(ph->session);
+ sc = pppoe_find_softc_by_session(session, netif);
+ if (sc == NULL) {
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
+ printf("pppoe: input for unknown session 0x%x, sending PADT\n", session);
+ pppoe_send_padt(netif, session, shost);
+#endif
+ goto drop;
+ }
+
+ plen = ntohs(ph->plen);
+
+ if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) {
+ /* bail out */
+ PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n"));
+ LINK_STATS_INC(link.lenerr);
+ goto drop;
+ }
+
+ PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
+ pb->len, plen));
+
+ if (pb->len < plen) {
+ goto drop;
+ }
+
+ pppInProcOverEthernet(sc->sc_pd, pb);
+
+ return;
+
+drop:
+ pbuf_free(pb);
+}
+
+static err_t
+pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)
+{
+ struct eth_hdr *ethhdr;
+ u16_t etype;
+ err_t res;
+
+ if (!sc->sc_ethif) {
+ pbuf_free(pb);
+ return ERR_IF;
+ }
+
+ ethhdr = (struct eth_hdr *)pb->payload;
+ etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;
+ ethhdr->type = htons(etype);
+ MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr));
+ MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr));
+
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,
+ sc->sc_state, sc->sc_session,
+ sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5],
+ pb->tot_len));
+
+ res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);
+
+ pbuf_free(pb);
+
+ return res;
+}
+
+static err_t
+pppoe_send_padi(struct pppoe_softc *sc)
+{
+ struct pbuf *pb;
+ u8_t *p;
+ int len;
+#ifdef PPPOE_TODO
+ int l1 = 0, l2 = 0; /* XXX: gcc */
+#endif /* PPPOE_TODO */
+
+ if (sc->sc_state >PPPOE_STATE_PADI_SENT) {
+ PPPDEBUG(LOG_ERR, ("ERROR: pppoe_send_padi in state %d", sc->sc_state));
+ }
+
+ /* 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 */
+#ifdef PPPOE_TODO
+ if (sc->sc_service_name != NULL) {
+ l1 = (int)strlen(sc->sc_service_name);
+ len += l1;
+ }
+ if (sc->sc_concentrator_name != NULL) {
+ l2 = (int)strlen(sc->sc_concentrator_name);
+ len += 2 + 2 + l2;
+ }
+#endif /* PPPOE_TODO */
+ LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff",
+ sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff);
+
+ /* allocate a buffer */
+ pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len), PBUF_RAM);
+ if (!pb) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
+
+ p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
+ /* fill in pkt */
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len);
+ PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
+#ifdef PPPOE_TODO
+ if (sc->sc_service_name != NULL) {
+ PPPOE_ADD_16(p, l1);
+ MEMCPY(p, sc->sc_service_name, l1);
+ p += l1;
+ } else
+#endif /* PPPOE_TODO */
+ {
+ PPPOE_ADD_16(p, 0);
+ }
+#ifdef PPPOE_TODO
+ if (sc->sc_concentrator_name != NULL) {
+ PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);
+ PPPOE_ADD_16(p, l2);
+ MEMCPY(p, sc->sc_concentrator_name, l2);
+ p += l2;
+ }
+#endif /* PPPOE_TODO */
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sizeof(sc));
+ MEMCPY(p, &sc, sizeof sc);
+
+ /* send pkt */
+ return pppoe_output(sc, pb);
+}
+
+static void
+pppoe_timeout(void *arg)
+{
+ int retry_wait, err;
+ struct pppoe_softc *sc = (struct pppoe_softc*)arg;
+
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
+
+ switch (sc->sc_state) {
+ case PPPOE_STATE_PADI_SENT:
+ /*
+ * We have two basic ways of retrying:
+ * - Quick retry mode: try a few times in short sequence
+ * - Slow retry mode: we already had a connection successfully
+ * established and will try infinitely (without user
+ * intervention)
+ * We only enter slow retry mode if IFF_LINK1 (aka autodial)
+ * is not set.
+ */
+
+ /* initialize for quick retry mode */
+ retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);
+
+ sc->sc_padi_retried++;
+ if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
+#if 0
+ if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
+ /* slow retry mode */
+ retry_wait = PPPOE_SLOW_RETRY;
+ } else
+#endif
+ {
+ pppoe_abort_connect(sc);
+ return;
+ }
+ }
+ 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));
+ }
+ sys_timeout(retry_wait, pppoe_timeout, sc);
+ break;
+
+ case PPPOE_STATE_PADR_SENT:
+ sc->sc_padr_retried++;
+ if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
+ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
+ sc->sc_state = PPPOE_STATE_PADI_SENT;
+ sc->sc_padr_retried = 0;
+ if ((err = pppoe_send_padi(sc)) != 0) {
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
+ }
+ sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);
+ 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));
+ }
+ sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
+ break;
+ case PPPOE_STATE_CLOSING:
+ pppoe_do_disconnect(sc);
+ break;
+ default:
+ return; /* all done, work in peace */
+ }
+}
+
+/* Start a connection (i.e. initiate discovery phase) */
+int
+pppoe_connect(struct pppoe_softc *sc)
+{
+ int err;
+
+ if (sc->sc_state != PPPOE_STATE_INITIAL) {
+ return EBUSY;
+ }
+
+#ifdef PPPOE_SERVER
+ /* wait PADI if IFF_PASSIVE */
+ if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
+ return 0;
+ }
+#endif
+ /* save state, in case we fail to send PADI */
+ sc->sc_state = PPPOE_STATE_PADI_SENT;
+ sc->sc_padr_retried = 0;
+ err = pppoe_send_padi(sc);
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
+ sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);
+ return err;
+}
+
+/* disconnect */
+void
+pppoe_disconnect(struct pppoe_softc *sc)
+{
+ if (sc->sc_state < PPPOE_STATE_SESSION) {
+ return;
+ }
+ /*
+ * Do not call pppoe_disconnect here, the upper layer state
+ * machine gets confused by this. We must return from this
+ * function and defer disconnecting to the timeout handler.
+ */
+ sc->sc_state = PPPOE_STATE_CLOSING;
+ sys_timeout(20, pppoe_timeout, sc);
+}
+
+static int
+pppoe_do_disconnect(struct pppoe_softc *sc)
+{
+ int err;
+
+ if (sc->sc_state < PPPOE_STATE_SESSION) {
+ err = EBUSY;
+ } else {
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
+ err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);
+ }
+
+ /* cleanup softc */
+ sc->sc_state = PPPOE_STATE_INITIAL;
+ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
+ sc->sc_ac_cookie_len = 0;
+#ifdef PPPOE_SERVER
+ if (sc->sc_hunique) {
+ mem_free(sc->sc_hunique);
+ sc->sc_hunique = NULL;
+ }
+ sc->sc_hunique_len = 0;
+#endif
+ sc->sc_session = 0;
+
+ sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */
+
+ return err;
+}
+
+/* Connection attempt aborted */
+static void
+pppoe_abort_connect(struct pppoe_softc *sc)
+{
+ printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ sc->sc_state = PPPOE_STATE_CLOSING;
+
+ sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */
+
+ /* clear connection state */
+ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
+ sc->sc_state = PPPOE_STATE_INITIAL;
+}
+
+/* Send a PADR packet */
+static err_t
+pppoe_send_padr(struct pppoe_softc *sc)
+{
+ struct pbuf *pb;
+ u8_t *p;
+ size_t len;
+#ifdef PPPOE_TODO
+ size_t l1 = 0; /* XXX: gcc */
+#endif /* PPPOE_TODO */
+
+ if (sc->sc_state != PPPOE_STATE_PADR_SENT) {
+ return ERR_CONN;
+ }
+
+ len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */
+#ifdef PPPOE_TODO
+ if (sc->sc_service_name != NULL) { /* service name tag maybe empty */
+ l1 = strlen(sc->sc_service_name);
+ len += l1;
+ }
+#endif /* PPPOE_TODO */
+ if (sc->sc_ac_cookie_len > 0) {
+ len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */
+ }
+ LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff",
+ sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff);
+ pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len), PBUF_RAM);
+ if (!pb) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
+ p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);
+ PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
+#ifdef PPPOE_TODO
+ if (sc->sc_service_name != NULL) {
+ PPPOE_ADD_16(p, l1);
+ MEMCPY(p, sc->sc_service_name, l1);
+ p += l1;
+ } else
+#endif /* PPPOE_TODO */
+ {
+ PPPOE_ADD_16(p, 0);
+ }
+ if (sc->sc_ac_cookie_len > 0) {
+ PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
+ PPPOE_ADD_16(p, sc->sc_ac_cookie_len);
+ MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);
+ p += sc->sc_ac_cookie_len;
+ }
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sizeof(sc));
+ MEMCPY(p, &sc, sizeof sc);
+
+ return pppoe_output(sc, pb);
+}
+
+/* send a PADT packet */
+static err_t
+pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)
+{
+ struct pbuf *pb;
+ struct eth_hdr *ethhdr;
+ err_t res;
+ u8_t *p;
+
+ pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM);
+ if (!pb) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
+
+ ethhdr = (struct eth_hdr *)pb->payload;
+ ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC);
+ MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));
+ MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr));
+
+ p = (u8_t*)(ethhdr + 1);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);
+
+ res = outgoing_if->linkoutput(outgoing_if, pb);
+
+ pbuf_free(pb);
+
+ return res;
+}
+
+#ifdef PPPOE_SERVER
+static err_t
+pppoe_send_pado(struct pppoe_softc *sc)
+{
+ struct pbuf *pb;
+ u8_t *p;
+ size_t len;
+
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
+ return ERR_CONN;
+ }
+
+ /* calc length */
+ len = 0;
+ /* include ac_cookie */
+ len += 2 + 2 + sizeof(sc);
+ /* include hunique */
+ len += 2 + 2 + sc->sc_hunique_len;
+ pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
+ if (!pb) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
+ p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
+ PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
+ PPPOE_ADD_16(p, sizeof(sc));
+ MEMCPY(p, &sc, sizeof(sc));
+ p += sizeof(sc);
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sc->sc_hunique_len);
+ MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
+ return pppoe_output(sc, pb);
+}
+
+static err_t
+pppoe_send_pads(struct pppoe_softc *sc)
+{
+ struct pbuf *pb;
+ u8_t *p;
+ size_t len, l1 = 0; /* XXX: gcc */
+
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
+ return ERR_CONN;
+ }
+
+ sc->sc_session = mono_time.tv_sec % 0xff + 1;
+ /* calc length */
+ len = 0;
+ /* include hunique */
+ len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/
+ if (sc->sc_service_name != NULL) { /* service name tag maybe empty */
+ l1 = strlen(sc->sc_service_name);
+ len += l1;
+ }
+ pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
+ if (!pb) {
+ return ERR_MEM;
+ }
+ LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
+ p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
+ PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
+ if (sc->sc_service_name != NULL) {
+ PPPOE_ADD_16(p, l1);
+ MEMCPY(p, sc->sc_service_name, l1);
+ p += l1;
+ } else {
+ PPPOE_ADD_16(p, 0);
+ }
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sc->sc_hunique_len);
+ MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
+ return pppoe_output(sc, pb);
+}
+#endif
+
+err_t
+pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)
+{
+ u8_t *p;
+ size_t len;
+
+ /* are we ready to process data yet? */
+ if (sc->sc_state < PPPOE_STATE_SESSION) {
+ /*sppp_flush(&sc->sc_sppp.pp_if);*/
+ pbuf_free(pb);
+ return ERR_CONN;
+ }
+
+ len = pb->tot_len;
+
+ /* make room for Ethernet header - should not fail */
+ if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) {
+ /* bail out */
+ PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
+ LINK_STATS_INC(link.lenerr);
+ pbuf_free(pb);
+ return ERR_BUF;
+ }
+
+ p = (u8_t*)pb->payload + sizeof(struct eth_hdr);
+ PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
+
+ return pppoe_output(sc, pb);
+}
+
+#if 0 /*def PFIL_HOOKS*/
+static int
+pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)
+{
+ struct pppoe_softc *sc;
+ int s;
+
+ if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {
+ return 0;
+ }
+
+ LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
+ if (sc->sc_ethif != ifp) {
+ continue;
+ }
+ if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {
+ sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+ printf("%c%c%"U16_F": ethernet interface detached, going down\n",
+ sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
+ }
+ sc->sc_ethif = NULL;
+ pppoe_clear_softc(sc, "ethernet interface detached");
+ }
+
+ return 0;
+}
+#endif
+
+static void
+pppoe_clear_softc(struct pppoe_softc *sc, const char *message)
+{
+ LWIP_UNUSED_ARG(message);
+
+ /* stop timer */
+ sys_untimeout(pppoe_timeout, sc);
+ PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message));
+
+ /* fix our state */
+ sc->sc_state = PPPOE_STATE_INITIAL;
+
+ /* notify upper layers */
+ sc->sc_linkStatusCB(sc->sc_pd, 0);
+
+ /* clean up softc */
+ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
+ sc->sc_ac_cookie_len = 0;
+ sc->sc_session = 0;
+}
+
+#endif /* PPPOE_SUPPORT */
+
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pppdebug.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pppdebug.h
new file mode 100644
index 0000000000..81349971db
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/pppdebug.h
@@ -0,0 +1,73 @@
+/*****************************************************************************
+* pppdebug.h - System debugging utilities.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* portions Copyright (c) 1998 Global Election Systems Inc.
+* portions Copyright (c) 2001 by Cognizant Pty Ltd.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY (please don't use tabs!)
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Original.
+*
+*****************************************************************************
+*/
+#ifndef PPPDEBUG_H
+#define PPPDEBUG_H
+
+/* Trace levels. */
+#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE)
+#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE)
+#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING)
+#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING)
+#define LOG_INFO (PPP_DEBUG)
+#define LOG_DETAIL (PPP_DEBUG)
+#define LOG_DEBUG (PPP_DEBUG)
+
+
+#define TRACELCP PPP_DEBUG
+
+#if PPP_DEBUG
+
+#define AUTHDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define IPCPDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define UPAPDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define LCPDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define FSMDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define CHAPDEBUG(a, b) LWIP_DEBUGF(a, b)
+#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b)
+
+#else /* PPP_DEBUG */
+
+#define AUTHDEBUG(a, b)
+#define IPCPDEBUG(a, b)
+#define UPAPDEBUG(a, b)
+#define LCPDEBUG(a, b)
+#define FSMDEBUG(a, b)
+#define CHAPDEBUG(a, b)
+#define PPPDEBUG(a, b)
+
+#endif /* PPP_DEBUG */
+
+#endif /* PPPDEBUG_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.c
new file mode 100644
index 0000000000..2f35caf6a0
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.c
@@ -0,0 +1,249 @@
+/*****************************************************************************
+* randm.c - Random number generator program file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1998 by Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
+* Extracted from avos.
+*****************************************************************************/
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "md5.h"
+#include "randm.h"
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include <string.h>
+
+#if MD5_SUPPORT /* this module depends on MD5 */
+#define RANDPOOLSZ 16 /* Bytes stored in the pool of randomness. */
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static char randPool[RANDPOOLSZ]; /* Pool of randomness. */
+static long randCount = 0; /* Pseudo-random incrementer */
+
+
+/***********************************/
+/*** PUBLIC FUNCTION DEFINITIONS ***/
+/***********************************/
+/*
+ * Initialize the random number generator.
+ *
+ * Since this is to be called on power up, we don't have much
+ * system randomess to work with. Here all we use is the
+ * real-time clock. We'll accumulate more randomness as soon
+ * as things start happening.
+ */
+void
+avRandomInit()
+{
+ avChurnRand(NULL, 0);
+}
+
+/*
+ * Churn the randomness pool on a random event. Call this early and often
+ * on random and semi-random system events to build randomness in time for
+ * usage. For randomly timed events, pass a null pointer and a zero length
+ * and this will use the system timer and other sources to add randomness.
+ * If new random data is available, pass a pointer to that and it will be
+ * included.
+ *
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427
+ */
+void
+avChurnRand(char *randData, u32_t randLen)
+{
+ MD5_CTX md5;
+
+ /* LWIP_DEBUGF(LOG_INFO, ("churnRand: %u@%P\n", randLen, randData)); */
+ MD5Init(&md5);
+ MD5Update(&md5, (u_char *)randPool, sizeof(randPool));
+ if (randData) {
+ MD5Update(&md5, (u_char *)randData, randLen);
+ } else {
+ struct {
+ /* INCLUDE fields for any system sources of randomness */
+ char foobar;
+ } sysData;
+
+ /* Load sysData fields here. */
+ MD5Update(&md5, (u_char *)&sysData, sizeof(sysData));
+ }
+ MD5Final((u_char *)randPool, &md5);
+/* LWIP_DEBUGF(LOG_INFO, ("churnRand: -> 0\n")); */
+}
+
+/*
+ * Use the random pool to generate random data. This degrades to pseudo
+ * random when used faster than randomness is supplied using churnRand().
+ * Note: It's important that there be sufficient randomness in randPool
+ * before this is called for otherwise the range of the result may be
+ * narrow enough to make a search feasible.
+ *
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427
+ *
+ * XXX Why does he not just call churnRand() for each block? Probably
+ * so that you don't ever publish the seed which could possibly help
+ * predict future values.
+ * XXX Why don't we preserve md5 between blocks and just update it with
+ * randCount each time? Probably there is a weakness but I wish that
+ * it was documented.
+ */
+void
+avGenRand(char *buf, u32_t bufLen)
+{
+ MD5_CTX md5;
+ u_char tmp[16];
+ u32_t n;
+
+ while (bufLen > 0) {
+ n = LWIP_MIN(bufLen, RANDPOOLSZ);
+ MD5Init(&md5);
+ MD5Update(&md5, (u_char *)randPool, sizeof(randPool));
+ MD5Update(&md5, (u_char *)&randCount, sizeof(randCount));
+ MD5Final(tmp, &md5);
+ randCount++;
+ MEMCPY(buf, tmp, n);
+ buf += n;
+ bufLen -= n;
+ }
+}
+
+/*
+ * Return a new random number.
+ */
+u32_t
+avRandom()
+{
+ u32_t newRand;
+
+ avGenRand((char *)&newRand, sizeof(newRand));
+
+ return newRand;
+}
+
+#else /* MD5_SUPPORT */
+
+/*****************************/
+/*** LOCAL DATA STRUCTURES ***/
+/*****************************/
+static int avRandomized = 0; /* Set when truely randomized. */
+static u32_t avRandomSeed = 0; /* 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.
+ */
+void
+avRandomInit()
+{
+#if 0
+ /* Get a pointer into the last 4 bytes of clockBuf. */
+ u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]);
+
+ /*
+ * Initialize our seed using the real-time clock, the idle
+ * counter, the millisecond timer, and the hardware timer
+ * tick counter. The real-time clock and the hardware
+ * tick counter are the best sources of randomness but
+ * since the tick counter is only 16 bit (and truncated
+ * at that), the idle counter and millisecond timer
+ * (which may be small values) are added to help
+ * randomize the lower 16 bits of the seed.
+ */
+ readClk();
+ avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr
+ + ppp_mtime() + ((u32_t)TM1 << 16) + TM1;
+#else
+ avRandomSeed += sys_jiffies(); /* XXX */
+#endif
+
+ /* Initialize the Borland random number generator. */
+ srand((unsigned)avRandomSeed);
+}
+
+/*
+ * Randomize our random seed value. Here we use the fact that
+ * this function is called at *truely 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.
+ */
+void
+avRandomize(void)
+{
+ static u32_t last_jiffies;
+
+ if (!avRandomized) {
+ avRandomized = !0;
+ avRandomInit();
+ /* The initialization function also updates the seed. */
+ } else {
+ /* avRandomSeed += (avRandomSeed << 16) + TM1; */
+ avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */
+ }
+ last_jiffies = sys_jiffies();
+}
+
+/*
+ * Return a new 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
+ * operator or network events in which case it will be pseudo random
+ * seeded by the real time clock.
+ */
+u32_t
+avRandom()
+{
+ return ((((u32_t)rand() << 16) + rand()) + avRandomSeed);
+}
+
+#endif /* MD5_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.h
new file mode 100644
index 0000000000..a0984b0202
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/randm.h
@@ -0,0 +1,81 @@
+/*****************************************************************************
+* randm.h - Random number generator header file.
+*
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
+* Copyright (c) 1998 Global Election Systems Inc.
+*
+* The authors hereby grant permission to use, copy, modify, distribute,
+* and license this software and its documentation for any purpose, provided
+* that existing copyright notices are retained in all copies and that this
+* notice and the following disclaimer are included verbatim in any
+* distributions. No written agreement, license, or royalty fee is required
+* for any of the authorized uses.
+*
+* THIS SOFTWARE IS PROVIDED BY THE 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 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.
+*
+******************************************************************************
+* REVISION HISTORY
+*
+* 03-01-01 Marc Boucher <marc@mbsi.ca>
+* Ported to lwIP.
+* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
+* Extracted from avos.
+*****************************************************************************/
+
+#ifndef RANDM_H
+#define RANDM_H
+
+/***********************
+*** PUBLIC FUNCTIONS ***
+***********************/
+/*
+ * Initialize the random number generator.
+ */
+void avRandomInit(void);
+
+/*
+ * Churn the randomness pool on a random event. Call this early and often
+ * on random and semi-random system events to build randomness in time for
+ * usage. For randomly timed events, pass a null pointer and a zero length
+ * and this will use the system timer and other sources to add randomness.
+ * If new random data is available, pass a pointer to that and it will be
+ * included.
+ */
+void avChurnRand(char *randData, u32_t randLen);
+
+/*
+ * Randomize our random seed value. To be called for truely random events
+ * such as user operations and network traffic.
+ */
+#if MD5_SUPPORT
+#define avRandomize() avChurnRand(NULL, 0)
+#else /* MD5_SUPPORT */
+void avRandomize(void);
+#endif /* MD5_SUPPORT */
+
+/*
+ * Use the random pool to generate random data. This degrades to pseudo
+ * random when used faster than randomness is supplied using churnRand().
+ * Thus it's important to make sure that the results of this are not
+ * published directly because one could predict the next result to at
+ * least some degree. Also, it's important to get a good seed before
+ * the first use.
+ */
+void avGenRand(char *buf, u32_t bufLen);
+
+/*
+ * Return a new random number.
+ */
+u32_t avRandom(void);
+
+
+#endif /* RANDM_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.c
new file mode 100644
index 0000000000..b7f2d54c62
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.c
@@ -0,0 +1,652 @@
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * Initial distribution.
+ *
+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
+ * so that the entire packet being decompressed doesn't have
+ * to be in contiguous memory (just the compressed header).
+ *
+ * Modified March 1998 by Guy Lancaster, glanca@gesn.com,
+ * for a 16 bit processor.
+ */
+
+#include "lwip/opt.h"
+
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+#include "ppp.h"
+#include "pppdebug.h"
+
+#include "vj.h"
+
+#include <string.h>
+
+#if VJ_SUPPORT
+
+#if LINK_STATS
+#define INCR(counter) ++comp->stats.counter
+#else
+#define INCR(counter)
+#endif
+
+void
+vj_compress_init(struct vjcompress *comp)
+{
+ register u_char i;
+ register struct cstate *tstate = comp->tstate;
+
+#if MAX_SLOTS == 0
+ memset((char *)comp, 0, sizeof(*comp));
+#endif
+ comp->maxSlotIndex = MAX_SLOTS - 1;
+ comp->compressSlot = 0; /* Disable slot ID compression by default. */
+ for (i = MAX_SLOTS - 1; i > 0; --i) {
+ tstate[i].cs_id = i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+ tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = VJF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+ if ((u_short)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (u_char)(n); \
+ cp[0] = (u_char)((n) >> 8); \
+ cp += 2; \
+ } else { \
+ *cp++ = (u_char)(n); \
+ } \
+}
+#define ENCODEZ(n) { \
+ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (u_char)(n); \
+ cp[0] = (u_char)((n) >> 8); \
+ cp += 2; \
+ } else { \
+ *cp++ = (u_char)(n); \
+ } \
+}
+
+#define DECODEL(f) { \
+ if (*cp == 0) {\
+ u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \
+ (f) = htonl(tmp); \
+ cp += 3; \
+ } else { \
+ u32_t tmp = ntohl(f) + (u32_t)*cp++; \
+ (f) = htonl(tmp); \
+ } \
+}
+
+#define DECODES(f) { \
+ if (*cp == 0) {\
+ u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \
+ (f) = htons(tmp); \
+ cp += 3; \
+ } else { \
+ u_short tmp = ntohs(f) + (u_short)*cp++; \
+ (f) = htons(tmp); \
+ } \
+}
+
+#define DECODEU(f) { \
+ if (*cp == 0) {\
+ (f) = htons(((u_short)cp[1] << 8) | cp[2]); \
+ cp += 3; \
+ } else { \
+ (f) = htons((u_short)*cp++); \
+ } \
+}
+
+/*
+ * vj_compress_tcp - Attempt to do Van Jacobson header compression on a
+ * packet. This assumes that nb and comp are not null and that the first
+ * buffer of the chain contains a valid IP header.
+ * Return the VJ type code indicating whether or not the packet was
+ * compressed.
+ */
+u_int
+vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb)
+{
+ register struct ip_hdr *ip = (struct ip_hdr *)pb->payload;
+ register struct cstate *cs = comp->last_cs->cs_next;
+ register u_short hlen = IPH_HL(ip);
+ register struct tcp_hdr *oth;
+ register struct tcp_hdr *th;
+ register u_short deltaS, deltaA;
+ register u_long deltaL;
+ register u_int changes = 0;
+ u_char new_seq[16];
+ register u_char *cp = new_seq;
+
+ /*
+ * Check that the packet is IP proto TCP.
+ */
+ if (IPH_PROTO(ip) != IP_PROTO_TCP) {
+ return (TYPE_IP);
+ }
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't
+ * `compressible' (i.e., ACK isn't set or some other control bit is
+ * set).
+ */
+ if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || pb->tot_len < 40) {
+ return (TYPE_IP);
+ }
+ th = (struct tcp_hdr *)&((long *)ip)[hlen];
+ if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
+ return (TYPE_IP);
+ }
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
+ * to locate (or create) the connection state. Special case the
+ * most recently used connection since it's most likely to be used
+ * again & we don't have to do any reordering if it's used.
+ */
+ INCR(vjs_packets);
+ if (!ip_addr_cmp(&ip->src, &cs->cs_ip.src)
+ || !ip_addr_cmp(&ip->dest, &cs->cs_ip.dest)
+ || *(long *)th != ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) {
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with
+ * last_cs pointing to the end of the list. The
+ * list is kept in lru order by moving a state to the
+ * head of the list whenever it is referenced. Since
+ * the list is short and, empirically, the connection
+ * we want is almost always near the front, we locate
+ * states via linear search. If we don't find a state
+ * for the datagram, the oldest state is (re-)used.
+ */
+ register struct cstate *lcs;
+ register struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs; cs = cs->cs_next;
+ INCR(vjs_searches);
+ if (ip_addr_cmp(&ip->src, &cs->cs_ip.src)
+ && ip_addr_cmp(&ip->dest, &cs->cs_ip.dest)
+ && *(long *)th == ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) {
+ goto found;
+ }
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation.
+ * Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set
+ * last_cs to update the lru linkage.
+ */
+ INCR(vjs_misses);
+ comp->last_cs = lcs;
+ hlen += TCPH_OFFSET(th);
+ hlen <<= 2;
+ /* Check that the IP/TCP headers are contained in the first buffer. */
+ if (hlen > pb->len) {
+ return (TYPE_IP);
+ }
+ goto uncompressed;
+
+ found:
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if (cs == lastcs) {
+ comp->last_cs = lcs;
+ } else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ oth = (struct tcp_hdr *)&((long *)&cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += TCPH_OFFSET(th);
+ hlen <<= 2;
+ /* Check that the IP/TCP headers are contained in the first buffer. */
+ if (hlen > pb->len) {
+ PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
+ return (TYPE_IP);
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first
+ * line of the `if' checks the IP protocol version, header length &
+ * type of service. The 2nd line checks the "Don't fragment" bit.
+ * The 3rd line checks the time-to-live and protocol (the protocol
+ * check is unnecessary but costless). The 4th line checks the TCP
+ * header length. The 5th line checks IP options, if any. The 6th
+ * line checks TCP options, if any. If any of these things are
+ * different between the previous & current datagram, we send the
+ * current datagram `uncompressed'.
+ */
+ if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0]
+ || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3]
+ || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4]
+ || TCPH_OFFSET(th) != TCPH_OFFSET(oth)
+ || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
+ || (TCPH_OFFSET(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_OFFSET(th) - 5) << 2))) {
+ goto uncompressed;
+ }
+
+ /*
+ * Figure out which of the changing fields changed. The
+ * receiver expects changes in the order: urgent, window,
+ * ack, seq (the order minimizes the number of temporaries
+ * needed in this section of code).
+ */
+ if (TCPH_FLAGS(th) & TCP_URG) {
+ deltaS = ntohs(th->urgp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->urgp != oth->urgp) {
+ /* argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793
+ * doesn't prohibit the change so we have to deal
+ * with it. */
+ goto uncompressed;
+ }
+
+ if ((deltaS = (u_short)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+
+ if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) {
+ if (deltaL > 0xffff) {
+ goto uncompressed;
+ }
+ deltaA = (u_short)deltaL;
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+
+ if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) {
+ if (deltaL > 0xffff) {
+ goto uncompressed;
+ }
+ deltaS = (u_short)deltaL;
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+
+ switch(changes) {
+ case 0:
+ /*
+ * Nothing changed. If this packet contains data and the
+ * last one didn't, this is probably a data packet following
+ * an ack (normal on an interactive connection) and we send
+ * it compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
+ ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
+ break;
+ }
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /*
+ * actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+ goto uncompressed;
+
+ case NEW_S|NEW_A:
+ if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip)));
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+ if (TCPH_FLAGS(th) & TCP_PSH) {
+ changes |= TCP_PUSH_BIT;
+ }
+ /*
+ * Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = ntohs(th->chksum);
+ BCOPY(ip, &cs->cs_ip, hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet.
+ * (cp - new_seq) is the number of bytes we need for compressed
+ * sequence numbers. In addition we need one byte for the change
+ * mask, one for the connection id and two for the tcp checksum.
+ * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
+ * many bytes of the original packet to toss so subtract the two to
+ * get the new packet size.
+ */
+ deltaS = (u_short)(cp - new_seq);
+ if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ if(pbuf_header(pb, -hlen)){
+ /* Can we cope with this failing? Just assert for now */
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ }
+ cp = (u_char *)pb->payload;
+ *cp++ = (u_char)(changes | NEW_C);
+ *cp++ = cs->cs_id;
+ } else {
+ hlen -= deltaS + 3;
+ if(pbuf_header(pb, -hlen)) {
+ /* Can we cope with this failing? Just assert for now */
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ }
+ cp = (u_char *)pb->payload;
+ *cp++ = (u_char)changes;
+ }
+ *cp++ = (u_char)(deltaA >> 8);
+ *cp++ = (u_char)deltaA;
+ BCOPY(new_seq, cp, deltaS);
+ INCR(vjs_compressed);
+ return (TYPE_COMPRESSED_TCP);
+
+ /*
+ * Update connection state cs & send uncompressed packet (that is,
+ * a regular ip/tcp packet but with the 'conversation id' we hope
+ * to use on future compressed packets in the protocol field).
+ */
+uncompressed:
+ BCOPY(ip, &cs->cs_ip, hlen);
+ IPH_PROTO_SET(ip, cs->cs_id);
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+/*
+ * Called when we may have missed a packet.
+ */
+void
+vj_uncompress_err(struct vjcompress *comp)
+{
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+}
+
+/*
+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
+ * Return 0 on success, -1 on failure.
+ */
+int
+vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
+{
+ register u_int hlen;
+ register struct cstate *cs;
+ register struct ip_hdr *ip;
+
+ ip = (struct ip_hdr *)nb->payload;
+ hlen = IPH_HL(ip) << 2;
+ if (IPH_PROTO(ip) >= MAX_SLOTS
+ || hlen + sizeof(struct tcp_hdr) > nb->len
+ || (hlen += TCPH_OFFSET(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2)
+ > nb->len
+ || hlen > MAX_HDR) {
+ PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
+ IPH_PROTO(ip), hlen, nb->len));
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+ return -1;
+ }
+ cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
+ comp->flags &=~ VJF_TOSS;
+ IPH_PROTO_SET(ip, IP_PROTO_TCP);
+ BCOPY(ip, &cs->cs_ip, hlen);
+ cs->cs_hlen = (u_short)hlen;
+ INCR(vjs_uncompressedin);
+ return 0;
+}
+
+/*
+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.
+ * The packet is composed of a buffer chain and the first buffer
+ * must contain an accurate chain length.
+ * The first buffer must include the entire compressed TCP/IP header.
+ * This procedure replaces the compressed header with the uncompressed
+ * header and returns the length of the VJ header.
+ */
+int
+vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
+{
+ u_char *cp;
+ struct tcp_hdr *th;
+ struct cstate *cs;
+ u_short *bp;
+ struct pbuf *n0 = *nb;
+ u32_t tmp;
+ u_int vjlen, hlen, changes;
+
+ INCR(vjs_compressedin);
+ cp = (u_char *)n0->payload;
+ changes = *cp++;
+ if (changes & NEW_C) {
+ /*
+ * Make sure the state index is in range, then grab the state.
+ * If we have a good state index, clear the 'discard' flag.
+ */
+ if (*cp >= MAX_SLOTS) {
+ PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp));
+ goto bad;
+ }
+
+ comp->flags &=~ VJF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+ /*
+ * this packet has an implicit state index. If we've
+ * had a line error since the last time we got an
+ * explicit state index, we have to toss the packet.
+ */
+ if (comp->flags & VJF_TOSS) {
+ PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n"));
+ INCR(vjs_tossed);
+ return (-1);
+ }
+ }
+ cs = &comp->rstate[comp->last_recv];
+ hlen = IPH_HL(&cs->cs_ip) << 2;
+ th = (struct tcp_hdr *)&((u_char *)&cs->cs_ip)[hlen];
+ th->chksum = htons((*cp << 8) | cp[1]);
+ cp += 2;
+ if (changes & TCP_PUSH_BIT) {
+ TCPH_SET_FLAG(th, TCP_PSH);
+ } else {
+ TCPH_UNSET_FLAG(th, TCP_PSH);
+ }
+
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
+ /* some compilers can't nest inline assembler.. */
+ tmp = ntohl(th->ackno) + i;
+ th->ackno = htonl(tmp);
+ tmp = ntohl(th->seqno) + i;
+ th->seqno = htonl(tmp);
+ }
+ break;
+
+ case SPECIAL_D:
+ /* some compilers can't nest inline assembler.. */
+ tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
+ th->seqno = htonl(tmp);
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ TCPH_SET_FLAG(th, TCP_URG);
+ DECODEU(th->urgp);
+ } else {
+ TCPH_UNSET_FLAG(th, TCP_URG);
+ }
+ if (changes & NEW_W) {
+ DECODES(th->wnd);
+ }
+ if (changes & NEW_A) {
+ DECODEL(th->ackno);
+ }
+ if (changes & NEW_S) {
+ DECODEL(th->seqno);
+ }
+ break;
+ }
+ if (changes & NEW_I) {
+ DECODES(cs->cs_ip._id);
+ } else {
+ IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1);
+ IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip)));
+ }
+
+ /*
+ * At this point, cp points to the first byte of data in the
+ * packet. Fill in the IP total length and update the IP
+ * header checksum.
+ */
+ vjlen = (u_short)(cp - (u_char*)n0->payload);
+ if (n0->len < vjlen) {
+ /*
+ * We must have dropped some characters (crc should detect
+ * this but the old slip framing won't)
+ */
+ PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n",
+ n0->len, vjlen));
+ goto bad;
+ }
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ tmp = n0->tot_len - vjlen + cs->cs_hlen;
+ IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp));
+#else
+ IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen));
+#endif
+
+ /* recompute the ip header checksum */
+ bp = (u_short *) &cs->cs_ip;
+ IPH_CHKSUM_SET(&cs->cs_ip, 0);
+ for (tmp = 0; hlen > 0; hlen -= 2) {
+ tmp += *bp++;
+ }
+ tmp = (tmp & 0xffff) + (tmp >> 16);
+ tmp = (tmp & 0xffff) + (tmp >> 16);
+ IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~tmp));
+
+ /* Remove the compressed header and prepend the uncompressed header. */
+ if(pbuf_header(n0, -((s16_t)(vjlen)))) {
+ /* Can we cope with this failing? Just assert for now */
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ goto bad;
+ }
+
+ if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
+ struct pbuf *np, *q;
+ u8_t *bufptr;
+
+ np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
+ if(!np) {
+ PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
+ goto bad;
+ }
+
+ if(pbuf_header(np, -cs->cs_hlen)) {
+ /* Can we cope with this failing? Just assert for now */
+ LWIP_ASSERT("pbuf_header failed\n", 0);
+ goto bad;
+ }
+
+ bufptr = n0->payload;
+ for(q = np; q != NULL; q = q->next) {
+ MEMCPY(q->payload, bufptr, q->len);
+ bufptr += q->len;
+ }
+
+ if(n0->next) {
+ pbuf_chain(np, n0->next);
+ pbuf_dechain(n0);
+ }
+ pbuf_free(n0);
+ n0 = np;
+ }
+
+ if(pbuf_header(n0, cs->cs_hlen)) {
+ struct pbuf *np;
+
+ LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
+ np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
+ if(!np) {
+ PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
+ goto bad;
+ }
+ pbuf_cat(np, n0);
+ n0 = np;
+ }
+ LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
+ MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
+
+ *nb = n0;
+
+ return vjlen;
+
+bad:
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+ return (-1);
+}
+
+#endif /* VJ_SUPPORT */
+
+#endif /* PPP_SUPPORT */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.h
new file mode 100644
index 0000000000..fad1213646
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/vj.h
@@ -0,0 +1,156 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * 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.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef VJ_H
+#define VJ_H
+
+#include "lwip/ip.h"
+#include "lwip/tcp_impl.h"
+
+#define MAX_SLOTS 16 /* must be > 2 and < 256 */
+#define MAX_HDR 128
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * 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
+ * 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
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used state (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */
+ } vjcs_u;
+};
+#define cs_ip vjcs_u.csu_ip
+#define cs_hdr vjcs_u.csu_hdr
+
+
+struct vjstat {
+ unsigned long vjs_packets; /* outbound packets */
+ unsigned long vjs_compressed; /* outbound compressed packets */
+ unsigned long vjs_searches; /* searches for connection state */
+ unsigned long vjs_misses; /* times couldn't find conn. state */
+ unsigned long vjs_uncompressedin; /* inbound uncompressed packets */
+ unsigned long vjs_compressedin; /* inbound compressed packets */
+ unsigned long vjs_errorin; /* inbound unknown type packets */
+ unsigned long vjs_tossed; /* inbound packets tossed because of error */
+};
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+struct vjcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+ u_char maxSlotIndex;
+ u_char compressSlot; /* Flag indicating OK to compress slot ID. */
+#if LINK_STATS
+ struct vjstat stats;
+#endif
+ struct cstate tstate[MAX_SLOTS]; /* xmit connection states */
+ struct cstate rstate[MAX_SLOTS]; /* receive connection states */
+};
+
+/* flag values */
+#define VJF_TOSS 1U /* tossing rcvd frames because of input err */
+
+extern void vj_compress_init (struct vjcompress *comp);
+extern u_int vj_compress_tcp (struct vjcompress *comp, struct pbuf *pb);
+extern void vj_uncompress_err (struct vjcompress *comp);
+extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp);
+extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp);
+
+#endif /* VJ_H */
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/slipif.c b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/slipif.c
new file mode 100644
index 0000000000..c19333dd70
--- /dev/null
+++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/slipif.c
@@ -0,0 +1,367 @@
+/**
+ * @file
+ * SLIP Interface
+ *
+ */
+
+/*
+ * 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. 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 built upon the file: src/arch/rtxc/netif/sioslip.c
+ *
+ * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
+ */
+
+/*
+ * 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
+ */
+
+#include "netif/slipif.h"
+#include "lwip/opt.h"
+
+#if LWIP_HAVE_SLIPIF
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "lwip/sio.h"
+
+#define SLIP_BLOCK 1
+#define SLIP_DONTBLOCK 0
+
+#define SLIP_END 0300 /* 0xC0 */
+#define SLIP_ESC 0333 /* 0xDB */
+#define SLIP_ESC_END 0334 /* 0xDC */
+#define SLIP_ESC_ESC 0335 /* 0xDD */
+
+#define SLIP_MAX_SIZE 1500
+
+enum slipif_recv_state {
+ SLIP_RECV_NORMAL,
+ SLIP_RECV_ESCAPE,
+};
+
+struct slipif_priv {
+ sio_fd_t sd;
+ /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
+ struct pbuf *p, *q;
+ enum slipif_recv_state state;
+ u16_t i, recved;
+};
+
+/**
+ * Send a pbuf doing the necessary SLIP encapsulation
+ *
+ * Uses the serial layer's sio_send()
+ *
+ * @param netif the lwip network interface structure for this slipif
+ * @param p the pbuf chaing packet to send
+ * @param ipaddr the ip address to send the packet to (not used for slipif)
+ * @return always returns ERR_OK since the serial layer does not provide return values
+ */
+err_t
+slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
+{
+ struct slipif_priv *priv;
+ struct pbuf *q;
+ u16_t i;
+ u8_t c;
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
+ LWIP_ASSERT("p != NULL", (p != NULL));
+
+ LWIP_UNUSED_ARG(ipaddr);
+
+ priv = netif->state;
+
+ /* Send pbuf out on the serial I/O device. */
+ sio_send(SLIP_END, priv->sd);
+
+ for (q = p; q != NULL; q = q->next) {
+ for (i = 0; i < q->len; i++) {
+ c = ((u8_t *)q->payload)[i];
+ switch (c) {
+ case SLIP_END:
+ sio_send(SLIP_ESC, priv->sd);
+ sio_send(SLIP_ESC_END, priv->sd);
+ break;
+ case SLIP_ESC:
+ sio_send(SLIP_ESC, priv->sd);
+ sio_send(SLIP_ESC_ESC, priv->sd);
+ break;
+ default:
+ sio_send(c, priv->sd);
+ break;
+ }
+ }
+ }
+ sio_send(SLIP_END, priv->sd);
+ return ERR_OK;
+}
+
+/**
+ * Static function for easy use of blockig or non-blocking
+ * sio_read
+ *
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @param block if 1, call sio_read; if 0, call sio_tryread
+ * @return return value of sio_read of sio_tryread
+ */
+static u32_t
+slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block)
+{
+ if (block) {
+ return sio_read(fd, data, len);
+ } else {
+ return sio_tryread(fd, data, len);
+ }
+}
+
+/**
+ * Handle the incoming SLIP stream character by character
+ *
+ * Poll the serial layer by calling sio_read() or sio_tryread().
+ *
+ * @param netif the lwip network interface structure for this slipif
+ * @param block if 1, block until data is received; if 0, return when all data
+ * from the buffer is received (multiple calls to this function will
+ * return a complete packet, NULL is returned before - used for polling)
+ * @return The IP packet when SLIP_END is received
+ */
+static struct pbuf *
+slipif_input(struct netif *netif, u8_t block)
+{
+ struct slipif_priv *priv;
+ u8_t c;
+ struct pbuf *t;
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
+
+ priv = netif->state;
+
+ while (slip_sio_read(priv->sd, &c, 1, block) > 0) {
+ switch (priv->state) {
+ case SLIP_RECV_NORMAL:
+ switch (c) {
+ case SLIP_END:
+ if (priv->recved > 0) {
+ /* Received whole packet. */
+ /* Trim the pbuf to the size of the received packet. */
+ pbuf_realloc(priv->q, priv->recved);
+
+ LINK_STATS_INC(link.recv);
+
+ LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
+ t = priv->q;
+ priv->p = priv->q = NULL;
+ priv->i = priv->recved = 0;
+ return t;
+ }
+ continue;
+ case SLIP_ESC:
+ priv->state = SLIP_RECV_ESCAPE;
+ continue;
+ }
+ break;
+ case SLIP_RECV_ESCAPE:
+ switch (c) {
+ case SLIP_ESC_END:
+ c = SLIP_END;
+ break;
+ case SLIP_ESC_ESC:
+ c = SLIP_ESC;
+ break;
+ }
+ priv->state = SLIP_RECV_NORMAL;
+ /* FALLTHROUGH */
+ }
+
+ /* byte received, packet not yet completely received */
+ if (priv->p == NULL) {
+ /* allocate a new pbuf */
+ LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
+ priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
+
+ if (priv->p == NULL) {
+ LINK_STATS_INC(link.drop);
+ LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
+ /* don't process any further since we got no pbuf to receive to */
+ break;
+ }
+
+ if (priv->q != NULL) {
+ /* 'chain' the pbuf to the existing chain */
+ pbuf_cat(priv->q, priv->p);
+ } else {
+ /* p is the first pbuf in the chain */
+ priv->q = priv->p;
+ }
+ }
+
+ /* this automatically drops bytes if > SLIP_MAX_SIZE */
+ if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
+ ((u8_t *)priv->p->payload)[priv->i] = c;
+ priv->recved++;
+ priv->i++;
+ if (priv->i >= priv->p->len) {
+ /* on to the next pbuf */
+ priv->i = 0;
+ if (priv->p->next != NULL && priv->p->next->len > 0) {
+ /* p is a chain, on to the next in the chain */
+ priv->p = priv->p->next;
+ } else {
+ /* p is a single pbuf, set it to NULL so next time a new
+ * pbuf is allocated */
+ priv->p = NULL;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+#if !NO_SYS
+/**
+ * The SLIP input thread.
+ *
+ * Feed the IP layer with incoming packets
+ *
+ * @param nf the lwip network interface structure for this slipif
+ */
+static void
+slipif_loop_thread(void *nf)
+{
+ struct pbuf *p;
+ struct netif *netif = (struct netif *)nf;
+
+ while (1) {
+ p = slipif_input(netif, SLIP_BLOCK);
+ if (p != NULL) {
+ if (netif->input(p, netif) != ERR_OK) {
+ pbuf_free(p);
+ p = NULL;
+ }
+ }
+ }
+}
+#endif /* !NO_SYS */
+
+/**
+ * SLIP netif initialization
+ *
+ * Call the arch specific sio_open and remember
+ * the opened device in the state field of the netif.
+ *
+ * @param netif the lwip network interface structure for this slipif
+ * @return ERR_OK if serial line could be opened,
+ * ERR_MEM if no memory could be allocated,
+ * ERR_IF is serial line couldn't be opened
+ *
+ * @note netif->num must contain the number of the serial port to open
+ * (0 by default)
+ */
+err_t
+slipif_init(struct netif *netif)
+{
+ struct slipif_priv *priv;
+
+ LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
+
+ /* Allocate private data */
+ priv = mem_malloc(sizeof(struct slipif_priv));
+ if (!priv) {
+ return ERR_MEM;
+ }
+
+ netif->name[0] = 's';
+ netif->name[1] = 'l';
+ netif->output = slipif_output;
+ netif->mtu = SLIP_MAX_SIZE;
+ netif->flags |= NETIF_FLAG_POINTTOPOINT;
+
+ /* Try to open the serial port (netif->num contains the port number). */
+ priv->sd = sio_open(netif->num);
+ if (!priv->sd) {
+ /* Opening the serial port failed. */
+ mem_free(priv);
+ return ERR_IF;
+ }
+
+ /* Initialize private data */
+ priv->p = NULL;
+ priv->q = NULL;
+ priv->state = SLIP_RECV_NORMAL;
+ priv->i = 0;
+ priv->recved = 0;
+
+ netif->state = priv;
+
+ /* initialize the snmp variables and counters inside the struct netif
+ * ifSpeed: no assumption can be made without knowing more about the
+ * serial line!
+ */
+ NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
+
+ /* Create a thread to poll the serial line. */
+ sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
+ SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
+ return ERR_OK;
+}
+
+/**
+ * Polls the serial device and feeds the IP layer with incoming packets.
+ *
+ * @param netif The lwip network interface structure for this slipif
+ */
+void
+slipif_poll(struct netif *netif)
+{
+ struct pbuf *p;
+ struct slipif_priv *priv;
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
+
+ priv = netif->state;
+
+ while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) {
+ if (netif->input(p, netif) != ERR_OK) {
+ pbuf_free(p);
+ }
+ }
+}
+
+#endif /* LWIP_HAVE_SLIPIF */