105a244b4SYoshinobu Inoue /* 205a244b4SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 305a244b4SYoshinobu Inoue * All rights reserved. 405a244b4SYoshinobu Inoue * 505a244b4SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 605a244b4SYoshinobu Inoue * modification, are permitted provided that the following conditions 705a244b4SYoshinobu Inoue * are met: 805a244b4SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 905a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1005a244b4SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1105a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1205a244b4SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1305a244b4SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1405a244b4SYoshinobu Inoue * may be used to endorse or promote products derived from this software 1505a244b4SYoshinobu Inoue * without specific prior written permission. 1605a244b4SYoshinobu Inoue * 1705a244b4SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1805a244b4SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1905a244b4SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2005a244b4SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2105a244b4SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2205a244b4SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2305a244b4SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2405a244b4SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2505a244b4SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2605a244b4SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2705a244b4SYoshinobu Inoue * SUCH DAMAGE. 2805a244b4SYoshinobu Inoue * 2905a244b4SYoshinobu Inoue * $FreeBSD$ 3005a244b4SYoshinobu Inoue */ 3105a244b4SYoshinobu Inoue 3205a244b4SYoshinobu Inoue #include <sys/param.h> 3305a244b4SYoshinobu Inoue #include <sys/types.h> 3405a244b4SYoshinobu Inoue #include <sys/socket.h> 3505a244b4SYoshinobu Inoue 3605a244b4SYoshinobu Inoue #include <netinet/in.h> 3705a244b4SYoshinobu Inoue #include <netinet/ip6.h> 3805a244b4SYoshinobu Inoue 3905a244b4SYoshinobu Inoue #include <string.h> 4005a244b4SYoshinobu Inoue #include <stdio.h> 4105a244b4SYoshinobu Inoue 4205a244b4SYoshinobu Inoue static int ip6optlen(u_int8_t *opt, u_int8_t *lim); 4305a244b4SYoshinobu Inoue static void inet6_insert_padopt(u_char *p, int len); 4405a244b4SYoshinobu Inoue 4505a244b4SYoshinobu Inoue /* 4605a244b4SYoshinobu Inoue * This function returns the number of bytes required to hold an option 4705a244b4SYoshinobu Inoue * when it is stored as ancillary data, including the cmsghdr structure 4805a244b4SYoshinobu Inoue * at the beginning, and any padding at the end (to make its size a 4905a244b4SYoshinobu Inoue * multiple of 8 bytes). The argument is the size of the structure 5005a244b4SYoshinobu Inoue * defining the option, which must include any pad bytes at the 5105a244b4SYoshinobu Inoue * beginning (the value y in the alignment term "xn + y"), the type 5205a244b4SYoshinobu Inoue * byte, the length byte, and the option data. 5305a244b4SYoshinobu Inoue */ 5405a244b4SYoshinobu Inoue int 5505a244b4SYoshinobu Inoue inet6_option_space(nbytes) 5605a244b4SYoshinobu Inoue int nbytes; 5705a244b4SYoshinobu Inoue { 5805a244b4SYoshinobu Inoue nbytes += 2; /* we need space for nxt-hdr and length fields */ 5905a244b4SYoshinobu Inoue return(CMSG_SPACE((nbytes + 7) & ~7)); 6005a244b4SYoshinobu Inoue } 6105a244b4SYoshinobu Inoue 6205a244b4SYoshinobu Inoue /* 6305a244b4SYoshinobu Inoue * This function is called once per ancillary data object that will 6405a244b4SYoshinobu Inoue * contain either Hop-by-Hop or Destination options. It returns 0 on 6505a244b4SYoshinobu Inoue * success or -1 on an error. 6605a244b4SYoshinobu Inoue */ 6705a244b4SYoshinobu Inoue int 6805a244b4SYoshinobu Inoue inet6_option_init(bp, cmsgp, type) 6905a244b4SYoshinobu Inoue void *bp; 7005a244b4SYoshinobu Inoue struct cmsghdr **cmsgp; 7105a244b4SYoshinobu Inoue int type; 7205a244b4SYoshinobu Inoue { 738fb3f3f6SDavid E. O'Brien struct cmsghdr *ch = (struct cmsghdr *)bp; 7405a244b4SYoshinobu Inoue 7505a244b4SYoshinobu Inoue /* argument validation */ 7605a244b4SYoshinobu Inoue if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS) 7705a244b4SYoshinobu Inoue return(-1); 7805a244b4SYoshinobu Inoue 7905a244b4SYoshinobu Inoue ch->cmsg_level = IPPROTO_IPV6; 8005a244b4SYoshinobu Inoue ch->cmsg_type = type; 8105a244b4SYoshinobu Inoue ch->cmsg_len = CMSG_LEN(0); 8205a244b4SYoshinobu Inoue 8305a244b4SYoshinobu Inoue *cmsgp = ch; 8405a244b4SYoshinobu Inoue return(0); 8505a244b4SYoshinobu Inoue } 8605a244b4SYoshinobu Inoue 8705a244b4SYoshinobu Inoue /* 8805a244b4SYoshinobu Inoue * This function appends a Hop-by-Hop option or a Destination option 8905a244b4SYoshinobu Inoue * into an ancillary data object that has been initialized by 9005a244b4SYoshinobu Inoue * inet6_option_init(). This function returns 0 if it succeeds or -1 on 9105a244b4SYoshinobu Inoue * an error. 9205a244b4SYoshinobu Inoue * multx is the value x in the alignment term "xn + y" described 9305a244b4SYoshinobu Inoue * earlier. It must have a value of 1, 2, 4, or 8. 9405a244b4SYoshinobu Inoue * plusy is the value y in the alignment term "xn + y" described 9505a244b4SYoshinobu Inoue * earlier. It must have a value between 0 and 7, inclusive. 9605a244b4SYoshinobu Inoue */ 9705a244b4SYoshinobu Inoue int 9805a244b4SYoshinobu Inoue inet6_option_append(cmsg, typep, multx, plusy) 9905a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 10005a244b4SYoshinobu Inoue const u_int8_t *typep; 10105a244b4SYoshinobu Inoue int multx; 10205a244b4SYoshinobu Inoue int plusy; 10305a244b4SYoshinobu Inoue { 10405a244b4SYoshinobu Inoue int padlen, optlen, off; 1058fb3f3f6SDavid E. O'Brien u_char *bp = (u_char *)cmsg + cmsg->cmsg_len; 10605a244b4SYoshinobu Inoue struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg); 10705a244b4SYoshinobu Inoue 10805a244b4SYoshinobu Inoue /* argument validation */ 10905a244b4SYoshinobu Inoue if (multx != 1 && multx != 2 && multx != 4 && multx != 8) 11005a244b4SYoshinobu Inoue return(-1); 11105a244b4SYoshinobu Inoue if (plusy < 0 || plusy > 7) 11205a244b4SYoshinobu Inoue return(-1); 11305a244b4SYoshinobu Inoue if (typep[0] > 255) 11405a244b4SYoshinobu Inoue return(-1); 11505a244b4SYoshinobu Inoue 11605a244b4SYoshinobu Inoue /* 11705a244b4SYoshinobu Inoue * If this is the first option, allocate space for the 11805a244b4SYoshinobu Inoue * first 2 bytes(for next header and length fields) of 11905a244b4SYoshinobu Inoue * the option header. 12005a244b4SYoshinobu Inoue */ 12105a244b4SYoshinobu Inoue if (bp == (u_char *)eh) { 12205a244b4SYoshinobu Inoue bp += 2; 12305a244b4SYoshinobu Inoue cmsg->cmsg_len += 2; 12405a244b4SYoshinobu Inoue } 12505a244b4SYoshinobu Inoue 12605a244b4SYoshinobu Inoue /* calculate pad length before the option. */ 12705a244b4SYoshinobu Inoue off = bp - (u_char *)eh; 12805a244b4SYoshinobu Inoue padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) - 12905a244b4SYoshinobu Inoue (off % multx); 13005a244b4SYoshinobu Inoue padlen += plusy; 13105a244b4SYoshinobu Inoue /* insert padding */ 13205a244b4SYoshinobu Inoue inet6_insert_padopt(bp, padlen); 13305a244b4SYoshinobu Inoue cmsg->cmsg_len += padlen; 13405a244b4SYoshinobu Inoue bp += padlen; 13505a244b4SYoshinobu Inoue 13605a244b4SYoshinobu Inoue /* copy the option */ 13705a244b4SYoshinobu Inoue if (typep[0] == IP6OPT_PAD1) 13805a244b4SYoshinobu Inoue optlen = 1; 13905a244b4SYoshinobu Inoue else 14005a244b4SYoshinobu Inoue optlen = typep[1] + 2; 14105a244b4SYoshinobu Inoue memcpy(bp, typep, optlen); 14205a244b4SYoshinobu Inoue bp += optlen; 14305a244b4SYoshinobu Inoue cmsg->cmsg_len += optlen; 14405a244b4SYoshinobu Inoue 14505a244b4SYoshinobu Inoue /* calculate pad length after the option and insert the padding */ 14605a244b4SYoshinobu Inoue off = bp - (u_char *)eh; 14705a244b4SYoshinobu Inoue padlen = ((off + 7) & ~7) - off; 14805a244b4SYoshinobu Inoue inet6_insert_padopt(bp, padlen); 14905a244b4SYoshinobu Inoue bp += padlen; 15005a244b4SYoshinobu Inoue cmsg->cmsg_len += padlen; 15105a244b4SYoshinobu Inoue 15205a244b4SYoshinobu Inoue /* update the length field of the ip6 option header */ 15305a244b4SYoshinobu Inoue eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1; 15405a244b4SYoshinobu Inoue 15505a244b4SYoshinobu Inoue return(0); 15605a244b4SYoshinobu Inoue } 15705a244b4SYoshinobu Inoue 15805a244b4SYoshinobu Inoue /* 15905a244b4SYoshinobu Inoue * This function appends a Hop-by-Hop option or a Destination option 16005a244b4SYoshinobu Inoue * into an ancillary data object that has been initialized by 16105a244b4SYoshinobu Inoue * inet6_option_init(). This function returns a pointer to the 8-bit 16205a244b4SYoshinobu Inoue * option type field that starts the option on success, or NULL on an 16305a244b4SYoshinobu Inoue * error. 16405a244b4SYoshinobu Inoue * The difference between this function and inet6_option_append() is 16505a244b4SYoshinobu Inoue * that the latter copies the contents of a previously built option into 16605a244b4SYoshinobu Inoue * the ancillary data object while the current function returns a 16705a244b4SYoshinobu Inoue * pointer to the space in the data object where the option's TLV must 16805a244b4SYoshinobu Inoue * then be built by the caller. 16905a244b4SYoshinobu Inoue * 17005a244b4SYoshinobu Inoue */ 17105a244b4SYoshinobu Inoue u_int8_t * 17205a244b4SYoshinobu Inoue inet6_option_alloc(cmsg, datalen, multx, plusy) 17305a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 17405a244b4SYoshinobu Inoue int datalen; 17505a244b4SYoshinobu Inoue int multx; 17605a244b4SYoshinobu Inoue int plusy; 17705a244b4SYoshinobu Inoue { 17805a244b4SYoshinobu Inoue int padlen, off; 1798fb3f3f6SDavid E. O'Brien u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len; 18005a244b4SYoshinobu Inoue u_int8_t *retval; 18105a244b4SYoshinobu Inoue struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg); 18205a244b4SYoshinobu Inoue 18305a244b4SYoshinobu Inoue /* argument validation */ 18405a244b4SYoshinobu Inoue if (multx != 1 && multx != 2 && multx != 4 && multx != 8) 18505a244b4SYoshinobu Inoue return(NULL); 18605a244b4SYoshinobu Inoue if (plusy < 0 || plusy > 7) 18705a244b4SYoshinobu Inoue return(NULL); 18805a244b4SYoshinobu Inoue 18905a244b4SYoshinobu Inoue /* 19005a244b4SYoshinobu Inoue * If this is the first option, allocate space for the 19105a244b4SYoshinobu Inoue * first 2 bytes(for next header and length fields) of 19205a244b4SYoshinobu Inoue * the option header. 19305a244b4SYoshinobu Inoue */ 19405a244b4SYoshinobu Inoue if (bp == (u_char *)eh) { 19505a244b4SYoshinobu Inoue bp += 2; 19605a244b4SYoshinobu Inoue cmsg->cmsg_len += 2; 19705a244b4SYoshinobu Inoue } 19805a244b4SYoshinobu Inoue 19905a244b4SYoshinobu Inoue /* calculate pad length before the option. */ 20005a244b4SYoshinobu Inoue off = bp - (u_char *)eh; 20105a244b4SYoshinobu Inoue padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) - 20205a244b4SYoshinobu Inoue (off % multx); 20305a244b4SYoshinobu Inoue padlen += plusy; 20405a244b4SYoshinobu Inoue /* insert padding */ 20505a244b4SYoshinobu Inoue inet6_insert_padopt(bp, padlen); 20605a244b4SYoshinobu Inoue cmsg->cmsg_len += padlen; 20705a244b4SYoshinobu Inoue bp += padlen; 20805a244b4SYoshinobu Inoue 20905a244b4SYoshinobu Inoue /* keep space to store specified length of data */ 21005a244b4SYoshinobu Inoue retval = bp; 21105a244b4SYoshinobu Inoue bp += datalen; 21205a244b4SYoshinobu Inoue cmsg->cmsg_len += datalen; 21305a244b4SYoshinobu Inoue 21405a244b4SYoshinobu Inoue /* calculate pad length after the option and insert the padding */ 21505a244b4SYoshinobu Inoue off = bp - (u_char *)eh; 21605a244b4SYoshinobu Inoue padlen = ((off + 7) & ~7) - off; 21705a244b4SYoshinobu Inoue inet6_insert_padopt(bp, padlen); 21805a244b4SYoshinobu Inoue bp += padlen; 21905a244b4SYoshinobu Inoue cmsg->cmsg_len += padlen; 22005a244b4SYoshinobu Inoue 22105a244b4SYoshinobu Inoue /* update the length field of the ip6 option header */ 22205a244b4SYoshinobu Inoue eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1; 22305a244b4SYoshinobu Inoue 22405a244b4SYoshinobu Inoue return(retval); 22505a244b4SYoshinobu Inoue } 22605a244b4SYoshinobu Inoue 22705a244b4SYoshinobu Inoue /* 22805a244b4SYoshinobu Inoue * This function processes the next Hop-by-Hop option or Destination 22905a244b4SYoshinobu Inoue * option in an ancillary data object. If another option remains to be 23005a244b4SYoshinobu Inoue * processed, the return value of the function is 0 and *tptrp points to 23105a244b4SYoshinobu Inoue * the 8-bit option type field (which is followed by the 8-bit option 23205a244b4SYoshinobu Inoue * data length, followed by the option data). If no more options remain 23305a244b4SYoshinobu Inoue * to be processed, the return value is -1 and *tptrp is NULL. If an 23405a244b4SYoshinobu Inoue * error occurs, the return value is -1 and *tptrp is not NULL. 23505a244b4SYoshinobu Inoue * (RFC 2292, 6.3.5) 23605a244b4SYoshinobu Inoue */ 23705a244b4SYoshinobu Inoue int 23805a244b4SYoshinobu Inoue inet6_option_next(cmsg, tptrp) 23905a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 24005a244b4SYoshinobu Inoue u_int8_t **tptrp; 24105a244b4SYoshinobu Inoue { 24205a244b4SYoshinobu Inoue struct ip6_ext *ip6e; 24305a244b4SYoshinobu Inoue int hdrlen, optlen; 24405a244b4SYoshinobu Inoue u_int8_t *lim; 24505a244b4SYoshinobu Inoue 24605a244b4SYoshinobu Inoue if (cmsg->cmsg_level != IPPROTO_IPV6 || 24705a244b4SYoshinobu Inoue (cmsg->cmsg_type != IPV6_HOPOPTS && 24805a244b4SYoshinobu Inoue cmsg->cmsg_type != IPV6_DSTOPTS)) 24905a244b4SYoshinobu Inoue return(-1); 25005a244b4SYoshinobu Inoue 25105a244b4SYoshinobu Inoue /* message length validation */ 25205a244b4SYoshinobu Inoue if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext))) 25305a244b4SYoshinobu Inoue return(-1); 25405a244b4SYoshinobu Inoue ip6e = (struct ip6_ext *)CMSG_DATA(cmsg); 25505a244b4SYoshinobu Inoue hdrlen = (ip6e->ip6e_len + 1) << 3; 25605a244b4SYoshinobu Inoue if (cmsg->cmsg_len < CMSG_SPACE(hdrlen)) 25705a244b4SYoshinobu Inoue return(-1); 25805a244b4SYoshinobu Inoue 25905a244b4SYoshinobu Inoue /* 26005a244b4SYoshinobu Inoue * If the caller does not specify the starting point, 26105a244b4SYoshinobu Inoue * simply return the 1st option. 26205a244b4SYoshinobu Inoue * Otherwise, search the option list for the next option. 26305a244b4SYoshinobu Inoue */ 26405a244b4SYoshinobu Inoue lim = (u_int8_t *)ip6e + hdrlen; 26505a244b4SYoshinobu Inoue if (*tptrp == NULL) 26605a244b4SYoshinobu Inoue *tptrp = (u_int8_t *)(ip6e + 1); 26705a244b4SYoshinobu Inoue else { 26805a244b4SYoshinobu Inoue if ((optlen = ip6optlen(*tptrp, lim)) == 0) 26905a244b4SYoshinobu Inoue return(-1); 27005a244b4SYoshinobu Inoue 27105a244b4SYoshinobu Inoue *tptrp = *tptrp + optlen; 27205a244b4SYoshinobu Inoue } 27305a244b4SYoshinobu Inoue if (*tptrp >= lim) { /* there is no option */ 27405a244b4SYoshinobu Inoue *tptrp = NULL; 27505a244b4SYoshinobu Inoue return(-1); 27605a244b4SYoshinobu Inoue } 27705a244b4SYoshinobu Inoue /* 27805a244b4SYoshinobu Inoue * Finally, checks if the next option is safely stored in the 27905a244b4SYoshinobu Inoue * cmsg data. 28005a244b4SYoshinobu Inoue */ 28105a244b4SYoshinobu Inoue if (ip6optlen(*tptrp, lim) == 0) 28205a244b4SYoshinobu Inoue return(-1); 28305a244b4SYoshinobu Inoue else 28405a244b4SYoshinobu Inoue return(0); 28505a244b4SYoshinobu Inoue } 28605a244b4SYoshinobu Inoue 28705a244b4SYoshinobu Inoue /* 28805a244b4SYoshinobu Inoue * This function is similar to the inet6_option_next() function, 28905a244b4SYoshinobu Inoue * except this function lets the caller specify the option type to be 29005a244b4SYoshinobu Inoue * searched for, instead of always returning the next option in the 29105a244b4SYoshinobu Inoue * ancillary data object. 29205a244b4SYoshinobu Inoue * Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think 29305a244b4SYoshinobu Inoue * it's a typo. The variable should be type of u_int8_t **. 29405a244b4SYoshinobu Inoue */ 29505a244b4SYoshinobu Inoue int 29605a244b4SYoshinobu Inoue inet6_option_find(cmsg, tptrp, type) 29705a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 29805a244b4SYoshinobu Inoue u_int8_t **tptrp; 29905a244b4SYoshinobu Inoue int type; 30005a244b4SYoshinobu Inoue { 30105a244b4SYoshinobu Inoue struct ip6_ext *ip6e; 30205a244b4SYoshinobu Inoue int hdrlen, optlen; 30305a244b4SYoshinobu Inoue u_int8_t *optp, *lim; 30405a244b4SYoshinobu Inoue 30505a244b4SYoshinobu Inoue if (cmsg->cmsg_level != IPPROTO_IPV6 || 30605a244b4SYoshinobu Inoue (cmsg->cmsg_type != IPV6_HOPOPTS && 30705a244b4SYoshinobu Inoue cmsg->cmsg_type != IPV6_DSTOPTS)) 30805a244b4SYoshinobu Inoue return(-1); 30905a244b4SYoshinobu Inoue 31005a244b4SYoshinobu Inoue /* message length validation */ 31105a244b4SYoshinobu Inoue if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext))) 31205a244b4SYoshinobu Inoue return(-1); 31305a244b4SYoshinobu Inoue ip6e = (struct ip6_ext *)CMSG_DATA(cmsg); 31405a244b4SYoshinobu Inoue hdrlen = (ip6e->ip6e_len + 1) << 3; 31505a244b4SYoshinobu Inoue if (cmsg->cmsg_len < CMSG_SPACE(hdrlen)) 31605a244b4SYoshinobu Inoue return(-1); 31705a244b4SYoshinobu Inoue 31805a244b4SYoshinobu Inoue /* 31905a244b4SYoshinobu Inoue * If the caller does not specify the starting point, 32005a244b4SYoshinobu Inoue * search from the beginning of the option list. 32105a244b4SYoshinobu Inoue * Otherwise, search from *the next option* of the specified point. 32205a244b4SYoshinobu Inoue */ 32305a244b4SYoshinobu Inoue lim = (u_int8_t *)ip6e + hdrlen; 32405a244b4SYoshinobu Inoue if (*tptrp == NULL) 32505a244b4SYoshinobu Inoue *tptrp = (u_int8_t *)(ip6e + 1); 32605a244b4SYoshinobu Inoue else { 32705a244b4SYoshinobu Inoue if ((optlen = ip6optlen(*tptrp, lim)) == 0) 32805a244b4SYoshinobu Inoue return(-1); 32905a244b4SYoshinobu Inoue 33005a244b4SYoshinobu Inoue *tptrp = *tptrp + optlen; 33105a244b4SYoshinobu Inoue } 33205a244b4SYoshinobu Inoue for (optp = *tptrp; optp < lim; optp += optlen) { 33305a244b4SYoshinobu Inoue if (*optp == type) { 33405a244b4SYoshinobu Inoue *tptrp = optp; 33505a244b4SYoshinobu Inoue return(0); 33605a244b4SYoshinobu Inoue } 33705a244b4SYoshinobu Inoue if ((optlen = ip6optlen(optp, lim)) == 0) 33805a244b4SYoshinobu Inoue return(-1); 33905a244b4SYoshinobu Inoue } 34005a244b4SYoshinobu Inoue 34105a244b4SYoshinobu Inoue /* search failed */ 34205a244b4SYoshinobu Inoue *tptrp = NULL; 34305a244b4SYoshinobu Inoue return(-1); 34405a244b4SYoshinobu Inoue } 34505a244b4SYoshinobu Inoue 34605a244b4SYoshinobu Inoue /* 34705a244b4SYoshinobu Inoue * Calculate the length of a given IPv6 option. Also checks 34805a244b4SYoshinobu Inoue * if the option is safely stored in user's buffer according to the 34905a244b4SYoshinobu Inoue * calculated length and the limitation of the buffer. 35005a244b4SYoshinobu Inoue */ 35105a244b4SYoshinobu Inoue static int 35205a244b4SYoshinobu Inoue ip6optlen(opt, lim) 35305a244b4SYoshinobu Inoue u_int8_t *opt, *lim; 35405a244b4SYoshinobu Inoue { 35505a244b4SYoshinobu Inoue int optlen; 35605a244b4SYoshinobu Inoue 35705a244b4SYoshinobu Inoue if (*opt == IP6OPT_PAD1) 35805a244b4SYoshinobu Inoue optlen = 1; 35905a244b4SYoshinobu Inoue else { 36005a244b4SYoshinobu Inoue /* is there enough space to store type and len? */ 36105a244b4SYoshinobu Inoue if (opt + 2 > lim) 36205a244b4SYoshinobu Inoue return(0); 36305a244b4SYoshinobu Inoue optlen = *(opt + 1) + 2; 36405a244b4SYoshinobu Inoue } 36505a244b4SYoshinobu Inoue if (opt + optlen <= lim) 36605a244b4SYoshinobu Inoue return(optlen); 36705a244b4SYoshinobu Inoue 36805a244b4SYoshinobu Inoue return(0); 36905a244b4SYoshinobu Inoue } 37005a244b4SYoshinobu Inoue 37105a244b4SYoshinobu Inoue static void 37205a244b4SYoshinobu Inoue inet6_insert_padopt(u_char *p, int len) 37305a244b4SYoshinobu Inoue { 37405a244b4SYoshinobu Inoue switch(len) { 37505a244b4SYoshinobu Inoue case 0: 37605a244b4SYoshinobu Inoue return; 37705a244b4SYoshinobu Inoue case 1: 37805a244b4SYoshinobu Inoue p[0] = IP6OPT_PAD1; 37905a244b4SYoshinobu Inoue return; 38005a244b4SYoshinobu Inoue default: 38105a244b4SYoshinobu Inoue p[0] = IP6OPT_PADN; 38205a244b4SYoshinobu Inoue p[1] = len - 2; 38305a244b4SYoshinobu Inoue memset(&p[2], 0, len - 2); 38405a244b4SYoshinobu Inoue return; 38505a244b4SYoshinobu Inoue } 38605a244b4SYoshinobu Inoue } 387