PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/platform/FNET/fnet_stack/stack/fnet_ip6.c

https://gitlab.com/fuggles/ucos
C | 2199 lines | 1353 code | 333 blank | 513 comment | 279 complexity | fd239a34b17675e53feef3aeb08b5dc7 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. /**************************************************************************
  2. *
  3. * Copyright 2011-2015 by Andrey Butok. FNET Community.
  4. * Copyright 2008-2010 by Andrey Butok. Freescale Semiconductor, Inc.
  5. *
  6. ***************************************************************************
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License Version 3
  9. * or later (the "LGPL").
  10. *
  11. * As a special exception, the copyright holders of the FNET project give you
  12. * permission to link the FNET sources with independent modules to produce an
  13. * executable, regardless of the license terms of these independent modules,
  14. * and to copy and distribute the resulting executable under terms of your
  15. * choice, provided that you also meet, for each linked independent module,
  16. * the terms and conditions of the license of that module.
  17. * An independent module is a module which is not derived from or based
  18. * on this library.
  19. * If you modify the FNET sources, you may extend this exception
  20. * to your version of the FNET sources, but you are not obligated
  21. * to do so. If you do not wish to do so, delete this
  22. * exception statement from your version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  27. *
  28. * You should have received a copy of the GNU General Public License
  29. * and the GNU Lesser General Public License along with this program.
  30. * If not, see <http://www.gnu.org/licenses/>.
  31. *
  32. **********************************************************************/ /*!
  33. *
  34. * @file fnet_ip6.c
  35. *
  36. * @author Andrey Butok
  37. *
  38. * @brief IPv6 protocol implementation.
  39. *
  40. ***************************************************************************/
  41. #include "fnet.h"
  42. #if FNET_CFG_IP6
  43. #include "fnet_ip6_prv.h"
  44. #include "fnet_ip_prv.h"
  45. #include "fnet_icmp.h"
  46. #include "fnet_checksum.h"
  47. #include "fnet_timer_prv.h"
  48. #include "fnet_socket_prv.h"
  49. #include "fnet_netif_prv.h"
  50. #include "fnet_prot.h"
  51. #include "fnet_loop.h"
  52. #include "fnet_igmp.h"
  53. #include "fnet_prot.h"
  54. #include "fnet_raw.h"
  55. #include "fnet_mld.h"
  56. /******************************************************************
  57. * Ext. header handler results.
  58. *******************************************************************/
  59. typedef enum{
  60. FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT, /* Stop processing.*/
  61. FNET_IP6_EXT_HEADER_HANDLER_RESULT_NEXT, /* Go to the next Ext. Header processing.*/
  62. FNET_IP6_EXT_HEADER_HANDLER_RESULT_TRANSPORT /* Go to Transport Layer processing.*/
  63. } fnet_ip6_ext_header_handler_result_t;
  64. /******************************************************************
  65. * Extension Header Handler structure
  66. *******************************************************************/
  67. typedef struct fnet_ip6_ext_header
  68. {
  69. unsigned long type; /* Identifies the type of header. */
  70. fnet_ip6_ext_header_handler_result_t (*handler)(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb); /* Extension header handler.*/
  71. } fnet_ip6_ext_header_t;
  72. /******************************************************************
  73. * Function Prototypes
  74. *******************************************************************/
  75. static void fnet_ip6_netif_output(struct fnet_netif *netif, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t* nb);
  76. static int fnet_ip6_ext_header_process(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb);
  77. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_fragment_header(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb);
  78. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_routing_header(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb);
  79. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_options (fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb);
  80. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_no_next_header (fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb);
  81. static void fnet_ip6_input_low( void *cookie );
  82. #if FNET_CFG_IP6_FRAGMENTATION
  83. static void fnet_ip6_frag_list_add( fnet_ip6_frag_list_t ** head, fnet_ip6_frag_list_t *fl );
  84. static void fnet_ip6_frag_list_del( fnet_ip6_frag_list_t ** head, fnet_ip6_frag_list_t *fl );
  85. static void fnet_ip6_frag_add( fnet_ip6_frag_header_t ** head, fnet_ip6_frag_header_t *frag, fnet_ip6_frag_header_t *frag_prev );
  86. static void fnet_ip6_frag_del( fnet_ip6_frag_header_t ** head, fnet_ip6_frag_header_t *frag );
  87. static void fnet_ip6_frag_list_free( fnet_ip6_frag_list_t *list );
  88. static fnet_netbuf_t *fnet_ip6_reassembly(fnet_netif_t *netif, fnet_netbuf_t ** nb_ptr, fnet_netbuf_t *ip6_nb, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip );
  89. static void fnet_ip6_timer(void *cookie);
  90. #endif
  91. /******************************************************************
  92. * Extension Header Handler List
  93. *******************************************************************/
  94. fnet_ip6_ext_header_t fnet_ip6_ext_header_list[] =
  95. {
  96. {FNET_IP6_TYPE_NO_NEXT_HEADER, fnet_ip6_ext_header_handler_no_next_header}
  97. ,{FNET_IP6_TYPE_HOP_BY_HOP_OPTIONS, fnet_ip6_ext_header_handler_options}
  98. ,{FNET_IP6_TYPE_DESTINATION_OPTIONS, fnet_ip6_ext_header_handler_options}
  99. ,{FNET_IP6_TYPE_ROUTING_HEADER, fnet_ip6_ext_header_handler_routing_header}
  100. ,{FNET_IP6_TYPE_FRAGMENT_HEADER, fnet_ip6_ext_header_handler_fragment_header}
  101. /* ADD YOUR EXTENSION HEADER HANDLERS HERE.*/
  102. };
  103. #define FNET_IP6_EXT_HEADER_LIST_SIZE (sizeof(fnet_ip6_ext_header_list)/sizeof(fnet_ip6_ext_header_t))
  104. /************************************************************************
  105. * Policy Table (RFC3484)
  106. *************************************************************************/
  107. typedef struct fnet_ip6_if_policy_entry
  108. {
  109. fnet_ip6_addr_t prefix; /* Prefix of an IP address. */
  110. unsigned long prefix_length; /* Prefix length (in bits). The number of leading bits
  111. * in the Prefix that are valid. */
  112. unsigned long precedence; /* Precedence value used for sorting destination addresses.*/
  113. unsigned long label; /* The label value Label(A) allows for policies that prefer a particular
  114. * source address prefix for use with a destination address prefix.*/
  115. } fnet_ip6_if_policy_entry_t;
  116. /* RFC3484 Default policy table:*/
  117. const fnet_ip6_if_policy_entry_t fnet_ip6_if_policy_table[] =
  118. {
  119. {FNET_IP6_ADDR_INIT(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1), 128, 50, 0},
  120. {FNET_IP6_ADDR_INIT(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), 0, 40, 1},
  121. {FNET_IP6_ADDR_INIT(0x20,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0), 16, 30, 2},
  122. {FNET_IP6_ADDR_INIT(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), 96, 20, 3},
  123. {FNET_IP6_ADDR_INIT(0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,0,0,0,0), 96, 10, 4}
  124. };
  125. #define FNET_IP6_IF_POLICY_TABLE_SIZE (sizeof(fnet_ip6_if_policy_table)/sizeof(fnet_ip6_if_policy_entry_t))
  126. static fnet_ip_queue_t ip6_queue;
  127. static fnet_event_desc_t ip6_event;
  128. #if FNET_CFG_IP6_FRAGMENTATION
  129. static fnet_ip6_frag_list_t *ip6_frag_list_head;
  130. static fnet_timer_desc_t ip6_timer_ptr;
  131. #endif
  132. /******************************************************************
  133. * Definitions of some costant IP6 addresses (BSD-like).
  134. *******************************************************************/
  135. const fnet_ip6_addr_t fnet_ip6_addr_any = FNET_IP6_ADDR_ANY_INIT;
  136. const fnet_ip6_addr_t fnet_ip6_addr_loopback = FNET_IP6_ADDR_LOOPBACK_INIT;
  137. const fnet_ip6_addr_t fnet_ip6_addr_nodelocal_allnodes = FNET_IP6_ADDR_NODELOCAL_ALLNODES_INIT;
  138. const fnet_ip6_addr_t fnet_ip6_addr_linklocal_allnodes = FNET_IP6_ADDR_LINKLOCAL_ALLNODES_INIT;
  139. const fnet_ip6_addr_t fnet_ip6_addr_linklocal_allrouters = FNET_IP6_ADDR_LINKLOCAL_ALLROUTERS_INIT;
  140. const fnet_ip6_addr_t fnet_ip6_addr_linklocal_allv2routers = FNET_IP6_ADDR_LINKLOCAL_ALLV2ROUTERS_INIT;
  141. const fnet_ip6_addr_t fnet_ip6_addr_linklocal_prefix = FNET_IP6_ADDR_LINKLOCAL_PREFIX_INIT;
  142. /* IPv6 Multicast list.*/
  143. fnet_ip6_multicast_list_entry_t fnet_ip6_multicast_list[FNET_CFG_MULTICAST_MAX];
  144. /************************************************************************
  145. * NAME: fnet_ip6_init
  146. *
  147. * DESCRIPTION: This function makes initialization of the IPv6 layer.
  148. *************************************************************************/
  149. int fnet_ip6_init( void )
  150. {
  151. int result = FNET_ERR;
  152. #if FNET_CFG_IP6_FRAGMENTATION
  153. ip6_frag_list_head = 0;
  154. ip6_timer_ptr = fnet_timer_new((FNET_IP6_TIMER_PERIOD / FNET_TIMER_PERIOD_MS), fnet_ip6_timer, 0);
  155. if(ip6_timer_ptr)
  156. {
  157. #endif
  158. /* Install IPv6 event handler. */
  159. ip6_event = fnet_event_init(fnet_ip6_input_low, 0);
  160. if(ip6_event != FNET_ERR)
  161. result = FNET_OK;
  162. #if FNET_CFG_IP6_FRAGMENTATION
  163. }
  164. #endif
  165. /* Clear the multicast list.*/
  166. fnet_memset_zero( fnet_ip6_multicast_list, sizeof(fnet_ip6_multicast_list));
  167. return result;
  168. }
  169. /************************************************************************
  170. * NAME: fnet_ip6_release
  171. *
  172. * DESCRIPTION: This function makes release of the all resources
  173. * allocated for IPv6 layer module.
  174. *************************************************************************/
  175. void fnet_ip6_release( void )
  176. {
  177. fnet_ip6_drain();
  178. #if FNET_CFG_IP6_FRAGMENTATION
  179. fnet_timer_free(ip6_timer_ptr);
  180. ip6_timer_ptr = 0;
  181. #endif
  182. }
  183. /************************************************************************
  184. * NAME: fnet_ip6_ext_header_process
  185. *
  186. * DESCRIPTION: Process IPv6 Extension Headers.
  187. *
  188. * RETURNS: FNET_OK - continue processing by transport layer.
  189. * FNET_ERR - stop processing.
  190. *************************************************************************/
  191. static int fnet_ip6_ext_header_process(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb)
  192. {
  193. int try_upper_layer = FNET_FALSE;
  194. unsigned char next_header;
  195. int ext_header_counter = 0;
  196. fnet_ip6_ext_header_t *ext_header;
  197. /* RFC 2460 4:
  198. * Therefore, extension headers must
  199. * be processed strictly in the order they appear in the packet; a
  200. * receiver must not, for example, scan through a packet looking for a
  201. * particular kind of extension header and process that header prior to
  202. * processing all preceding ones.
  203. */
  204. /* Process headers.*/
  205. do
  206. {
  207. int j;
  208. next_header = **next_header_p;
  209. ext_header = FNET_NULL;
  210. /* IPv6 nodes must accept and attempt to process extension headers in
  211. * any order and occurring any number of times in the same packet,
  212. * except for the Hop-by-Hop Options header which is restricted to
  213. * appear immediately after an IPv6 header only.*/
  214. /*TBD try to put it to main handler */
  215. if( (next_header == FNET_IP6_TYPE_HOP_BY_HOP_OPTIONS) && ext_header_counter)
  216. {
  217. fnet_netbuf_free_chain(*nb_p);
  218. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_NEXT_HEADER,
  219. (unsigned long)(*next_header_p) - (unsigned long)(ip6_nb->data_ptr), ip6_nb );
  220. return FNET_ERR;
  221. }
  222. for(j = 0; j < FNET_IP6_EXT_HEADER_LIST_SIZE; j++)
  223. {
  224. if(next_header == fnet_ip6_ext_header_list[j].type)
  225. {
  226. ext_header = &fnet_ip6_ext_header_list[j];
  227. break;
  228. }
  229. }
  230. if(ext_header)
  231. {
  232. fnet_ip6_ext_header_handler_result_t handler_result = ext_header->handler(netif, next_header_p, src_ip, dest_ip, nb_p, ip6_nb);
  233. switch(handler_result)
  234. {
  235. case FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT:
  236. return FNET_ERR;
  237. case FNET_IP6_EXT_HEADER_HANDLER_RESULT_NEXT:
  238. break;
  239. case FNET_IP6_EXT_HEADER_HANDLER_RESULT_TRANSPORT:
  240. try_upper_layer = FNET_TRUE;
  241. break;
  242. };
  243. }
  244. else
  245. {
  246. try_upper_layer = FNET_TRUE;
  247. }
  248. ext_header_counter++;
  249. }
  250. while((try_upper_layer == FNET_FALSE) || (ext_header != FNET_NULL));
  251. return FNET_OK;
  252. }
  253. /************************************************************************
  254. * NAME: fnet_ip6_ext_header_handler_no_next_header
  255. *
  256. * DESCRIPTION: Process No Next Header
  257. *************************************************************************/
  258. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_no_next_header (fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb)
  259. {
  260. FNET_COMP_UNUSED_ARG(netif);
  261. FNET_COMP_UNUSED_ARG(src_ip);
  262. FNET_COMP_UNUSED_ARG(dest_ip);
  263. FNET_COMP_UNUSED_ARG(next_header_p);
  264. /* RFC 2460: The value 59 in the Next Header field of an IPv6 header or any
  265. * extension header indicates that there is nothing following that
  266. * header. If the Payload Length field of the IPv6 header indicates the
  267. * presence of octets past the end of a header whose Next Header field
  268. * contains 59, those octets must be ignored.*/
  269. fnet_netbuf_free_chain(ip6_nb);
  270. fnet_netbuf_free_chain(*nb_p);
  271. return FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  272. }
  273. /************************************************************************
  274. * NAME: fnet_ip6_ext_header_handler_options
  275. *
  276. * DESCRIPTION: Process Hop by Hop Options and Destimation Options
  277. *************************************************************************/
  278. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_options (fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb)
  279. {
  280. fnet_netbuf_t *nb = *nb_p;
  281. fnet_ip6_options_header_t *options_h = nb->data_ptr;
  282. fnet_ip6_option_header_t *option;
  283. unsigned long offset;
  284. unsigned long length = (unsigned long)((options_h->hdr_ext_length<<3) + (8-2));
  285. FNET_COMP_UNUSED_ARG(src_ip);
  286. for(offset = 0; offset < length; )
  287. {
  288. option = (fnet_ip6_option_header_t *)&options_h->options[offset];
  289. /* The RFC2460 supports only PAD0 and PADN options.*/
  290. switch(option->type)
  291. {
  292. /* Pad1 option */
  293. case FNET_IP6_OPTION_TYPE_PAD1:
  294. offset++;
  295. break;
  296. /* Pad1 option */
  297. case FNET_IP6_OPTION_TYPE_PADN:
  298. offset += sizeof(fnet_ip6_option_header_t) + option->data_length;
  299. break;
  300. /* Unrecognized Options.*/
  301. default:
  302. /* The Option Type identifiers are internally encoded such that their
  303. * highest-order two bits specify the action that must be taken if the
  304. * processing IPv6 node does not recognize the Option Type.*/
  305. switch(option->type & FNET_IP6_OPTION_TYPE_UNRECOGNIZED_MASK)
  306. {
  307. /* 00 - skip over this option and continue processing the header.*/
  308. case FNET_IP6_OPTION_TYPE_UNRECOGNIZED_SKIP:
  309. break;
  310. /* 01 - discard the packet. */
  311. case FNET_IP6_OPTION_TYPE_UNRECOGNIZED_DISCARD:
  312. fnet_netbuf_free_chain(nb);
  313. fnet_netbuf_free_chain(ip6_nb);
  314. return FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  315. /* 10 - discard the packet and, regardless of whether or not the
  316. * packet’s Destination Address was a multicast address, send an
  317. * ICMP Parameter Problem, Code 2, message to the packet’s
  318. * Source Address, pointing to the unrecognized Option Type.*/
  319. case FNET_IP6_OPTION_TYPE_UNRECOGNIZED_DISCARD_ICMP:
  320. fnet_netbuf_free_chain(nb);
  321. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_OPTION,
  322. (unsigned long)(&option->type) - (unsigned long)(ip6_nb->data_ptr), ip6_nb ); /* TBD not tested.*/
  323. return FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  324. /* 11 - discard the packet and, only if the packet’s Destination
  325. * Address was not a multicast address, send an ICMP Parameter
  326. * Problem, Code 2, message to the packet’s Source Address,
  327. * pointing to the unrecognized Option Type.*/
  328. case FNET_IP6_OPTION_TYPE_UNRECOGNIZED_DISCARD_UICMP:
  329. fnet_netbuf_free_chain(nb);
  330. if(!FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
  331. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_OPTION,
  332. (unsigned long)(&option->type) - (unsigned long)(ip6_nb->data_ptr), ip6_nb ); /* TBD not tested.*/
  333. else
  334. fnet_netbuf_free_chain(ip6_nb);
  335. return FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  336. }
  337. offset += sizeof(fnet_ip6_option_header_t) + option->data_length;
  338. break;
  339. }
  340. }
  341. *next_header_p = &options_h->next_header;
  342. fnet_netbuf_trim(nb_p, (int)(length+2));
  343. return FNET_IP6_EXT_HEADER_HANDLER_RESULT_NEXT;
  344. }
  345. /************************************************************************
  346. * NAME: fnet_ip6_ext_header_handler_routing_header
  347. *
  348. * DESCRIPTION: Process Routing header.
  349. *************************************************************************/
  350. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_routing_header(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb)
  351. {
  352. fnet_ip6_ext_header_handler_result_t result;
  353. fnet_netbuf_t *nb = *nb_p;
  354. fnet_ip6_routing_header_t *routing_h;
  355. FNET_COMP_UNUSED_ARG(src_ip);
  356. FNET_COMP_UNUSED_ARG(dest_ip);
  357. routing_h = nb->data_ptr;
  358. /* RFC 2460 4.4: If, while processing a received packet, a node encounters a Routing
  359. * header with an unrecognized Routing Type value, the required behavior
  360. * of the node depends on the value of the Segments Left field, as
  361. * follows:
  362. * -If Segments Left is non-zero, the node must discard the packet and
  363. * send an ICMP Parameter Problem, Code 0, message to the packet’s
  364. * Source Address, pointing to the unrecognized Routing Type.
  365. */
  366. if( routing_h->segments_left > 0)
  367. {
  368. fnet_netbuf_free_chain(nb);
  369. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_HEADER,
  370. (unsigned long)(&routing_h->routing_type) - (unsigned long)(ip6_nb->data_ptr), ip6_nb ); /* TBD not tested.*/
  371. result = FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  372. }
  373. else
  374. {
  375. /* -If Segments Left is zero, the node must ignore the Routing header
  376. * and proceed to process the next header in the packet, whose type
  377. * is identified by the Next Header field in the Routing header.*/
  378. *next_header_p = &routing_h->next_header;
  379. fnet_netbuf_trim(nb_p, (routing_h->hdr_ext_length<<3)+(8));
  380. result = FNET_IP6_EXT_HEADER_HANDLER_RESULT_NEXT;
  381. }
  382. return result;
  383. }
  384. /************************************************************************
  385. * NAME: fnet_ip6_ext_header_handler_fragment_header
  386. *
  387. * DESCRIPTION: Process IPv6 Fragment header.
  388. *************************************************************************/
  389. #if FNET_CFG_IP6_FRAGMENTATION
  390. static fnet_ip6_ext_header_handler_result_t fnet_ip6_ext_header_handler_fragment_header(fnet_netif_t *netif, unsigned char **next_header_p, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t **nb_p, fnet_netbuf_t *ip6_nb)
  391. {
  392. fnet_ip6_ext_header_handler_result_t result;
  393. if( (*nb_p = fnet_ip6_reassembly(netif, nb_p, ip6_nb, src_ip, dest_ip )) != FNET_NULL)
  394. {
  395. fnet_ip6_header_t *ip6_header = ip6_nb->data_ptr;
  396. *next_header_p = &ip6_header->next_header;
  397. result = FNET_IP6_EXT_HEADER_HANDLER_RESULT_TRANSPORT;
  398. }
  399. else
  400. {
  401. result = FNET_IP6_EXT_HEADER_HANDLER_RESULT_EXIT;
  402. }
  403. return result;
  404. }
  405. #endif
  406. /************************************************************************
  407. * NAME: fnet_ip6_set_socket_addr
  408. *
  409. * DESCRIPTION: Prepare sockets addreses for upper protocol.
  410. *************************************************************************/
  411. void fnet_ip6_set_socket_addr(fnet_netif_t *netif, fnet_ip6_header_t *ip_hdr, struct sockaddr *src_addr, struct sockaddr *dest_addr )
  412. {
  413. fnet_memset_zero(src_addr, sizeof(struct sockaddr));
  414. src_addr->sa_family = AF_INET6;
  415. FNET_IP6_ADDR_COPY(&ip_hdr->source_addr, &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr);
  416. ((struct sockaddr_in6 *)(src_addr))->sin6_scope_id = netif->scope_id;
  417. fnet_memset_zero(dest_addr, sizeof(struct sockaddr));
  418. dest_addr->sa_family = AF_INET6;
  419. FNET_IP6_ADDR_COPY(&ip_hdr->destination_addr, &((struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr);
  420. ((struct sockaddr_in6 *)(dest_addr))->sin6_scope_id = netif->scope_id;
  421. }
  422. /************************************************************************
  423. * NAME: fnet_ip6_input
  424. *
  425. * DESCRIPTION: IPv6 input function.
  426. *************************************************************************/
  427. void fnet_ip6_input( fnet_netif_t *netif, fnet_netbuf_t *nb )
  428. {
  429. if(netif && nb)
  430. {
  431. if(fnet_ip_queue_append(&ip6_queue, netif, nb) != FNET_OK)
  432. {
  433. fnet_netbuf_free_chain(nb);
  434. return;
  435. }
  436. /* Raise IPv6 event.*/
  437. fnet_event_raise(ip6_event);
  438. }
  439. }
  440. /************************************************************************
  441. * NAME: fnet_ip6_input_low
  442. *
  443. * DESCRIPTION: This function performs handling of incoming IPv6 datagrams.
  444. *************************************************************************/
  445. static void fnet_ip6_input_low( void *cookie )
  446. {
  447. fnet_ip6_header_t *hdr;
  448. fnet_netif_t *netif;
  449. fnet_netbuf_t *nb;
  450. fnet_netbuf_t *tmp_nb;
  451. fnet_prot_if_t *protocol;
  452. fnet_ip6_addr_t *source_addr;
  453. fnet_ip6_addr_t *destination_addr;
  454. unsigned short payload_length;
  455. struct sockaddr src_addr;
  456. struct sockaddr dest_addr;
  457. FNET_COMP_UNUSED_ARG(cookie);
  458. fnet_isr_lock();
  459. while((nb = fnet_ip_queue_read(&ip6_queue, &netif)) != 0)
  460. {
  461. nb->next_chain = 0;
  462. /* RFC 4862: By disabling IP operation,
  463. * silently drop any IP packets received on the interface.*/
  464. if(netif->nd6_if_ptr && netif->nd6_if_ptr->ip6_disabled)
  465. {
  466. goto DROP;
  467. }
  468. /* The header must reside in contiguous area of memory. */
  469. if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_ip6_header_t))) == 0)
  470. {
  471. goto DROP;
  472. }
  473. nb = tmp_nb;
  474. hdr = nb->data_ptr;
  475. source_addr = &hdr->source_addr; /* TBD Save copy or do ICMP copy*/
  476. destination_addr = &hdr->destination_addr;
  477. payload_length = fnet_ntohs(hdr->length);
  478. if(nb->total_length > (sizeof(fnet_ip6_header_t)+ payload_length))
  479. {
  480. /* Logical size and the physical size of the packet should be the same.*/
  481. fnet_netbuf_trim(&nb, (int)sizeof(fnet_ip6_header_t) + (int)payload_length - (int)nb->total_length );
  482. }
  483. /*******************************************************************
  484. * Start IPv6 header processing.
  485. *******************************************************************/
  486. if( (nb->total_length >= sizeof(fnet_ip6_header_t)) /* Check Size of the packet. */
  487. && (nb->total_length >= (sizeof(fnet_ip6_header_t) + payload_length))
  488. && (FNET_IP6_HEADER_GET_VERSION(hdr) == 6) /* Check the IP Version. */
  489. && (!FNET_IP6_ADDR_IS_MULTICAST(&hdr->source_addr)) /* Validate source address. */
  490. && (fnet_netif_is_my_ip6_addr(netif, &hdr->destination_addr) /* Validate destination address. */
  491. || FNET_IP6_ADDR_IS_MULTICAST(&hdr->destination_addr)) /* Pass multicast destination address.*/
  492. )
  493. {
  494. unsigned char *next_header = &hdr->next_header;
  495. fnet_netbuf_t *ip6_nb;
  496. ip6_nb = fnet_netbuf_copy(nb, 0, ((nb->total_length > FNET_IP6_DEFAULT_MTU) ? FNET_IP6_DEFAULT_MTU : FNET_NETBUF_COPYALL),
  497. 0); /* Used mainly for ICMP errors .*/
  498. if(ip6_nb == FNET_NULL)
  499. goto DROP;
  500. #if FNET_CFG_CPU_ETH_HW_RX_PROTOCOL_CHECKSUM
  501. if((netif->features | FNET_NETIF_FEATURE_HW_RX_PROTOCOL_CHECKSUM) &&
  502. ((hdr->next_header == FNET_IP_PROTOCOL_ICMP) ||
  503. (hdr->next_header == FNET_IP_PROTOCOL_UDP) ||
  504. (hdr->next_header == FNET_IP_PROTOCOL_TCP)) )
  505. {
  506. nb->flags |= FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM;
  507. }
  508. #endif
  509. fnet_netbuf_trim(&nb, (int)sizeof(fnet_ip6_header_t));
  510. /********************************************
  511. * Extension headers processing.
  512. *********************************************/
  513. if(fnet_ip6_ext_header_process(netif, &next_header, source_addr, destination_addr, &nb, ip6_nb) == FNET_ERR)
  514. continue;
  515. /* Prepare addreses for upper protocol.*/
  516. fnet_ip6_set_socket_addr(netif, hdr, &src_addr, &dest_addr );
  517. #if FNET_CFG_RAW
  518. /* RAW Sockets input.*/
  519. fnet_raw_input(netif, &src_addr, &dest_addr, nb, ip6_nb);
  520. #endif
  521. /* Note: (http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_9-3/ipv6_internals.html)
  522. * Note that there is no standard extension header format, meaning that when a host
  523. * encounters a header that it does not recognize in the protocol chain, the only thing
  524. * it can do is discard the packet. Worse, firewalls and routers configured to filter IPv6
  525. * have the same problem: as soon as they encounter an unknown extension header,
  526. * they must decide to allow or disallow the packet, even though another header deeper
  527. * inside the packet would possibly trigger the opposite behavior. In other words, an IPv6
  528. * packet with a TCP payload that would normally be allowed through could be blocked if
  529. * there is an unknown extension header between the IPv6 and TCP headers.
  530. */
  531. /********************************************
  532. * Transport layer processing (ICMP/TCP/UDP).
  533. *********************************************/
  534. /* Find transport protocol.*/
  535. if((protocol = fnet_prot_find(AF_INET6, SOCK_UNSPEC, *next_header)) != FNET_NULL)
  536. {
  537. protocol->prot_input(netif, &src_addr, &dest_addr, nb, ip6_nb);
  538. /* After that nb may point to wrong place. Do not use it.*/
  539. }
  540. else
  541. /* No protocol found.*/
  542. {
  543. fnet_netbuf_free_chain(nb);
  544. /* RFC 2460 4:If, as a result of processing a header, a node is required to proceed
  545. * to the next header but the Next Header value in the current header is
  546. * unrecognized by the node, it should discard the packet and send an
  547. * ICMP Parameter Problem message to the source of the packet, with an
  548. * ICMP Code value of 1 ("unrecognized Next Header type encountered")
  549. * and the ICMP Pointer field containing the offset of the unrecognized
  550. * value within the original packet. The same action should be taken if
  551. * a node encounters a Next Header value of zero in any header other
  552. * than an IPv6 header.*/
  553. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_NEXT_HEADER,
  554. (unsigned long)(next_header) - (unsigned long)(ip6_nb->data_ptr), ip6_nb ); /* TBD not tested.*/
  555. }
  556. }
  557. else
  558. {
  559. DROP:
  560. fnet_netbuf_free_chain(nb);
  561. }
  562. } /* while end */
  563. fnet_isr_unlock();
  564. }
  565. /************************************************************************
  566. * NAME: fnet_ip6_addr_scope
  567. *
  568. * DESCRIPTION: Returns scope of the IPv6 address (Node-local,
  569. * link-local, site-local or global.).
  570. *************************************************************************/
  571. int fnet_ip6_addr_scope(fnet_ip6_addr_t *ip_addr)
  572. {
  573. int result = FNET_IP6_ADDR_SCOPE_GLOBAL;
  574. /* Local Host. */
  575. if(FNET_IP6_ADDR_IS_LINKLOCAL(ip_addr))
  576. {
  577. result = FNET_IP6_ADDR_SCOPE_LINKLOCAL;
  578. }
  579. else if(FNET_IP6_ADDR_IS_SITELOCAL(ip_addr))
  580. {
  581. result = FNET_IP6_ADDR_SCOPE_SITELOCAL;
  582. }
  583. else if(FNET_IP6_ADDR_IS_MULTICAST(ip_addr))/* Multicast. */
  584. {
  585. int scope = FNET_IP6_ADDR_MULTICAST_SCOPE(ip_addr);
  586. switch(scope)
  587. {
  588. case FNET_IP6_ADDR_SCOPE_INTERFACELOCAL:
  589. result = FNET_IP6_ADDR_SCOPE_INTERFACELOCAL;
  590. break;
  591. case FNET_IP6_ADDR_SCOPE_LINKLOCAL:
  592. result = FNET_IP6_ADDR_SCOPE_LINKLOCAL;
  593. break;
  594. case FNET_IP6_ADDR_SCOPE_SITELOCAL:
  595. result = FNET_IP6_ADDR_SCOPE_SITELOCAL;
  596. break;
  597. }
  598. }
  599. else if(FNET_IP6_ADDR_EQUAL(ip_addr, &fnet_ip6_addr_loopback)) /* Loopback interface - special case.*/
  600. {
  601. result = FNET_IP6_ADDR_SCOPE_INTERFACELOCAL;
  602. }
  603. return result;
  604. }
  605. /************************************************************************
  606. * NAME: fnet_ip6_common_prefix_length
  607. *
  608. * DESCRIPTION: RFC3484 2.2. Common Prefix Length
  609. * We define the common prefix length CommonPrefixLen(A, B) of two
  610. * addresses A and B as the length of the longest prefix (looking at the
  611. * most significant, or leftmost, bits) that the two addresses have in
  612. * common. It ranges from 0 to 128.
  613. *************************************************************************/
  614. int fnet_ip6_common_prefix_length(fnet_ip6_addr_t *ip_addr_1, fnet_ip6_addr_t *ip_addr_2)
  615. {
  616. int length = 0;
  617. int i;
  618. int bit_i;
  619. unsigned char byte_xor;
  620. for(i=0; i < sizeof(fnet_ip6_addr_t); i++)
  621. {
  622. /* XOR */
  623. byte_xor = (unsigned char)(ip_addr_1->addr[i] ^ ip_addr_2->addr[i]);
  624. for(bit_i = 0; bit_i<8; bit_i++)
  625. {
  626. if((byte_xor & 0x80) == 0x00)
  627. {
  628. length++;
  629. byte_xor<<=1; /* Shift to the next bit*/
  630. }
  631. else
  632. {
  633. break;
  634. }
  635. }
  636. }
  637. return length;
  638. }
  639. /************************************************************************
  640. * NAME: fnet_ip6_policy_label
  641. *
  642. * DESCRIPTION: Returns label value from policy table.
  643. *************************************************************************/
  644. unsigned long fnet_ip6_policy_label( fnet_ip6_addr_t *addr )
  645. {
  646. int i;
  647. unsigned long label = 0;
  648. int biggest_prefix_length = -1;
  649. /* Find the entry in the list. */
  650. for(i=0; i < FNET_IP6_IF_POLICY_TABLE_SIZE; i++)
  651. {
  652. int prefix_length = (int)(fnet_ip6_if_policy_table[i].prefix_length);
  653. if(fnet_ip6_addr_pefix_cmp((fnet_ip6_addr_t*)&fnet_ip6_if_policy_table[i].prefix, addr, (unsigned long)prefix_length) == FNET_TRUE)
  654. {
  655. if(prefix_length > biggest_prefix_length)
  656. {
  657. biggest_prefix_length = prefix_length;
  658. label = fnet_ip6_if_policy_table[i].label;
  659. }
  660. }
  661. }
  662. return label;
  663. }
  664. /************************************************************************
  665. * NAME: fnet_ip6_addr_pefix_cmp
  666. *
  667. * DESCRIPTION: Compares first "prefix_length" bits of the addresses.
  668. *************************************************************************/
  669. int fnet_ip6_addr_pefix_cmp(fnet_ip6_addr_t *addr_1, fnet_ip6_addr_t *addr_2, unsigned long prefix_length)
  670. {
  671. int result;
  672. unsigned long prefix_length_bytes = prefix_length>>3;
  673. unsigned long prefix_length_bits_mask = ((1<<(prefix_length%8))-1) << (8-(prefix_length%8));
  674. if((prefix_length <= 128)
  675. && (fnet_memcmp(addr_1, addr_2, (int)prefix_length_bytes) == 0)
  676. && ((addr_1->addr[prefix_length_bytes] & prefix_length_bits_mask) == (addr_2->addr[prefix_length_bytes] & prefix_length_bits_mask)) )
  677. {
  678. result = FNET_TRUE;
  679. }
  680. else
  681. {
  682. result = FNET_FALSE;
  683. }
  684. return result;
  685. }
  686. /************************************************************************
  687. * NAME: fnet_ip6_select_src_addr
  688. *
  689. * DESCRIPTION: Selects the best source address to use with a
  690. * destination address, Based on RFC3484.
  691. *************************************************************************/
  692. const fnet_ip6_addr_t *fnet_ip6_select_src_addr(fnet_netif_t *netif /* Optional.*/, fnet_ip6_addr_t *dest_addr)
  693. {
  694. int i;
  695. fnet_ip6_addr_t *best_addr = FNET_NULL;
  696. int best_scope;
  697. int dest_scope;
  698. int new_scope;
  699. int best_prefix_length;
  700. int new_prefix_length;
  701. unsigned long dest_label;
  702. unsigned long best_label;
  703. unsigned long new_label;
  704. fnet_netif_t *if_dest_cur;
  705. fnet_netif_t *if_dest_best = FNET_NULL;
  706. /* Just take the first/last interface.*/
  707. if(dest_addr)
  708. {
  709. for(if_dest_cur = fnet_netif_list; if_dest_cur != FNET_NULL ; if_dest_cur = if_dest_cur->next)
  710. {
  711. dest_scope = fnet_ip6_addr_scope(dest_addr);
  712. dest_label = fnet_ip6_policy_label(dest_addr);
  713. /* Just continue the first loop.*/
  714. for(i=0; i<FNET_NETIF_IP6_ADDR_MAX; i++)
  715. {
  716. /* Skip not used enries. */
  717. if(if_dest_cur->ip6_addr[i].state == FNET_NETIF_IP6_ADDR_STATE_NOT_USED)
  718. {
  719. continue;
  720. }
  721. else if(best_addr == FNET_NULL)
  722. {
  723. /* Just take the first used address, by default.=> Link-local address.*/
  724. best_addr = &if_dest_cur->ip6_addr[i].address;
  725. if_dest_best = if_dest_cur;
  726. }
  727. /* RFC3484 Source Address Selection.*/
  728. /* Rule 1: Prefer same address.*/
  729. if(FNET_IP6_ADDR_EQUAL(dest_addr, &if_dest_cur->ip6_addr[i].address))
  730. {
  731. best_addr = &if_dest_cur->ip6_addr[i].address;
  732. if_dest_best = if_dest_cur;
  733. break;
  734. }
  735. /* Rule 2: Prefer appropriate scope.*/
  736. /* If Scope(SA) < Scope(SB): If Scope(SA) < Scope(D), then prefer SB
  737. * and otherwise prefer SA. Similarly, if Scope(SB) < Scope(SA): If
  738. * Scope(SB) < Scope(D), then prefer SA and otherwise prefer SB.
  739. */
  740. best_scope = fnet_ip6_addr_scope(best_addr);
  741. new_scope = fnet_ip6_addr_scope(&if_dest_cur->ip6_addr[i].address);
  742. if(best_scope < new_scope)
  743. {
  744. if(best_scope < dest_scope)
  745. {
  746. best_addr = &if_dest_cur->ip6_addr[i].address; /* PFI take pointer at the begining.*/
  747. if_dest_best = if_dest_cur;
  748. }
  749. continue;
  750. }
  751. else if( new_scope < best_scope)
  752. {
  753. if( new_scope >= dest_scope)
  754. {
  755. best_addr = &if_dest_cur->ip6_addr[i].address;
  756. if_dest_best = if_dest_cur;
  757. }
  758. continue;
  759. }
  760. /* Rule 3: Avoid deprecated addresses.
  761. * XX: Not implemented - we do not store depricated addresses."*/
  762. /* Rule 4: Prefer home addresses.
  763. * XX: Not implemented - we do not have Mobile IPv6.*/
  764. /* Rule 5: Prefer outgoing interface.
  765. */
  766. if((if_dest_best == netif ) && (if_dest_cur != netif))
  767. {
  768. continue;
  769. }
  770. if((if_dest_best != netif ) && (if_dest_cur == netif))
  771. {
  772. best_addr = &if_dest_cur->ip6_addr[i].address;
  773. if_dest_best = if_dest_cur;
  774. continue;
  775. }
  776. /* Rule 6: Prefer matching label.
  777. * If Label(SA) = Label(D) and Label(SB) <> Label(D), then prefer SA.
  778. * Similarly, if Label(SB) = Label(D) and Label(SA) <> Label(D), then
  779. * prefer SB.
  780. */
  781. best_label = fnet_ip6_policy_label(best_addr);
  782. new_label = fnet_ip6_policy_label(&if_dest_cur->ip6_addr[i].address);
  783. if(best_label == dest_label)
  784. {
  785. if(new_label != dest_label)
  786. continue; /* Prefer SA.*/
  787. }
  788. if(new_label == dest_label)
  789. {
  790. if(new_label != dest_label)
  791. {
  792. best_addr = &if_dest_cur->ip6_addr[i].address;
  793. if_dest_best = if_dest_cur;
  794. continue;
  795. }
  796. }
  797. /* Rule 7: Prefer public addresses.
  798. * If SA is a public address and SB is a temporary address, then prefer
  799. * SA. Similarly, if SB is a public address and SA is a temporary
  800. * address, then prefer SB.
  801. * XX: We do not support "temporary"/"random" addresses.*/
  802. /* Rule 8: Use longest matching prefix.
  803. * If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA.
  804. * Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then
  805. * prefer SB.
  806. */
  807. best_prefix_length = fnet_ip6_common_prefix_length(best_addr, dest_addr);
  808. new_prefix_length = fnet_ip6_common_prefix_length(&if_dest_cur->ip6_addr[i].address, dest_addr);
  809. if(new_prefix_length > best_prefix_length)
  810. /* Found better one.*/
  811. {
  812. best_addr = &if_dest_cur->ip6_addr[i].address;
  813. if_dest_best = if_dest_cur;
  814. }
  815. } /* for(IP6_IF_ADDRESSES_MAX) */
  816. }/* for(if_dest_cur) */
  817. } /* if(dest_addr) */
  818. return best_addr;
  819. }
  820. /************************************************************************
  821. * NAME: fnet_ip6_mtu
  822. *
  823. * DESCRIPTION: Returns MTU (based on ND and PMTU).
  824. *
  825. * RETURNS: MTU
  826. *************************************************************************/
  827. unsigned long fnet_ip6_mtu( fnet_netif_t *netif)
  828. {
  829. unsigned long mtu;
  830. if(netif)
  831. {
  832. #if FNET_CFG_IP6_PMTU_DISCOVERY
  833. if(netif->pmtu) /* If PMTU is enabled for the interface.*/
  834. {
  835. mtu = netif->pmtu;
  836. }
  837. else
  838. #endif
  839. {
  840. mtu = netif->nd6_if_ptr ? netif->nd6_if_ptr->mtu : netif->mtu;
  841. }
  842. if(mtu < FNET_IP6_DEFAULT_MTU)
  843. mtu = FNET_IP6_DEFAULT_MTU;
  844. }
  845. else
  846. mtu = 0;
  847. return mtu;
  848. }
  849. /************************************************************************
  850. * NAME: fnet_ip6_route
  851. *
  852. * DESCRIPTION: This function performs IPv6 routing
  853. * on an outgoing IP packet.
  854. *************************************************************************/
  855. fnet_netif_t *fnet_ip6_route(fnet_ip6_addr_t *src_ip /*optional*/, fnet_ip6_addr_t *dest_ip)
  856. {
  857. fnet_netif_t *netif = FNET_NULL;
  858. /* Validate destination address. */
  859. /* RFC3513: The unspecified address must not be used as the destination address
  860. * of IPv6 packets or in IPv6 Routing Headers.*/
  861. if(!(dest_ip == FNET_NULL) && !FNET_IP6_ADDR_IS_UNSPECIFIED(dest_ip))
  862. {
  863. /*
  864. * The specified source address may
  865. * influence the candidate set, by affecting the choice of outgoing
  866. * interface. If the application or upper-layer specifies a source
  867. * address that is in the candidate set for the destination, then the
  868. * network layer MUST respect that choice. If the application or
  869. * upper-layer does not specify a source address, then the network layer
  870. * uses the source address selection algorithm
  871. */
  872. if((src_ip == FNET_NULL) || FNET_IP6_ADDR_IS_UNSPECIFIED(src_ip))
  873. /* Determine a source address. */
  874. {
  875. src_ip = (fnet_ip6_addr_t *)fnet_ip6_select_src_addr(FNET_NULL, dest_ip);
  876. }
  877. if(src_ip != FNET_NULL)
  878. {
  879. /* Determine an output interface. */
  880. netif = fnet_netif_get_by_ip6_addr(src_ip);
  881. }
  882. }
  883. return netif;
  884. }
  885. /************************************************************************
  886. * NAME: fnet_ip6_will_fragment
  887. *
  888. * DESCRIPTION: This function returns FNET_TRUE if the protocol message
  889. * will be fragmented by IPv6, and FNET_FALSE otherwise.
  890. *************************************************************************/
  891. int fnet_ip6_will_fragment( fnet_netif_t *netif, unsigned long protocol_message_size)
  892. {
  893. int res;
  894. if(
  895. #if FNET_CFG_IP6_PMTU_DISCOVERY
  896. /*
  897. * In response to an IPv6 packet that is sent to an IPv4 destination
  898. * (i.e., a packet that undergoes translation from IPv6 to IPv4), the
  899. * originating IPv6 node may receive an ICMP Packet Too Big message
  900. * reporting a Next-Hop MTU less than 1280. In that case, the IPv6 node
  901. * is not required to reduce the size of subsequent packets to less than
  902. * 1280, but must include a Fragment header in those packets so that the
  903. * IPv6-to-IPv4 translating router can obtain a suitable Identification
  904. * value to use in resulting IPv4 fragments. Note that this means the
  905. * payload may have to be reduced to 1232 octets (1280 minus 40 for the
  906. * IPv6 header and 8 for the Fragment header), and smaller still if
  907. * additional extension headers are used.
  908. */
  909. (netif->pmtu /* If PMTU is enabled.*/ && ((protocol_message_size + sizeof(fnet_ip6_header_t)) > netif->pmtu)) ||
  910. ( !netif->pmtu &&
  911. #endif
  912. ((protocol_message_size + sizeof(fnet_ip6_header_t)) > fnet_ip6_mtu(netif))
  913. #if FNET_CFG_IP6_PMTU_DISCOVERY
  914. )/* IP Fragmentation. */
  915. #endif
  916. )
  917. {
  918. res = FNET_TRUE;
  919. }
  920. else
  921. {
  922. res = FNET_FALSE;
  923. }
  924. return res;
  925. }
  926. /************************************************************************
  927. * NAME: fnet_ip6_output
  928. *
  929. * DESCRIPTION: IPv6 output function.
  930. *
  931. * RETURNS: FNET_OK=OK
  932. * FNET_ERR_NETUNREACH=No route
  933. * FNET_ERR_MSGSIZE=Size error
  934. * FNET_ERR_NOMEM=No memory
  935. *************************************************************************/
  936. int fnet_ip6_output(fnet_netif_t *netif /*optional*/, fnet_ip6_addr_t *src_ip /*optional*/, fnet_ip6_addr_t *dest_ip,
  937. unsigned char protocol, unsigned char hop_limit /*optional*/, fnet_netbuf_t *nb, FNET_COMP_PACKED_VAR unsigned short *checksum)
  938. {
  939. int error_code;
  940. fnet_netbuf_t *nb_header;
  941. fnet_ip6_header_t *ip6_header;
  942. unsigned long mtu;
  943. /* Check maximum packet size. */
  944. if((nb->total_length + sizeof(fnet_ip6_header_t)) > FNET_IP6_MAX_PACKET)
  945. {
  946. error_code = FNET_ERR_MSGSIZE;
  947. goto DROP;
  948. }
  949. /* Validate destination address. */
  950. /* RFC3513: The unspecified address must not be used as the destination address
  951. * of IPv6 packets or in IPv6 Routing Headers.*/
  952. if((dest_ip == FNET_NULL) || FNET_IP6_ADDR_IS_UNSPECIFIED(dest_ip))
  953. {
  954. error_code = FNET_ERR_DESTADDRREQ;
  955. goto DROP;
  956. }
  957. /*
  958. * The specified source address may
  959. * influence the candidate set, by affecting the choice of outgoing
  960. * interface. If the application or upper-layer specifies a source
  961. * address that is in the candidate set for the destination, then the
  962. * network layer MUST respect that choice. If the application or
  963. * upper-layer does not specify a source address, then the network layer
  964. * uses the source address selection algorithm
  965. */
  966. if(src_ip == FNET_NULL) /* It may be any address.*/
  967. /* Determine a source address. */
  968. {
  969. src_ip = (fnet_ip6_addr_t *)fnet_ip6_select_src_addr(netif, dest_ip);
  970. if(src_ip == FNET_NULL)
  971. {
  972. error_code = FNET_ERR_NETUNREACH;
  973. goto DROP;
  974. }
  975. }
  976. if(netif == FNET_NULL)
  977. /* Determine an output interface. */
  978. {
  979. netif = fnet_netif_get_by_ip6_addr(src_ip);
  980. if(netif == FNET_NULL) /* Ther is no any initializaed IF.*/
  981. {
  982. error_code = FNET_ERR_NETUNREACH;
  983. goto DROP;
  984. }
  985. }
  986. /* RFC 4862: By disabling IP operation, the node will then not
  987. * send any IP packets from the interface.*/
  988. if(netif->nd6_if_ptr && netif->nd6_if_ptr->ip6_disabled)
  989. {
  990. error_code = FNET_ERR_IPDISABLED;
  991. goto DROP;
  992. }
  993. /* Pseudo checksum. */
  994. if(checksum)
  995. *checksum = fnet_checksum_pseudo_end( *checksum, (char *)src_ip, (char *)dest_ip, sizeof(fnet_ip6_addr_t) );
  996. /****** Construct IP header. ******/
  997. if((nb_header = fnet_netbuf_new(sizeof(fnet_ip6_header_t), FNET_TRUE)) == 0)
  998. {
  999. error_code = FNET_ERR_NOMEM;
  1000. goto DROP;
  1001. }
  1002. ip6_header = nb_header->data_ptr;
  1003. ip6_header->version__tclass = FNET_IP6_VERSION<<4;
  1004. ip6_header->tclass__flowl = 0;
  1005. ip6_header->flowl = 0;
  1006. ip6_header->length = fnet_htons((unsigned short)nb->total_length);
  1007. ip6_header->next_header = protocol;
  1008. /* Set Hop Limit.*/
  1009. if(hop_limit == 0)
  1010. hop_limit = netif->nd6_if_ptr->cur_hop_limit; /* Defined by ND.*/
  1011. ip6_header->hop_limit = hop_limit;
  1012. FNET_IP6_ADDR_COPY(src_ip, &ip6_header->source_addr);
  1013. FNET_IP6_ADDR_COPY(dest_ip, &ip6_header->destination_addr);
  1014. mtu = fnet_ip6_mtu(netif);
  1015. if(
  1016. #if FNET_CFG_IP6_PMTU_DISCOVERY
  1017. /*
  1018. * In response to an IPv6 packet that is sent to an IPv4 destination
  1019. * (i.e., a packet that undergoes translation from IPv6 to IPv4), the
  1020. * originating IPv6 node may receive an ICMP Packet Too Big message
  1021. * reporting a Next-Hop MTU less than 1280. In that case, the IPv6 node
  1022. * is not required to reduce the size of subsequent packets to less than
  1023. * 1280, but must include a Fragment header in those packets so that the
  1024. * IPv6-to-IPv4 translating router can obtain a suitable Identification
  1025. * value to use in resulting IPv4 fragments. Note that this means the
  1026. * payload may have to be reduced to 1232 octets (1280 minus 40 for the
  1027. * IPv6 header and 8 for the Fragment header), and smaller still if
  1028. * additional extension headers are used.
  1029. */
  1030. (netif->pmtu /* If PMTU is enabled.*/ && ((nb->total_length + nb_header->total_length) > netif->pmtu)) ||
  1031. ( !netif->pmtu &&
  1032. #endif
  1033. ((nb->total_length + nb_header->total_length) > mtu)
  1034. #if FNET_CFG_IP6_PMTU_DISCOVERY
  1035. )/* IP Fragmentation. */
  1036. #endif
  1037. )
  1038. {
  1039. #if FNET_CFG_IP6_FRAGMENTATION
  1040. int first_frag_length;
  1041. int frag_length; /* The number of data in each fragment. */
  1042. int offset;
  1043. int error = 0;
  1044. fnet_netbuf_t *tmp_nb;
  1045. fnet_netbuf_t *nb_prev;
  1046. fnet_netbuf_t ** nb_next_ptr;
  1047. int header_length = sizeof(fnet_ip6_header_t) + sizeof(fnet_ip6_fragment_header_t);
  1048. fnet_ip6_header_t *ip6_header_new;
  1049. fnet_ip6_fragment_header_t *ip6_fragment_header;
  1050. fnet_ip6_fragment_header_t *ip6_fragment_header_new;
  1051. fnet_netbuf_t *nb_frag_header;
  1052. unsigned long total_length;
  1053. static unsigned long ip6_id = 0;
  1054. frag_length = (int)(mtu - header_length) & ~7; /* Rounded down to an 8-byte boundary.*/
  1055. first_frag_length = frag_length;
  1056. if(frag_length < 8) /* The MTU is too small.*/
  1057. {
  1058. error_code = FNET_ERR_MSGSIZE;
  1059. fnet_netbuf_free_chain(nb_header);
  1060. goto DROP;
  1061. }
  1062. if((nb_frag_header = fnet_netbuf_new(sizeof(fnet_ip6_fragment_header_t), FNET_TRUE)) == 0)
  1063. {
  1064. error_code = FNET_ERR_NOMEM;
  1065. fnet_netbuf_free_chain(nb_header);
  1066. goto DROP;
  1067. }
  1068. nb = fnet_netbuf_concat(nb_frag_header, nb);
  1069. nb = fnet_netbuf_concat(nb_header, nb);
  1070. nb_next_ptr = &nb->next_chain;
  1071. /* The header (and options) must reside in contiguous area of memory.*/
  1072. if((tmp_nb = fnet_netbuf_pullup(nb, header_length)) == 0)
  1073. {
  1074. error_code = FNET_ERR_NOMEM;
  1075. goto DROP;
  1076. }
  1077. nb = tmp_nb;
  1078. ip6_header = nb->data_ptr;
  1079. ip6_fragment_header = (fnet_ip6_fragment_header_t*)((unsigned long)ip6_header + sizeof(fnet_ip6_header_t));
  1080. nb_prev = nb;
  1081. total_length = nb->total_length;
  1082. ip6_id++;
  1083. ip6_header->next_header = FNET_IP6_TYPE_FRAGMENT_HEADER;
  1084. ip6_fragment_header->id = fnet_htonl(ip6_id);
  1085. ip6_fragment_header->_reserved = 0;
  1086. ip6_fragment_header->next_header = protocol;
  1087. ip6_fragment_header->offset_more = FNET_HTONS(FNET_IP6_FRAGMENT_MF_MASK);
  1088. /* Go through the whole data segment after first fragment.*/
  1089. for (offset = (header_length + frag_length); offset < total_length; offset += frag_length)
  1090. {
  1091. fnet_netbuf_t *nb_tmp;
  1092. nb = fnet_netbuf_new(header_length, FNET_FALSE); /* Allocate a new header.*/
  1093. if(nb == 0)
  1094. {
  1095. error++;
  1096. goto FRAG_END;
  1097. }
  1098. ip6_header_new = nb->data_ptr;
  1099. ip6_fragment_header_new = (fnet_ip6_fragment_header_t *)((unsigned long)ip6_header_new + sizeof(fnet_ip6_header_t));
  1100. fnet_memcpy(ip6_header_new, ip6_header, (unsigned int)header_length); /* Copy IPv6 header.*/
  1101. ip6_fragment_header_new->offset_more = fnet_htons((unsigned short)(offset - header_length) );
  1102. if(offset + frag_length >= total_length)
  1103. frag_length = (int)(total_length - offset);
  1104. else
  1105. ip6_fragment_header_new->offset_more |= FNET_HTONS(FNET_IP6_FRAGMENT_MF_MASK);
  1106. /* Copy the data from the original packet into the fragment.*/
  1107. if((nb_tmp = fnet_netbuf_copy(nb_prev, offset, frag_length, 0)) == 0)
  1108. {
  1109. error++;
  1110. fnet_netbuf_free_chain(nb);
  1111. goto FRAG_END;
  1112. }
  1113. nb = fnet_netbuf_concat(nb, nb_tmp);
  1114. ip6_header_new->length = fnet_htons((unsigned short)(nb->total_length - sizeof(fnet_ip6_header_t)) );
  1115. *nb_next_ptr = nb;
  1116. nb_next_ptr = &nb->next_chain;
  1117. }
  1118. /* Update the first fragment.*/
  1119. nb = nb_prev;
  1120. fnet_netbuf_trim(&nb, /*header_length +*/ first_frag_length - fnet_ntohs(ip6_header->length) /*- sizeof(fnet_ip6_header_t)*/ );
  1121. ip6_header->length = fnet_htons((unsigned short)(nb->total_length - sizeof(fnet_ip6_header_t)) );
  1122. FRAG_END:
  1123. for (nb = nb_prev; nb; nb = nb_prev) /* Send each fragment.*/
  1124. {
  1125. nb_prev = nb->next_chain;
  1126. nb->next_chain = 0;
  1127. if(error == 0)
  1128. {
  1129. fnet_ip6_netif_output(netif, src_ip, dest_ip, nb);
  1130. }
  1131. else
  1132. fnet_netbuf_free_chain(nb);
  1133. }
  1134. #else
  1135. error_code = FNET_ERR_MSGSIZE; /* Discard datagram.*/
  1136. goto DROP;
  1137. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1138. }
  1139. else
  1140. {
  1141. nb = fnet_netbuf_concat(nb_header, nb);
  1142. fnet_ip6_netif_output(netif, src_ip, dest_ip, nb);
  1143. }
  1144. return (FNET_OK);
  1145. DROP:
  1146. fnet_netbuf_free_chain(nb); /* Discard datagram */
  1147. return (error_code);
  1148. }
  1149. /************************************************************************
  1150. * NAME: fnet_ip6_netif_output
  1151. *
  1152. * DESCRIPTION:
  1153. *************************************************************************/
  1154. static void fnet_ip6_netif_output(struct fnet_netif *netif, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t* nb)
  1155. {
  1156. #if FNET_CFG_LOOPBACK
  1157. /***********************************************
  1158. * Handle possible loopback
  1159. ***********************************************/
  1160. /* Anything sent to one of the host's own IP address is sent to the loopback interface.*/
  1161. if(fnet_netif_is_my_ip6_addr(netif, dest_ip) == FNET_TRUE)
  1162. {
  1163. netif = FNET_LOOP_IF;
  1164. }
  1165. else
  1166. #endif /* FNET_CFG_LOOPBACK */
  1167. {
  1168. #if FNET_CFG_LOOPBACK && FNET_CFG_LOOPBACK_MULTICAST
  1169. /* Send Multicast packets also to the loopback.*/
  1170. if((netif != FNET_LOOP_IF) && FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
  1171. {
  1172. fnet_netbuf_t* nb_loop;
  1173. /* Datagrams sent to amulticast address are copied to the loopback interface.*/
  1174. if((nb_loop=fnet_netbuf_copy(nb, 0, FNET_NETBUF_COPYALL, FNET_TRUE))!=0)
  1175. {
  1176. fnet_loop_output_ip6(netif, src_ip, dest_ip, nb_loop);
  1177. }
  1178. }
  1179. #endif /* FNET_CFG_LOOPBACK && FNET_CFG_LOOPBACK_MULTICAST */
  1180. }
  1181. netif->api->output_ip6(netif, src_ip, dest_ip, nb); /* IPv6 Transmit function.*/
  1182. }
  1183. /************************************************************************
  1184. * NAME: fnet_ip6_get_solicited_multicast_addr
  1185. *
  1186. * DESCRIPTION: Get IPv6 solicited-node multicast address.
  1187. * It has the prefix FF02:0:0:0:0:1:FF00:0000/104 concatenated
  1188. * with the 24 low-order bits of a corresponding IPv6 unicast
  1189. * or anycast address.
  1190. *************************************************************************/
  1191. void fnet_ip6_get_solicited_multicast_addr(fnet_ip6_addr_t *ip_addr, fnet_ip6_addr_t *solicited_multicast_addr)
  1192. {
  1193. solicited_multicast_addr->addr[0]=0xFF;
  1194. solicited_multicast_addr->addr[1]=0x02;
  1195. solicited_multicast_addr->addr[2]=0x00;
  1196. solicited_multicast_addr->addr[3]=0x00;
  1197. solicited_multicast_addr->addr[4]=0x00;
  1198. solicited_multicast_addr->addr[5]=0x00;
  1199. solicited_multicast_addr->addr[6]=0x00;
  1200. solicited_multicast_addr->addr[7]=0x00;
  1201. solicited_multicast_addr->addr[8]=0x00;
  1202. solicited_multicast_addr->addr[9]=0x00;
  1203. solicited_multicast_addr->addr[10]=0x00;
  1204. solicited_multicast_addr->addr[11]=0x01;
  1205. solicited_multicast_addr->addr[12]=0xFF;
  1206. solicited_multicast_addr->addr[13]=ip_addr->addr[13];
  1207. solicited_multicast_addr->addr[14]=ip_addr->addr[14];
  1208. solicited_multicast_addr->addr[15]=ip_addr->addr[15];
  1209. }
  1210. /************************************************************************
  1211. * NAME: fnet_ip6_frag_list_free
  1212. *
  1213. * DESCRIPTION: This function frees list of datagram fragments.
  1214. *************************************************************************/
  1215. #if FNET_CFG_IP6_FRAGMENTATION /* PFI create general library fo list, linked lists etc.*/
  1216. static void fnet_ip6_frag_list_free( fnet_ip6_frag_list_t *list )
  1217. {
  1218. fnet_netbuf_t *nb;
  1219. fnet_isr_lock();
  1220. if(list)
  1221. {
  1222. while((volatile fnet_ip6_frag_header_t *)(list->frag_ptr) != 0)
  1223. {
  1224. nb = list->frag_ptr->nb;
  1225. fnet_ip6_frag_del((fnet_ip6_frag_header_t **)(&list->frag_ptr), list->frag_ptr);
  1226. fnet_netbuf_free_chain(nb);
  1227. }
  1228. fnet_ip6_frag_list_del(&ip6_frag_list_head, list);
  1229. fnet_free(list);
  1230. }
  1231. fnet_isr_unlock();
  1232. }
  1233. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1234. /************************************************************************
  1235. * NAME: fnet_ip6_frag_list_add
  1236. *
  1237. * DESCRIPTION: Adds frag list to the general frag list.
  1238. *************************************************************************/
  1239. #if FNET_CFG_IP6_FRAGMENTATION
  1240. static void fnet_ip6_frag_list_add( fnet_ip6_frag_list_t ** head, fnet_ip6_frag_list_t *fl )
  1241. {
  1242. fl->next = *head;
  1243. if(fl->next != 0)
  1244. fl->next->prev = fl;
  1245. fl->prev = 0;
  1246. *head = fl;
  1247. }
  1248. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1249. /************************************************************************
  1250. * NAME: fnet_ip6_frag_list_del
  1251. *
  1252. * DESCRIPTION: Deletes frag list from the general frag list.
  1253. *************************************************************************/
  1254. #if FNET_CFG_IP6_FRAGMENTATION
  1255. static void fnet_ip6_frag_list_del( fnet_ip6_frag_list_t ** head, fnet_ip6_frag_list_t *fl )
  1256. {
  1257. if(fl->prev == 0)
  1258. *head=fl->next;
  1259. else
  1260. fl->prev->next = fl->next;
  1261. if(fl->next != 0)
  1262. fl->next->prev = fl->prev;
  1263. }
  1264. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1265. /************************************************************************
  1266. * NAME: fnet_ip6_frag_add
  1267. *
  1268. * DESCRIPTION: Adds frag to the frag list.
  1269. *************************************************************************/
  1270. #if FNET_CFG_IP6_FRAGMENTATION
  1271. static void fnet_ip6_frag_add( fnet_ip6_frag_header_t ** head, fnet_ip6_frag_header_t *frag,
  1272. fnet_ip6_frag_header_t *frag_prev )
  1273. {
  1274. if(frag_prev && ( *head))
  1275. {
  1276. frag->next = frag_prev->next;
  1277. frag->prev = frag_prev;
  1278. frag_prev->next->prev = frag;
  1279. frag_prev->next = frag;
  1280. if((*head)->offset > frag->offset)
  1281. {
  1282. *head = frag;
  1283. }
  1284. }
  1285. else
  1286. {
  1287. frag->next = frag;
  1288. frag->prev = frag;
  1289. *head = frag;
  1290. }
  1291. }
  1292. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1293. /************************************************************************
  1294. * NAME: fnet_ip6_frag_del
  1295. *
  1296. * DESCRIPTION: Deletes frag from the frag list.
  1297. *************************************************************************/
  1298. #if FNET_CFG_IP6_FRAGMENTATION
  1299. static void fnet_ip6_frag_del( fnet_ip6_frag_header_t ** head, fnet_ip6_frag_header_t *frag )
  1300. {
  1301. if(frag->prev == frag)
  1302. *head=0;
  1303. else
  1304. {
  1305. frag->prev->next = frag->next;
  1306. frag->next->prev = frag->prev;
  1307. if(*head == frag)
  1308. *head=frag->next;
  1309. }
  1310. fnet_free(frag);
  1311. }
  1312. #endif /* FNET_CFG_IP6_FRAGMENTATION */
  1313. /************************************************************************
  1314. * NAME: fnet_ip6_reassembly
  1315. *
  1316. * DESCRIPTION: This function attempts to assemble a complete datagram.
  1317. *************************************************************************/
  1318. #if FNET_CFG_IP6_FRAGMENTATION
  1319. static fnet_netbuf_t *fnet_ip6_reassembly(fnet_netif_t *netif, fnet_netbuf_t ** nb_p, fnet_netbuf_t *ip6_nb, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip )
  1320. {
  1321. fnet_ip6_frag_list_t *frag_list_ptr;
  1322. fnet_ip6_frag_header_t *frag_ptr;
  1323. fnet_ip6_frag_header_t *cur_frag_ptr;
  1324. fnet_netbuf_t *nb = *nb_p;
  1325. fnet_netbuf_t *tmp_nb;
  1326. fnet_ip6_header_t *iphdr = (fnet_ip6_header_t *)ip6_nb->data_ptr;
  1327. int i;
  1328. unsigned char next_header;
  1329. unsigned long id;
  1330. unsigned short offset;
  1331. unsigned char mf;
  1332. unsigned short total_length;
  1333. fnet_ip6_fragment_header_t *ip6_fragment_header;
  1334. /* For this algorithm the all datagram must reside in contiguous area of memory.*/
  1335. if((tmp_nb = fnet_netbuf_pullup(nb, (int)nb->total_length)) == 0)
  1336. {
  1337. goto DROP_FRAG_1;
  1338. }
  1339. *nb_p = tmp_nb;
  1340. nb = tmp_nb;
  1341. /* Process fragment header.*/
  1342. ip6_fragment_header = nb->data_ptr;
  1343. next_header = ip6_fragment_header->next_header;
  1344. id = ip6_fragment_header->id;
  1345. offset = (unsigned short)FNET_IP6_FRAGMENT_OFFSET(ip6_fragment_header->offset_more);
  1346. mf = (unsigned char)FNET_IP6_FRAGMENT_MF(ip6_fragment_header->offset_more);
  1347. fnet_netbuf_trim(nb_p, sizeof(fnet_ip6_fragment_header_t));
  1348. nb = *nb_p;
  1349. total_length = (unsigned short)nb->length;
  1350. if(mf)
  1351. {
  1352. /* Fragments (except the last) must be multiples of 8 bytes */
  1353. if ((total_length & 0x07) != 0)
  1354. {
  1355. /* If the length of a fragment, as derived from the fragment packet’s
  1356. * Payload Length field, is not a multiple of 8 octets and the M flag
  1357. * of that fragment is 1, then that fragment must be discarded and an
  1358. * ICMP Parameter Problem, Code 0, message should be sent to the
  1359. * source of the fragment, pointing to the Payload Length field of
  1360. * the fragment packet. */
  1361. fnet_icmp6_error( netif, FNET_ICMP6_TYPE_PARAM_PROB, FNET_ICMP6_CODE_PP_HEADER,
  1362. (unsigned long)((unsigned long)(&iphdr->length) - (unsigned long)ip6_nb->data_ptr), ip6_nb ); /* TBD not tested.*/
  1363. goto DROP_FRAG_0;
  1364. }
  1365. }
  1366. /* Create fragment header.*/
  1367. if((cur_frag_ptr = fnet_malloc(sizeof(fnet_ip6_frag_header_t))) == 0)
  1368. goto DROP_FRAG_1;
  1369. cur_frag_ptr->mf = mf;
  1370. cur_frag_ptr->offset = offset;
  1371. cur_frag_ptr->nb = nb;
  1372. cur_frag_ptr->total_length = total_length;
  1373. /* Liner search of the list to locate the appropriate datagram for the current fragment.*/
  1374. for (frag_list_ptr = ip6_frag_list_head; frag_list_ptr != 0; frag_list_ptr = frag_list_ptr->next)
  1375. {
  1376. if( (frag_list_ptr->id == id)
  1377. && (frag_list_ptr->next_header == next_header)
  1378. && FNET_IP6_ADDR_EQUAL(&frag_list_ptr->source_addr, src_ip)
  1379. && FNET_IP6_ADDR_EQUAL(&frag_list_ptr->destination_addr, dest_ip))
  1380. break;
  1381. }
  1382. /* The first fragment of the new datagram.*/
  1383. if(frag_list_ptr == 0)
  1384. {
  1385. /* Create list.*/
  1386. if((frag_list_ptr = fnet_malloc_zero(sizeof(fnet_ip6_frag_list_t))) == 0)
  1387. goto DROP_FRAG_2;
  1388. fnet_ip6_frag_list_add(&ip6_frag_list_head, frag_list_ptr);
  1389. frag_list_ptr->ttl = FNET_IP6_FRAG_TTL;
  1390. frag_list_ptr->id = id;
  1391. frag_list_ptr->next_header = next_header;
  1392. FNET_IP6_ADDR_COPY(src_ip, &frag_list_ptr->source_addr);
  1393. FNET_IP6_ADDR_COPY(dest_ip, &frag_list_ptr->destination_addr);
  1394. frag_ptr = 0;
  1395. }
  1396. else
  1397. {
  1398. /* Find position in reassembly list.*/
  1399. frag_ptr = frag_list_ptr->frag_ptr;
  1400. do
  1401. {
  1402. if(frag_ptr->offset > cur_frag_ptr->offset)
  1403. break;
  1404. frag_ptr = frag_ptr->next;
  1405. }
  1406. while (frag_ptr != frag_list_ptr->frag_ptr);
  1407. /* Trims or discards icoming fragments.*/
  1408. if(frag_ptr != frag_list_ptr->frag_ptr)
  1409. {
  1410. if((i = frag_ptr->prev->offset + frag_ptr->prev->total_length - cur_frag_ptr->prev->offset) != 0)
  1411. {
  1412. if(i > cur_frag_ptr->total_length)
  1413. goto DROP_FRAG_2;
  1414. fnet_netbuf_trim(nb_p, i);
  1415. nb = *nb_p;
  1416. cur_frag_ptr->total_length -= i;
  1417. cur_frag_ptr->offset += i;
  1418. }
  1419. }
  1420. /* Trims or discards existing fragments.*/
  1421. while((frag_ptr != frag_list_ptr->frag_ptr)
  1422. && ((cur_frag_ptr->offset + cur_frag_ptr->total_length) > frag_ptr->offset))
  1423. {
  1424. i = (cur_frag_ptr->offset + cur_frag_ptr->total_length) - frag_ptr->offset;
  1425. if(i < frag_ptr->total_length)
  1426. {
  1427. frag_ptr->total_length -= i;
  1428. frag_ptr->offset += i;
  1429. fnet_netbuf_trim((fnet_netbuf_t **)&frag_ptr->nb, i);
  1430. break;
  1431. }
  1432. frag_ptr = frag_ptr->next;
  1433. fnet_netbuf_free_chain(frag_ptr->prev->nb);
  1434. fnet_ip6_frag_del((fnet_ip6_frag_header_t **)&frag_list_ptr->frag_ptr, frag_ptr->prev);
  1435. }
  1436. }
  1437. if(offset == 0) /* First fragment */
  1438. {
  1439. frag_list_ptr->hdr_length = iphdr->length;
  1440. frag_list_ptr->hdr_hop_limit = iphdr->hop_limit;
  1441. frag_list_ptr->netif = netif;
  1442. }
  1443. /* Insert fragment to the list.*/
  1444. fnet_ip6_frag_add((fnet_ip6_frag_header_t **)(&frag_list_ptr->frag_ptr), cur_frag_ptr, frag_ptr ? frag_ptr->prev : 0);
  1445. {
  1446. int offset_l = 0;
  1447. frag_ptr = frag_list_ptr->frag_ptr;
  1448. do
  1449. {
  1450. if(frag_ptr->offset != offset_l)
  1451. goto NEXT_FRAG;
  1452. offset_l += frag_ptr->total_length;
  1453. frag_ptr = frag_ptr->next;
  1454. } while (frag_ptr != frag_list_ptr->frag_ptr);
  1455. }
  1456. if(frag_ptr->prev->mf & 1)
  1457. goto NEXT_FRAG;
  1458. /* Reconstruct datagram.*/
  1459. frag_ptr = frag_list_ptr->frag_ptr;
  1460. nb = frag_ptr->nb;
  1461. frag_ptr = frag_ptr->next;
  1462. while(frag_ptr != frag_list_ptr->frag_ptr)
  1463. {
  1464. nb = fnet_netbuf_concat(nb, frag_ptr->nb);
  1465. frag_ptr = frag_ptr->next;
  1466. }
  1467. /* Reconstruct datagram header.*/
  1468. iphdr = (fnet_ip6_header_t *)ip6_nb->data_ptr;
  1469. iphdr->length = fnet_htons((unsigned short)nb->total_length);
  1470. iphdr->next_header = frag_list_ptr->next_header;
  1471. while(frag_list_ptr->frag_ptr != 0)
  1472. {
  1473. fnet_ip6_frag_del((fnet_ip6_frag_header_t **)(&frag_list_ptr->frag_ptr), frag_list_ptr->frag_ptr);
  1474. }
  1475. fnet_ip6_frag_list_del(&ip6_frag_list_head, frag_list_ptr);
  1476. fnet_free(frag_list_ptr);
  1477. return (nb);
  1478. DROP_FRAG_2:
  1479. fnet_free(cur_frag_ptr);
  1480. DROP_FRAG_1:
  1481. fnet_netbuf_free_chain(ip6_nb);
  1482. DROP_FRAG_0:
  1483. fnet_netbuf_free_chain(nb);
  1484. return (FNET_NULL);
  1485. NEXT_FRAG:
  1486. fnet_netbuf_free_chain(ip6_nb);
  1487. return (FNET_NULL);
  1488. }
  1489. #endif /* FNET_CFG_IP4_FRAGMENTATION */
  1490. /************************************************************************
  1491. * NAME: fnet_ip_timer
  1492. *
  1493. * DESCRIPTION: IP timer function.
  1494. *************************************************************************/
  1495. #if FNET_CFG_IP6_FRAGMENTATION
  1496. static void fnet_ip6_timer(void *cookie)
  1497. {
  1498. fnet_ip6_frag_list_t *frag_list_ptr;
  1499. fnet_ip6_frag_list_t *tmp_frag_list_ptr;
  1500. FNET_COMP_UNUSED_ARG(cookie);
  1501. fnet_isr_lock();
  1502. frag_list_ptr = ip6_frag_list_head;
  1503. while(frag_list_ptr != 0)
  1504. {
  1505. frag_list_ptr->ttl--;
  1506. if(frag_list_ptr->ttl == 0)
  1507. {
  1508. /* If the first fragment (i.e., the one
  1509. * with a Fragment Offset of zero) has been received, an ICMP Time
  1510. * Exceeded -- Fragment Reassembly Time Exceeded message should be
  1511. * sent to the source of that fragment.
  1512. */
  1513. if( frag_list_ptr->frag_ptr && (frag_list_ptr->frag_ptr->offset == 0) )
  1514. {
  1515. fnet_netbuf_t *nb_header;
  1516. fnet_netbuf_t *nb;
  1517. fnet_ip6_header_t *ip6_header;
  1518. fnet_ip6_fragment_header_t *ip6_fragment_header;
  1519. /*************************************
  1520. * Reconstact PCB for ICMP error.
  1521. *************************************/
  1522. nb_header = fnet_netbuf_new(sizeof(fnet_ip6_header_t) + sizeof(fnet_ip6_fragment_header_t), FNET_FALSE); /* Allocate a new header.*/
  1523. if(nb_header == FNET_NULL)
  1524. {
  1525. goto FREE_LIST;
  1526. }
  1527. nb = fnet_netbuf_copy(frag_list_ptr->frag_ptr->nb, 0, FNET_NETBUF_COPYALL, 0);
  1528. if(nb == FNET_NULL)
  1529. {
  1530. fnet_netbuf_free(nb_header);
  1531. goto FREE_LIST;
  1532. }
  1533. nb = fnet_netbuf_concat(nb_header, nb);
  1534. ip6_header = nb->data_ptr;
  1535. ip6_fragment_header = (fnet_ip6_fragment_header_t*)((unsigned long)ip6_header + sizeof(fnet_ip6_header_t));
  1536. /* IPv6 header.*/
  1537. ip6_header->version__tclass = FNET_IP6_VERSION<<4; /* PFI copy/save header*/
  1538. ip6_header->tclass__flowl = 0;
  1539. ip6_header->flowl = 0;
  1540. ip6_header->length = frag_list_ptr->hdr_length;
  1541. ip6_header->next_header = FNET_IP6_TYPE_FRAGMENT_HEADER;
  1542. ip6_header->hop_limit = frag_list_ptr->hdr_hop_limit;
  1543. FNET_IP6_ADDR_COPY(&frag_list_ptr->source_addr, &ip6_header->source_addr);
  1544. FNET_IP6_ADDR_COPY(&frag_list_ptr->destination_addr, &ip6_header->destination_addr);
  1545. /* Fragment header.*/
  1546. ip6_fragment_header->next_header = frag_list_ptr->next_header;
  1547. ip6_fragment_header->_reserved=0;
  1548. ip6_fragment_header->offset_more = fnet_htons(frag_list_ptr->frag_ptr->mf);
  1549. ip6_fragment_header->id = frag_list_ptr->id;
  1550. fnet_icmp6_error( frag_list_ptr->netif, FNET_ICMP6_TYPE_TIME_EXCEED, FNET_ICMP6_CODE_TE_FRG_REASSEMBLY,
  1551. 0, nb ); /* TBD not tested.*/
  1552. }
  1553. FREE_LIST:
  1554. tmp_frag_list_ptr = frag_list_ptr->next;
  1555. fnet_ip6_frag_list_free(frag_list_ptr);
  1556. frag_list_ptr = tmp_frag_list_ptr;
  1557. }
  1558. else
  1559. frag_list_ptr = frag_list_ptr->next;
  1560. }
  1561. fnet_isr_unlock();
  1562. }
  1563. #endif
  1564. /************************************************************************
  1565. * NAME: fnet_ip6_drain
  1566. *
  1567. * DESCRIPTION: This function tries to free not critical parts
  1568. * of memory occupied by the IPv6 module.
  1569. *************************************************************************/
  1570. void fnet_ip6_drain( void )
  1571. {
  1572. fnet_isr_lock();
  1573. #if FNET_CFG_IP6_FRAGMENTATION
  1574. while(((volatile fnet_ip6_frag_list_t *)ip6_frag_list_head) != 0)
  1575. {
  1576. fnet_ip6_frag_list_free(ip6_frag_list_head);
  1577. }
  1578. #endif
  1579. while(((volatile fnet_netbuf_t *)ip6_queue.head) != 0)
  1580. {
  1581. fnet_netbuf_del_chain(&ip6_queue.head, ip6_queue.head);
  1582. }
  1583. ip6_queue.count = 0;
  1584. fnet_isr_unlock();
  1585. }
  1586. /************************************************************************
  1587. * NAME: fnet_ip6_getsockopt
  1588. *
  1589. * DESCRIPTION: This function retrieves the current value
  1590. * of IPv6 socket option.
  1591. *************************************************************************/
  1592. int fnet_ip6_getsockopt(fnet_socket_t *sock, int optname, char *optval, unsigned int *optlen )
  1593. {
  1594. int result = FNET_OK;
  1595. switch(optname) /* Socket options processing. */
  1596. {
  1597. case IPV6_UNICAST_HOPS: /* Get IPv6 hop limit for outgoing unicast datagrams.*/
  1598. if(*optlen < sizeof(int))
  1599. {
  1600. result = FNET_ERR_INVAL;
  1601. break;
  1602. }
  1603. *((int*)optval) = (char)sock->options.ip6_opt.hops_unicast;
  1604. *optlen = sizeof(int);
  1605. break;
  1606. case IPV6_MULTICAST_HOPS: /* Get IPv6 hop limit for outgoing multicast datagrams.*/
  1607. if(*optlen < sizeof(int))
  1608. {
  1609. result = FNET_ERR_INVAL;
  1610. break;
  1611. }
  1612. *((int*)optval) = (char)sock->options.ip6_opt.hops_multicast;
  1613. *optlen = sizeof(int);
  1614. break;
  1615. default:
  1616. result = FNET_ERR_NOPROTOOPT; /* The option is unknown or unsupported.*/
  1617. break;
  1618. }
  1619. return result;
  1620. }
  1621. /************************************************************************
  1622. * NAME: fnet_ip6_setsockopt
  1623. *
  1624. * DESCRIPTION: This function sets the value of IPv6 socket option.
  1625. *************************************************************************/
  1626. int fnet_ip6_setsockopt( fnet_socket_t *sock, int optname, char *optval, unsigned int optlen )
  1627. {
  1628. int result = FNET_OK;
  1629. switch(optname) /* Socket options processing. */
  1630. {
  1631. /******************************/
  1632. case IPV6_UNICAST_HOPS: /* Set IPv6 hop limit for outgoing unicast datagrams. */
  1633. if(optlen != sizeof(int))
  1634. {
  1635. result = FNET_ERR_INVAL;
  1636. break;
  1637. }
  1638. sock->options.ip6_opt.hops_unicast = (unsigned char) (*((int *)(optval)));
  1639. break;
  1640. /******************************/
  1641. case IPV6_MULTICAST_HOPS: /* Set IPv6 hop limit for outgoing multicast datagrams. */
  1642. /* Validation.*/
  1643. if( (optlen != sizeof(int)) || !(sock->protocol_interface) || (sock->protocol_interface->type != SOCK_DGRAM ) )
  1644. {
  1645. result = FNET_ERR_INVAL;
  1646. break;
  1647. }
  1648. sock->options.ip6_opt.hops_multicast = (unsigned char) (*((int *)(optval)));
  1649. break;
  1650. /******************************/
  1651. case IPV6_JOIN_GROUP: /* Join the socket to the supplied IPv6 multicast group on
  1652. * the specified interface. */
  1653. case IPV6_LEAVE_GROUP: /* Drops membership to the given IPv6 multicast group and interface.*/
  1654. {
  1655. int i;
  1656. fnet_ip6_multicast_list_entry_t **multicast_entry = FNET_NULL;
  1657. struct ipv6_mreq *mreq = (struct ipv6_mreq *)optval;
  1658. fnet_netif_t *netif;
  1659. if(mreq->ipv6imr_interface == 0)
  1660. {
  1661. netif = (fnet_netif_t *)fnet_netif_get_default();
  1662. }
  1663. else
  1664. {
  1665. netif = (fnet_netif_t *)fnet_netif_get_by_scope_id(mreq->ipv6imr_interface);
  1666. }
  1667. if((optlen != sizeof(struct ipv6_mreq)) /* Check size.*/
  1668. || (netif == FNET_NULL) /* Found IF.*/
  1669. || (!FNET_IP6_ADDR_IS_MULTICAST(&mreq->ipv6imr_multiaddr.s6_addr)) /* Check if the address is multicast.*/
  1670. || !(sock->protocol_interface) || (sock->protocol_interface->type != SOCK_DGRAM )
  1671. )
  1672. {
  1673. result = FNET_ERR_INVAL;
  1674. break;
  1675. }
  1676. /* Find the existing entry with same parameters (if any).*/
  1677. for(i = 0; i < FNET_CFG_MULTICAST_SOCKET_MAX; i++)
  1678. {
  1679. if( (sock->ip6_multicast_entry[i] != FNET_NULL)
  1680. && (sock->ip6_multicast_entry[i]->user_counter)
  1681. && (sock->ip6_multicast_entry[i]->netif == netif)
  1682. && FNET_IP6_ADDR_EQUAL(&sock->ip6_multicast_entry[i]->group_addr, &mreq->ipv6imr_multiaddr.s6_addr))
  1683. {
  1684. multicast_entry = &sock->ip6_multicast_entry[i];
  1685. break; /* Found.*/
  1686. }
  1687. }
  1688. /******************************/
  1689. if(optname == IPV6_JOIN_GROUP)
  1690. {
  1691. if(multicast_entry != FNET_NULL)
  1692. {
  1693. /* Already joined.*/
  1694. result = FNET_ERR_ADDRINUSE;
  1695. break;
  1696. }
  1697. /* Find free entry.*/
  1698. for(i = 0; i < FNET_CFG_MULTICAST_SOCKET_MAX; i++)
  1699. {
  1700. if(sock->ip6_multicast_entry[i] == FNET_NULL)
  1701. {
  1702. multicast_entry = &sock->ip6_multicast_entry[i];
  1703. break; /* Found.*/
  1704. }
  1705. }
  1706. if(multicast_entry != FNET_NULL)
  1707. {
  1708. *multicast_entry = fnet_ip6_multicast_join( netif, &mreq->ipv6imr_multiaddr.s6_addr );
  1709. if(*multicast_entry == FNET_NULL)
  1710. {
  1711. result = FNET_ERR_ADDRINUSE;
  1712. break;
  1713. }
  1714. }
  1715. else
  1716. {
  1717. result = FNET_ERR_ADDRINUSE;
  1718. break;
  1719. }
  1720. }
  1721. /******************************/
  1722. else /* IPV6_LEAVE_GROUP */
  1723. {
  1724. if(multicast_entry != FNET_NULL)
  1725. {
  1726. /* Leave the group.*/
  1727. fnet_ip6_multicast_leave_entry(*multicast_entry);
  1728. *multicast_entry = FNET_NULL; /* Clear entry.*/
  1729. }
  1730. else
  1731. {
  1732. /* Join entry is not found.*/
  1733. result = FNET_ERR_INVAL;
  1734. break;
  1735. }
  1736. }
  1737. }
  1738. break;
  1739. /******************************/
  1740. default:
  1741. result = FNET_ERR_NOPROTOOPT; /* The option is unknown or unsupported. */
  1742. break;
  1743. }
  1744. return result;
  1745. }
  1746. /************************************************************************
  1747. * NAME: fnet_ip6_multicast_join
  1748. *
  1749. * DESCRIPTION: Join a IPv6 multicast group. Returns pointer to the entry in
  1750. * the multicast list, or FNET_NULL if any error.
  1751. *************************************************************************/
  1752. fnet_ip6_multicast_list_entry_t *fnet_ip6_multicast_join(fnet_netif_t *netif, const fnet_ip6_addr_t *group_addr )
  1753. {
  1754. int i;
  1755. fnet_ip6_multicast_list_entry_t *result = FNET_NULL;
  1756. /* Find existing entry or free one.*/
  1757. for(i=0; i < FNET_CFG_MULTICAST_MAX; i++)
  1758. {
  1759. if(fnet_ip6_multicast_list[i].user_counter > 0)
  1760. {
  1761. if((fnet_ip6_multicast_list[i].netif == netif) && FNET_IP6_ADDR_EQUAL(&fnet_ip6_multicast_list[i].group_addr, group_addr))
  1762. {
  1763. result = &fnet_ip6_multicast_list[i];
  1764. break; /* Found.*/
  1765. }
  1766. }
  1767. else /* user_counter == 0.*/
  1768. {
  1769. result = &fnet_ip6_multicast_list[i]; /* Save the last free.*/
  1770. break;
  1771. }
  1772. }
  1773. if(result)
  1774. {
  1775. result->user_counter++; /* Increment user counter.*/
  1776. if(result->user_counter == 1) /* New entry.*/
  1777. {
  1778. FNET_IP6_ADDR_COPY(group_addr, &result->group_addr);
  1779. result->netif = netif;
  1780. /* Join HW interface. */
  1781. fnet_netif_join_ip6_multicast ( (fnet_netif_desc_t) netif, group_addr );
  1782. #if FNET_CFG_MLD
  1783. /*
  1784. * When a host joins a new group, it should immediately transmit a
  1785. * Report for that group.
  1786. * //TBD To cover the possibility of the initial Report being lost or damaged, it is
  1787. * recommended that it be repeated once or twice after short delays.
  1788. */
  1789. fnet_mld_join(netif, (fnet_ip6_addr_t *)group_addr);
  1790. #endif
  1791. }
  1792. }
  1793. return result;
  1794. }
  1795. /************************************************************************
  1796. * NAME: fnet_ip6_multicast_find_entry
  1797. *
  1798. * DESCRIPTION: Find a IPv6 multicast group entry.
  1799. *************************************************************************/
  1800. fnet_ip6_multicast_list_entry_t *fnet_ip6_multicast_find_entry(fnet_netif_t *netif, const fnet_ip6_addr_t *group_addr )
  1801. {
  1802. int i;
  1803. fnet_ip6_multicast_list_entry_t *result = FNET_NULL;
  1804. /* Find existing entry or free one.*/
  1805. for(i=0; i < FNET_CFG_MULTICAST_MAX; i++)
  1806. {
  1807. if((fnet_ip6_multicast_list[i].user_counter > 0)
  1808. &&(fnet_ip6_multicast_list[i].netif == netif)
  1809. && FNET_IP6_ADDR_EQUAL(&fnet_ip6_multicast_list[i].group_addr, group_addr))
  1810. {
  1811. result = &fnet_ip6_multicast_list[i];
  1812. break; /* Found.*/
  1813. }
  1814. }
  1815. return result;
  1816. }
  1817. /************************************************************************
  1818. * NAME: fnet_ip6_multicast_leave
  1819. *
  1820. * DESCRIPTION: Leave the IPv6 multicast group.
  1821. *************************************************************************/
  1822. void fnet_ip6_multicast_leave(fnet_netif_t *netif, const fnet_ip6_addr_t *group_addr)
  1823. {
  1824. fnet_ip6_multicast_list_entry_t *multicast_entry;
  1825. multicast_entry = fnet_ip6_multicast_find_entry(netif, group_addr);
  1826. fnet_ip6_multicast_leave_entry(multicast_entry);
  1827. }
  1828. /************************************************************************
  1829. * NAME: fnet_ip6_multicast_leave_all
  1830. *
  1831. * DESCRIPTION: Leave the all IPv6 multicast groups.
  1832. *************************************************************************/
  1833. void fnet_ip6_multicast_leave_all(fnet_netif_t *netif)
  1834. {
  1835. int i;
  1836. for(i=0; i < FNET_CFG_MULTICAST_MAX; i++)
  1837. {
  1838. if((fnet_ip6_multicast_list[i].user_counter > 0)
  1839. &&(fnet_ip6_multicast_list[i].netif == netif))
  1840. {
  1841. fnet_ip6_multicast_leave_entry(&fnet_ip6_multicast_list[i]);
  1842. }
  1843. }
  1844. }
  1845. /************************************************************************
  1846. * NAME: fnet_ip6_multicast_leave_entry
  1847. *
  1848. * DESCRIPTION: Leave a multicast group.
  1849. *************************************************************************/
  1850. void fnet_ip6_multicast_leave_entry( fnet_ip6_multicast_list_entry_t *multicastentry )
  1851. {
  1852. if(multicastentry && multicastentry->user_counter)
  1853. {
  1854. multicastentry->user_counter--; /* Decrement user counter.*/
  1855. if(multicastentry->user_counter == 0)
  1856. {
  1857. #if FNET_CFG_MLD
  1858. /* Leave via MLD */
  1859. fnet_mld_leave(multicastentry->netif, &multicastentry->group_addr);
  1860. #endif
  1861. /* Leave HW interface. */
  1862. fnet_netif_leave_ip6_multicast ( (fnet_netif_desc_t) multicastentry->netif, &multicastentry->group_addr );
  1863. }
  1864. }
  1865. }
  1866. #endif /* FNET_CFG_IP6 */