4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This code is conformant to RFC 3542.
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/sysmacros.h>
38 #include <netinet/in.h>
39 #include <netinet/ip6.h>
43 #define bufpos(p) ((p) - (uint8_t *)extbuf)
46 * Section 10.1 RFC3542. This function returns the size of the empty
47 * extension header. If extbuf is not NULL then it initializes its length
48 * field. If extlen is invalid then -1 is returned.
51 inet6_opt_init(void *extbuf
, socklen_t extlen
)
53 if (extbuf
&& ((extlen
< 0) || (extlen
% 8))) {
58 *(uint8_t *)extbuf
= 0;
59 *((uint8_t *)extbuf
+ 1) = extlen
/8 - 1;
66 * Section 10.2 RFC3542. This function appends an option to an already
67 * initialized option buffer. inet6_opt_append() returns the total length
68 * after adding the option.
71 inet6_opt_append(void *extbuf
, socklen_t extlen
, int offset
, uint8_t type
,
72 socklen_t len
, uint_t align
, void **databufp
)
76 int remainder
, padbytes
;
79 (align
!= 1 && align
!= 2 && align
!= 4 && align
!= 8) ||
80 len
< 0 || len
> 255 || type
< 2) {
86 * The length of the buffer is the minimum of the length
87 * passed in and the length stamped onto the buffer. The
88 * length stamped onto the buffer is the number of 8 byte
89 * octets in the buffer minus 1.
91 extlen
= MIN(extlen
, (*((uint8_t *)extbuf
+ 1) + 1) * 8);
94 remainder
= (offset
+ 2 + len
) % align
;
98 padbytes
= align
- remainder
;
101 endlen
= offset
+ padbytes
+ 2 + len
;
102 if ((endlen
> extlen
) || !extbuf
) {
110 p
= (uint8_t *)extbuf
+ offset
;
113 * Pad out the buffer here with pad options. If its only
114 * one byte then there is a special TLV with no L or V, just
115 * a zero to say skip this byte. For two bytes or more
116 * we have a special TLV with type 0 and length the number of
123 *(p
+ 1) = padbytes
- 2;
124 memset(p
+ 2, 0, padbytes
- 2);
138 * Section 10.3 RFC3542. This function returns the updated total length.
139 * This functions inserts pad options to complete the option header as
143 inet6_opt_finish(void *extbuf
, socklen_t extlen
, int offset
)
150 * The length of the buffer is the minimum of the length
151 * passed in and the length stamped onto the buffer. The
152 * length stamped onto the buffer is the number of 8 byte
153 * octets in the buffer minus 1.
155 extlen
= MIN(extlen
, (*((uint8_t *)extbuf
+ 1) + 1) * 8);
158 padbytes
= 8 - (offset
% 8);
162 if ((offset
+ padbytes
> extlen
) || !extbuf
) {
166 return (offset
+ padbytes
);
170 p
= (uint8_t *)extbuf
+ offset
;
173 * Pad out the buffer here with pad options. If its only
174 * one byte then there is a special TLV with no L or V, just
175 * a zero to say skip this byte. For two bytes or more
176 * we have a special TLV with type 0 and length the number of
183 *(p
+ 1) = padbytes
- 2;
184 memset(p
+ 2, 0, padbytes
- 2);
189 return (offset
+ padbytes
);
193 * Section 10.4 RFC3542. Ths function takes a pointer to the data as
194 * returned by inet6_opt_append and inserts the data.
197 inet6_opt_set_val(void *databuf
, int offset
, void *val
, socklen_t vallen
)
199 memcpy((uint8_t *)databuf
+ offset
, val
, vallen
);
200 return (offset
+ vallen
);
204 * Section 10.5 RFC 3542. Starting walking the option header offset into the
205 * header. Returns where we left off. You take the output of this function
206 * and pass it back in as offset to iterate. -1 is returned on error.
208 * We use the fact that the first unsigned 8 bit quantity in the option
209 * header is the type and the second is the length.
212 inet6_opt_next(void *extbuf
, socklen_t extlen
, int offset
, uint8_t *typep
,
213 socklen_t
*lenp
, void **databufp
)
219 * The length of the buffer is the minimum of the length
220 * passed in and the length stamped onto the buffer. The
221 * length stamped onto the buffer is the number of 8 byte
222 * octets in the buffer minus 1.
224 extlen
= MIN(extlen
, (*((uint8_t *)extbuf
+ 1) + 1) * 8);
225 end
= (uint8_t *)extbuf
+ extlen
;
230 /* assumption: IP6OPT_PAD1 == 0 and IP6OPT_PADN == 1 */
231 p
= (uint8_t *)extbuf
+ offset
;
232 while (*p
== IP6OPT_PAD1
|| *p
== IP6OPT_PADN
) {
238 /* *(p + 1) is the length of the option. */
239 if (p
+ 2 + *(p
+ 1) >= end
)
246 /* type, len, and data must fit... */
247 if ((p
+ 2 >= end
) || (p
+ 2 + *(p
+ 1) > end
)) {
261 return ((p
- (uint8_t *)extbuf
) + 2 + *lenp
);
265 * Section 10.6 RFC 3542. Starting walking the option header offset into the
266 * header. Returns where we left off. You take the output of this function
267 * and pass it back in as offset to iterate. -1 is returned on error.
269 * We use the fact that the first unsigned 8 bit quantity in the option
270 * header is the type and the second is the length.
273 inet6_opt_find(void *extbuf
, socklen_t extlen
, int offset
, uint8_t type
,
274 socklen_t
*lenp
, void **databufp
)
279 offset
= inet6_opt_next(extbuf
, extlen
, offset
, &newtype
, lenp
,
284 } while (newtype
!= type
);
286 /* value to feed back into inet6_opt_find() as offset */
291 * Section 10.7 RFC 3542. databuf should be a pointer as returned by
292 * inet6_opt_next or inet6_opt_find. The data is extracted from the option
296 inet6_opt_get_val(void *databuf
, int offset
, void *val
, socklen_t vallen
)
298 memcpy(val
, (uint8_t *)databuf
+ offset
, vallen
);
299 return (offset
+ vallen
);