PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1424 line
48KB

  1. /**************************************************************************
  2. *
  3. * Copyright 2008-2018 by Andrey Butok. FNET Community
  4. *
  5. ***************************************************************************
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  8. * not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. ***************************************************************************
  20. *
  21. * IP protocol implementation.
  22. *
  23. ***************************************************************************/
  24. #include "fnet.h"
  25. #include "fnet_ip4_prv.h"
  26. #include "fnet_icmp4.h"
  27. #include "fnet_checksum_prv.h"
  28. #include "fnet_timer_prv.h"
  29. #include "fnet_loop.h"
  30. #include "fnet_raw.h"
  31. #include "fnet_stack_prv.h"
  32. #include "fnet_ip_prv.h"
  33. #include "fnet_igmp.h"
  34. /* Check max/min. values.*/
  35. #if (FNET_IP4_MAX_PACKET > 65535U)
  36. #error "FNET_IP4_MAX_PACKET may not be more than 65535."
  37. #endif
  38. #if (FNET_IP4_MAX_PACKET < 200U)
  39. #error "FNET_IP4_MAX_PACKET must be more than 200."
  40. #endif
  41. #if FNET_CFG_IP4
  42. #if FNET_CFG_IP4_FRAGMENTATION
  43. static fnet_ip4_frag_list_t *ip_frag_list_head;
  44. static fnet_timer_desc_t ip_timer_ptr;
  45. #endif
  46. static fnet_ip_queue_t ip_queue;
  47. static fnet_event_desc_t ip_event;
  48. #if FNET_CFG_MULTICAST
  49. fnet_ip4_multicast_list_entry_t fnet_ip4_multicast_list[FNET_CFG_MULTICAST_MAX];
  50. #endif /* FNET_CFG_MULTICAST */
  51. /************************************************************************
  52. * Function Prototypes
  53. *************************************************************************/
  54. static void _fnet_ip4_netif_output(struct fnet_netif *netif, fnet_ip4_addr_t dest_ip_addr, fnet_netbuf_t *nb, fnet_bool_t do_not_route);
  55. static void _fnet_ip4_input_low(void *cookie);
  56. static fnet_bool_t _fnet_ip4_addr_is_onlink(fnet_netif_t *netif, fnet_ip4_addr_t addr);
  57. #if FNET_CFG_IP4_FRAGMENTATION
  58. static void _fnet_ip4_reassembly( fnet_netbuf_t **nb_ptr );
  59. static void _fnet_ip4_frag_list_add( fnet_ip4_frag_list_t **head, fnet_ip4_frag_list_t *fl );
  60. static void _fnet_ip4_frag_list_del( fnet_ip4_frag_list_t **head, fnet_ip4_frag_list_t *fl );
  61. static void _fnet_ip4_frag_add( fnet_ip4_frag_header_t *FNET_COMP_PACKED_VAR *head, fnet_ip4_frag_header_t *frag, fnet_ip4_frag_header_t *frag_prev );
  62. static void _fnet_ip4_frag_del( fnet_ip4_frag_header_t *FNET_COMP_PACKED_VAR *head, fnet_ip4_frag_header_t *frag );
  63. static void _fnet_ip4_frag_list_free( fnet_ip4_frag_list_t *list );
  64. static void _fnet_ip4_timer(fnet_uint32_t cookie );
  65. #endif
  66. #if FNET_CFG_DEBUG_TRACE_IP4 && FNET_CFG_DEBUG_TRACE
  67. static void _fnet_ip4_trace(fnet_uint8_t *str, fnet_ip4_header_t *ip_hdr);
  68. #else
  69. #define _fnet_ip4_trace(str, ip_hdr) do{}while(0)
  70. #endif
  71. /************************************************************************
  72. * DESCRIPTION: This function makes initialization of the IP layer.
  73. *************************************************************************/
  74. fnet_return_t _fnet_ip4_init( void )
  75. {
  76. fnet_return_t result = FNET_ERR;
  77. #if FNET_CFG_IP4_FRAGMENTATION
  78. ip_frag_list_head = 0;
  79. ip_timer_ptr = _fnet_timer_new(FNET_IP4_TIMER_PERIOD, _fnet_ip4_timer, 0u);
  80. if(ip_timer_ptr)
  81. {
  82. #endif
  83. #if FNET_CFG_MULTICAST
  84. /* Clear the multicast list.*/
  85. fnet_memset_zero(fnet_ip4_multicast_list, sizeof(fnet_ip4_multicast_list));
  86. #endif /* FNET_CFG_MULTICAST */
  87. /* Install SW Interrupt handler. */
  88. ip_event = fnet_event_init(_fnet_ip4_input_low, 0u);
  89. if(ip_event)
  90. {
  91. result = FNET_OK;
  92. }
  93. #if FNET_CFG_IP4_FRAGMENTATION
  94. }
  95. #endif
  96. return result;
  97. }
  98. /************************************************************************
  99. * DESCRIPTION: This function makes release of the all resources
  100. * allocated for IP layer module.
  101. *************************************************************************/
  102. void _fnet_ip4_release( void )
  103. {
  104. _fnet_ip4_drain();
  105. #if FNET_CFG_IP4_FRAGMENTATION
  106. _fnet_timer_free(ip_timer_ptr);
  107. ip_timer_ptr = 0;
  108. #endif
  109. }
  110. /************************************************************************
  111. * DESCRIPTION: This function performs IP routing
  112. * on an outgoing IP packet.
  113. *************************************************************************/
  114. fnet_netif_t *_fnet_ip4_route( fnet_ip4_addr_t dest_ip )
  115. {
  116. fnet_netif_t *netif;
  117. fnet_netif_t *res_netif = FNET_NULL;
  118. fnet_netif_t *netif_default = _fnet_netif_get_default();
  119. /* Local network */
  120. for (netif = fnet_netif_list; netif != 0; netif = netif->next)
  121. {
  122. if(netif->ip4_addr.subnetmask && ((dest_ip & netif->ip4_addr.subnetmask) == (netif->ip4_addr.address & netif->ip4_addr.subnetmask)))
  123. {
  124. res_netif = netif;
  125. break;
  126. }
  127. }
  128. /* Public network. Get interface wit a gateway. */
  129. if(res_netif == FNET_NULL)
  130. {
  131. /* Default interface has priority. */
  132. if(netif_default && netif_default->ip4_addr.gateway)
  133. {
  134. res_netif = netif_default;
  135. }
  136. else
  137. {
  138. for (netif = fnet_netif_list; netif != 0; netif = netif->next)
  139. {
  140. /* If there is a gateway */
  141. if(netif->ip4_addr.gateway)
  142. {
  143. res_netif = netif;
  144. break;
  145. }
  146. }
  147. }
  148. }
  149. /* If there is no proper interface - choose the default one */
  150. if(res_netif == FNET_NULL)
  151. {
  152. res_netif = netif_default;
  153. }
  154. #if FNET_CFG_LOOPBACK
  155. /* Anything sent to one of the host's own IP address is sent to the loopback interface.*/
  156. if(res_netif && (dest_ip == res_netif->ip4_addr.address))
  157. {
  158. res_netif = FNET_LOOP_IF;
  159. }
  160. #endif /* FNET_CFG_LOOPBACK */
  161. return res_netif;
  162. }
  163. /************************************************************************
  164. * DESCRIPTION: This function returns FNET_TRUE if the protocol message
  165. * will be fragmented by IPv4, and FNET_FALSE otherwise.
  166. *************************************************************************/
  167. fnet_bool_t _fnet_ip4_will_fragment( fnet_netif_t *netif, fnet_size_t protocol_message_size)
  168. {
  169. fnet_bool_t res;
  170. if((protocol_message_size + sizeof(fnet_ip4_header_t)) > netif->netif_mtu)
  171. {
  172. res = FNET_TRUE;
  173. }
  174. else
  175. {
  176. res = FNET_FALSE;
  177. }
  178. return res;
  179. }
  180. /************************************************************************
  181. * DESCRIPTION: IP output function.
  182. *
  183. * RETURNS: FNET_OK=OK
  184. * FNET_ERR_NETUNREACH=No route
  185. * FNET_ERR_MSGSIZE=Size error
  186. * FNET_ERR_NOMEM=No memory
  187. *************************************************************************/
  188. fnet_error_t _fnet_ip4_output( fnet_netif_t *netif, fnet_ip4_addr_t src_ip, fnet_ip4_addr_t dest_ip,
  189. fnet_uint8_t protocol, fnet_uint8_t tos, fnet_uint8_t ttl,
  190. fnet_netbuf_t *nb, fnet_bool_t DF, fnet_bool_t do_not_route,
  191. FNET_COMP_PACKED_VAR fnet_uint16_t *checksum )
  192. {
  193. static fnet_uint16_t ip_id = 0u;
  194. fnet_netbuf_t *nb_header;
  195. fnet_ip4_header_t *ipheader;
  196. fnet_size_t total_length;
  197. fnet_error_t error_code;
  198. if(netif == 0)
  199. {
  200. if((netif = _fnet_ip4_route(dest_ip)) == 0) /* No route */
  201. {
  202. error_code = FNET_ERR_NETUNREACH;
  203. goto DROP;
  204. }
  205. }
  206. /* If source address not specified, use address of outgoing interface */
  207. if(src_ip == INADDR_ANY)
  208. {
  209. src_ip = netif->ip4_addr.address;
  210. }
  211. if((nb->total_length + sizeof(fnet_ip4_header_t)) > FNET_IP4_MAX_PACKET)
  212. {
  213. error_code = FNET_ERR_MSGSIZE;
  214. goto DROP;
  215. }
  216. /* Construct IP header */
  217. if((nb_header = _fnet_netbuf_new(sizeof(fnet_ip4_header_t), FNET_TRUE)) == 0)
  218. {
  219. error_code = FNET_ERR_NOMEM;
  220. goto DROP;
  221. }
  222. /* Pseudo checksum. */
  223. if(checksum)
  224. {
  225. *checksum = _fnet_checksum_pseudo_netbuf_end( *checksum, (fnet_uint8_t *)&src_ip, (fnet_uint8_t *)&dest_ip, sizeof(fnet_ip4_addr_t) );
  226. }
  227. ipheader = (fnet_ip4_header_t *)nb_header->data_ptr;
  228. FNET_IP_HEADER_SET_VERSION(ipheader, (fnet_uint8_t)FNET_IP4_VERSION); /* version =4 */
  229. ipheader->id = fnet_htons(ip_id++); /* Id */
  230. ipheader->tos = tos; /* Type of service */
  231. total_length = (fnet_uint16_t)(nb->total_length + sizeof(fnet_ip4_header_t)); /* total length*/
  232. FNET_IP_HEADER_SET_HEADER_LENGTH(ipheader, sizeof(fnet_ip4_header_t) >> 2);
  233. ipheader->flags_fragment_offset = 0x0000u; /* flags & fragment offset field */
  234. if(DF)
  235. {
  236. ipheader->flags_fragment_offset |= FNET_HTONS(FNET_IP4_DF);
  237. }
  238. ipheader->ttl = ttl; /* time to live */
  239. ipheader->protocol = protocol; /* protocol */
  240. ipheader->source_addr = src_ip; /* source address */
  241. ipheader->desination_addr = dest_ip; /* destination address */
  242. ipheader->total_length = fnet_htons((fnet_uint16_t)total_length);
  243. nb = _fnet_netbuf_concat(nb_header, nb);
  244. if(total_length > netif->netif_mtu) /* IP Fragmentation. */
  245. {
  246. #if FNET_CFG_IP4_FRAGMENTATION
  247. fnet_size_t first_frag_length;
  248. fnet_size_t frag_length; /* The number of data in each fragment. */
  249. fnet_size_t offset;
  250. fnet_index_t error = 0u;
  251. fnet_netbuf_t *nb_prev;
  252. fnet_netbuf_t **nb_next_ptr = &nb->next_chain;
  253. fnet_size_t new_header_length;
  254. fnet_size_t header_length = (fnet_size_t)(FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2);
  255. fnet_ip4_header_t *new_ipheader;
  256. frag_length = (netif->netif_mtu - header_length) & ~7u; /* rounded down to an 8-byte boundary.*/
  257. first_frag_length = frag_length;
  258. if(((ipheader->flags_fragment_offset & FNET_HTONS(FNET_IP4_DF)) != 0u) || /* The fragmentation is prohibited. */
  259. (frag_length < 8u)) /* The MTU is too small.*/
  260. {
  261. error_code = FNET_ERR_MSGSIZE;
  262. goto DROP;
  263. }
  264. /* The header (and options) must reside in contiguous area of memory.*/
  265. if(_fnet_netbuf_pullup(&nb, header_length) == FNET_ERR)
  266. {
  267. error_code = FNET_ERR_NOMEM;
  268. goto DROP;
  269. }
  270. ipheader = (fnet_ip4_header_t *)nb->data_ptr;
  271. nb_prev = nb;
  272. /* Go through the whole data segment after first fragment.*/
  273. for (offset = (header_length + frag_length); offset < total_length; offset += frag_length)
  274. {
  275. fnet_netbuf_t *nb_tmp;
  276. nb = _fnet_netbuf_new(header_length, FNET_FALSE); /* Allocate a new header.*/
  277. if(nb == 0)
  278. {
  279. error++;
  280. goto FRAG_END;
  281. }
  282. fnet_memcpy(nb->data_ptr, ipheader, header_length); /* Copy IP header.*/
  283. new_ipheader = (fnet_ip4_header_t *)nb->data_ptr;
  284. new_header_length = sizeof(fnet_ip4_header_t);
  285. FNET_IP_HEADER_SET_HEADER_LENGTH(new_ipheader, (fnet_uint8_t)(new_header_length >> 2));
  286. new_ipheader->flags_fragment_offset = fnet_htons((fnet_uint16_t)((offset - header_length) >> 3));
  287. if(offset + frag_length >= total_length)
  288. {
  289. frag_length = (total_length - offset);
  290. }
  291. else
  292. {
  293. new_ipheader->flags_fragment_offset |= FNET_HTONS(FNET_IP4_MF);
  294. }
  295. /* Copy the data from the original packet into the fragment.*/
  296. if((nb_tmp = _fnet_netbuf_copy(nb_prev, offset, frag_length, FNET_FALSE)) == 0)
  297. {
  298. error++;
  299. _fnet_netbuf_free_chain(nb);
  300. goto FRAG_END;
  301. }
  302. nb = _fnet_netbuf_concat(nb, nb_tmp);
  303. new_ipheader->total_length = fnet_htons((fnet_uint16_t)nb->total_length);
  304. *nb_next_ptr = nb;
  305. nb_next_ptr = &nb->next_chain;
  306. }
  307. /* Update the first fragment.*/
  308. nb = nb_prev;
  309. _fnet_netbuf_trim(&nb, (fnet_int32_t)(header_length + first_frag_length - fnet_ntohs(ipheader->total_length)));
  310. ipheader->total_length = fnet_htons((fnet_uint16_t)nb->total_length);
  311. ipheader->flags_fragment_offset |= FNET_HTONS(FNET_IP4_MF);
  312. FRAG_END:
  313. for (nb = nb_prev; nb; nb = nb_prev) /* Send each fragment.*/
  314. {
  315. nb_prev = nb->next_chain;
  316. nb->next_chain = 0;
  317. if(error == 0u)
  318. {
  319. _fnet_ip4_trace("TX", nb->data_ptr); /* Print IP header. */
  320. _fnet_ip4_netif_output(netif, dest_ip, nb, do_not_route);
  321. }
  322. else
  323. {
  324. _fnet_netbuf_free_chain(nb);
  325. }
  326. }
  327. #else
  328. error_code = FNET_ERR_MSGSIZE; /* Discard datagram.*/
  329. goto DROP;
  330. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  331. }
  332. else
  333. {
  334. _fnet_ip4_netif_output(netif, dest_ip, nb, do_not_route);
  335. }
  336. return (FNET_ERR_OK);
  337. DROP:
  338. _fnet_netbuf_free_chain(nb); /* Discard datagram */
  339. return (error_code);
  340. }
  341. /************************************************************************
  342. * DESCRIPTION:
  343. *************************************************************************/
  344. static void _fnet_ip4_netif_output(struct fnet_netif *netif, fnet_ip4_addr_t dest_ip_addr, fnet_netbuf_t *nb, fnet_bool_t do_not_route)
  345. {
  346. fnet_ip4_header_t *ipheader = (fnet_ip4_header_t *)nb->data_ptr;
  347. /* IPv4 Header Checksum*/
  348. ipheader->checksum = 0u;
  349. #if FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM
  350. if(netif->features & FNET_NETIF_FEATURE_HW_TX_IP_CHECKSUM)
  351. nb->flags |= FNET_NETBUF_FLAG_HW_IP_CHECKSUM;
  352. else
  353. #endif
  354. ipheader->checksum = _fnet_checksum_netbuf(nb, (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2); /* IP checksum*/
  355. if( /* Datagrams sent to a broadcast address */
  356. (_fnet_ip4_addr_is_broadcast(dest_ip_addr, netif))
  357. /* Datagrams sent to a multicast address. */
  358. || FNET_IP4_ADDR_IS_MULTICAST(dest_ip_addr) )
  359. {
  360. #if FNET_CFG_LOOPBACK && (FNET_CFG_LOOPBACK_MULTICAST || FNET_CFG_LOOPBACK_BROADCAST)
  361. fnet_netbuf_t *nb_loop;
  362. if(netif != FNET_LOOP_IF) /* Avoid double send to the loopback interface.*/
  363. {
  364. /* Datagrams sent to a broadcast/multicast address are copied to the loopback interface.*/
  365. if((nb_loop = _fnet_netbuf_copy(nb, 0, FNET_NETBUF_COPYALL, FNET_TRUE)) != 0)
  366. {
  367. _fnet_loop_output_ip4(netif, dest_ip_addr, nb_loop);
  368. }
  369. }
  370. #endif /* FNET_CFG_LOOPBACK && (FNET_CFG_LOOPBACK_MULTICAST || FNET_CFG_LOOPBACK_BROADCAST) */
  371. }
  372. else
  373. {
  374. if(!((do_not_route) || (_fnet_ip4_addr_is_onlink(netif, dest_ip_addr) == FNET_TRUE)))
  375. {
  376. /* Use the default router as the address to send.*/
  377. dest_ip_addr = netif->ip4_addr.gateway;
  378. }
  379. }
  380. /* Send to Interface.*/
  381. netif->netif_api->netif_output_ip4(netif, dest_ip_addr, nb);
  382. }
  383. /************************************************************************
  384. * DESCRIPTION: Checks if the address is on-link.
  385. * Returns FNET_TRUE if it is on-link, FNET_FALSE otherwise.
  386. *************************************************************************/
  387. static fnet_bool_t _fnet_ip4_addr_is_onlink(fnet_netif_t *netif, fnet_ip4_addr_t addr)
  388. {
  389. fnet_bool_t on_link;
  390. if(((addr & netif->ip4_addr.subnetmask) == (netif->ip4_addr.address & netif->ip4_addr.subnetmask))
  391. /* RFC3927: If the destination address is in the 169.254/16 prefix, then the sender
  392. MUST send its packet directly to the destination on the same physical link. This MUST be
  393. done whether the interface is configured with a Link-Local or a routable IPv4 address. */
  394. || ((addr & FNET_IP4_ADDR_LINK_LOCAL_PREFIX) == (FNET_IP4_ADDR_LINK_LOCAL_PREFIX)))
  395. {
  396. on_link = FNET_TRUE;
  397. }
  398. else
  399. {
  400. on_link = FNET_FALSE;
  401. }
  402. return on_link;
  403. }
  404. /************************************************************************
  405. * DESCRIPTION: Prepare sockets addreses for upper protocol.
  406. *************************************************************************/
  407. void _fnet_ip4_set_socket_addr(fnet_netif_t *netif, fnet_ip4_header_t *ip_hdr, struct fnet_sockaddr *src_addr, struct fnet_sockaddr *dest_addr )
  408. {
  409. fnet_memset_zero(src_addr, sizeof(struct fnet_sockaddr));
  410. src_addr->sa_family = AF_INET;
  411. src_addr->sa_scope_id = netif->scope_id;
  412. ((struct fnet_sockaddr_in *)(src_addr))->sin_addr.s_addr = ip_hdr->source_addr;
  413. fnet_memset_zero(dest_addr, sizeof(struct fnet_sockaddr));
  414. dest_addr->sa_family = AF_INET;
  415. dest_addr->sa_scope_id = netif->scope_id;
  416. ((struct fnet_sockaddr_in *)(dest_addr))->sin_addr.s_addr = ip_hdr->desination_addr;
  417. }
  418. /************************************************************************
  419. * DESCRIPTION: IP input function.
  420. *************************************************************************/
  421. void _fnet_ip4_input( fnet_netif_t *netif, fnet_netbuf_t *nb )
  422. {
  423. if(netif && nb)
  424. {
  425. if(_fnet_ip_queue_append(&ip_queue, netif, nb) != FNET_OK)
  426. {
  427. _fnet_netbuf_free_chain(nb);
  428. return;
  429. }
  430. /* Initiate S/W Interrupt*/
  431. fnet_event_raise(ip_event);
  432. }
  433. }
  434. /************************************************************************
  435. * DESCRIPTION: This function performs handling of incoming datagrams.
  436. *************************************************************************/
  437. static void _fnet_ip4_input_low(void *cookie)
  438. {
  439. fnet_ip4_header_t *hdr;
  440. fnet_netbuf_t *ip4_nb;
  441. fnet_prot_if_t *protocol;
  442. fnet_netif_t *netif;
  443. fnet_netbuf_t *nb;
  444. fnet_ip4_addr_t destination_addr;
  445. fnet_size_t total_length;
  446. fnet_size_t header_length;
  447. struct fnet_sockaddr src_addr;
  448. struct fnet_sockaddr dest_addr;
  449. FNET_COMP_UNUSED_ARG(cookie);
  450. fnet_isr_lock();
  451. while((nb = _fnet_ip_queue_read(&ip_queue, &netif)) != 0)
  452. {
  453. nb->next_chain = 0;
  454. /* The header must reside in contiguous area of memory. */
  455. if(_fnet_netbuf_pullup(&nb, sizeof(fnet_ip4_header_t)) == FNET_ERR)
  456. {
  457. _fnet_netbuf_free_chain(nb);
  458. continue;
  459. }
  460. hdr = (fnet_ip4_header_t *)nb->data_ptr;
  461. destination_addr = hdr->desination_addr;
  462. total_length = fnet_ntohs(hdr->total_length);
  463. header_length = (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(hdr) << 2;
  464. _fnet_ip4_trace("RX", hdr); /* Print IP header. */
  465. if((nb->total_length >= total_length) /* Check the amount of data*/
  466. && (nb->total_length >= sizeof(fnet_ip4_header_t))
  467. && (FNET_IP_HEADER_GET_VERSION(hdr) == 4u) /* Check the IP Version*/
  468. && (header_length >= sizeof(fnet_ip4_header_t)) /* Check the IP header length*/
  469. && (total_length >= header_length)
  470. #if FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM || FNET_CFG_CPU_ETH_HW_RX_IP_CHECKSUM
  471. && ((netif->features & FNET_NETIF_FEATURE_HW_RX_IP_CHECKSUM)
  472. || (nb->flags | FNET_NETBUF_FLAG_HW_IP_CHECKSUM)
  473. || (_fnet_checksum_netbuf(nb, header_length) == 0u) ) /* Checksum*/
  474. #else
  475. && (_fnet_checksum_netbuf(nb, header_length) == 0u) /* Checksum*/
  476. #endif
  477. && ((destination_addr == netif->ip4_addr.address) /* It is final destination*/
  478. || (_fnet_ip4_addr_is_broadcast(destination_addr, netif))
  479. || ((netif->ip4_addr.address == INADDR_ANY) && ((nb->flags & FNET_NETBUF_FLAG_BROADCAST) == FNET_NETBUF_FLAG_BROADCAST)) /* Check frame broadcast flag, in case no address signed yet (e.g. DHCP).*/
  480. #if FNET_CFG_MULTICAST
  481. || (FNET_IP4_ADDR_IS_MULTICAST(destination_addr))
  482. #endif
  483. || (netif->netif_api->netif_type == FNET_NETIF_TYPE_LOOPBACK)
  484. )
  485. )
  486. {
  487. if(nb->total_length > total_length)
  488. {
  489. /* Logical size and the physical size of the packet should be the same.*/
  490. _fnet_netbuf_trim(&nb, (fnet_int32_t)(total_length - nb->total_length));
  491. }
  492. /* Reassembly.*/
  493. if((hdr->flags_fragment_offset & ~FNET_HTONS(FNET_IP4_DF)) != 0u) /* the MF bit or fragment offset is nonzero.*/
  494. {
  495. #if FNET_CFG_IP4_FRAGMENTATION
  496. _fnet_ip4_reassembly(&nb);
  497. if(nb == FNET_NULL)
  498. {
  499. continue;
  500. }
  501. hdr = (fnet_ip4_header_t *)nb->data_ptr;
  502. header_length = (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(hdr) << 2;
  503. #else
  504. _fnet_netbuf_free_chain(nb);
  505. continue;
  506. #endif
  507. }
  508. #if FNET_CFG_CPU_ETH_HW_RX_PROTOCOL_CHECKSUM
  509. else
  510. {
  511. if((netif->features & FNET_NETIF_FEATURE_HW_RX_PROTOCOL_CHECKSUM) &&
  512. ((hdr->protocol == FNET_PROT_ICMP4) ||
  513. (hdr->protocol == FNET_PROT_UDP) ||
  514. (hdr->protocol == FNET_PROT_TCP)) )
  515. {
  516. nb->flags |= FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM;
  517. }
  518. }
  519. #endif
  520. if(nb->total_length > FNET_IP4_MAX_PACKET)
  521. {
  522. _fnet_netbuf_free_chain(nb); /* Discard datagram */
  523. continue;
  524. }
  525. ip4_nb = _fnet_netbuf_copy(nb, 0u, (header_length + 8u), FNET_FALSE);
  526. _fnet_netbuf_trim(&nb, (fnet_int32_t)header_length);
  527. /**************************************
  528. * Send to upper layers.
  529. **************************************/
  530. /* Prepare addreses for upper protocol.*/
  531. _fnet_ip4_set_socket_addr(netif, hdr, &src_addr, &dest_addr );
  532. #if FNET_CFG_RAW
  533. /* RAW Sockets inpput.*/
  534. _fnet_raw_input(netif, &src_addr, &dest_addr, nb, ip4_nb);
  535. #endif
  536. /* Find transport protocol.*/
  537. if((protocol = _fnet_prot_find(AF_INET, SOCK_UNSPEC, (fnet_uint32_t)hdr->protocol)) != FNET_NULL)
  538. {
  539. protocol->prot_input(netif, &src_addr, &dest_addr, nb, ip4_nb);
  540. /* After that nb may point to wrong place. Do not use it.*/
  541. }
  542. else
  543. /* No protocol found.*/
  544. {
  545. _fnet_netbuf_free_chain(nb);
  546. _fnet_icmp4_error(netif, FNET_ICMP4_UNREACHABLE, FNET_ICMP4_UNREACHABLE_PROTOCOL, ip4_nb);
  547. }
  548. }
  549. else
  550. {
  551. _fnet_netbuf_free_chain(nb);
  552. }
  553. } /* while end */
  554. fnet_isr_unlock();
  555. }
  556. /************************************************************************
  557. * DESCRIPTION: This function attempts to assemble a complete datagram.
  558. *************************************************************************/
  559. #if FNET_CFG_IP4_FRAGMENTATION
  560. static void _fnet_ip4_reassembly( fnet_netbuf_t **nb_ptr )
  561. {
  562. fnet_ip4_frag_list_t *frag_list_ptr;
  563. fnet_ip4_frag_header_t *frag_ptr;
  564. fnet_ip4_frag_header_t *cur_frag_ptr;
  565. fnet_netbuf_t *nb = *nb_ptr;
  566. fnet_ip4_header_t *iphdr;
  567. fnet_size_t i;
  568. fnet_uint16_t offset;
  569. fnet_size_t hdr_length;
  570. /* For this algorithm the all datagram must reside in contiguous area of memory.*/
  571. if(_fnet_netbuf_pullup(&nb, nb->total_length) == FNET_ERR)
  572. {
  573. goto DROP_FRAG;
  574. }
  575. iphdr = (fnet_ip4_header_t *)nb->data_ptr;
  576. /* Liner search of the list to locate the appropriate datagram for the current fragment.*/
  577. for (frag_list_ptr = ip_frag_list_head; frag_list_ptr != 0; frag_list_ptr = frag_list_ptr->next)
  578. {
  579. if((frag_list_ptr->id == iphdr->id) && (frag_list_ptr->protocol == iphdr->protocol)
  580. && (frag_list_ptr->source_addr == iphdr->source_addr)
  581. && (frag_list_ptr->desination_addr == iphdr->desination_addr))
  582. {
  583. break;
  584. }
  585. }
  586. cur_frag_ptr = (fnet_ip4_frag_header_t *)iphdr;
  587. /* Exclude the standard IP header and options.*/
  588. hdr_length = (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(iphdr) << 2;
  589. _fnet_netbuf_trim(&nb, (fnet_int32_t)hdr_length);
  590. cur_frag_ptr->total_length = (fnet_uint16_t)(fnet_ntohs(cur_frag_ptr->total_length) - hdr_length); /* Host endian.*/
  591. if(frag_list_ptr == 0) /* The first fragment of the new datagram.*/
  592. {
  593. if((frag_list_ptr = (fnet_ip4_frag_list_t *)_fnet_malloc_zero(sizeof(fnet_ip4_frag_list_t))) == 0) /* Create list.*/
  594. {
  595. goto DROP_FRAG;
  596. }
  597. _fnet_ip4_frag_list_add(&ip_frag_list_head, frag_list_ptr);
  598. frag_list_ptr->ttl = (fnet_uint8_t)FNET_IP4_FRAG_TTL;
  599. frag_list_ptr->id = iphdr->id;
  600. frag_list_ptr->protocol = iphdr->protocol;
  601. frag_list_ptr->source_addr = iphdr->source_addr;
  602. frag_list_ptr->desination_addr = iphdr->desination_addr;
  603. frag_ptr = 0;
  604. if((iphdr->flags_fragment_offset & FNET_HTONS(FNET_IP4_MF)) != 0u)
  605. {
  606. cur_frag_ptr->mf |= 1u;
  607. }
  608. cur_frag_ptr->offset = (fnet_uint16_t)(fnet_ntohs(cur_frag_ptr->offset) << 3); /* Convert offset to bytes (Host endian).*/
  609. cur_frag_ptr->nb = nb;
  610. _fnet_ip4_frag_add(&frag_list_ptr->frag_ptr, cur_frag_ptr, FNET_NULL);
  611. }
  612. else
  613. {
  614. if((iphdr->flags_fragment_offset & FNET_HTONS(FNET_IP4_MF)) != 0u)
  615. {
  616. cur_frag_ptr->mf |= 1u;
  617. }
  618. cur_frag_ptr->offset = (fnet_uint16_t)(fnet_ntohs(cur_frag_ptr->offset) << 3); /* Convert offset to bytes.*/
  619. cur_frag_ptr->nb = nb;
  620. /* Find position in reassembly list.*/
  621. frag_ptr = frag_list_ptr->frag_ptr;
  622. do
  623. {
  624. if(frag_ptr->offset > cur_frag_ptr->offset)
  625. {
  626. break;
  627. }
  628. frag_ptr = frag_ptr->next;
  629. }
  630. while (frag_ptr != frag_list_ptr->frag_ptr);
  631. /* Trims or discards icoming fragments.*/
  632. if(frag_ptr != frag_list_ptr->frag_ptr)
  633. {
  634. if((i = (fnet_size_t)(frag_ptr->prev->offset + frag_ptr->prev->total_length - cur_frag_ptr->offset)) != 0u)
  635. {
  636. if(i >= cur_frag_ptr->total_length)
  637. {
  638. goto DROP_FRAG;
  639. }
  640. _fnet_netbuf_trim(&nb, (fnet_int32_t)i);
  641. cur_frag_ptr->total_length -= (fnet_uint16_t)i;
  642. cur_frag_ptr->offset += (fnet_uint16_t)i;
  643. }
  644. }
  645. /* Trims or discards existing fragments.*/
  646. while((frag_ptr != frag_list_ptr->frag_ptr)
  647. && ((cur_frag_ptr->offset + cur_frag_ptr->total_length) > frag_ptr->offset))
  648. {
  649. i = (fnet_size_t)((cur_frag_ptr->offset + cur_frag_ptr->total_length) - frag_ptr->offset);
  650. if(i < frag_ptr->total_length)
  651. {
  652. frag_ptr->total_length -= (fnet_uint16_t)i;
  653. frag_ptr->offset += (fnet_uint16_t)i;
  654. _fnet_netbuf_trim((fnet_netbuf_t **)&frag_ptr->nb, (fnet_int32_t)i);
  655. break;
  656. }
  657. frag_ptr = frag_ptr->next;
  658. _fnet_netbuf_free_chain(frag_ptr->prev->nb);
  659. _fnet_ip4_frag_del(&frag_list_ptr->frag_ptr, frag_ptr->prev);
  660. }
  661. /* Insert fragment to the list.*/
  662. _fnet_ip4_frag_add(&frag_list_ptr->frag_ptr, cur_frag_ptr, frag_ptr->prev);
  663. }
  664. offset = 0u;
  665. frag_ptr = frag_list_ptr->frag_ptr;
  666. do
  667. {
  668. if(frag_ptr->offset != offset)
  669. {
  670. goto NEXT_FRAG;
  671. }
  672. offset += frag_ptr->total_length;
  673. frag_ptr = frag_ptr->next;
  674. }
  675. while (frag_ptr != frag_list_ptr->frag_ptr);
  676. if((frag_ptr->prev->mf & 1u) != 0u)
  677. {
  678. goto NEXT_FRAG;
  679. }
  680. /* Reconstruct datagram.*/
  681. frag_ptr = frag_list_ptr->frag_ptr;
  682. nb = frag_ptr->nb;
  683. frag_ptr = frag_ptr->next;
  684. while(frag_ptr != frag_list_ptr->frag_ptr)
  685. {
  686. nb = _fnet_netbuf_concat(nb, frag_ptr->nb);
  687. frag_ptr = frag_ptr->next;
  688. }
  689. /* Reconstruct datagram header.*/
  690. iphdr = (fnet_ip4_header_t *)frag_list_ptr->frag_ptr;
  691. nb->total_length += (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(iphdr) << 2;
  692. nb->length += (fnet_size_t)FNET_IP_HEADER_GET_HEADER_LENGTH(iphdr) << 2;
  693. nb->data_ptr = (fnet_uint8_t *)nb->data_ptr - (FNET_IP_HEADER_GET_HEADER_LENGTH(iphdr) << 2);
  694. iphdr->total_length = fnet_htons((fnet_uint16_t)nb->total_length);
  695. iphdr->source_addr = frag_list_ptr->source_addr;
  696. iphdr->desination_addr = frag_list_ptr->desination_addr;
  697. iphdr->protocol = frag_list_ptr->protocol;
  698. iphdr->tos &= ~1u;
  699. _fnet_ip4_frag_list_del(&ip_frag_list_head, frag_list_ptr);
  700. _fnet_free(frag_list_ptr);
  701. goto EXIT;
  702. DROP_FRAG:
  703. _fnet_netbuf_free_chain(nb);
  704. NEXT_FRAG:
  705. nb = FNET_NULL;
  706. EXIT:
  707. *nb_ptr = nb;
  708. }
  709. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  710. /************************************************************************
  711. * DESCRIPTION: IP timer function.
  712. *************************************************************************/
  713. #if FNET_CFG_IP4_FRAGMENTATION
  714. static void _fnet_ip4_timer(fnet_uint32_t cookie)
  715. {
  716. fnet_ip4_frag_list_t *frag_list_ptr;
  717. fnet_ip4_frag_list_t *tmp_frag_list_ptr;
  718. FNET_COMP_UNUSED_ARG(cookie);
  719. fnet_isr_lock();
  720. frag_list_ptr = ip_frag_list_head;
  721. while(frag_list_ptr != 0)
  722. {
  723. frag_list_ptr->ttl--;
  724. if(frag_list_ptr->ttl == 0u)
  725. {
  726. tmp_frag_list_ptr = frag_list_ptr->next;
  727. _fnet_ip4_frag_list_free(frag_list_ptr);
  728. frag_list_ptr = tmp_frag_list_ptr;
  729. }
  730. else
  731. {
  732. frag_list_ptr = frag_list_ptr->next;
  733. }
  734. }
  735. fnet_isr_unlock();
  736. }
  737. #endif
  738. /************************************************************************
  739. * DESCRIPTION: This function tries to free not critical parts
  740. * of memory occupied by the IP module.
  741. *************************************************************************/
  742. void _fnet_ip4_drain( void )
  743. {
  744. fnet_isr_lock();
  745. #if FNET_CFG_IP4_FRAGMENTATION
  746. while(((volatile fnet_ip4_frag_list_t *)ip_frag_list_head) != 0)
  747. {
  748. _fnet_ip4_frag_list_free(ip_frag_list_head);
  749. }
  750. #endif
  751. while(((volatile fnet_netbuf_t *)ip_queue.head) != 0)
  752. {
  753. _fnet_netbuf_queue_del(&ip_queue.head, ip_queue.head);
  754. }
  755. ip_queue.count = 0u;
  756. fnet_isr_unlock();
  757. }
  758. /************************************************************************
  759. * DESCRIPTION: This function frees list of datagram fragments.
  760. *************************************************************************/
  761. #if FNET_CFG_IP4_FRAGMENTATION
  762. static void _fnet_ip4_frag_list_free( fnet_ip4_frag_list_t *list )
  763. {
  764. fnet_netbuf_t *nb;
  765. if(list)
  766. {
  767. fnet_isr_lock();
  768. while((volatile fnet_ip4_frag_header_t *)(list->frag_ptr) != 0)
  769. {
  770. nb = list->frag_ptr->nb;
  771. _fnet_ip4_frag_del((fnet_ip4_frag_header_t **)(&list->frag_ptr), list->frag_ptr);
  772. _fnet_netbuf_free_chain(nb);
  773. }
  774. _fnet_ip4_frag_list_del(&ip_frag_list_head, list);
  775. _fnet_free(list);
  776. fnet_isr_unlock();
  777. }
  778. }
  779. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  780. /************************************************************************
  781. * DESCRIPTION: Adds frag list to the general frag list.
  782. *************************************************************************/
  783. #if FNET_CFG_IP4_FRAGMENTATION
  784. static void _fnet_ip4_frag_list_add( fnet_ip4_frag_list_t **head, fnet_ip4_frag_list_t *fl )
  785. {
  786. fl->next = *head;
  787. if(fl->next != 0)
  788. {
  789. fl->next->prev = fl;
  790. }
  791. fl->prev = 0;
  792. *head = fl;
  793. }
  794. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  795. /************************************************************************
  796. * DESCRIPTION: Deletes frag list from the general frag list.
  797. *************************************************************************/
  798. #if FNET_CFG_IP4_FRAGMENTATION
  799. static void _fnet_ip4_frag_list_del( fnet_ip4_frag_list_t **head, fnet_ip4_frag_list_t *fl )
  800. {
  801. if(fl->prev == 0)
  802. {
  803. *head = fl->next;
  804. }
  805. else
  806. {
  807. fl->prev->next = fl->next;
  808. }
  809. if(fl->next != 0)
  810. {
  811. fl->next->prev = fl->prev;
  812. }
  813. }
  814. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  815. /************************************************************************
  816. * DESCRIPTION: Adds frag to the frag list.
  817. *************************************************************************/
  818. #if FNET_CFG_IP4_FRAGMENTATION
  819. static void _fnet_ip4_frag_add( fnet_ip4_frag_header_t *FNET_COMP_PACKED_VAR *head, fnet_ip4_frag_header_t *frag,
  820. fnet_ip4_frag_header_t *frag_prev )
  821. {
  822. if(frag_prev && ( *head))
  823. {
  824. frag->next = frag_prev->next;
  825. frag->prev = frag_prev;
  826. frag_prev->next->prev = frag;
  827. frag_prev->next = frag;
  828. if((*head)->offset > frag->offset)
  829. {
  830. *head = frag;
  831. }
  832. }
  833. else
  834. {
  835. frag->next = frag;
  836. frag->prev = frag;
  837. *head = frag;
  838. }
  839. }
  840. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  841. /************************************************************************
  842. * DESCRIPTION: Deletes frag from the frag list.
  843. *************************************************************************/
  844. #if FNET_CFG_IP4_FRAGMENTATION
  845. static void _fnet_ip4_frag_del( fnet_ip4_frag_header_t *FNET_COMP_PACKED_VAR *head, fnet_ip4_frag_header_t *frag )
  846. {
  847. if(frag->prev == frag)
  848. {
  849. *head = 0;
  850. }
  851. else
  852. {
  853. frag->prev->next = frag->next;
  854. frag->next->prev = frag->prev;
  855. if(*head == frag)
  856. {
  857. *head = frag->next;
  858. }
  859. }
  860. }
  861. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  862. #if FNET_CFG_MULTICAST
  863. /************************************************************************
  864. * DESCRIPTION: Join a multicast group. Returns pointer to the entry in
  865. * the multicast list, or FNET_NULL if any error;
  866. *************************************************************************/
  867. fnet_ip4_multicast_list_entry_t *_fnet_ip4_multicast_join( fnet_netif_t *netif, fnet_ip4_addr_t group_addr )
  868. {
  869. fnet_index_t i;
  870. fnet_ip4_multicast_list_entry_t *result = FNET_NULL;
  871. /* Find existing entry or free one.*/
  872. for(i = 0u; i < FNET_CFG_MULTICAST_MAX; i++)
  873. {
  874. if(fnet_ip4_multicast_list[i].user_counter > 0u)
  875. {
  876. if((fnet_ip4_multicast_list[i].netif == netif) && (fnet_ip4_multicast_list[i].group_addr == group_addr))
  877. {
  878. result = &fnet_ip4_multicast_list[i];
  879. break; /* Found.*/
  880. }
  881. }
  882. else /* user_counter == 0.*/
  883. {
  884. result = &fnet_ip4_multicast_list[i]; /* Save the last free.*/
  885. }
  886. }
  887. if(result)
  888. {
  889. result->user_counter++; /* Increment user counter.*/
  890. if(result->user_counter == 1u) /* New entry.*/
  891. {
  892. result->group_addr = group_addr;
  893. result->netif = netif;
  894. /* Join HW interface. */
  895. _fnet_netif_join_ip4_multicast ( (fnet_netif_desc_t) netif, group_addr );
  896. #if FNET_CFG_IGMP /* Send IGMP report.*/
  897. /*
  898. * When a host joins a new group, it should immediately transmit a
  899. * Report for that group.
  900. * TBD To cover the possibility of the initial Report being lost or damaged, it is
  901. * recommended that it be repeated once or twice after short delays.
  902. */
  903. _fnet_igmp_join(netif, group_addr );
  904. #endif /* FNET_CFG_IGMP */
  905. }
  906. }
  907. return result;
  908. }
  909. /************************************************************************
  910. * DESCRIPTION: Leave a multicast group.
  911. *************************************************************************/
  912. void _fnet_ip4_multicast_leave_entry( fnet_ip4_multicast_list_entry_t *multicastentry )
  913. {
  914. if(multicastentry)
  915. {
  916. multicastentry->user_counter--; /* Decrement user counter.*/
  917. if(multicastentry->user_counter == 0u)
  918. {
  919. #if FNET_CFG_IGMP /* Send IGMP leave.*/
  920. /* Leave via IGMP */
  921. _fnet_igmp_leave( multicastentry->netif, multicastentry->group_addr );
  922. #endif /* FNET_CFG_IGMP */
  923. /* Leave HW interface. */
  924. _fnet_netif_leave_ip4_multicast ( (fnet_netif_desc_t) multicastentry->netif, multicastentry->group_addr );
  925. }
  926. }
  927. }
  928. #endif /* FNET_CFG_MULTICAST */
  929. /************************************************************************
  930. * DESCRIPTION: Is the address is broadcast?
  931. *************************************************************************/
  932. fnet_bool_t _fnet_ip4_addr_is_broadcast( fnet_ip4_addr_t addr, fnet_netif_t *netif )
  933. {
  934. fnet_netif_ip4_addr_t *netif_addr;
  935. fnet_bool_t result = FNET_FALSE;
  936. if((addr == INADDR_BROADCAST) /* Limited broadcast */
  937. || (addr == INADDR_ANY)
  938. || (addr == FNET_IP4_ADDR_LINK_LOCAL_BROADCAST) )/* Link-local broadcast (RFC3927)*/
  939. {
  940. result = FNET_TRUE;
  941. }
  942. else if(netif == FNET_NULL)
  943. {
  944. _fnet_stack_mutex_lock();
  945. for (netif = fnet_netif_list; netif != 0; netif = netif->next)
  946. {
  947. netif_addr = &(netif->ip4_addr);
  948. if( (addr == netif_addr->netbroadcast) || /* Net-directed broadcast */
  949. (addr == netif_addr->subnetbroadcast) || /* Subnet-directed broadcast */
  950. (addr == netif_addr->subnet))
  951. {
  952. result = FNET_TRUE;
  953. break;
  954. }
  955. }
  956. _fnet_stack_mutex_unlock();
  957. }
  958. else
  959. {
  960. netif_addr = &(netif->ip4_addr);
  961. if( (addr == netif_addr->netbroadcast) || /* Net-directed broadcast */
  962. (addr == netif_addr->subnetbroadcast) || /* Subnet-directed broadcast */
  963. (addr == netif_addr->subnet))
  964. {
  965. result = FNET_TRUE;
  966. }
  967. }
  968. return result;
  969. }
  970. /*Todo path MTU discovery feature
  971. *Todo get MTU from a routing table, depending on destination MTU*/
  972. fnet_size_t _fnet_ip4_maximum_packet( fnet_ip4_addr_t dest_ip )
  973. {
  974. fnet_size_t result;
  975. #if FNET_CFG_IP4_FRAGMENTATION == 0
  976. {
  977. fnet_netif_t *netif;
  978. if((netif = _fnet_ip4_route(dest_ip)) == 0) /* No route*/
  979. {
  980. result = FNET_IP4_MAX_PACKET;
  981. }
  982. else
  983. {
  984. result = netif->netif_mtu;
  985. }
  986. }
  987. #else
  988. FNET_COMP_UNUSED_ARG(dest_ip);
  989. result = FNET_IP4_MAX_PACKET;
  990. #endif
  991. result = (result - (FNET_IP4_MAX_OPTIONS + sizeof(fnet_ip4_header_t))) & (~0x3LU);
  992. return result;
  993. }
  994. /************************************************************************
  995. * DESCRIPTION: This function retrieves the current value
  996. * of IPv4 socket option.
  997. *************************************************************************/
  998. fnet_error_t _fnet_ip4_getsockopt(struct _fnet_socket_if_t *sock, fnet_socket_options_t optname, void *optval, fnet_size_t *optlen )
  999. {
  1000. fnet_error_t result = FNET_ERR_OK;
  1001. switch(optname) /* Socket options processing. */
  1002. {
  1003. case IP_TOS: /* Get IP TOS for outgoing datagrams.*/
  1004. if(*optlen < sizeof(fnet_uint32_t))
  1005. {
  1006. result = FNET_ERR_INVAL;
  1007. break;
  1008. }
  1009. *((fnet_uint32_t *)optval) = (fnet_uint32_t)sock->options.ip4_opt.tos;
  1010. *optlen = sizeof(fnet_uint32_t);
  1011. break;
  1012. case IP_TTL: /* Get IP TTL for outgoing datagrams.*/
  1013. if(*optlen < sizeof(fnet_uint32_t))
  1014. {
  1015. result = FNET_ERR_INVAL;
  1016. break;
  1017. }
  1018. *((fnet_uint32_t *)optval) = (fnet_uint32_t)sock->options.ip4_opt.ttl;
  1019. *optlen = sizeof(fnet_uint32_t);
  1020. break;
  1021. #if FNET_CFG_MULTICAST
  1022. case IP_MULTICAST_TTL: /* Get IP TTL for outgoing datagrams.*/
  1023. if(*optlen < sizeof(fnet_uint32_t))
  1024. {
  1025. result = FNET_ERR_INVAL;
  1026. break;
  1027. }
  1028. *((fnet_uint32_t *)optval) = (fnet_uint32_t)sock->options.ip4_opt.ttl_multicast;
  1029. *optlen = sizeof(fnet_uint32_t);
  1030. break;
  1031. #endif /* FNET_CFG_MULTICAST */
  1032. default:
  1033. result = FNET_ERR_NOPROTOOPT; /* The option is unknown or unsupported.*/
  1034. break;
  1035. }
  1036. return result;
  1037. }
  1038. /************************************************************************
  1039. * DESCRIPTION: This function sets the value of IPv4 socket option.
  1040. *************************************************************************/
  1041. fnet_error_t _fnet_ip4_setsockopt(struct _fnet_socket_if_t *sock, fnet_socket_options_t optname, const void *optval, fnet_size_t optlen )
  1042. {
  1043. fnet_error_t result = FNET_ERR_OK;
  1044. switch(optname) /* Socket options processing. */
  1045. {
  1046. /******************************/
  1047. case IP_TOS: /* Set IP TOS for outgoing datagrams. */
  1048. if(optlen < sizeof(fnet_uint32_t))
  1049. {
  1050. result = FNET_ERR_INVAL;
  1051. break;
  1052. }
  1053. sock->options.ip4_opt.tos = (fnet_uint8_t) (*((const fnet_uint32_t *)(optval)));
  1054. break;
  1055. /******************************/
  1056. case IP_TTL: /* Set IP TTL for outgoing datagrams. */
  1057. if(optlen < sizeof(fnet_uint32_t))
  1058. {
  1059. result = FNET_ERR_INVAL;
  1060. break;
  1061. }
  1062. sock->options.ip4_opt.ttl = (fnet_uint8_t) (*((const fnet_uint32_t *)(optval)));
  1063. break;
  1064. #if FNET_CFG_MULTICAST
  1065. /******************************/
  1066. case IP_MULTICAST_TTL: /* Set IP TTL for outgoing Multicast datagrams. */
  1067. /* Validation.*/
  1068. if( (optlen < sizeof(fnet_uint32_t)) || (!(sock->protocol_interface)) || (sock->protocol_interface->type != SOCK_DGRAM ) )
  1069. {
  1070. result = FNET_ERR_INVAL;
  1071. break;
  1072. }
  1073. sock->options.ip4_opt.ttl_multicast = (fnet_uint8_t) (*((const fnet_uint32_t *)(optval)));
  1074. break;
  1075. /******************************/
  1076. case IP_ADD_MEMBERSHIP: /* Join the socket to the supplied multicast group on
  1077. * the specified interface. */
  1078. case IP_DROP_MEMBERSHIP: /* Drops membership to the given multicast group and interface.*/
  1079. {
  1080. fnet_index_t i;
  1081. fnet_ip4_multicast_list_entry_t **multicast_entry = FNET_NULL;
  1082. const struct fnet_ip_mreq *mreq = (const struct fnet_ip_mreq *)optval;
  1083. fnet_netif_t *netif;
  1084. if(mreq->imr_interface == 0u)
  1085. {
  1086. netif = _fnet_netif_get_default();
  1087. }
  1088. else
  1089. {
  1090. netif = _fnet_netif_get_by_scope_id(mreq->imr_interface);
  1091. }
  1092. if((optlen != sizeof(struct fnet_ip_mreq)) /* Check size.*/
  1093. || (netif == FNET_NULL) /* Found IF.*/
  1094. || (!FNET_IP4_ADDR_IS_MULTICAST(mreq->imr_multiaddr.s_addr)) /* Check if the address is multicast.*/
  1095. || (!(sock->protocol_interface)) || (sock->protocol_interface->type != SOCK_DGRAM )
  1096. )
  1097. {
  1098. result = FNET_ERR_INVAL;
  1099. break;
  1100. }
  1101. /* Find the existing entry with same parameters.*/
  1102. for(i = 0u; i < FNET_CFG_MULTICAST_SOCKET_MAX; i++)
  1103. {
  1104. if( (sock->ip4_multicast_entry[i] != FNET_NULL)
  1105. && (sock->ip4_multicast_entry[i]->netif == netif)
  1106. && (sock->ip4_multicast_entry[i]->group_addr == mreq->imr_multiaddr.s_addr) )
  1107. {
  1108. multicast_entry = &sock->ip4_multicast_entry[i];
  1109. break; /* Found.*/
  1110. }
  1111. }
  1112. /******************************/
  1113. if(optname == IP_ADD_MEMBERSHIP)
  1114. {
  1115. if(multicast_entry != FNET_NULL)
  1116. {
  1117. /* Already joined.*/
  1118. result = FNET_ERR_ADDRINUSE;
  1119. break;
  1120. }
  1121. /* Find free entry.*/
  1122. for(i = 0u; i < FNET_CFG_MULTICAST_SOCKET_MAX; i++)
  1123. {
  1124. if(sock->ip4_multicast_entry[i] == FNET_NULL)
  1125. {
  1126. multicast_entry = &sock->ip4_multicast_entry[i];
  1127. break; /* Found.*/
  1128. }
  1129. }
  1130. if(multicast_entry != FNET_NULL)
  1131. {
  1132. *multicast_entry = _fnet_ip4_multicast_join( netif, mreq->imr_multiaddr.s_addr );
  1133. if(*multicast_entry == FNET_NULL)
  1134. {
  1135. result = FNET_ERR_ADDRINUSE;
  1136. break;
  1137. }
  1138. }
  1139. else
  1140. {
  1141. result = FNET_ERR_ADDRINUSE;
  1142. break;
  1143. }
  1144. }
  1145. /******************************/
  1146. else /* IP_DROP_MEMBERSHIP */
  1147. {
  1148. if(multicast_entry != FNET_NULL)
  1149. {
  1150. /* Leave the group.*/
  1151. _fnet_ip4_multicast_leave_entry(*multicast_entry);
  1152. *multicast_entry = FNET_NULL;
  1153. }
  1154. else
  1155. {
  1156. /* Join entry is not foud.*/
  1157. result = FNET_ERR_INVAL;
  1158. break;
  1159. }
  1160. }
  1161. }
  1162. break;
  1163. #endif /* FNET_CFG_MULTICAST */
  1164. /******************************/
  1165. default:
  1166. result = FNET_ERR_NOPROTOOPT; /* The option is unknown or unsupported. */
  1167. break;
  1168. }
  1169. return result;
  1170. }
  1171. /************************************************************************
  1172. * DESCRIPTION: Prints an IP header. For debug needs only.
  1173. *************************************************************************/
  1174. #if FNET_CFG_DEBUG_TRACE_IP4 && FNET_CFG_DEBUG_TRACE
  1175. static void _fnet_ip4_trace(fnet_uint8_t *str, fnet_ip4_header_t *ip_hdr)
  1176. {
  1177. fnet_uint8_t ip_str[FNET_IP4_ADDR_STR_SIZE];
  1178. fnet_printf(FNET_SERIAL_ESC_FG_GREEN"%s", str); /* Print app-specific header.*/
  1179. fnet_println("[IPv4 header]"FNET_SERIAL_ESC_ATTR_RESET);
  1180. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1181. fnet_println("|(V) %2d |(HL)%2d |(TOS) 0x%02x |(L) %5u |",
  1182. FNET_IP_HEADER_GET_VERSION(ip_hdr),
  1183. FNET_IP_HEADER_GET_HEADER_LENGTH(ip_hdr),
  1184. ip_hdr->tos,
  1185. fnet_ntohs(ip_hdr->total_length));
  1186. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1187. fnet_println("|(Id) %5u |(F)%u |(Offset) %4u |",
  1188. fnet_ntohs(ip_hdr->id),
  1189. fnet_ntohs(FNET_IP_HEADER_GET_FLAG(ip_hdr)) >> 15,
  1190. fnet_ntohs(FNET_IP_HEADER_GET_OFFSET(ip_hdr)));
  1191. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1192. fnet_println("|(TTL) %3u |(Proto) "FNET_SERIAL_ESC_FG_BLUE"%3u"FNET_SERIAL_ESC_ATTR_RESET" |(Cheksum) 0x%04x |",
  1193. ip_hdr->ttl,
  1194. ip_hdr->protocol,
  1195. fnet_ntohs(ip_hdr->checksum));
  1196. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1197. fnet_println("|(Src) "FNET_SERIAL_ESC_FG_BLUE"%15s"FNET_SERIAL_ESC_ATTR_RESET" |",
  1198. fnet_inet_ntoa(*(struct fnet_in_addr *)(&ip_hdr->source_addr), ip_str));
  1199. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1200. fnet_println("|(Dest) "FNET_SERIAL_ESC_FG_BLUE"%15s"FNET_SERIAL_ESC_ATTR_RESET" |",
  1201. fnet_inet_ntoa(*(struct fnet_in_addr *)(&ip_hdr->desination_addr), ip_str));
  1202. fnet_println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
  1203. }
  1204. #endif /* FNET_CFG_DEBUG_TRACE_IP4 */
  1205. #endif /* FNET_CFG_IP4 */