summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/ip6opt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/ip6opt.c')
-rw-r--r--src/lib/libc/net/ip6opt.c227
1 files changed, 226 insertions, 1 deletions
diff --git a/src/lib/libc/net/ip6opt.c b/src/lib/libc/net/ip6opt.c
index d3d68a54bf..b215f9ac3e 100644
--- a/src/lib/libc/net/ip6opt.c
+++ b/src/lib/libc/net/ip6opt.c
@@ -1,4 +1,5 @@
1/* $OpenBSD: ip6opt.c,v 1.3 2006/12/08 21:32:59 itojun Exp $ */ 1/* $OpenBSD: ip6opt.c,v 1.4 2006/12/09 01:12:28 itojun Exp $ */
2/* $KAME: ip6opt.c,v 1.18 2005/06/15 07:11:35 keiichi Exp $ */
2 3
3/* 4/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -103,8 +104,10 @@ inet6_option_append(struct cmsghdr *cmsg, const u_int8_t *typep, int multx,
103 return (-1); 104 return (-1);
104 if (plusy < 0 || plusy > 7) 105 if (plusy < 0 || plusy > 7)
105 return (-1); 106 return (-1);
107#if 0
106 if (typep[0] > 255) 108 if (typep[0] > 255)
107 return (-1); 109 return (-1);
110#endif
108 111
109 /* 112 /*
110 * If this is the first option, allocate space for the 113 * If this is the first option, allocate space for the
@@ -369,3 +372,225 @@ inet6_insert_padopt(u_char *p, int len)
369 return; 372 return;
370 } 373 }
371} 374}
375
376/*
377 * The following functions are defined in RFC3542, which is a successor
378 * of RFC2292.
379 */
380
381int
382inet6_opt_init(void *extbuf, socklen_t extlen)
383{
384 struct ip6_ext *ext = (struct ip6_ext *)extbuf;
385
386 if (extlen < 0 || (extlen % 8))
387 return (-1);
388
389 if (ext) {
390 if (extlen == 0)
391 return (-1);
392 ext->ip6e_len = (extlen >> 3) - 1;
393 }
394
395 return (2); /* sizeof the next and the length fields */
396}
397
398int
399inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
400 socklen_t len, u_int8_t align, void **databufp)
401{
402 int currentlen = offset, padlen = 0;
403
404 /*
405 * The option type must have a value from 2 to 255, inclusive.
406 * (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
407 */
408#if 0 /* always false */
409 if (type < 2 || type > 255)
410#else
411 if (type < 2)
412#endif
413 return (-1);
414
415 /*
416 * The option data length must have a value between 0 and 255,
417 * inclusive, and is the length of the option data that follows.
418 */
419 if (len < 0 || len > 255)
420 return (-1);
421
422 /*
423 * The align parameter must have a value of 1, 2, 4, or 8.
424 * The align value can not exceed the value of len.
425 */
426 if (align != 1 && align != 2 && align != 4 && align != 8)
427 return (-1);
428 if (align > len)
429 return (-1);
430
431 /* Calculate the padding length. */
432 currentlen += 2 + len; /* 2 means "type + len" */
433 if (currentlen % align)
434 padlen = align - (currentlen % align);
435
436 /* The option must fit in the extension header buffer. */
437 currentlen += padlen;
438 if (extlen && /* XXX: right? */
439 currentlen > extlen)
440 return (-1);
441
442 if (extbuf) {
443 u_int8_t *optp = (u_int8_t *)extbuf + offset;
444
445 if (padlen == 1) {
446 /* insert a Pad1 option */
447 *optp = IP6OPT_PAD1;
448 optp++;
449 } else if (padlen > 0) {
450 /* insert a PadN option for alignment */
451 *optp++ = IP6OPT_PADN;
452 *optp++ = padlen - 2;
453 memset(optp, 0, padlen - 2);
454 optp += (padlen - 2);
455 }
456
457 *optp++ = type;
458 *optp++ = len;
459
460 *databufp = optp;
461 }
462
463 return (currentlen);
464}
465
466int
467inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
468{
469 int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;;
470
471 if (extbuf) {
472 u_int8_t *padp;
473 int padlen = updatelen - offset;
474
475 if (updatelen > extlen)
476 return (-1);
477
478 padp = (u_int8_t *)extbuf + offset;
479 if (padlen == 1)
480 *padp = IP6OPT_PAD1;
481 else if (padlen > 0) {
482 *padp++ = IP6OPT_PADN;
483 *padp++ = (padlen - 2);
484 memset(padp, 0, padlen - 2);
485 }
486 }
487
488 return (updatelen);
489}
490
491int
492inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
493{
494
495 memcpy((u_int8_t *)databuf + offset, val, vallen);
496 return (offset + vallen);
497}
498
499int
500inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
501 socklen_t *lenp, void **databufp)
502{
503 u_int8_t *optp, *lim;
504 int optlen;
505
506 /* Validate extlen. XXX: is the variable really necessary?? */
507 if (extlen == 0 || (extlen % 8))
508 return (-1);
509 lim = (u_int8_t *)extbuf + extlen;
510
511 /*
512 * If this is the first time this function called for this options
513 * header, simply return the 1st option.
514 * Otherwise, search the option list for the next option.
515 */
516 if (offset == 0)
517 optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
518 else
519 optp = (u_int8_t *)extbuf + offset;
520
521 /* Find the next option skipping any padding options. */
522 while (optp < lim) {
523 switch(*optp) {
524 case IP6OPT_PAD1:
525 optp++;
526 break;
527 case IP6OPT_PADN:
528 if ((optlen = ip6optlen(optp, lim)) == 0)
529 goto optend;
530 optp += optlen;
531 break;
532 default: /* found */
533 if ((optlen = ip6optlen(optp, lim)) == 0)
534 goto optend;
535 *typep = *optp;
536 *lenp = optlen - 2;
537 *databufp = optp + 2;
538 return (optp + optlen - (u_int8_t *)extbuf);
539 }
540 }
541
542 optend:
543 *databufp = NULL; /* for safety */
544 return (-1);
545}
546
547int
548inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
549 socklen_t *lenp, void **databufp)
550{
551 u_int8_t *optp, *lim;
552 int optlen;
553
554 /* Validate extlen. XXX: is the variable really necessary?? */
555 if (extlen == 0 || (extlen % 8))
556 return (-1);
557 lim = (u_int8_t *)extbuf + extlen;
558
559 /*
560 * If this is the first time this function called for this options
561 * header, simply return the 1st option.
562 * Otherwise, search the option list for the next option.
563 */
564 if (offset == 0)
565 optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
566 else
567 optp = (u_int8_t *)extbuf + offset;
568
569 /* Find the specified option */
570 while (optp < lim) {
571 if ((optlen = ip6optlen(optp, lim)) == 0)
572 goto optend;
573
574 if (*optp == type) { /* found */
575 *lenp = optlen - 2;
576 *databufp = optp + 2;
577 return (optp + optlen - (u_int8_t *)extbuf);
578 }
579
580 optp += optlen;
581 }
582
583 optend:
584 *databufp = NULL; /* for safety */
585 return (-1);
586}
587
588int
589inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
590{
591
592 /* we can't assume alignment here */
593 memcpy(val, (u_int8_t *)databuf + offset, vallen);
594
595 return (offset + vallen);
596}