Implementation of the NetworkSocketAPI for LWIP

Dependencies:   lwip-eth lwip-sys lwip

Dependents:   HelloLWIPInterface HelloLWIPInterfaceNonBlocking LWIPInterfaceTests SimpleHTTPExample ... more

Committer:
Christopher Haster
Date:
Thu Feb 25 11:09:49 2016 -0600
Revision:
2:7fb7e78cb17f
Parent:
1:2fbcfc9c12dd
Child:
3:774869068511
Added rudimentary implementation of the LWIPInterface

Who changed what in which revision?

UserRevisionLine numberNew contents of line
geky 1:2fbcfc9c12dd 1 /* LWIP implementation of NetworkInterfaceAPI
geky 1:2fbcfc9c12dd 2 * Copyright (c) 2015 ARM Limited
geky 1:2fbcfc9c12dd 3 *
geky 1:2fbcfc9c12dd 4 * Licensed under the Apache License, Version 2.0 (the "License");
geky 1:2fbcfc9c12dd 5 * you may not use this file except in compliance with the License.
geky 1:2fbcfc9c12dd 6 * You may obtain a copy of the License at
geky 1:2fbcfc9c12dd 7 *
geky 1:2fbcfc9c12dd 8 * http://www.apache.org/licenses/LICENSE-2.0
geky 1:2fbcfc9c12dd 9 *
geky 1:2fbcfc9c12dd 10 * Unless required by applicable law or agreed to in writing, software
geky 1:2fbcfc9c12dd 11 * distributed under the License is distributed on an "AS IS" BASIS,
geky 1:2fbcfc9c12dd 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
geky 1:2fbcfc9c12dd 13 * See the License for the specific language governing permissions and
geky 1:2fbcfc9c12dd 14 * limitations under the License.
geky 1:2fbcfc9c12dd 15 */
geky 1:2fbcfc9c12dd 16
Christopher Haster 2:7fb7e78cb17f 17 #include "LWIPInterface.h"
Christopher Haster 2:7fb7e78cb17f 18
Christopher Haster 2:7fb7e78cb17f 19 #include "mbed.h"
Christopher Haster 2:7fb7e78cb17f 20 #include "lwip/inet.h"
Christopher Haster 2:7fb7e78cb17f 21 #include "lwip/netif.h"
Christopher Haster 2:7fb7e78cb17f 22 #include "lwip/dhcp.h"
Christopher Haster 2:7fb7e78cb17f 23 #include "lwip/tcpip.h"
Christopher Haster 2:7fb7e78cb17f 24 #include "lwip/sockets.h"
Christopher Haster 2:7fb7e78cb17f 25 #include "lwip/netdb.h"
Christopher Haster 2:7fb7e78cb17f 26 #include "netif/etharp.h"
Christopher Haster 2:7fb7e78cb17f 27 #include "eth_arch.h"
Christopher Haster 2:7fb7e78cb17f 28
Christopher Haster 2:7fb7e78cb17f 29
Christopher Haster 2:7fb7e78cb17f 30 #define LWIP_TIMEOUT 15000
Christopher Haster 2:7fb7e78cb17f 31
Christopher Haster 2:7fb7e78cb17f 32
Christopher Haster 2:7fb7e78cb17f 33 /* TCP/IP and Network Interface Initialisation */
Christopher Haster 2:7fb7e78cb17f 34 static LWIPInterface *iface = 0;
Christopher Haster 2:7fb7e78cb17f 35 static struct netif netif;
Christopher Haster 2:7fb7e78cb17f 36
Christopher Haster 2:7fb7e78cb17f 37 static char mac_addr[NS_MAC_SIZE] = "\0";
Christopher Haster 2:7fb7e78cb17f 38
Christopher Haster 2:7fb7e78cb17f 39 static Semaphore tcpip_inited(0);
Christopher Haster 2:7fb7e78cb17f 40 static Semaphore netif_linked(0);
Christopher Haster 2:7fb7e78cb17f 41 static Semaphore netif_up(0);
Christopher Haster 2:7fb7e78cb17f 42
Christopher Haster 2:7fb7e78cb17f 43 static void tcpip_init_done(void *) {
Christopher Haster 2:7fb7e78cb17f 44 tcpip_inited.release();
Christopher Haster 2:7fb7e78cb17f 45 }
Christopher Haster 2:7fb7e78cb17f 46
Christopher Haster 2:7fb7e78cb17f 47 static void netif_link_callback(struct netif *netif) {
Christopher Haster 2:7fb7e78cb17f 48 if (netif_is_link_up(netif)) {
Christopher Haster 2:7fb7e78cb17f 49 netif_linked.release();
Christopher Haster 2:7fb7e78cb17f 50 }
Christopher Haster 2:7fb7e78cb17f 51 }
Christopher Haster 2:7fb7e78cb17f 52
Christopher Haster 2:7fb7e78cb17f 53 static void netif_status_callback(struct netif *netif) {
Christopher Haster 2:7fb7e78cb17f 54 if (netif_is_up(netif)) {
Christopher Haster 2:7fb7e78cb17f 55 iface->setIPAddress (inet_ntoa(netif->ip_addr));
Christopher Haster 2:7fb7e78cb17f 56 iface->setNetworkMask(inet_ntoa(netif->netmask));
Christopher Haster 2:7fb7e78cb17f 57 iface->setGateway (inet_ntoa(netif->gw));
Christopher Haster 2:7fb7e78cb17f 58 netif_up.release();
Christopher Haster 2:7fb7e78cb17f 59 }
Christopher Haster 2:7fb7e78cb17f 60 }
Christopher Haster 2:7fb7e78cb17f 61
Christopher Haster 2:7fb7e78cb17f 62 static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
Christopher Haster 2:7fb7e78cb17f 63 tcpip_init(tcpip_init_done, NULL);
Christopher Haster 2:7fb7e78cb17f 64 tcpip_inited.wait();
Christopher Haster 2:7fb7e78cb17f 65
Christopher Haster 2:7fb7e78cb17f 66 memset((void*) &netif, 0, sizeof(netif));
Christopher Haster 2:7fb7e78cb17f 67 netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
Christopher Haster 2:7fb7e78cb17f 68 netif_set_default(&netif);
Christopher Haster 2:7fb7e78cb17f 69
Christopher Haster 2:7fb7e78cb17f 70 netif_set_link_callback (&netif, netif_link_callback);
Christopher Haster 2:7fb7e78cb17f 71 netif_set_status_callback(&netif, netif_status_callback);
Christopher Haster 2:7fb7e78cb17f 72 }
Christopher Haster 2:7fb7e78cb17f 73
Christopher Haster 2:7fb7e78cb17f 74 static void set_mac_address(void) {
Christopher Haster 2:7fb7e78cb17f 75 #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
Christopher Haster 2:7fb7e78cb17f 76 snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
Christopher Haster 2:7fb7e78cb17f 77 MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
Christopher Haster 2:7fb7e78cb17f 78 #else
Christopher Haster 2:7fb7e78cb17f 79 char mac[6];
Christopher Haster 2:7fb7e78cb17f 80 mbed_mac_address(mac);
Christopher Haster 2:7fb7e78cb17f 81 snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Christopher Haster 2:7fb7e78cb17f 82 #endif
Christopher Haster 2:7fb7e78cb17f 83 }
Christopher Haster 2:7fb7e78cb17f 84
Christopher Haster 2:7fb7e78cb17f 85
Christopher Haster 2:7fb7e78cb17f 86 // LWIPInterface implementation
Christopher Haster 2:7fb7e78cb17f 87 int32_t LWIPInterface::connect()
Christopher Haster 2:7fb7e78cb17f 88 {
Christopher Haster 2:7fb7e78cb17f 89 // Only one instance of LWIP is currently supported
Christopher Haster 2:7fb7e78cb17f 90 if (iface) {
Christopher Haster 2:7fb7e78cb17f 91 return NS_ERROR_DEVICE_ERROR;
Christopher Haster 2:7fb7e78cb17f 92 }
Christopher Haster 2:7fb7e78cb17f 93
Christopher Haster 2:7fb7e78cb17f 94 iface = this;
Christopher Haster 2:7fb7e78cb17f 95
Christopher Haster 2:7fb7e78cb17f 96 // Set up network
Christopher Haster 2:7fb7e78cb17f 97 set_mac_address();
Christopher Haster 2:7fb7e78cb17f 98
Christopher Haster 2:7fb7e78cb17f 99 if (getDHCP()) {
Christopher Haster 2:7fb7e78cb17f 100 init_netif(0, 0, 0);
Christopher Haster 2:7fb7e78cb17f 101 } else {
Christopher Haster 2:7fb7e78cb17f 102 ip_addr_t ip_n, mask_n, gateway_n;
Christopher Haster 2:7fb7e78cb17f 103 inet_aton(getIPAddress(), &ip_n);
Christopher Haster 2:7fb7e78cb17f 104 inet_aton(getNetworkMask(), &mask_n);
Christopher Haster 2:7fb7e78cb17f 105 inet_aton(getGateway(), &gateway_n);
Christopher Haster 2:7fb7e78cb17f 106 init_netif(&ip_n, &mask_n, &gateway_n);
Christopher Haster 2:7fb7e78cb17f 107 }
Christopher Haster 2:7fb7e78cb17f 108
Christopher Haster 2:7fb7e78cb17f 109 // Connect to network
Christopher Haster 2:7fb7e78cb17f 110 eth_arch_enable_interrupts();
Christopher Haster 2:7fb7e78cb17f 111
Christopher Haster 2:7fb7e78cb17f 112 if (getDHCP()) {
Christopher Haster 2:7fb7e78cb17f 113 dhcp_start(&netif);
Christopher Haster 2:7fb7e78cb17f 114
Christopher Haster 2:7fb7e78cb17f 115 // Wait for an IP Address
Christopher Haster 2:7fb7e78cb17f 116 // -1: error, 0: timeout
Christopher Haster 2:7fb7e78cb17f 117 if (netif_up.wait(LWIP_TIMEOUT) < 0) {
Christopher Haster 2:7fb7e78cb17f 118 return NS_ERROR_TIMEOUT;
Christopher Haster 2:7fb7e78cb17f 119 }
Christopher Haster 2:7fb7e78cb17f 120 } else {
Christopher Haster 2:7fb7e78cb17f 121 netif_set_up(&netif);
Christopher Haster 2:7fb7e78cb17f 122
Christopher Haster 2:7fb7e78cb17f 123 // Wait for the link up
Christopher Haster 2:7fb7e78cb17f 124 if (netif_linked.wait(LWIP_TIMEOUT) < 0) {
Christopher Haster 2:7fb7e78cb17f 125 return NS_ERROR_TIMEOUT;
Christopher Haster 2:7fb7e78cb17f 126 }
Christopher Haster 2:7fb7e78cb17f 127 }
Christopher Haster 2:7fb7e78cb17f 128
Christopher Haster 2:7fb7e78cb17f 129 return 0;
Christopher Haster 2:7fb7e78cb17f 130 }
Christopher Haster 2:7fb7e78cb17f 131
Christopher Haster 2:7fb7e78cb17f 132 int32_t LWIPInterface::disconnect()
Christopher Haster 2:7fb7e78cb17f 133 {
Christopher Haster 2:7fb7e78cb17f 134 if (getDHCP()) {
Christopher Haster 2:7fb7e78cb17f 135 dhcp_release(&netif);
Christopher Haster 2:7fb7e78cb17f 136 dhcp_stop(&netif);
Christopher Haster 2:7fb7e78cb17f 137 } else {
Christopher Haster 2:7fb7e78cb17f 138 netif_set_down(&netif);
Christopher Haster 2:7fb7e78cb17f 139 }
Christopher Haster 2:7fb7e78cb17f 140
Christopher Haster 2:7fb7e78cb17f 141 eth_arch_disable_interrupts();
Christopher Haster 2:7fb7e78cb17f 142
Christopher Haster 2:7fb7e78cb17f 143 return 0;
Christopher Haster 2:7fb7e78cb17f 144 }
Christopher Haster 2:7fb7e78cb17f 145
Christopher Haster 2:7fb7e78cb17f 146 const char *LWIPInterface::getMACAddress()
Christopher Haster 2:7fb7e78cb17f 147 {
Christopher Haster 2:7fb7e78cb17f 148 return mac_addr;
Christopher Haster 2:7fb7e78cb17f 149 }
Christopher Haster 2:7fb7e78cb17f 150
Christopher Haster 2:7fb7e78cb17f 151
Christopher Haster 2:7fb7e78cb17f 152 /** LWIPSocket class
Christopher Haster 2:7fb7e78cb17f 153 * Implementation of the TCP SocketInterface for LWIP
Christopher Haster 2:7fb7e78cb17f 154 */
Christopher Haster 2:7fb7e78cb17f 155 class LWIPSocket : public SocketInterface
Christopher Haster 2:7fb7e78cb17f 156 {
Christopher Haster 2:7fb7e78cb17f 157 public:
Christopher Haster 2:7fb7e78cb17f 158 LWIPSocket(int fd) : fd(fd) {}
Christopher Haster 2:7fb7e78cb17f 159
Christopher Haster 2:7fb7e78cb17f 160 // Implementation of SocketInterface
Christopher Haster 2:7fb7e78cb17f 161 virtual int32_t open(const char *ip, uint16_t port);
Christopher Haster 2:7fb7e78cb17f 162 virtual int32_t close();
Christopher Haster 2:7fb7e78cb17f 163
Christopher Haster 2:7fb7e78cb17f 164 virtual int32_t send(const void *data, uint32_t size);
Christopher Haster 2:7fb7e78cb17f 165 virtual int32_t recv(void *data, uint32_t size);
Christopher Haster 2:7fb7e78cb17f 166
Christopher Haster 2:7fb7e78cb17f 167 int fd;
Christopher Haster 2:7fb7e78cb17f 168 };
Christopher Haster 2:7fb7e78cb17f 169
Christopher Haster 2:7fb7e78cb17f 170
Christopher Haster 2:7fb7e78cb17f 171 SocketInterface *LWIPInterface::createSocket(socket_protocol_t proto)
Christopher Haster 2:7fb7e78cb17f 172 {
Christopher Haster 2:7fb7e78cb17f 173 int type = (proto == SOCK_UDP) ? SOCK_DGRAM : SOCK_STREAM;
Christopher Haster 2:7fb7e78cb17f 174 int fd = lwip_socket(AF_INET, type, 0);
Christopher Haster 2:7fb7e78cb17f 175
Christopher Haster 2:7fb7e78cb17f 176 if (fd < 0) {
Christopher Haster 2:7fb7e78cb17f 177 return 0;
Christopher Haster 2:7fb7e78cb17f 178 }
Christopher Haster 2:7fb7e78cb17f 179
Christopher Haster 2:7fb7e78cb17f 180 return new LWIPSocket(fd);
Christopher Haster 2:7fb7e78cb17f 181 }
Christopher Haster 2:7fb7e78cb17f 182
Christopher Haster 2:7fb7e78cb17f 183 void LWIPInterface::destroySocket(SocketInterface *siface)
Christopher Haster 2:7fb7e78cb17f 184 {
Christopher Haster 2:7fb7e78cb17f 185 LWIPSocket *socket = (LWIPSocket *)siface;
Christopher Haster 2:7fb7e78cb17f 186 lwip_close(socket->fd);
Christopher Haster 2:7fb7e78cb17f 187
Christopher Haster 2:7fb7e78cb17f 188 delete socket;
Christopher Haster 2:7fb7e78cb17f 189 }
Christopher Haster 2:7fb7e78cb17f 190
Christopher Haster 2:7fb7e78cb17f 191
Christopher Haster 2:7fb7e78cb17f 192 // TCP SocketInterface implementation
Christopher Haster 2:7fb7e78cb17f 193 int32_t LWIPSocket::open(const char *ip, uint16_t port)
Christopher Haster 2:7fb7e78cb17f 194 {
Christopher Haster 2:7fb7e78cb17f 195 struct sockaddr_in host;
Christopher Haster 2:7fb7e78cb17f 196 memset(&host, 0, sizeof host);
Christopher Haster 2:7fb7e78cb17f 197 inet_aton(ip, &host.sin_addr);
Christopher Haster 2:7fb7e78cb17f 198 host.sin_family = AF_INET;
Christopher Haster 2:7fb7e78cb17f 199 host.sin_port = htons(port);
Christopher Haster 2:7fb7e78cb17f 200
Christopher Haster 2:7fb7e78cb17f 201 if (lwip_connect(fd, (const struct sockaddr *)&host, sizeof host) < 0) {
Christopher Haster 2:7fb7e78cb17f 202 return NS_ERROR_NO_CONNECTION;
Christopher Haster 2:7fb7e78cb17f 203 }
Christopher Haster 2:7fb7e78cb17f 204
Christopher Haster 2:7fb7e78cb17f 205 return 0;
Christopher Haster 2:7fb7e78cb17f 206 }
Christopher Haster 2:7fb7e78cb17f 207
Christopher Haster 2:7fb7e78cb17f 208 int32_t LWIPSocket::close()
Christopher Haster 2:7fb7e78cb17f 209 {
Christopher Haster 2:7fb7e78cb17f 210 return 0;
Christopher Haster 2:7fb7e78cb17f 211 }
Christopher Haster 2:7fb7e78cb17f 212
Christopher Haster 2:7fb7e78cb17f 213 int32_t LWIPSocket::send(const void *voiddata, uint32_t size)
Christopher Haster 2:7fb7e78cb17f 214 {
Christopher Haster 2:7fb7e78cb17f 215 uint8_t *data = (uint8_t *)voiddata;
Christopher Haster 2:7fb7e78cb17f 216 uint32_t writtenLen = 0;
Christopher Haster 2:7fb7e78cb17f 217
Christopher Haster 2:7fb7e78cb17f 218 while (writtenLen < size) {
Christopher Haster 2:7fb7e78cb17f 219 int ret = lwip_send(fd, data + writtenLen, size - writtenLen, 0);
Christopher Haster 2:7fb7e78cb17f 220
Christopher Haster 2:7fb7e78cb17f 221 if (ret > 0) {
Christopher Haster 2:7fb7e78cb17f 222 writtenLen += ret;
Christopher Haster 2:7fb7e78cb17f 223 } else if (ret == 0) {
Christopher Haster 2:7fb7e78cb17f 224 return NS_ERROR_NO_CONNECTION;
Christopher Haster 2:7fb7e78cb17f 225 } else {
Christopher Haster 2:7fb7e78cb17f 226 return NS_ERROR_DEVICE_ERROR;
Christopher Haster 2:7fb7e78cb17f 227 }
Christopher Haster 2:7fb7e78cb17f 228 }
Christopher Haster 2:7fb7e78cb17f 229
Christopher Haster 2:7fb7e78cb17f 230 return 0;
Christopher Haster 2:7fb7e78cb17f 231 }
Christopher Haster 2:7fb7e78cb17f 232
Christopher Haster 2:7fb7e78cb17f 233 int32_t LWIPSocket::recv(void *data, uint32_t size)
Christopher Haster 2:7fb7e78cb17f 234 {
Christopher Haster 2:7fb7e78cb17f 235 int ret = lwip_recv(fd, data, size, MSG_DONTWAIT);
Christopher Haster 2:7fb7e78cb17f 236
Christopher Haster 2:7fb7e78cb17f 237 if (ret > 0) {
Christopher Haster 2:7fb7e78cb17f 238 return ret;
Christopher Haster 2:7fb7e78cb17f 239 } else if (ret == 0) {
Christopher Haster 2:7fb7e78cb17f 240 return NS_ERROR_NO_CONNECTION;
Christopher Haster 2:7fb7e78cb17f 241 } else if (ret == -1) {
Christopher Haster 2:7fb7e78cb17f 242 return 0;
Christopher Haster 2:7fb7e78cb17f 243 } else {
Christopher Haster 2:7fb7e78cb17f 244 return NS_ERROR_DEVICE_ERROR;
Christopher Haster 2:7fb7e78cb17f 245 }
Christopher Haster 2:7fb7e78cb17f 246 }
Christopher Haster 2:7fb7e78cb17f 247
Christopher Haster 2:7fb7e78cb17f 248