1 /*
2 * ipreasm -- Routines for reassembly of fragmented IPv4 and IPv6 packets.
3 *
4 * Copyright (c) 2007 Jan Andres <jandres@gmx.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 */
10
11 #include "nmsg_port_net.h"
12
13 #include <assert.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stddef.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <pcap.h>
23
24 #include "ipreasm.h"
25
26 #define REASM_IP_HASH_SIZE 1021U
27
28
29 enum entry_state {
30 STATE_ACTIVE,
31 STATE_INVALID
32 };
33
34
35 enum reasm_proto {
36 PROTO_IPV4,
37 PROTO_IPV6
38 };
39
40
41 /*
42 * This tuple uniquely identifies all fragments belonging to
43 * the same IPv4 packet.
44 */
45 struct reasm_id_ipv4 {
46 uint8_t ip_src[4], ip_dst[4];
47 uint16_t ip_id;
48 uint8_t ip_proto;
49 };
50
51
52 /*
53 * Same for IPv6.
54 */
55 struct reasm_id_ipv6 {
56 uint8_t ip_src[16], ip_dst[16];
57 uint32_t ip_id;
58 };
59
60
61 union reasm_id {
62 struct reasm_id_ipv4 ipv4;
63 struct reasm_id_ipv6 ipv6;
64 };
65
66
67 struct reasm_frag_entry {
68 unsigned len; /* payload length of this fragment */
69 unsigned offset; /* offset of this fragment into the payload of the reassembled packet */
70 unsigned data_offset; /* offset to the data pointer where payload starts */
71 unsigned char *data; /* payload starts at data + data_offset */
72 struct reasm_frag_entry *next;
73 };
74
75
76 /*
77 * Reception of a complete packet is detected by counting the number
78 * of "holes" that remain between the cached fragments. A hole is
79 * assumed to exist at the upper end of the packet until the final
80 * fragment has been received. When the number of holes drops to 0,
81 * all fragments have been received and the packet can be reassembled.
82 */
83 struct reasm_ip_entry {
84 union reasm_id id;
85 unsigned len, holes, frag_count, hash;
86 reasm_time_t timeout;
87 enum entry_state state;
88 enum reasm_proto protocol;
89 struct reasm_frag_entry *frags;
90 struct reasm_ip_entry *prev, *next;
91 struct reasm_ip_entry *time_prev, *time_next;
92 };
93
94
95 /*
96 * This struct contains some metadata, the main hash table, and a pointer
97 * to the first entry that will time out. A linked list is kept in the
98 * order in which packets will time out. Using a linked list for this
99 * purpose requires that packets are input in chronological order, and
100 * that a constant timeout value is used, which doesn't change even when
101 * the entry's state transitions from active to invalid.
102 */
103 struct reasm_ip {
104 struct reasm_ip_entry *table[REASM_IP_HASH_SIZE];
105 struct reasm_ip_entry *time_first, *time_last;
106 unsigned waiting, max_waiting, timed_out, dropped_frags;
107 reasm_time_t timeout;
108 };
109
110
111 /*
112 * Hash functions.
113 */
114 static unsigned reasm_ipv4_hash (const struct reasm_id_ipv4 *id);
115 static unsigned reasm_ipv6_hash (const struct reasm_id_ipv6 *id);
116
117 /*
118 * Insert a new fragment to the correct position in the list of fragments.
119 * Check for fragment overlap and other error conditions. Update the
120 * "hole count".
121 */
122 static bool add_fragment (struct reasm_ip_entry *entry, struct reasm_frag_entry *frag, bool last_frag);
123
124 /*
125 * Is the entry complete, ready for reassembly?
126 */
127 static bool is_complete (struct reasm_ip_entry *entry);
128
129 /*
130 * Create the reassembled packet.
131 */
132 static void assemble (struct reasm_ip_entry *entry, unsigned char *out_packet, unsigned *output_len);
133
134 /*
135 * Drop and free entries.
136 */
137 static void drop_entry (struct reasm_ip *reasm, struct reasm_ip_entry *entry);
138 static void free_entry (struct reasm_ip_entry *entry);
139
140 /*
141 * Dispose of any entries which have expired before "now".
142 */
143 static void process_timeouts (struct reasm_ip *reasm, reasm_time_t now);
144
145 /*
146 * Create fragment structure from IPv6 packet. Returns NULL if the input
147 * is not a fragment.
148 * This function is called by parse_packet(), don't call it directly.
149 */
150 static struct reasm_frag_entry *frag_from_ipv6 (const unsigned char *packet, unsigned frag_hdr_offset, uint32_t *ip_id, bool *last_frag);
151
152 /*
153 * Compare packet identification tuples for specified protocol.
154 */
155 static bool reasm_id_equal (enum reasm_proto proto, const union reasm_id *left, const union reasm_id *right);
156
157 /*
158 * Create fragment structure from an IPv4 or IPv6 packet. Returns NULL
159 * if the input is not a fragment.
160 */
161 static struct reasm_frag_entry *parse_packet (const unsigned char *packet, unsigned len, unsigned frag_hdr_offset, enum reasm_proto *protocol, union reasm_id *id, unsigned *hash, bool *last_frag);
162
163
164 static unsigned
reasm_ipv4_hash(const struct reasm_id_ipv4 * id)165 reasm_ipv4_hash (const struct reasm_id_ipv4 *id)
166 {
167 unsigned hash = 0;
168 int i;
169
170 for (i = 0; i < 4; i++) {
171 hash = 37U * hash + id->ip_src[i];
172 hash = 37U * hash + id->ip_dst[i];
173 }
174
175 hash = 59U * hash + id->ip_id;
176
177 hash = 47U * hash + id->ip_proto;
178
179 return hash;
180 }
181
182
183 static unsigned
reasm_ipv6_hash(const struct reasm_id_ipv6 * id)184 reasm_ipv6_hash (const struct reasm_id_ipv6 *id)
185 {
186 unsigned hash = 0;
187 int i;
188
189 for (i = 0; i < 16; i++) {
190 hash = 37U * hash + id->ip_src[i];
191 hash = 37U * hash + id->ip_dst[i];
192 }
193
194 hash = 59U * hash + id->ip_id;
195
196 return hash;
197 }
198
199
200 bool
reasm_ip_next(struct reasm_ip * reasm,const unsigned char * packet,unsigned len,unsigned frag_hdr_offset,reasm_time_t timestamp,unsigned char * out_packet,unsigned * output_len)201 reasm_ip_next (struct reasm_ip *reasm, const unsigned char *packet, unsigned len, unsigned frag_hdr_offset, reasm_time_t timestamp, unsigned char *out_packet, unsigned *output_len)
202 {
203 enum reasm_proto proto;
204 union reasm_id id;
205 unsigned hash = 0;
206 bool last_frag = 0;
207 struct reasm_frag_entry *frag;
208 struct reasm_ip_entry *entry;
209
210 process_timeouts (reasm, timestamp);
211
212 frag = parse_packet (packet, len, frag_hdr_offset, &proto, &id, &hash, &last_frag);
213 if (frag == NULL) {
214 *output_len = 0;
215 return false; /* some packet that we don't recognize as a fragment */
216 }
217
218 hash %= REASM_IP_HASH_SIZE;
219 entry = reasm->table[hash];
220 while (entry != NULL && (proto != entry->protocol || !reasm_id_equal (proto, &id, &entry->id)))
221 entry = entry->next;
222
223 if (entry == NULL) {
224 struct reasm_frag_entry *list_head;
225
226 entry = malloc (sizeof (*entry));
227 if (entry == NULL) {
228 free (frag);
229 abort ();
230 }
231
232 list_head = malloc (sizeof (*list_head));
233 if (list_head == NULL) {
234 free (frag);
235 free (entry);
236 abort ();
237 }
238
239 memset(entry, 0, sizeof *entry);
240 entry->id = id;
241 entry->len = 0;
242 entry->holes = 1;
243 entry->frags = list_head;
244 entry->hash = hash;
245 entry->protocol = proto;
246 entry->timeout = timestamp + reasm->timeout;
247 entry->state = STATE_ACTIVE;
248 entry->prev = NULL;
249 entry->next = reasm->table[hash];
250 entry->time_prev = reasm->time_last;
251 entry->time_next = NULL;
252
253 memset(list_head, 0, sizeof *list_head);
254 list_head->len = 0;
255 list_head->offset = 0;
256 list_head->data_offset = 0;
257 list_head->data = NULL;
258
259 if (entry->next != NULL)
260 entry->next->prev = entry;
261 reasm->table[hash] = entry;
262
263 if (reasm->time_last != NULL)
264 reasm->time_last->time_next = entry;
265 else
266 reasm->time_first = entry;
267 reasm->time_last = entry;
268
269 reasm->waiting++;
270 if (reasm->waiting > reasm->max_waiting)
271 reasm->max_waiting = reasm->waiting;
272 }
273
274 if (entry->state != STATE_ACTIVE) {
275 reasm->dropped_frags++;
276 *output_len = 0;
277 free(frag->data);
278 free(frag);
279 return true;
280 }
281
282 if (!add_fragment (entry, frag, last_frag)) {
283 entry->state = STATE_INVALID;
284 reasm->dropped_frags += entry->frag_count + 1;
285 *output_len = 0;
286 free(frag->data);
287 free(frag);
288 return true;
289 }
290
291 if (!is_complete (entry)) {
292 *output_len = 0;
293 return true;
294 }
295
296 assemble (entry, out_packet, output_len);
297 drop_entry (reasm, entry);
298 return true;
299 }
300
301
302 static bool
add_fragment(struct reasm_ip_entry * entry,struct reasm_frag_entry * frag,bool last_frag)303 add_fragment (struct reasm_ip_entry *entry, struct reasm_frag_entry *frag, bool last_frag)
304 {
305 bool fit_left, fit_right;
306 struct reasm_frag_entry *cur, *next;
307
308 /*
309 * When a fragment is inserted into the list, different cases can occur
310 * concerning the number of holes.
311 * - The new fragment can be inserted in the middle of a hole, such that
312 * it will split the hole in two. The number of holes increases by 1.
313 * - The new fragment can be attached to one end of a hole, such that
314 * the rest of the hole remains at the opposite side of the fragment.
315 * The number of holes remains constant.
316 * - The new fragment can fill a hole completely. The number of holes
317 * decreases by 1.
318 */
319
320 /*
321 * If more fragments follow and the payload size is not an integer
322 * multiple of 8, the packet will never be reassembled completely.
323 */
324 if (!last_frag && (frag->len & 7) != 0)
325 return false;
326
327 if (entry->len != 0 && frag->len + frag->offset > entry->len)
328 return false; /* fragment extends past end of packet */
329
330 fit_left = false;
331 fit_right = false;
332
333 if (last_frag) {
334 if (entry->len != 0)
335 return false;
336 entry->len = frag->offset + frag->len;
337 fit_right = true;
338 }
339
340 cur = entry->frags;
341
342 while (cur->next != NULL && cur->next->offset <= frag->offset)
343 cur = cur->next;
344 next = cur->next;
345
346 /* Fragment is to be inserted between cur and next; next may be NULL. */
347
348 /* Overlap checks. */
349 if (cur->offset + cur->len > frag->offset)
350 return false; /* overlaps with cur */
351 else if (cur->offset + cur->len == frag->offset)
352 fit_left = true;
353
354 if (next != NULL) {
355 if (last_frag)
356 return false; /* next extends past end of packet */
357 if (frag->offset + frag->len > next->offset)
358 return false; /* overlaps with next */
359 else if (frag->offset + frag->len == next->offset)
360 fit_right = true;
361 }
362
363 /*
364 * Everything's fine, insert it.
365 */
366 if (frag->len != 0) {
367 frag->next = cur->next;
368 cur->next = frag;
369
370 if (fit_left && fit_right)
371 entry->holes--;
372 else if (!fit_left && !fit_right)
373 entry->holes++;
374
375 entry->frag_count++;
376 } else {
377 /*
378 * If the fragment has zero size, we don't insert it into the list,
379 * but one case remains to be handled: If the zero-size fragment
380 * is the last fragment, and fits exactly with the fragment to its
381 * left, the number of holes decreases.
382 */
383 if (last_frag && fit_left)
384 entry->holes--;
385 }
386
387
388 return true;
389 }
390
391
392 struct reasm_ip *
reasm_ip_new(void)393 reasm_ip_new (void)
394 {
395 struct reasm_ip *reasm = malloc (sizeof (*reasm));
396 if (reasm == NULL)
397 return NULL;
398
399 memset (reasm, 0, sizeof (*reasm));
400 return reasm;
401 }
402
403
404 void
reasm_ip_free(struct reasm_ip * reasm)405 reasm_ip_free (struct reasm_ip *reasm)
406 {
407 while (reasm->time_first != NULL)
408 drop_entry (reasm, reasm->time_first);
409 free (reasm);
410 }
411
412
413 static bool
is_complete(struct reasm_ip_entry * entry)414 is_complete (struct reasm_ip_entry *entry)
415 {
416 return entry->holes == 0;
417 }
418
419
420 static void
assemble(struct reasm_ip_entry * entry,unsigned char * out_packet,unsigned * output_len)421 assemble (struct reasm_ip_entry *entry, unsigned char *out_packet, unsigned *output_len)
422 {
423 struct reasm_frag_entry *frag = entry->frags->next; /* skip list head */
424 unsigned offset0 = frag->data_offset;
425
426 switch (entry->protocol) {
427 case PROTO_IPV4:
428 break;
429 case PROTO_IPV6:
430 offset0 -= 8; /* size of frag header */
431 break;
432 default:
433 abort ();
434 }
435
436 if (entry->len + offset0 > *output_len) {
437 /* The output buffer is too small. */
438 *output_len = 0;
439 return;
440 }
441
442 *output_len = entry->len + offset0;
443
444 /* copy the (unfragmentable) header from the first fragment received */
445 memcpy (out_packet, frag->data, offset0);
446
447 /* join all the payload fragments together */
448 while (frag != NULL) {
449 memcpy (out_packet + offset0 + frag->offset, frag->data + frag->data_offset, frag->len);
450 frag = frag->next;
451 }
452
453 /* some cleanups, e.g. update the length field of reassembled packet */
454 switch (entry->protocol) {
455 case PROTO_IPV4: {
456 struct nmsg_iphdr *ip_header = (struct nmsg_iphdr *) out_packet;
457 unsigned i, hl = 4 * ip_header->ip_hl;
458 int32_t sum = 0;
459 ip_header->ip_len = htons (offset0 + entry->len);
460 ip_header->ip_off = 0;
461 ip_header->ip_sum = 0;
462
463 /* Recompute checksum. */
464 for (i = 0; i < hl; i += 2) {
465 uint16_t cur = (uint16_t) out_packet[i] << 8 | out_packet[i + 1];
466 sum += cur;
467 if ((sum & 0x80000000) != 0)
468 sum = (sum & 0xffff) + (sum >> 16);
469 }
470 while ((sum >> 16) != 0)
471 sum = (sum & 0xffff) + (sum >> 16);
472 ip_header->ip_sum = htons (~sum);
473 break;
474 }
475 case PROTO_IPV6: {
476 struct ip6_hdr *ip6_header = (struct ip6_hdr *) out_packet;
477 ip6_header->ip6_plen = htons (offset0 + entry->len - 40);
478 break;
479 }
480 default:
481 abort ();
482 }
483 }
484
485
486 static void
drop_entry(struct reasm_ip * reasm,struct reasm_ip_entry * entry)487 drop_entry (struct reasm_ip *reasm, struct reasm_ip_entry *entry)
488 {
489 if (entry->prev != NULL)
490 entry->prev->next = entry->next;
491 else
492 reasm->table[entry->hash] = entry->next;
493
494 if (entry->next != NULL)
495 entry->next->prev = entry->prev;
496
497 if (entry->time_prev != NULL)
498 entry->time_prev->time_next = entry->time_next;
499 else
500 reasm->time_first = entry->time_next;
501
502 if (entry->time_next != NULL)
503 entry->time_next->time_prev = entry->time_prev;
504 else
505 reasm->time_last = entry->time_prev;
506
507 reasm->waiting--;
508
509 free_entry (entry);
510 }
511
512
513 static void
free_entry(struct reasm_ip_entry * entry)514 free_entry (struct reasm_ip_entry *entry)
515 {
516 struct reasm_frag_entry *frag = entry->frags, *next;
517 while (frag != NULL) {
518 next = frag->next;
519 if (frag->data != NULL)
520 free (frag->data);
521 free (frag);
522 frag = next;
523 }
524
525 free (entry);
526 }
527
528
529 unsigned
reasm_ip_waiting(const struct reasm_ip * reasm)530 reasm_ip_waiting (const struct reasm_ip *reasm)
531 {
532 return reasm->waiting;
533 }
534
535
536 unsigned
reasm_ip_max_waiting(const struct reasm_ip * reasm)537 reasm_ip_max_waiting (const struct reasm_ip *reasm)
538 {
539 return reasm->max_waiting;
540 }
541
542
543 unsigned
reasm_ip_timed_out(const struct reasm_ip * reasm)544 reasm_ip_timed_out (const struct reasm_ip *reasm)
545 {
546 return reasm->timed_out;
547 }
548
549
550 unsigned
reasm_ip_dropped_frags(const struct reasm_ip * reasm)551 reasm_ip_dropped_frags (const struct reasm_ip *reasm)
552 {
553 return reasm->dropped_frags;
554 }
555
556
557 bool
reasm_ip_set_timeout(struct reasm_ip * reasm,reasm_time_t timeout)558 reasm_ip_set_timeout (struct reasm_ip *reasm, reasm_time_t timeout)
559 {
560 if (reasm->time_first != NULL)
561 return false;
562
563 reasm->timeout = timeout;
564 return true;
565 }
566
567
568 static void
process_timeouts(struct reasm_ip * reasm,reasm_time_t now)569 process_timeouts (struct reasm_ip *reasm, reasm_time_t now)
570 {
571 while (reasm->time_first != NULL && reasm->time_first->timeout < now) {
572 reasm->timed_out++;
573 drop_entry (reasm, reasm->time_first);
574 }
575 }
576
577
578 static struct reasm_frag_entry *
frag_from_ipv6(const unsigned char * packet,unsigned frag_hdr_offset,uint32_t * ip_id,bool * last_frag)579 frag_from_ipv6 (const unsigned char *packet, unsigned frag_hdr_offset, uint32_t *ip_id, bool *last_frag)
580 {
581 const struct ip6_hdr *ip6_header = (const struct ip6_hdr *) packet;
582 unsigned offset = 40; /* IPv6 header size */
583 uint8_t nxt = ip6_header->ip6_nxt;
584 unsigned total_len = 40 + ntohs (ip6_header->ip6_plen);
585 unsigned last_nxt = offsetof (struct ip6_hdr, ip6_nxt);
586 struct reasm_frag_entry *frag;
587 const struct ip6_frag *frag_header;
588 unsigned char *frag_data;
589
590 /*
591 * IPv6 extension headers from RFC 2460:
592 * 0 Hop-by-Hop Options
593 * 43 Routing
594 * 44 Fragment
595 * 60 Destination Options
596 *
597 * We look out for the Fragment header; the other 3 header
598 * types listed above are recognized and considered safe to
599 * skip over if they occur before the Fragment header.
600 * Any unrecognized header will cause processing to stop and
601 * a subsequent Fragment header to stay unrecognized.
602 */
603 if (frag_hdr_offset != 0)
604 offset = frag_hdr_offset;
605 else {
606 while (nxt == IPPROTO_HOPOPTS || nxt == IPPROTO_ROUTING || nxt == IPPROTO_DSTOPTS) {
607 unsigned exthdr_len;
608
609 if (offset + 2 > total_len)
610 return NULL; /* header extends past end of packet */
611
612 exthdr_len = 8 + 8 * packet[offset + 1];
613 if (offset + exthdr_len > total_len)
614 return NULL; /* header extends past end of packet */
615
616 nxt = packet[offset];
617 last_nxt = offset;
618 offset += exthdr_len;
619 }
620
621 if (nxt != IPPROTO_FRAGMENT)
622 return NULL;
623 }
624
625 if (offset + 8 > total_len)
626 return NULL; /* Fragment header extends past end of packet */
627
628 frag = malloc (sizeof (*frag));
629 if (frag == NULL)
630 abort ();
631
632 frag_header = (const struct ip6_frag *) (packet + offset);
633 offset += 8;
634
635 frag_data = malloc (total_len);
636 if (frag_data == NULL)
637 abort ();
638 memcpy (frag_data, packet, total_len);
639
640 /*
641 * The Fragment header will be removed on reassembly, so we have to
642 * replace the Next Header field of the previous header (which is
643 * currently IPPROTO_FRAGMENT), with the Next Header field of the
644 * Fragment header.
645 *
646 * XXX We really shouldn't manipulate the input packet in-place.
647 */
648 frag_data[last_nxt] = frag_header->ip6f_nxt;
649
650 memset(frag, 0, sizeof *frag);
651 frag->len = total_len - offset;
652 frag->data_offset = offset;
653 frag->offset = ntohs (frag_header->ip6f_offlg & IP6F_OFF_MASK);
654 frag->data = frag_data;
655
656 *ip_id = ntohl (frag_header->ip6f_ident);
657 *last_frag = (frag_header->ip6f_offlg & IP6F_MORE_FRAG) == 0;
658
659 return frag;
660 }
661
662
663 static bool
reasm_id_equal(enum reasm_proto proto,const union reasm_id * left,const union reasm_id * right)664 reasm_id_equal (enum reasm_proto proto, const union reasm_id *left, const union reasm_id *right)
665 {
666 switch (proto) {
667 case PROTO_IPV4:
668 return memcmp (left->ipv4.ip_src, right->ipv4.ip_src, 4) == 0
669 && memcmp (left->ipv4.ip_dst, right->ipv4.ip_dst, 4) == 0
670 && left->ipv4.ip_id == right->ipv4.ip_id
671 && left->ipv4.ip_proto == right->ipv4.ip_proto;
672 case PROTO_IPV6:
673 return memcmp (left->ipv6.ip_src, right->ipv6.ip_src, 16) == 0
674 && memcmp (left->ipv6.ip_dst, right->ipv6.ip_dst, 16) == 0
675 && left->ipv6.ip_id == right->ipv6.ip_id;
676 default:
677 abort ();
678 }
679 }
680
681
682 static struct reasm_frag_entry *
parse_packet(const unsigned char * packet,unsigned len,unsigned frag_hdr_offset,enum reasm_proto * protocol,union reasm_id * id,unsigned * hash,bool * last_frag)683 parse_packet (const unsigned char *packet, unsigned len, unsigned frag_hdr_offset, enum reasm_proto *protocol, union reasm_id *id, unsigned *hash, bool *last_frag)
684 {
685 const struct nmsg_iphdr *ip_header = (const struct nmsg_iphdr *) packet;
686 struct reasm_frag_entry *frag = NULL;
687
688 switch (ip_header->ip_v) {
689 case 4: {
690 uint16_t offset = ntohs (ip_header->ip_off);
691
692 *protocol = PROTO_IPV4;
693 if (len >= (unsigned) ntohs (ip_header->ip_len) &&
694 (offset & (IP_MF | IP_OFFMASK)) != 0)
695 {
696 unsigned pl_hl, pl_len, pl_off;
697 u_char *frag_data;
698
699 frag = malloc (sizeof (*frag));
700 if (frag == NULL)
701 abort ();
702
703 pl_hl = ip_header->ip_hl * 4;
704 pl_len = ntohs (ip_header->ip_len);
705 pl_off = (offset & IP_OFFMASK) * 8;
706 frag_data = malloc (pl_len);
707 if (frag_data == NULL)
708 abort ();
709 memcpy (frag_data, packet, pl_len);
710
711 frag->len = pl_len - pl_hl;
712 frag->offset = pl_off;
713 frag->data_offset = ip_header->ip_hl * 4;
714 frag->data = frag_data;
715
716 *last_frag = (offset & IP_MF) == 0;
717
718 memcpy (id->ipv4.ip_src, &ip_header->ip_src, 4);
719 memcpy (id->ipv4.ip_dst, &ip_header->ip_dst, 4);
720 id->ipv4.ip_id = ntohs (ip_header->ip_id);
721 id->ipv4.ip_proto = ip_header->ip_p;
722
723 *hash = reasm_ipv4_hash (&id->ipv4);
724 }
725 break;
726 }
727
728 case 6: {
729 const struct ip6_hdr *ip6_header =
730 (const struct ip6_hdr *) packet;
731 *protocol = PROTO_IPV6;
732 if (len >= (unsigned) ntohs (ip6_header->ip6_plen) + 40)
733 frag = frag_from_ipv6 (packet, frag_hdr_offset, &id->ipv6.ip_id, last_frag);
734 if (frag != NULL) {
735 memcpy (id->ipv6.ip_src, &ip6_header->ip6_src, 16);
736 memcpy (id->ipv6.ip_dst, &ip6_header->ip6_dst, 16);
737 *hash = reasm_ipv6_hash (&id->ipv6);
738 }
739 break;
740 }
741
742 default:
743 break;
744 }
745
746 return frag;
747 }
748