Home | History | Annotate | Line # | Download | only in net
ip6opt.c revision 1.8.2.1
      1  1.8.2.1   nathanw /*	$NetBSD: ip6opt.c,v 1.8.2.1 2002/06/21 18:18:16 nathanw Exp $	*/
      2      1.2    itojun 
      3      1.1    itojun /*
      4      1.1    itojun  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5      1.1    itojun  * All rights reserved.
      6      1.1    itojun  *
      7      1.1    itojun  * Redistribution and use in source and binary forms, with or without
      8      1.1    itojun  * modification, are permitted provided that the following conditions
      9      1.1    itojun  * are met:
     10      1.1    itojun  * 1. Redistributions of source code must retain the above copyright
     11      1.1    itojun  *    notice, this list of conditions and the following disclaimer.
     12      1.1    itojun  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1    itojun  *    notice, this list of conditions and the following disclaimer in the
     14      1.1    itojun  *    documentation and/or other materials provided with the distribution.
     15      1.1    itojun  * 3. Neither the name of the project nor the names of its contributors
     16      1.1    itojun  *    may be used to endorse or promote products derived from this software
     17      1.1    itojun  *    without specific prior written permission.
     18      1.1    itojun  *
     19      1.1    itojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20      1.1    itojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21      1.1    itojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22      1.1    itojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23      1.1    itojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24      1.1    itojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25      1.1    itojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26      1.1    itojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27      1.1    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28      1.1    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29      1.1    itojun  * SUCH DAMAGE.
     30      1.1    itojun  */
     31      1.7    itojun 
     32      1.7    itojun #include <sys/cdefs.h>
     33      1.7    itojun #if defined(LIBC_SCCS) && !defined(lint)
     34  1.8.2.1   nathanw __RCSID("$NetBSD: ip6opt.c,v 1.8.2.1 2002/06/21 18:18:16 nathanw Exp $");
     35      1.7    itojun #endif /* LIBC_SCCS and not lint */
     36      1.1    itojun 
     37      1.6    itojun #include "namespace.h"
     38      1.1    itojun #include <sys/param.h>
     39      1.1    itojun #include <sys/types.h>
     40      1.1    itojun #include <sys/socket.h>
     41      1.1    itojun 
     42      1.1    itojun #include <netinet/in.h>
     43      1.1    itojun #include <netinet/ip6.h>
     44      1.1    itojun 
     45      1.3     lukem #include <assert.h>
     46      1.1    itojun #include <string.h>
     47      1.1    itojun #include <stdio.h>
     48      1.6    itojun 
     49      1.6    itojun #ifdef __weak_alias
     50      1.6    itojun __weak_alias(inet6_option_alloc,_inet6_option_alloc)
     51      1.6    itojun __weak_alias(inet6_option_append,_inet6_option_append)
     52      1.6    itojun __weak_alias(inet6_option_find,_inet6_option_find)
     53      1.6    itojun __weak_alias(inet6_option_init,_inet6_option_init)
     54      1.6    itojun __weak_alias(inet6_option_next,_inet6_option_next)
     55      1.6    itojun __weak_alias(inet6_option_space,_inet6_option_space)
     56      1.6    itojun #endif
     57      1.1    itojun 
     58      1.1    itojun static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
     59      1.5   mycroft static void inet6_insert_padopt(u_char *p, size_t len);
     60      1.1    itojun 
     61      1.1    itojun /*
     62      1.1    itojun  * This function returns the number of bytes required to hold an option
     63      1.1    itojun  * when it is stored as ancillary data, including the cmsghdr structure
     64      1.1    itojun  * at the beginning, and any padding at the end (to make its size a
     65      1.1    itojun  * multiple of 8 bytes).  The argument is the size of the structure
     66      1.1    itojun  * defining the option, which must include any pad bytes at the
     67      1.1    itojun  * beginning (the value y in the alignment term "xn + y"), the type
     68      1.1    itojun  * byte, the length byte, and the option data.
     69      1.1    itojun  */
     70      1.1    itojun int
     71      1.1    itojun inet6_option_space(nbytes)
     72      1.1    itojun 	int nbytes;
     73      1.1    itojun {
     74      1.1    itojun 	nbytes += 2;	/* we need space for nxt-hdr and length fields */
     75      1.1    itojun 	return(CMSG_SPACE((nbytes + 7) & ~7));
     76      1.1    itojun }
     77      1.1    itojun 
     78      1.1    itojun /*
     79      1.1    itojun  * This function is called once per ancillary data object that will
     80      1.1    itojun  * contain either Hop-by-Hop or Destination options.  It returns 0 on
     81      1.1    itojun  * success or -1 on an error.
     82      1.1    itojun  */
     83      1.1    itojun int
     84      1.1    itojun inet6_option_init(bp, cmsgp, type)
     85      1.1    itojun 	void *bp;
     86      1.1    itojun 	struct cmsghdr **cmsgp;
     87      1.1    itojun 	int type;
     88      1.1    itojun {
     89      1.3     lukem 	register struct cmsghdr *ch;
     90      1.3     lukem 
     91      1.3     lukem 	_DIAGASSERT(bp != NULL);
     92      1.3     lukem 	_DIAGASSERT(cmsgp != NULL);
     93      1.3     lukem 
     94      1.3     lukem 	ch = (struct cmsghdr *)bp;
     95      1.1    itojun 
     96      1.1    itojun 	/* argument validation */
     97      1.1    itojun 	if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
     98      1.1    itojun 		return(-1);
     99      1.1    itojun 
    100      1.1    itojun 	ch->cmsg_level = IPPROTO_IPV6;
    101      1.1    itojun 	ch->cmsg_type = type;
    102      1.1    itojun 	ch->cmsg_len = CMSG_LEN(0);
    103      1.1    itojun 
    104      1.1    itojun 	*cmsgp = ch;
    105      1.1    itojun 	return(0);
    106      1.1    itojun }
    107      1.1    itojun 
    108      1.1    itojun /*
    109      1.1    itojun  * This function appends a Hop-by-Hop option or a Destination option
    110      1.1    itojun  * into an ancillary data object that has been initialized by
    111      1.1    itojun  * inet6_option_init().  This function returns 0 if it succeeds or -1 on
    112      1.1    itojun  * an error.
    113      1.1    itojun  * multx is the value x in the alignment term "xn + y" described
    114      1.1    itojun  * earlier.  It must have a value of 1, 2, 4, or 8.
    115      1.1    itojun  * plusy is the value y in the alignment term "xn + y" described
    116      1.1    itojun  * earlier.  It must have a value between 0 and 7, inclusive.
    117      1.1    itojun  */
    118      1.1    itojun int
    119      1.1    itojun inet6_option_append(cmsg, typep, multx, plusy)
    120      1.1    itojun 	struct cmsghdr *cmsg;
    121      1.1    itojun 	const u_int8_t *typep;
    122      1.1    itojun 	int multx;
    123      1.1    itojun 	int plusy;
    124      1.1    itojun {
    125      1.5   mycroft 	size_t padlen, optlen, off;
    126      1.3     lukem 	register u_char *bp;
    127      1.3     lukem 	struct ip6_ext *eh;
    128      1.3     lukem 
    129      1.3     lukem 	_DIAGASSERT(cmsg != NULL);
    130      1.3     lukem 	_DIAGASSERT(typep != NULL);
    131      1.3     lukem 
    132      1.8  christos 	bp = (u_char *)(void *)cmsg + cmsg->cmsg_len;
    133      1.8  christos 	eh = (struct ip6_ext *)(void *)CMSG_DATA(cmsg);
    134      1.1    itojun 
    135      1.1    itojun 	/* argument validation */
    136      1.1    itojun 	if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
    137      1.1    itojun 		return(-1);
    138      1.1    itojun 	if (plusy < 0 || plusy > 7)
    139      1.1    itojun 		return(-1);
    140      1.1    itojun 
    141      1.1    itojun 	/*
    142      1.1    itojun 	 * If this is the first option, allocate space for the
    143      1.1    itojun 	 * first 2 bytes(for next header and length fields) of
    144      1.1    itojun 	 * the option header.
    145      1.1    itojun 	 */
    146      1.8  christos 	if (bp == (u_char *)(void *)eh) {
    147      1.1    itojun 		bp += 2;
    148      1.1    itojun 		cmsg->cmsg_len += 2;
    149      1.1    itojun 	}
    150      1.1    itojun 
    151      1.1    itojun 	/* calculate pad length before the option. */
    152      1.8  christos 	off = bp - (u_char *)(void *)eh;
    153      1.1    itojun 	padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
    154      1.1    itojun 		(off % multx);
    155      1.1    itojun 	padlen += plusy;
    156      1.1    itojun 	/* insert padding */
    157      1.1    itojun 	inet6_insert_padopt(bp, padlen);
    158      1.1    itojun 	cmsg->cmsg_len += padlen;
    159      1.1    itojun 	bp += padlen;
    160      1.1    itojun 
    161      1.1    itojun 	/* copy the option */
    162      1.1    itojun 	if (typep[0] == IP6OPT_PAD1)
    163      1.1    itojun 		optlen = 1;
    164      1.1    itojun 	else
    165      1.1    itojun 		optlen = typep[1] + 2;
    166      1.5   mycroft 	memcpy(bp, typep, (size_t)optlen);
    167      1.1    itojun 	bp += optlen;
    168      1.1    itojun 	cmsg->cmsg_len += optlen;
    169      1.1    itojun 
    170      1.1    itojun 	/* calculate pad length after the option and insert the padding */
    171      1.8  christos 	off = bp - (u_char *)(void *)eh;
    172      1.1    itojun 	padlen = ((off + 7) & ~7) - off;
    173      1.1    itojun 	inet6_insert_padopt(bp, padlen);
    174      1.1    itojun 	bp += padlen;
    175      1.1    itojun 	cmsg->cmsg_len += padlen;
    176      1.1    itojun 
    177      1.1    itojun 	/* update the length field of the ip6 option header */
    178      1.8  christos 	off = bp - (u_char *)(void *)eh;
    179      1.5   mycroft 	eh->ip6e_len = (off >> 3) - 1;
    180      1.1    itojun 
    181      1.1    itojun 	return(0);
    182      1.1    itojun }
    183      1.1    itojun 
    184      1.1    itojun /*
    185      1.1    itojun  * This function appends a Hop-by-Hop option or a Destination option
    186      1.1    itojun  * into an ancillary data object that has been initialized by
    187      1.1    itojun  * inet6_option_init().  This function returns a pointer to the 8-bit
    188      1.1    itojun  * option type field that starts the option on success, or NULL on an
    189      1.1    itojun  * error.
    190      1.1    itojun  * The difference between this function and inet6_option_append() is
    191      1.1    itojun  * that the latter copies the contents of a previously built option into
    192      1.1    itojun  * the ancillary data object while the current function returns a
    193      1.1    itojun  * pointer to the space in the data object where the option's TLV must
    194      1.1    itojun  * then be built by the caller.
    195      1.1    itojun  *
    196      1.1    itojun  */
    197      1.1    itojun u_int8_t *
    198      1.1    itojun inet6_option_alloc(cmsg, datalen, multx, plusy)
    199      1.1    itojun 	struct cmsghdr *cmsg;
    200      1.1    itojun 	int datalen;
    201      1.1    itojun 	int multx;
    202      1.1    itojun 	int plusy;
    203      1.1    itojun {
    204      1.5   mycroft 	size_t padlen, off;
    205      1.3     lukem 	register u_int8_t *bp;
    206      1.1    itojun 	u_int8_t *retval;
    207      1.3     lukem 	struct ip6_ext *eh;
    208      1.3     lukem 
    209      1.3     lukem 	_DIAGASSERT(cmsg != NULL);
    210      1.3     lukem 
    211      1.8  christos 	bp = (u_char *)(void *)cmsg + cmsg->cmsg_len;
    212      1.8  christos 	eh = (struct ip6_ext *)(void *)CMSG_DATA(cmsg);
    213      1.1    itojun 
    214      1.1    itojun 	/* argument validation */
    215      1.1    itojun 	if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
    216      1.1    itojun 		return(NULL);
    217      1.1    itojun 	if (plusy < 0 || plusy > 7)
    218      1.1    itojun 		return(NULL);
    219      1.1    itojun 
    220      1.1    itojun 	/*
    221      1.1    itojun 	 * If this is the first option, allocate space for the
    222      1.1    itojun 	 * first 2 bytes(for next header and length fields) of
    223      1.1    itojun 	 * the option header.
    224      1.1    itojun 	 */
    225      1.8  christos 	if (bp == (u_char *)(void *)eh) {
    226      1.1    itojun 		bp += 2;
    227      1.1    itojun 		cmsg->cmsg_len += 2;
    228      1.1    itojun 	}
    229      1.1    itojun 
    230      1.1    itojun 	/* calculate pad length before the option. */
    231      1.8  christos 	off = bp - (u_char *)(void *)eh;
    232      1.1    itojun 	padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
    233      1.1    itojun 		(off % multx);
    234      1.1    itojun 	padlen += plusy;
    235      1.1    itojun 	/* insert padding */
    236      1.1    itojun 	inet6_insert_padopt(bp, padlen);
    237      1.1    itojun 	cmsg->cmsg_len += padlen;
    238      1.1    itojun 	bp += padlen;
    239      1.1    itojun 
    240      1.1    itojun 	/* keep space to store specified length of data */
    241      1.1    itojun 	retval = bp;
    242      1.1    itojun 	bp += datalen;
    243      1.1    itojun 	cmsg->cmsg_len += datalen;
    244      1.1    itojun 
    245      1.1    itojun 	/* calculate pad length after the option and insert the padding */
    246      1.8  christos 	off = bp - (u_char *)(void *)eh;
    247      1.1    itojun 	padlen = ((off + 7) & ~7) - off;
    248      1.1    itojun 	inet6_insert_padopt(bp, padlen);
    249      1.1    itojun 	bp += padlen;
    250      1.1    itojun 	cmsg->cmsg_len += padlen;
    251      1.1    itojun 
    252      1.1    itojun 	/* update the length field of the ip6 option header */
    253      1.8  christos 	off = bp - (u_char *)(void *)eh;
    254      1.5   mycroft 	eh->ip6e_len = (off >> 3) - 1;
    255      1.1    itojun 
    256      1.1    itojun 	return(retval);
    257      1.1    itojun }
    258      1.1    itojun 
    259      1.1    itojun /*
    260      1.1    itojun  * This function processes the next Hop-by-Hop option or Destination
    261      1.1    itojun  * option in an ancillary data object.  If another option remains to be
    262      1.1    itojun  * processed, the return value of the function is 0 and *tptrp points to
    263      1.1    itojun  * the 8-bit option type field (which is followed by the 8-bit option
    264      1.1    itojun  * data length, followed by the option data).  If no more options remain
    265      1.1    itojun  * to be processed, the return value is -1 and *tptrp is NULL.  If an
    266      1.1    itojun  * error occurs, the return value is -1 and *tptrp is not NULL.
    267      1.1    itojun  * (RFC 2292, 6.3.5)
    268      1.1    itojun  */
    269      1.1    itojun int
    270      1.1    itojun inet6_option_next(cmsg, tptrp)
    271      1.1    itojun 	const struct cmsghdr *cmsg;
    272      1.1    itojun 	u_int8_t **tptrp;
    273      1.1    itojun {
    274      1.1    itojun 	struct ip6_ext *ip6e;
    275      1.1    itojun 	int hdrlen, optlen;
    276      1.1    itojun 	u_int8_t *lim;
    277      1.1    itojun 
    278      1.3     lukem 	_DIAGASSERT(cmsg != NULL);
    279      1.3     lukem 	_DIAGASSERT(tptrp != NULL);
    280      1.3     lukem 
    281      1.1    itojun 	if (cmsg->cmsg_level != IPPROTO_IPV6 ||
    282      1.1    itojun 	    (cmsg->cmsg_type != IPV6_HOPOPTS &&
    283      1.1    itojun 	     cmsg->cmsg_type != IPV6_DSTOPTS))
    284      1.1    itojun 		return(-1);
    285      1.1    itojun 
    286      1.1    itojun 	/* message length validation */
    287      1.1    itojun 	if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
    288      1.1    itojun 		return(-1);
    289      1.8  christos 	/* LINTED const castaway */
    290      1.8  christos 	ip6e = (struct ip6_ext *)(void *)CMSG_DATA(cmsg);
    291      1.1    itojun 	hdrlen = (ip6e->ip6e_len + 1) << 3;
    292      1.1    itojun 	if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
    293      1.1    itojun 		return(-1);
    294      1.1    itojun 
    295      1.1    itojun 	/*
    296      1.1    itojun 	 * If the caller does not specify the starting point,
    297      1.1    itojun 	 * simply return the 1st option.
    298      1.1    itojun 	 * Otherwise, search the option list for the next option.
    299      1.1    itojun 	 */
    300      1.8  christos 	lim = (u_int8_t *)(void *)ip6e + hdrlen;
    301      1.1    itojun 	if (*tptrp == NULL)
    302      1.8  christos 		*tptrp = (u_int8_t *)(void *)(ip6e + 1);
    303      1.1    itojun 	else {
    304      1.1    itojun 		if ((optlen = ip6optlen(*tptrp, lim)) == 0)
    305      1.1    itojun 			return(-1);
    306      1.1    itojun 
    307      1.1    itojun 		*tptrp = *tptrp + optlen;
    308      1.1    itojun 	}
    309      1.1    itojun 	if (*tptrp >= lim) {	/* there is no option */
    310      1.1    itojun 		*tptrp = NULL;
    311      1.1    itojun 		return(-1);
    312      1.1    itojun 	}
    313      1.1    itojun 	/*
    314      1.1    itojun 	 * Finally, checks if the next option is safely stored in the
    315      1.1    itojun 	 * cmsg data.
    316      1.1    itojun 	 */
    317      1.1    itojun 	if (ip6optlen(*tptrp, lim) == 0)
    318      1.1    itojun 		return(-1);
    319      1.1    itojun 	else
    320      1.1    itojun 		return(0);
    321      1.1    itojun }
    322      1.1    itojun 
    323      1.1    itojun /*
    324      1.1    itojun  * This function is similar to the inet6_option_next() function,
    325      1.1    itojun  * except this function lets the caller specify the option type to be
    326      1.1    itojun  * searched for, instead of always returning the next option in the
    327      1.1    itojun  * ancillary data object.
    328      1.1    itojun  * Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think
    329      1.1    itojun  *       it's a typo. The variable should be type of u_int8_t **.
    330      1.1    itojun  */
    331      1.1    itojun int
    332      1.1    itojun inet6_option_find(cmsg, tptrp, type)
    333      1.1    itojun 	const struct cmsghdr *cmsg;
    334      1.1    itojun 	u_int8_t **tptrp;
    335      1.1    itojun 	int type;
    336      1.1    itojun {
    337      1.1    itojun 	struct ip6_ext *ip6e;
    338      1.1    itojun 	int hdrlen, optlen;
    339      1.1    itojun 	u_int8_t *optp, *lim;
    340      1.1    itojun 
    341      1.3     lukem 	_DIAGASSERT(cmsg != NULL);
    342      1.3     lukem 	_DIAGASSERT(tptrp != NULL);
    343      1.3     lukem 
    344      1.1    itojun 	if (cmsg->cmsg_level != IPPROTO_IPV6 ||
    345      1.1    itojun 	    (cmsg->cmsg_type != IPV6_HOPOPTS &&
    346      1.1    itojun 	     cmsg->cmsg_type != IPV6_DSTOPTS))
    347      1.1    itojun 		return(-1);
    348      1.1    itojun 
    349      1.1    itojun 	/* message length validation */
    350      1.1    itojun 	if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
    351      1.1    itojun 		return(-1);
    352      1.8  christos 	/* LINTED const castaway */
    353      1.8  christos 	ip6e = (struct ip6_ext *)(void *)CMSG_DATA(cmsg);
    354      1.1    itojun 	hdrlen = (ip6e->ip6e_len + 1) << 3;
    355      1.1    itojun 	if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
    356      1.1    itojun 		return(-1);
    357      1.1    itojun 
    358      1.1    itojun 	/*
    359      1.1    itojun 	 * If the caller does not specify the starting point,
    360      1.1    itojun 	 * search from the beginning of the option list.
    361      1.1    itojun 	 * Otherwise, search from *the next option* of the specified point.
    362      1.1    itojun 	 */
    363      1.8  christos 	lim = (u_int8_t *)(void *)ip6e + hdrlen;
    364      1.1    itojun 	if (*tptrp == NULL)
    365      1.8  christos 		*tptrp = (u_int8_t *)(void *)(ip6e + 1);
    366      1.1    itojun 	else {
    367      1.1    itojun 		if ((optlen = ip6optlen(*tptrp, lim)) == 0)
    368      1.1    itojun 			return(-1);
    369      1.1    itojun 
    370      1.1    itojun 		*tptrp = *tptrp + optlen;
    371      1.1    itojun 	}
    372      1.1    itojun 	for (optp = *tptrp; optp < lim; optp += optlen) {
    373      1.1    itojun 		if (*optp == type) {
    374      1.1    itojun 			*tptrp = optp;
    375      1.1    itojun 			return(0);
    376      1.1    itojun 		}
    377      1.1    itojun 		if ((optlen = ip6optlen(optp, lim)) == 0)
    378      1.1    itojun 			return(-1);
    379      1.1    itojun 	}
    380      1.1    itojun 
    381      1.1    itojun 	/* search failed */
    382      1.1    itojun 	*tptrp = NULL;
    383      1.1    itojun 	return(-1);
    384      1.1    itojun }
    385      1.1    itojun 
    386      1.1    itojun /*
    387      1.1    itojun  * Calculate the length of a given IPv6 option. Also checks
    388      1.1    itojun  * if the option is safely stored in user's buffer according to the
    389      1.1    itojun  * calculated length and the limitation of the buffer.
    390      1.1    itojun  */
    391      1.1    itojun static int
    392      1.1    itojun ip6optlen(opt, lim)
    393      1.1    itojun 	u_int8_t *opt, *lim;
    394      1.1    itojun {
    395      1.1    itojun 	int optlen;
    396      1.1    itojun 
    397      1.3     lukem 	_DIAGASSERT(opt != NULL);
    398      1.3     lukem 	_DIAGASSERT(lim != NULL);
    399      1.3     lukem 
    400      1.1    itojun 	if (*opt == IP6OPT_PAD1)
    401      1.1    itojun 		optlen = 1;
    402      1.1    itojun 	else {
    403      1.1    itojun 		/* is there enough space to store type and len? */
    404      1.1    itojun 		if (opt + 2 > lim)
    405      1.1    itojun 			return(0);
    406      1.1    itojun 		optlen = *(opt + 1) + 2;
    407      1.1    itojun 	}
    408      1.1    itojun 	if (opt + optlen <= lim)
    409      1.1    itojun 		return(optlen);
    410      1.1    itojun 
    411      1.1    itojun 	return(0);
    412      1.1    itojun }
    413      1.1    itojun 
    414      1.1    itojun static void
    415      1.5   mycroft inet6_insert_padopt(u_char *p, size_t len)
    416      1.1    itojun {
    417      1.3     lukem 
    418      1.3     lukem 	_DIAGASSERT(p != NULL);
    419      1.3     lukem 
    420      1.1    itojun 	switch(len) {
    421      1.1    itojun 	 case 0:
    422      1.1    itojun 		 return;
    423      1.1    itojun 	 case 1:
    424      1.1    itojun 		 p[0] = IP6OPT_PAD1;
    425      1.1    itojun 		 return;
    426      1.1    itojun 	 default:
    427      1.1    itojun 		 p[0] = IP6OPT_PADN;
    428      1.1    itojun 		 p[1] = len - 2;
    429      1.1    itojun 		 memset(&p[2], 0, len - 2);
    430      1.1    itojun 		 return;
    431      1.1    itojun 	}
    432      1.1    itojun }
    433