Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_build_ip.c
CommitLineData
86530b38
AT
1/*
2 * $Id: libnet_build_ip.c,v 1.20 2005/11/29 22:18:48 carlosc 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
43libnet_ptag_t
44libnet_build_ipv4(u_int16_t len, u_int8_t tos, u_int16_t id, u_int16_t frag,
45u_int8_t ttl, u_int8_t prot, u_int16_t sum, u_int32_t src, u_int32_t dst,
46u_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);
244bad:
245 libnet_pblock_delete(l, p);
246 return (-1);
247}
248
249libnet_ptag_t
250libnet_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
329bad:
330 libnet_pblock_delete(l, p);
331 return (-1);
332}
333
334libnet_ptag_t
335libnet_build_ipv4_options(u_int8_t *options, u_int32_t options_s, libnet_t *l,
336libnet_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));
451bad:
452 libnet_pblock_delete(l, p);
453 return (-1);
454}
455
456libnet_ptag_t
457libnet_build_ipv6(u_int8_t tc, u_int32_t fl, u_int16_t len, u_int8_t nh,
458u_int8_t hl, struct libnet_in6_addr src, struct libnet_in6_addr dst,
459u_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) | ((tc & 0xf0) >> 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#if 0 // sbehera
523 /* no checksum for IPv6 */
524 return (ptag ? ptag : libnet_pblock_update(l, p, LIBNET_IPV6_H,
525 LIBNET_PBLOCK_IPV6_H));
526#endif
527/********sbehera */
528 if (!ptag) {
529 ptag = libnet_pblock_update(l, p, LIBNET_IPV6_H,
530 LIBNET_PBLOCK_IPV6_H);
531 }
532
533 libnet_pblock_record_ip_offset(l, l->total_size);
534
535 return (ptag);
536bad:
537 libnet_pblock_delete(l, p);
538 return (-1);
539}
540
541libnet_ptag_t
542libnet_build_ipv6_frag(u_int8_t nh, u_int8_t reserved, u_int16_t frag,
543u_int32_t id, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
544libnet_ptag_t ptag)
545{
546 u_int32_t n;
547 u_int16_t h;
548 libnet_pblock_t *p;
549 struct libnet_ipv6_frag_hdr ipv6_frag_hdr;
550
551 if (l == NULL)
552 {
553 return (-1);
554 }
555
556 n = LIBNET_IPV6_FRAG_H + payload_s;
557 h = 0;
558
559 if (LIBNET_IPV6_FRAG_H + payload_s > IP_MAXPACKET)
560 {
561 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
562 "%s(): IP packet too large\n", __func__);
563 return (-1);
564 }
565
566 /*
567 * Find the existing protocol block if a ptag is specified, or create
568 * a new one.
569 */
570 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_FRAG_H);
571 if (p == NULL)
572 {
573 return (-1);
574 }
575
576 memset(&ipv6_frag_hdr, 0 , sizeof(ipv6_frag_hdr));
577 ipv6_frag_hdr.ip_nh = nh;
578 ipv6_frag_hdr.ip_reserved = reserved;
579 ipv6_frag_hdr.ip_frag = frag;
580 ipv6_frag_hdr.ip_id = id;
581
582 /*
583 * Appened the protocol unit to the list.
584 */
585 n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_frag_hdr,
586 LIBNET_IPV6_FRAG_H);
587 if (n == -1)
588 {
589 goto bad;
590 }
591
592 /*
593 * Sanity check the payload arguments.
594 */
595 if ((payload && !payload_s) || (!payload && payload_s))
596 {
597 sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
598 goto bad;
599 }
600
601 /*
602 * Append the payload to the list if it exists.
603 */
604 if (payload && payload_s)
605 {
606 n = libnet_pblock_append(l, p, payload, payload_s);
607 if (n == -1)
608 {
609 goto bad;
610 }
611 }
612
613 /*
614 * Update the protocol block's meta information and return the protocol
615 * tag id of this pblock. This tag will be used to locate the pblock
616 * in order to modify the protocol header in subsequent calls.
617 */
618 return (ptag ? ptag : libnet_pblock_update(l, p, h,
619 LIBNET_PBLOCK_IPV6_FRAG_H));
620bad:
621 libnet_pblock_delete(l, p);
622 return (-1);
623}
624
625libnet_ptag_t
626libnet_build_ipv6_routing(u_int8_t nh, u_int8_t len, u_int8_t rtype,
627u_int8_t segments, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
628libnet_ptag_t ptag)
629{
630 u_int32_t n;
631 u_int16_t h;
632 libnet_pblock_t *p;
633 struct libnet_ipv6_routing_hdr ipv6_routing_hdr;
634
635 if (l == NULL)
636 {
637 return (-1);
638 }
639
640 /* Important: IPv6 routing header routes are specified using the payload
641 * interface!
642 */
643 n = LIBNET_IPV6_ROUTING_H + payload_s;
644 h = 0;
645
646 if (LIBNET_IPV6_ROUTING_H + payload_s > IP_MAXPACKET)
647 {
648 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
649 "%s(): IP packet too large\n", __func__);
650 return (-1);
651 }
652
653 /*
654 * Find the existing protocol block if a ptag is specified, or create
655 * a new one.
656 */
657 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_ROUTING_H);
658 if (p == NULL)
659 {
660 return (-1);
661 }
662
663 memset(&ipv6_routing_hdr, 0 , sizeof(ipv6_routing_hdr));
664 ipv6_routing_hdr.ip_nh = nh;
665 ipv6_routing_hdr.ip_len = len;
666 ipv6_routing_hdr.ip_rtype = rtype;
667 ipv6_routing_hdr.ip_segments = segments;
668
669 /*
670 * Appened the protocol unit to the list.
671 */
672 n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_routing_hdr,
673 LIBNET_IPV6_ROUTING_H);
674 if (n == -1)
675 {
676 goto bad;
677 }
678
679 /*
680 * Sanity check the payload arguments.
681 */
682 if ((payload && !payload_s) || (!payload && payload_s))
683 {
684 sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
685 goto bad;
686 }
687
688 /*
689 * Append the payload to the list if it exists.
690 */
691 if (payload && payload_s)
692 {
693 n = libnet_pblock_append(l, p, payload, payload_s);
694 if (n == -1)
695 {
696 goto bad;
697 }
698 }
699
700 /*
701 * Update the protocol block's meta information and return the protocol
702 * tag id of this pblock. This tag will be used to locate the pblock
703 * in order to modify the protocol header in subsequent calls.
704 */
705 return (ptag ? ptag : libnet_pblock_update(l, p, h,
706 LIBNET_PBLOCK_IPV6_ROUTING_H));
707bad:
708 libnet_pblock_delete(l, p);
709 return (-1);
710}
711
712libnet_ptag_t
713libnet_build_ipv6_destopts(u_int8_t nh, u_int8_t len, u_int8_t *payload,
714u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
715{
716 u_int32_t n;
717 u_int16_t h;
718 libnet_pblock_t *p;
719 struct libnet_ipv6_destopts_hdr ipv6_destopts_hdr;
720
721 if (l == NULL)
722 {
723 return (-1);
724 }
725
726 /* Important: IPv6 dest opts information is specified using the payload
727 * interface!
728 */
729 n = LIBNET_IPV6_DESTOPTS_H + payload_s;
730 h = 0;
731
732 if (LIBNET_IPV6_DESTOPTS_H + payload_s > IP_MAXPACKET)
733 {
734 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
735 "%s(): IP packet too large\n", __func__);
736 return (-1);
737 }
738
739 /*
740 * Find the existing protocol block if a ptag is specified, or create
741 * a new one.
742 */
743 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_DESTOPTS_H);
744 if (p == NULL)
745 {
746 return (-1);
747 }
748
749 memset(&ipv6_destopts_hdr, 0 , sizeof(ipv6_destopts_hdr));
750 ipv6_destopts_hdr.ip_nh = nh;
751 ipv6_destopts_hdr.ip_len = len;
752
753 /*
754 * Appened the protocol unit to the list.
755 */
756 n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_destopts_hdr,
757 LIBNET_IPV6_DESTOPTS_H);
758 if (n == -1)
759 {
760 goto bad;
761 }
762
763 /*
764 * Sanity check the payload arguments.
765 */
766 if ((payload && !payload_s) || (!payload && payload_s))
767 {
768 sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
769 goto bad;
770 }
771
772 /*
773 * Append the payload to the list if it exists.
774 */
775 if (payload && payload_s)
776 {
777 n = libnet_pblock_append(l, p, payload, payload_s);
778 if (n == -1)
779 {
780 goto bad;
781 }
782 }
783
784 /*
785 * Update the protocol block's meta information and return the protocol
786 * tag id of this pblock. This tag will be used to locate the pblock
787 * in order to modify the protocol header in subsequent calls.
788 */
789 return (ptag ? ptag : libnet_pblock_update(l, p, h,
790 LIBNET_PBLOCK_IPV6_DESTOPTS_H));
791bad:
792 libnet_pblock_delete(l, p);
793 return (-1);
794}
795
796libnet_ptag_t
797libnet_build_ipv6_hbhopts(u_int8_t nh, u_int8_t len, u_int8_t *payload,
798u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
799{
800 u_int32_t n;
801 u_int16_t h;
802 libnet_pblock_t *p;
803 struct libnet_ipv6_hbhopts_hdr ipv6_hbhopts_hdr;
804
805 if (l == NULL)
806 {
807 return (-1);
808 }
809
810 /* Important: IPv6 hop by hop opts information is specified using the
811 * payload interface!
812 */
813 n = LIBNET_IPV6_HBHOPTS_H + payload_s;
814 h = 0;
815
816 if (LIBNET_IPV6_HBHOPTS_H + payload_s > IP_MAXPACKET)
817 {
818 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
819 "%s(): IP packet too large\n", __func__);
820 return (-1);
821 }
822
823 /*
824 * Find the existing protocol block if a ptag is specified, or create
825 * a new one.
826 */
827 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_HBHOPTS_H);
828 if (p == NULL)
829 {
830 return (-1);
831 }
832
833 memset(&ipv6_hbhopts_hdr, 0 , sizeof(ipv6_hbhopts_hdr));
834 ipv6_hbhopts_hdr.ip_nh = nh;
835 ipv6_hbhopts_hdr.ip_len = len;
836
837 /*
838 * Appened the protocol unit to the list.
839 */
840 n = libnet_pblock_append(l, p, (u_int8_t *)&ipv6_hbhopts_hdr,
841 LIBNET_IPV6_HBHOPTS_H);
842 if (n == -1)
843 {
844 goto bad;
845 }
846
847 /*
848 * Sanity check the payload arguments.
849 */
850 if ((payload && !payload_s) || (!payload && payload_s))
851 {
852 sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
853 goto bad;
854 }
855
856 /*
857 * Append the payload to the list if it exists.
858 */
859 if (payload && payload_s)
860 {
861 n = libnet_pblock_append(l, p, payload, payload_s);
862 if (n == -1)
863 {
864 goto bad;
865 }
866 }
867
868 /*
869 * Update the protocol block's meta information and return the protocol
870 * tag id of this pblock. This tag will be used to locate the pblock
871 * in order to modify the protocol header in subsequent calls.
872 */
873 return (ptag ? ptag : libnet_pblock_update(l, p, h,
874 LIBNET_PBLOCK_IPV6_HBHOPTS_H));
875bad:
876 libnet_pblock_delete(l, p);
877 return (-1);
878}
879
880libnet_ptag_t
881libnet_autobuild_ipv6(u_int16_t len, u_int8_t nh, struct libnet_in6_addr dst,
882 libnet_t *l)
883{
884
885 /* NYI */
886 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
887 "%s(): not yet implemented\n", __func__);
888 return (-1);
889}
890
891/* EOF */