lwipthread.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /*
  14. * **** This file incorporates work covered by the following copyright and ****
  15. * **** permission notice: ****
  16. *
  17. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  18. * All rights reserved.
  19. *
  20. * Redistribution and use in source and binary forms, with or without modification,
  21. * are permitted provided that the following conditions are met:
  22. *
  23. * 1. Redistributions of source code must retain the above copyright notice,
  24. * this list of conditions and the following disclaimer.
  25. * 2. Redistributions in binary form must reproduce the above copyright notice,
  26. * this list of conditions and the following disclaimer in the documentation
  27. * and/or other materials provided with the distribution.
  28. * 3. The name of the author may not be used to endorse or promote products
  29. * derived from this software without specific prior written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  32. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  33. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  34. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  35. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  36. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  37. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  38. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  39. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  40. * OF SUCH DAMAGE.
  41. *
  42. * This file is part of the lwIP TCP/IP stack.
  43. *
  44. * Author: Adam Dunkels <adam@sics.se>
  45. *
  46. */
  47. /**
  48. * @file lwipthread.c
  49. * @brief LWIP wrapper thread code.
  50. * @addtogroup LWIP_THREAD
  51. * @{
  52. */
  53. #include "hal.h"
  54. #include "evtimer.h"
  55. #include "lwipthread.h"
  56. #include <lwip/opt.h>
  57. #include <lwip/def.h>
  58. #include <lwip/mem.h>
  59. #include <lwip/pbuf.h>
  60. #include <lwip/sys.h>
  61. #include <lwip/stats.h>
  62. #include <lwip/snmp.h>
  63. #include <lwip/tcpip.h>
  64. #include <netif/etharp.h>
  65. #include <lwip/netifapi.h>
  66. #if LWIP_DHCP
  67. #include <lwip/dhcp.h>
  68. #endif
  69. #if LWIP_AUTOIP
  70. #include <lwip/autoip.h>
  71. #endif
  72. #define PERIODIC_TIMER_ID 1
  73. #define FRAME_RECEIVED_ID 2
  74. /*
  75. * Suspension point for initialization procedure.
  76. */
  77. thread_reference_t lwip_trp = NULL;
  78. /*
  79. * Stack area for the LWIP-MAC thread.
  80. */
  81. static THD_WORKING_AREA(wa_lwip_thread, LWIP_THREAD_STACK_SIZE);
  82. /*
  83. * Initialization.
  84. */
  85. static void low_level_init(struct netif *netif) {
  86. /* set MAC hardware address length */
  87. netif->hwaddr_len = ETHARP_HWADDR_LEN;
  88. /* maximum transfer unit */
  89. netif->mtu = LWIP_NETIF_MTU;
  90. /* device capabilities */
  91. /* don't set NETIF_FLAG_ETHARP if this device is not an Ethernet one */
  92. netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
  93. /* Do whatever else is needed to initialize interface. */
  94. }
  95. /*
  96. * This function does the actual transmission of the packet. The packet is
  97. * contained in the pbuf that is passed to the function. This pbuf
  98. * might be chained.
  99. *
  100. * @param netif the lwip network interface structure for this ethernetif
  101. * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
  102. * @return ERR_OK if the packet could be sent
  103. * an err_t value if the packet couldn't be sent
  104. *
  105. * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
  106. * strange results. You might consider waiting for space in the DMA queue
  107. * to become available since the stack doesn't retry to send a packet
  108. * dropped because of memory failure (except for the TCP timers).
  109. */
  110. static err_t low_level_output(struct netif *netif, struct pbuf *p) {
  111. struct pbuf *q;
  112. MACTransmitDescriptor td;
  113. (void)netif;
  114. if (macWaitTransmitDescriptor(&ETHD1, &td, TIME_MS2I(LWIP_SEND_TIMEOUT)) != MSG_OK)
  115. return ERR_TIMEOUT;
  116. #if ETH_PAD_SIZE
  117. pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
  118. #endif
  119. /* Iterates through the pbuf chain. */
  120. for(q = p; q != NULL; q = q->next)
  121. macWriteTransmitDescriptor(&td, (uint8_t *)q->payload, (size_t)q->len);
  122. macReleaseTransmitDescriptor(&td);
  123. MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
  124. if (((u8_t*)p->payload)[0] & 1) {
  125. /* broadcast or multicast packet*/
  126. MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
  127. }
  128. else {
  129. /* unicast packet */
  130. MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
  131. }
  132. /* increase ifoutdiscards or ifouterrors on error */
  133. #if ETH_PAD_SIZE
  134. pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  135. #endif
  136. LINK_STATS_INC(link.xmit);
  137. return ERR_OK;
  138. }
  139. /*
  140. * Receives a frame.
  141. * Allocates a pbuf and transfers the bytes of the incoming
  142. * packet from the interface into the pbuf.
  143. *
  144. * @param netif the lwip network interface structure for this ethernetif
  145. * @return a pbuf filled with the received packet (including MAC header)
  146. * NULL on memory error
  147. */
  148. static bool low_level_input(struct netif *netif, struct pbuf **pbuf) {
  149. MACReceiveDescriptor rd;
  150. struct pbuf *q;
  151. u16_t len;
  152. (void)netif;
  153. osalDbgAssert(pbuf != NULL, "invalid null pointer");
  154. if (macWaitReceiveDescriptor(&ETHD1, &rd, TIME_IMMEDIATE) != MSG_OK)
  155. return false;
  156. len = (u16_t)rd.size;
  157. #if ETH_PAD_SIZE
  158. len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
  159. #endif
  160. /* We allocate a pbuf chain of pbufs from the pool. */
  161. *pbuf = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  162. if (*pbuf != NULL) {
  163. #if ETH_PAD_SIZE
  164. pbuf_header(pbuf, -ETH_PAD_SIZE); /* drop the padding word */
  165. #endif
  166. /* Iterates through the pbuf chain. */
  167. for(q = *pbuf; q != NULL; q = q->next)
  168. macReadReceiveDescriptor(&rd, (uint8_t *)q->payload, (size_t)q->len);
  169. macReleaseReceiveDescriptor(&rd);
  170. MIB2_STATS_NETIF_ADD(netif, ifinoctets, *pbuf->tot_len);
  171. if (*(uint8_t *)((*pbuf)->payload) & 1) {
  172. /* broadcast or multicast packet*/
  173. MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
  174. }
  175. else {
  176. /* unicast packet*/
  177. MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
  178. }
  179. #if ETH_PAD_SIZE
  180. pbuf_header(pbuf, ETH_PAD_SIZE); /* reclaim the padding word */
  181. #endif
  182. LINK_STATS_INC(link.recv);
  183. }
  184. else {
  185. macReleaseReceiveDescriptor(&rd); // Drop packet
  186. LINK_STATS_INC(link.memerr);
  187. LINK_STATS_INC(link.drop);
  188. MIB2_STATS_NETIF_INC(netif, ifindiscards);
  189. }
  190. return true;
  191. }
  192. /*
  193. * Called at the beginning of the program to set up the
  194. * network interface. It calls the function low_level_init() to do the
  195. * actual setup of the hardware.
  196. *
  197. * This function should be passed as a parameter to netifapi_netif_add().
  198. *
  199. * @param netif the lwip network interface structure for this ethernetif
  200. * @return ERR_OK if the loopif is initialised
  201. * ERR_MEM if private data couldn't be allocated
  202. * any other err_t on error
  203. */
  204. static err_t ethernetif_init(struct netif *netif) {
  205. osalDbgAssert((netif != NULL), "netif != NULL");
  206. /*
  207. * Initialize the snmp variables and counters inside the struct netif.
  208. * The last argument should be replaced with your link speed, in units
  209. * of bits per second.
  210. */
  211. MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LWIP_LINK_SPEED);
  212. netif->state = NULL;
  213. netif->name[0] = LWIP_IFNAME0;
  214. netif->name[1] = LWIP_IFNAME1;
  215. /* We directly use etharp_output() here to save a function call.
  216. * You can instead declare your own function an call etharp_output()
  217. * from it if you have to do some checks before sending (e.g. if link
  218. * is available...) */
  219. netif->output = etharp_output;
  220. netif->linkoutput = low_level_output;
  221. /* initialize the hardware */
  222. low_level_init(netif);
  223. return ERR_OK;
  224. }
  225. /**
  226. * @brief LWIP handling thread.
  227. *
  228. * @param[in] p pointer to a @p lwipthread_opts structure or @p NULL
  229. * @return The function does not return.
  230. */
  231. static THD_FUNCTION(lwip_thread, p) {
  232. event_timer_t evt;
  233. event_listener_t el0, el1;
  234. ip_addr_t ip, gateway, netmask;
  235. static struct netif thisif = { 0 };
  236. static const MACConfig mac_config = {thisif.hwaddr};
  237. net_addr_mode_t addressMode;
  238. err_t result;
  239. chRegSetThreadName(LWIP_THREAD_NAME);
  240. /* Initializes the thing.*/
  241. tcpip_init(NULL, NULL);
  242. /* TCP/IP parameters, runtime or compile time.*/
  243. if (p) {
  244. struct lwipthread_opts *opts = p;
  245. unsigned i;
  246. for (i = 0; i < 6; i++)
  247. thisif.hwaddr[i] = opts->macaddress[i];
  248. ip.addr = opts->address;
  249. gateway.addr = opts->gateway;
  250. netmask.addr = opts->netmask;
  251. addressMode = opts->addrMode;
  252. #if LWIP_NETIF_HOSTNAME
  253. thisif.hostname = opts->ourHostName;
  254. #endif
  255. }
  256. else {
  257. thisif.hwaddr[0] = LWIP_ETHADDR_0;
  258. thisif.hwaddr[1] = LWIP_ETHADDR_1;
  259. thisif.hwaddr[2] = LWIP_ETHADDR_2;
  260. thisif.hwaddr[3] = LWIP_ETHADDR_3;
  261. thisif.hwaddr[4] = LWIP_ETHADDR_4;
  262. thisif.hwaddr[5] = LWIP_ETHADDR_5;
  263. LWIP_IPADDR(&ip);
  264. LWIP_GATEWAY(&gateway);
  265. LWIP_NETMASK(&netmask);
  266. addressMode = NET_ADDRESS_STATIC;
  267. #if LWIP_NETIF_HOSTNAME
  268. thisif.hostname = NULL;
  269. #endif
  270. }
  271. #if LWIP_NETIF_HOSTNAME
  272. if (thisif.hostname == NULL)
  273. thisif.hostname = LWIP_NETIF_HOSTNAME_STRING;
  274. #endif
  275. macStart(&ETHD1, &mac_config);
  276. /* Add interface. */
  277. result = netifapi_netif_add(&thisif, &ip, &netmask, &gateway, NULL, ethernetif_init, tcpip_input);
  278. if (result != ERR_OK)
  279. {
  280. chThdSleepMilliseconds(1000); // Give some time to print any other diagnostics.
  281. osalSysHalt("netif_add error"); // Not sure what else we can do if an error occurs here.
  282. };
  283. netif_set_default(&thisif);
  284. switch (addressMode)
  285. {
  286. #if LWIP_AUTOIP
  287. case NET_ADDRESS_AUTO:
  288. autoip_start(&thisif);
  289. break;
  290. #endif
  291. default:
  292. netif_set_up(&thisif);
  293. break;
  294. }
  295. /* Setup event sources.*/
  296. evtObjectInit(&evt, LWIP_LINK_POLL_INTERVAL);
  297. evtStart(&evt);
  298. chEvtRegisterMask(&evt.et_es, &el0, PERIODIC_TIMER_ID);
  299. chEvtRegisterMask(macGetReceiveEventSource(&ETHD1), &el1, FRAME_RECEIVED_ID);
  300. chEvtAddEvents(PERIODIC_TIMER_ID | FRAME_RECEIVED_ID);
  301. /* Resumes the caller and goes to the final priority.*/
  302. chThdResume(&lwip_trp, MSG_OK);
  303. chThdSetPriority(LWIP_THREAD_PRIORITY);
  304. while (true) {
  305. eventmask_t mask = chEvtWaitAny(ALL_EVENTS);
  306. if (mask & PERIODIC_TIMER_ID) {
  307. bool current_link_status = macPollLinkStatus(&ETHD1);
  308. if (current_link_status != netif_is_link_up(&thisif)) {
  309. if (current_link_status) {
  310. tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
  311. &thisif, 0);
  312. #if LWIP_DHCP
  313. if (addressMode == NET_ADDRESS_DHCP)
  314. dhcp_start(&thisif);
  315. #endif
  316. }
  317. else {
  318. tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
  319. &thisif, 0);
  320. #if LWIP_DHCP
  321. if (addressMode == NET_ADDRESS_DHCP)
  322. dhcp_stop(&thisif);
  323. #endif
  324. }
  325. }
  326. }
  327. if (mask & FRAME_RECEIVED_ID) {
  328. struct pbuf *p;
  329. while (low_level_input(&thisif, &p)) {
  330. if (p != NULL) {
  331. struct eth_hdr *ethhdr = p->payload;
  332. switch (htons(ethhdr->type)) {
  333. /* IP or ARP packet? */
  334. case ETHTYPE_IP:
  335. case ETHTYPE_ARP:
  336. /* full packet send to tcpip_thread to process */
  337. if (thisif.input(p, &thisif) == ERR_OK)
  338. break;
  339. LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
  340. /* Falls through */
  341. default:
  342. pbuf_free(p);
  343. }
  344. }
  345. }
  346. }
  347. }
  348. }
  349. /**
  350. * @brief Initializes the lwIP subsystem.
  351. * @note The function exits after the initialization is finished.
  352. *
  353. * @param[in] opts pointer to the configuration structure, if @p NULL
  354. * then the static configuration is used.
  355. */
  356. void lwipInit(const lwipthread_opts_t *opts) {
  357. /* Creating the lwIP thread (it changes priority internally).*/
  358. chThdCreateStatic(wa_lwip_thread, sizeof (wa_lwip_thread),
  359. chThdGetPriorityX() - 1, lwip_thread, (void *)opts);
  360. /* Waiting for the lwIP thread complete initialization. Note,
  361. this thread reaches the thread reference object first because
  362. the relative priorities.*/
  363. chSysLock();
  364. chThdSuspendS(&lwip_trp);
  365. chSysUnlock();
  366. }
  367. /** @} */