Annotation of embedaddon/libnet/src/libnet_build_ip.c, revision 1.1.1.1
1.1 misho 1: /*
2: * $Id: libnet_build_ip.c,v 1.18 2004/03/16 18:40:59 mike Exp $
3: *
4: * libnet
5: * libnet_build_ip.c - IP packet assembler
6: *
7: * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
8: * All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: *
31: */
32:
33: #if (HAVE_CONFIG_H)
34: #include "../include/config.h"
35: #endif
36: #if (!(_WIN32) || (__CYGWIN__))
37: #include "../include/libnet.h"
38: #else
39: #include "../include/win32/libnet.h"
40: #endif
41:
42:
43: libnet_ptag_t
44: libnet_build_ipv4(u_int16_t len, u_int8_t tos, u_int16_t id, u_int16_t frag,
45: u_int8_t ttl, u_int8_t prot, u_int16_t sum, u_int32_t src, u_int32_t dst,
46: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
47: {
48: int offset;
49: u_int32_t h, n, i, j;
50: libnet_pblock_t *p, *p_data, *p_temp;
51: struct libnet_ipv4_hdr ip_hdr;
52: libnet_ptag_t ptag_data, ptag_hold;
53:
54: if (l == NULL)
55: {
56: return (-1);
57: }
58:
59: n = LIBNET_IPV4_H; /* size of memory block */
60: h = len; /* header length */
61: ptag_data = 0; /* used if options are present */
62:
63: if (h + payload_s > IP_MAXPACKET)
64: {
65: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
66: "%s(): IP packet too large\n", __func__);
67: return (-1);
68: }
69:
70: /*
71: * Find the existing protocol block if a ptag is specified, or create
72: * a new one.
73: */
74: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV4_H);
75: if (p == NULL)
76: {
77: return (-1);
78: }
79:
80: memset(&ip_hdr, 0, sizeof(ip_hdr));
81: ip_hdr.ip_v = 4; /* version 4 */
82: ip_hdr.ip_hl = 5; /* 20 byte header */
83:
84: /* check to see if there are IP options to include */
85: if (p->prev)
86: {
87: if (p->prev->type == LIBNET_PBLOCK_IPO_H)
88: {
89: /*
90: * Count up number of 32-bit words in options list, padding if
91: * neccessary.
92: */
93: for (i = 0, j = 0; i < p->prev->b_len; i++)
94: {
95: (i % 4) ? j : j++;
96: }
97: ip_hdr.ip_hl += j;
98: }
99: }
100:
101: ip_hdr.ip_tos = tos; /* IP tos */
102: ip_hdr.ip_len = htons(h); /* total length */
103: ip_hdr.ip_id = htons(id); /* IP ID */
104: ip_hdr.ip_off = htons(frag); /* fragmentation flags */
105: ip_hdr.ip_ttl = ttl; /* time to live */
106: ip_hdr.ip_p = prot; /* transport protocol */
107: ip_hdr.ip_sum = (sum ? htons(sum) : 0); /* checksum */
108: ip_hdr.ip_src.s_addr = src; /* source ip */
109: ip_hdr.ip_dst.s_addr = dst; /* destination ip */
110:
111: n = libnet_pblock_append(l, p, (u_int8_t *)&ip_hdr, LIBNET_IPV4_H);
112: if (n == -1)
113: {
114: goto bad;
115: }
116:
117: /* save the original ptag value */
118: ptag_hold = ptag;
119:
120: if (ptag == LIBNET_PTAG_INITIALIZER)
121: {
122: ptag = libnet_pblock_update(l, p, LIBNET_IPV4_H, LIBNET_PBLOCK_IPV4_H);
123: }
124:
125: /* find and set the appropriate ptag, or else use the default of 0 */
126: offset = payload_s;
127: if (ptag_hold && p->prev)
128: {
129: p_temp = p->prev;
130: while (p_temp->prev &&
131: (p_temp->type != LIBNET_PBLOCK_IPDATA) &&
132: (p_temp->type != LIBNET_PBLOCK_IPV4_H))
133: {
134: p_temp = p_temp->prev;
135: }
136:
137: if (p_temp->type == LIBNET_PBLOCK_IPDATA)
138: {
139: ptag_data = p_temp->ptag;
140: offset -= p_temp->b_len;
141: p->h_len += offset;
142: }
143: else
144: {
145: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
146: "%s(): IPv4 data pblock not found\n", __func__);
147: }
148: }
149:
150: if ((payload && !payload_s) || (!payload && payload_s))
151: {
152: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
153: "%s(): payload inconsistency\n", __func__);
154: goto bad;
155: }
156:
157: if (payload && payload_s)
158: {
159: /* update ptag_data with the new payload */
160: p_data = libnet_pblock_probe(l, ptag_data, payload_s,
161: LIBNET_PBLOCK_IPDATA);
162: if (p_data == NULL)
163: {
164: return (-1);
165: }
166:
167: if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
168: {
169: goto bad;
170: }
171:
172: if (ptag_data == LIBNET_PTAG_INITIALIZER)
173: {
174: if (p_data->prev->type == LIBNET_PBLOCK_IPV4_H)
175: {
176: libnet_pblock_update(l, p_data, payload_s,
177: LIBNET_PBLOCK_IPDATA);
178: /* swap pblocks to correct the protocol order */
179: libnet_pblock_swap(l, p->ptag, p_data->ptag);
180: }
181: else
182: {
183: /* update without setting this as the final pblock */
184: p_data->type = LIBNET_PBLOCK_IPDATA;
185: p_data->ptag = ++(l->ptag_state);
186: p_data->h_len = payload_s;
187:
188: /* Adjust h_len for checksum. */
189: p->h_len += payload_s;
190:
191: /* data was added after the initial construction */
192: for (p_temp = l->protocol_blocks;
193: p_temp->type == LIBNET_PBLOCK_IPV4_H ||
194: p_temp->type == LIBNET_PBLOCK_IPO_H;
195: p_temp = p_temp->next)
196: {
197: libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
198: break;
199: }
200:
201: /* the end block needs to have its next pointer cleared */
202: l->pblock_end->next = NULL;
203: }
204:
205: if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_IPO_H)
206: {
207: libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag);
208: }
209: }
210: }
211: else
212: {
213: p_data = libnet_pblock_find(l, ptag_data);
214: if (p_data)
215: {
216: libnet_pblock_delete(l, p_data);
217: }
218: else
219: {
220: /*
221: * XXX - When this completes successfully, libnet errbuf contains
222: * an error message so to come correct, we'll clear it.
223: */
224: memset(l->err_buf, 0, sizeof (l->err_buf));
225: }
226: }
227: if (sum == 0)
228: {
229: /*
230: * If checksum is zero, by default libnet will compute a checksum
231: * for the user. The programmer can override this by calling
232: * libnet_toggle_checksum(l, ptag, 1);
233: */
234: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
235: }
236:
237: /*
238: * FREDRAYNAL: as we insert a new IP header, all checksums for headers
239: * placed after this one will refer to here.
240: */
241: libnet_pblock_record_ip_offset(l, l->total_size);
242:
243: return (ptag);
244: bad:
245: libnet_pblock_delete(l, p);
246: return (-1);
247: }
248:
249: libnet_ptag_t
250: libnet_autobuild_ipv4(u_int16_t len, u_int8_t prot, u_int32_t dst, libnet_t *l)
251: {
252: u_int32_t n, i, j, src;
253: u_int16_t h;
254: libnet_pblock_t *p;
255: libnet_ptag_t ptag;
256: struct libnet_ipv4_hdr ip_hdr;
257:
258: if (l == NULL)
259: {
260: return (-1);
261: }
262:
263: n = LIBNET_IPV4_H; /* size of memory block */
264: h = len; /* header length */
265: ptag = LIBNET_PTAG_INITIALIZER;
266: src = libnet_get_ipaddr4(l);
267: if (src == -1)
268: {
269: /* err msg set in libnet_get_ipaddr() */
270: return (-1);
271: }
272:
273: /*
274: * Create a new pblock.
275: */
276: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV4_H);
277: if (p == NULL)
278: {
279: return (-1);
280: }
281:
282: memset(&ip_hdr, 0, sizeof(ip_hdr));
283: ip_hdr.ip_v = 4; /* version 4 */
284: ip_hdr.ip_hl = 5; /* 20 byte header */
285:
286: /* check to see if there are IP options to include */
287: if (p->prev)
288: {
289: if (p->prev->type == LIBNET_PBLOCK_IPO_H)
290: {
291: /*
292: * Count up number of 32-bit words in options list, padding if
293: * neccessary.
294: */
295: for (i = 0, j = 0; i < p->prev->b_len; i++)
296: {
297: (i % 4) ? j : j++;
298: }
299: ip_hdr.ip_hl += j;
300: }
301: }
302:
303: ip_hdr.ip_tos = 0; /* IP tos */
304: ip_hdr.ip_len = htons(h); /* total length */
305: ip_hdr.ip_id = htons((l->ptag_state) & 0x0000ffff); /* IP ID */
306: ip_hdr.ip_off = 0; /* fragmentation flags */
307: ip_hdr.ip_ttl = 64; /* time to live */
308: ip_hdr.ip_p = prot; /* transport protocol */
309: ip_hdr.ip_sum = 0; /* checksum */
310: ip_hdr.ip_src.s_addr = src; /* source ip */
311: ip_hdr.ip_dst.s_addr = dst; /* destination ip */
312:
313: n = libnet_pblock_append(l, p, (u_int8_t *)&ip_hdr, LIBNET_IPV4_H);
314: if (n == -1)
315: {
316: goto bad;
317: }
318:
319: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
320: ptag = libnet_pblock_update(l, p, LIBNET_IPV4_H, LIBNET_PBLOCK_IPV4_H);
321:
322: /*
323: * FREDRAYNAL: as we insert a new IP header, all checksums for headers
324: * placed after this one will refer to here.
325: */
326: libnet_pblock_record_ip_offset(l, l->total_size);
327: return (ptag);
328:
329: bad:
330: libnet_pblock_delete(l, p);
331: return (-1);
332: }
333:
334: libnet_ptag_t
335: libnet_build_ipv4_options(u_int8_t *options, u_int32_t options_s, libnet_t *l,
336: libnet_ptag_t ptag)
337: {
338: int offset, underflow;
339: u_int32_t i, j, n, adj_size;
340: libnet_pblock_t *p, *p_temp;
341: struct libnet_ipv4_hdr *ip_hdr;
342:
343: if (l == NULL)
344: {
345: return (-1);
346: }
347:
348: underflow = 0;
349: offset = 0;
350:
351: /* check options list size */
352: if (options_s > LIBNET_MAXOPTION_SIZE)
353: {
354: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
355: "%s(): options list is too large %d\n", __func__, options_s);
356: return (-1);
357: }
358:
359: adj_size = options_s;
360: if (adj_size % 4)
361: {
362: /* size of memory block with padding */
363: adj_size += 4 - (options_s % 4);
364: }
365:
366: /* if this pblock already exists, determine if there is a size diff */
367: if (ptag)
368: {
369: p_temp = libnet_pblock_find(l, ptag);
370: if (p_temp)
371: {
372: if (adj_size >= p_temp->b_len)
373: {
374: offset = adj_size - p_temp->b_len;
375: }
376: else
377: {
378: offset = p_temp->b_len - adj_size;
379: underflow = 1;
380: }
381: }
382: else
383: {
384: /*
385: * XXX - When this completes successfully, libnet errbuf contains
386: * an error message so to come correct, we'll clear it.
387: */
388: memset(l->err_buf, 0, sizeof (l->err_buf));
389: }
390: }
391:
392: /*
393: * Find the existing protocol block if a ptag is specified, or create
394: * a new one.
395: */
396: p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_IPO_H);
397: if (p == NULL)
398: {
399: return (-1);
400: }
401:
402: /* append options */
403: n = libnet_pblock_append(l, p, options, options_s);
404: if (n == -1)
405: {
406: goto bad;
407: }
408:
409: /* append padding */
410: n = libnet_pblock_append(l, p, "\0\0\0", adj_size - options_s);
411: if (n == -1)
412: {
413: goto bad;
414: }
415:
416: if (ptag && p->next)
417: {
418: p_temp = p->next;
419: while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
420: {
421: p_temp = p_temp->next;
422: }
423:
424: /* fix the IP header size */
425: if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
426: {
427: /*
428: * Count up number of 32-bit words in options list, padding if
429: * neccessary.
430: */
431: for (i = 0, j = 0; i < p->b_len; i++)
432: {
433: (i % 4) ? j : j++;
434: }
435: ip_hdr = (struct libnet_ipv4_hdr *) p_temp->buf;
436: ip_hdr->ip_hl = j + 5;
437:
438: if (!underflow)
439: {
440: p_temp->h_len += offset;
441: }
442: else
443: {
444: p_temp->h_len -= offset;
445: }
446: }
447: }
448:
449: return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
450: LIBNET_PBLOCK_IPO_H));
451: bad:
452: libnet_pblock_delete(l, p);
453: return (-1);
454: }
455:
456: libnet_ptag_t
457: libnet_build_ipv6(u_int8_t tc, u_int32_t fl, u_int16_t len, u_int8_t nh,
458: u_int8_t hl, struct libnet_in6_addr src, struct libnet_in6_addr dst,
459: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
460: {
461: u_int32_t n;
462: libnet_pblock_t *p;
463: struct libnet_ipv6_hdr ip_hdr;
464:
465: if (l == NULL)
466: {
467: return (-1);
468: }
469:
470: n = LIBNET_IPV6_H + payload_s; /* size of memory block */
471:
472: if (LIBNET_IPV6_H + payload_s > IP_MAXPACKET)
473: {
474: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
475: "%s(): IP packet too large\n", __func__);
476: return (-1);
477: }
478:
479: /*
480: * Find the existing protocol block if a ptag is specified, or create
481: * a new one.
482: */
483: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_H);
484: if (p == NULL)
485: {
486: return (-1);
487: }
488:
489: memset(&ip_hdr, 0, sizeof(ip_hdr));
490: ip_hdr.ip_flags[0] = 0x06 << 4;
491: ip_hdr.ip_flags[1] = ((tc & 0x0F) << 4) | ((fl & 0xF0000) >> 16);
492: ip_hdr.ip_flags[2] = fl & 0x0FF00 >> 8;
493: ip_hdr.ip_flags[3] = fl & 0x000FF;
494: ip_hdr.ip_len = htons(len);
495: ip_hdr.ip_nh = nh;
496: ip_hdr.ip_hl = hl;
497: ip_hdr.ip_src = src;
498: ip_hdr.ip_dst = dst;
499:
500: n = libnet_pblock_append(l, p, (u_int8_t *)&ip_hdr, LIBNET_IPV6_H);
501: if (n == -1)
502: {
503: goto bad;
504: }
505:
506: if ((payload && !payload_s) || (!payload && payload_s))
507: {
508: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
509: "%s(): payload inconsistency\n", __func__);
510: goto bad;
511: }
512:
513: if (payload && payload_s)
514: {
515: n = libnet_pblock_append(l, p, payload, payload_s);
516: if (n == -1)
517: {
518: goto bad;
519: }
520: }
521:
522: /* no checksum for IPv6 */
523: return (ptag ? ptag : libnet_pblock_update(l, p, LIBNET_IPV6_H,
524: LIBNET_PBLOCK_IPV6_H));
525: bad:
526: libnet_pblock_delete(l, p);
527: return (-1);
528: }
529:
530: libnet_ptag_t
531: libnet_build_ipv6_frag(u_int8_t nh, u_int8_t reserved, u_int16_t frag,
532: u_int32_t id, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
533: libnet_ptag_t ptag)
534: {
535: u_int32_t n;
536: u_int16_t h;
537: libnet_pblock_t *p;
538: struct libnet_ipv6_frag_hdr ipv6_frag_hdr;
539:
540: if (l == NULL)
541: {
542: return (-1);
543: }
544:
545: n = LIBNET_IPV6_FRAG_H + payload_s;
546: h = 0;
547:
548: if (LIBNET_IPV6_FRAG_H + payload_s > IP_MAXPACKET)
549: {
550: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
551: "%s(): IP packet too large\n", __func__);
552: return (-1);
553: }
554:
555: /*
556: * Find the existing protocol block if a ptag is specified, or create
557: * a new one.
558: */
559: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_FRAG_H);
560: if (p == NULL)
561: {
562: return (-1);
563: }
564:
565: memset(&ipv6_frag_hdr, 0 , sizeof(ipv6_frag_hdr));
566: ipv6_frag_hdr.ip_nh = nh;
567: ipv6_frag_hdr.ip_reserved = reserved;
568: ipv6_frag_hdr.ip_frag = frag;
569: ipv6_frag_hdr.ip_id = id;
570:
571: /*
572: * Appened the protocol unit to the list.
573: */
574: n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_frag_hdr,
575: LIBNET_IPV6_FRAG_H);
576: if (n == -1)
577: {
578: goto bad;
579: }
580:
581: /*
582: * Sanity check the payload arguments.
583: */
584: if ((payload && !payload_s) || (!payload && payload_s))
585: {
586: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
587: goto bad;
588: }
589:
590: /*
591: * Append the payload to the list if it exists.
592: */
593: if (payload && payload_s)
594: {
595: n = libnet_pblock_append(l, p, payload, payload_s);
596: if (n == -1)
597: {
598: goto bad;
599: }
600: }
601:
602: /*
603: * Update the protocol block's meta information and return the protocol
604: * tag id of this pblock. This tag will be used to locate the pblock
605: * in order to modify the protocol header in subsequent calls.
606: */
607: return (ptag ? ptag : libnet_pblock_update(l, p, h,
608: LIBNET_PBLOCK_IPV6_FRAG_H));
609: bad:
610: libnet_pblock_delete(l, p);
611: return (-1);
612: }
613:
614: libnet_ptag_t
615: libnet_build_ipv6_routing(u_int8_t nh, u_int8_t len, u_int8_t rtype,
616: u_int8_t segments, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
617: libnet_ptag_t ptag)
618: {
619: u_int32_t n;
620: u_int16_t h;
621: libnet_pblock_t *p;
622: struct libnet_ipv6_routing_hdr ipv6_routing_hdr;
623:
624: if (l == NULL)
625: {
626: return (-1);
627: }
628:
629: /* Important: IPv6 routing header routes are specified using the payload
630: * interface!
631: */
632: n = LIBNET_IPV6_ROUTING_H + payload_s;
633: h = 0;
634:
635: if (LIBNET_IPV6_ROUTING_H + payload_s > IP_MAXPACKET)
636: {
637: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
638: "%s(): IP packet too large\n", __func__);
639: return (-1);
640: }
641:
642: /*
643: * Find the existing protocol block if a ptag is specified, or create
644: * a new one.
645: */
646: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_ROUTING_H);
647: if (p == NULL)
648: {
649: return (-1);
650: }
651:
652: memset(&ipv6_routing_hdr, 0 , sizeof(ipv6_routing_hdr));
653: ipv6_routing_hdr.ip_nh = nh;
654: ipv6_routing_hdr.ip_len = len;
655: ipv6_routing_hdr.ip_rtype = rtype;
656: ipv6_routing_hdr.ip_segments = segments;
657:
658: /*
659: * Appened the protocol unit to the list.
660: */
661: n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_routing_hdr,
662: LIBNET_IPV6_ROUTING_H);
663: if (n == -1)
664: {
665: goto bad;
666: }
667:
668: /*
669: * Sanity check the payload arguments.
670: */
671: if ((payload && !payload_s) || (!payload && payload_s))
672: {
673: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
674: goto bad;
675: }
676:
677: /*
678: * Append the payload to the list if it exists.
679: */
680: if (payload && payload_s)
681: {
682: n = libnet_pblock_append(l, p, payload, payload_s);
683: if (n == -1)
684: {
685: goto bad;
686: }
687: }
688:
689: /*
690: * Update the protocol block's meta information and return the protocol
691: * tag id of this pblock. This tag will be used to locate the pblock
692: * in order to modify the protocol header in subsequent calls.
693: */
694: return (ptag ? ptag : libnet_pblock_update(l, p, h,
695: LIBNET_PBLOCK_IPV6_ROUTING_H));
696: bad:
697: libnet_pblock_delete(l, p);
698: return (-1);
699: }
700:
701: libnet_ptag_t
702: libnet_build_ipv6_destopts(u_int8_t nh, u_int8_t len, u_int8_t *payload,
703: u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
704: {
705: u_int32_t n;
706: u_int16_t h;
707: libnet_pblock_t *p;
708: struct libnet_ipv6_destopts_hdr ipv6_destopts_hdr;
709:
710: if (l == NULL)
711: {
712: return (-1);
713: }
714:
715: /* Important: IPv6 dest opts information is specified using the payload
716: * interface!
717: */
718: n = LIBNET_IPV6_DESTOPTS_H + payload_s;
719: h = 0;
720:
721: if (LIBNET_IPV6_DESTOPTS_H + payload_s > IP_MAXPACKET)
722: {
723: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
724: "%s(): IP packet too large\n", __func__);
725: return (-1);
726: }
727:
728: /*
729: * Find the existing protocol block if a ptag is specified, or create
730: * a new one.
731: */
732: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_DESTOPTS_H);
733: if (p == NULL)
734: {
735: return (-1);
736: }
737:
738: memset(&ipv6_destopts_hdr, 0 , sizeof(ipv6_destopts_hdr));
739: ipv6_destopts_hdr.ip_nh = nh;
740: ipv6_destopts_hdr.ip_len = len;
741:
742: /*
743: * Appened the protocol unit to the list.
744: */
745: n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_destopts_hdr,
746: LIBNET_IPV6_DESTOPTS_H);
747: if (n == -1)
748: {
749: goto bad;
750: }
751:
752: /*
753: * Sanity check the payload arguments.
754: */
755: if ((payload && !payload_s) || (!payload && payload_s))
756: {
757: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
758: goto bad;
759: }
760:
761: /*
762: * Append the payload to the list if it exists.
763: */
764: if (payload && payload_s)
765: {
766: n = libnet_pblock_append(l, p, payload, payload_s);
767: if (n == -1)
768: {
769: goto bad;
770: }
771: }
772:
773: /*
774: * Update the protocol block's meta information and return the protocol
775: * tag id of this pblock. This tag will be used to locate the pblock
776: * in order to modify the protocol header in subsequent calls.
777: */
778: return (ptag ? ptag : libnet_pblock_update(l, p, h,
779: LIBNET_PBLOCK_IPV6_DESTOPTS_H));
780: bad:
781: libnet_pblock_delete(l, p);
782: return (-1);
783: }
784:
785: libnet_ptag_t
786: libnet_build_ipv6_hbhopts(u_int8_t nh, u_int8_t len, u_int8_t *payload,
787: u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
788: {
789: u_int32_t n;
790: u_int16_t h;
791: libnet_pblock_t *p;
792: struct libnet_ipv6_hbhopts_hdr ipv6_hbhopts_hdr;
793:
794: if (l == NULL)
795: {
796: return (-1);
797: }
798:
799: /* Important: IPv6 hop by hop opts information is specified using the
800: * payload interface!
801: */
802: n = LIBNET_IPV6_HBHOPTS_H + payload_s;
803: h = 0;
804:
805: if (LIBNET_IPV6_HBHOPTS_H + payload_s > IP_MAXPACKET)
806: {
807: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
808: "%s(): IP packet too large\n", __func__);
809: return (-1);
810: }
811:
812: /*
813: * Find the existing protocol block if a ptag is specified, or create
814: * a new one.
815: */
816: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_HBHOPTS_H);
817: if (p == NULL)
818: {
819: return (-1);
820: }
821:
822: memset(&ipv6_hbhopts_hdr, 0 , sizeof(ipv6_hbhopts_hdr));
823: ipv6_hbhopts_hdr.ip_nh = nh;
824: ipv6_hbhopts_hdr.ip_len = len;
825:
826: /*
827: * Appened the protocol unit to the list.
828: */
829: n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_hbhopts_hdr,
830: LIBNET_IPV6_HBHOPTS_H);
831: if (n == -1)
832: {
833: goto bad;
834: }
835:
836: /*
837: * Sanity check the payload arguments.
838: */
839: if ((payload && !payload_s) || (!payload && payload_s))
840: {
841: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
842: goto bad;
843: }
844:
845: /*
846: * Append the payload to the list if it exists.
847: */
848: if (payload && payload_s)
849: {
850: n = libnet_pblock_append(l, p, payload, payload_s);
851: if (n == -1)
852: {
853: goto bad;
854: }
855: }
856:
857: /*
858: * Update the protocol block's meta information and return the protocol
859: * tag id of this pblock. This tag will be used to locate the pblock
860: * in order to modify the protocol header in subsequent calls.
861: */
862: return (ptag ? ptag : libnet_pblock_update(l, p, h,
863: LIBNET_PBLOCK_IPV6_HBHOPTS_H));
864: bad:
865: libnet_pblock_delete(l, p);
866: return (-1);
867: }
868:
869: libnet_ptag_t
870: libnet_autobuild_ipv6(u_int16_t len, u_int8_t nh, struct libnet_in6_addr dst,
871: libnet_t *l)
872: {
873:
874: /* NYI */
875: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
876: "%s(): not yet implemented\n", __func__);
877: return (-1);
878: }
879:
880: /* EOF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>