Bug #653 ยป rfc3542-opt-and-rth.patch
lib/libc/net/ip6opt.c Wed May 23 21:42:13 2007 +0300 โ lib/libc/net/ip6opt.c Fri May 25 06:12:44 2007 +0300 | ||
---|---|---|
return;
|
||
}
|
||
}
|
||
/*
|
||
* The following functions are defined in RFC3542, which is a successor
|
||
* of RFC2292.
|
||
*/
|
||
int
|
||
inet6_opt_init(void *extbuf, socklen_t extlen)
|
||
{
|
||
struct ip6_ext *ext = (struct ip6_ext *)extbuf;
|
||
if (extlen < 0 || (extlen % 8))
|
||
return (-1);
|
||
if (ext) {
|
||
if (extlen == 0)
|
||
return (-1);
|
||
ext->ip6e_len = (extlen >> 3) - 1;
|
||
}
|
||
return (2); /* sizeof the next and the length fields */
|
||
}
|
||
int
|
||
inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
|
||
socklen_t len, u_int8_t align, void **databufp)
|
||
{
|
||
int currentlen = offset, padlen = 0;
|
||
/*
|
||
* The option type must have a value from 2 to 255, inclusive.
|
||
* (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
|
||
*/
|
||
#if 0 /* always false */
|
||
if (type < 2 || type > 255)
|
||
#else
|
||
if (type < 2)
|
||
#endif
|
||
return (-1);
|
||
/*
|
||
* The option data length must have a value between 0 and 255,
|
||
* inclusive, and is the length of the option data that follows.
|
||
*/
|
||
if (len < 0 || len > 255)
|
||
return (-1);
|
||
/*
|
||
* The align parameter must have a value of 1, 2, 4, or 8.
|
||
* The align value can not exceed the value of len.
|
||
*/
|
||
if (align != 1 && align != 2 && align != 4 && align != 8)
|
||
return (-1);
|
||
if (align > len)
|
||
return (-1);
|
||
/* Calculate the padding length. */
|
||
currentlen += 2 + len; /* 2 means "type + len" */
|
||
if (currentlen % align)
|
||
padlen = align - (currentlen % align);
|
||
/* The option must fit in the extension header buffer. */
|
||
currentlen += padlen;
|
||
if (extlen && /* XXX: right? */
|
||
currentlen > extlen)
|
||
return (-1);
|
||
if (extbuf) {
|
||
u_int8_t *optp = (u_int8_t *)extbuf + offset;
|
||
if (padlen == 1) {
|
||
/* insert a Pad1 option */
|
||
*optp = IP6OPT_PAD1;
|
||
optp++;
|
||
} else if (padlen > 0) {
|
||
/* insert a PadN option for alignment */
|
||
*optp++ = IP6OPT_PADN;
|
||
*optp++ = padlen - 2;
|
||
memset(optp, 0, padlen - 2);
|
||
optp += (padlen - 2);
|
||
}
|
||
*optp++ = type;
|
||
*optp++ = len;
|
||
*databufp = optp;
|
||
}
|
||
return (currentlen);
|
||
}
|
||
int
|
||
inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
|
||
{
|
||
int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;;
|
||
if (extbuf) {
|
||
u_int8_t *padp;
|
||
int padlen = updatelen - offset;
|
||
if (updatelen > extlen)
|
||
return (-1);
|
||
padp = (u_int8_t *)extbuf + offset;
|
||
if (padlen == 1)
|
||
*padp = IP6OPT_PAD1;
|
||
else if (padlen > 0) {
|
||
*padp++ = IP6OPT_PADN;
|
||
*padp++ = (padlen - 2);
|
||
memset(padp, 0, padlen - 2);
|
||
}
|
||
}
|
||
return (updatelen);
|
||
}
|
||
int
|
||
inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
|
||
{
|
||
memcpy((u_int8_t *)databuf + offset, val, vallen);
|
||
return (offset + vallen);
|
||
}
|
||
int
|
||
inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
|
||
socklen_t *lenp, void **databufp)
|
||
{
|
||
u_int8_t *optp, *lim;
|
||
int optlen;
|
||
/* Validate extlen. XXX: is the variable really necessary?? */
|
||
if (extlen == 0 || (extlen % 8))
|
||
return (-1);
|
||
lim = (u_int8_t *)extbuf + extlen;
|
||
/*
|
||
* If this is the first time this function called for this options
|
||
* header, simply return the 1st option.
|
||
* Otherwise, search the option list for the next option.
|
||
*/
|
||
if (offset == 0)
|
||
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
|
||
else
|
||
optp = (u_int8_t *)extbuf + offset;
|
||
/* Find the next option skipping any padding options. */
|
||
while (optp < lim) {
|
||
switch(*optp) {
|
||
case IP6OPT_PAD1:
|
||
optp++;
|
||
break;
|
||
case IP6OPT_PADN:
|
||
if ((optlen = ip6optlen(optp, lim)) == 0)
|
||
goto optend;
|
||
optp += optlen;
|
||
break;
|
||
default: /* found */
|
||
if ((optlen = ip6optlen(optp, lim)) == 0)
|
||
goto optend;
|
||
*typep = *optp;
|
||
*lenp = optlen - 2;
|
||
*databufp = optp + 2;
|
||
return (optp + optlen - (u_int8_t *)extbuf);
|
||
}
|
||
}
|
||
optend:
|
||
*databufp = NULL; /* for safety */
|
||
return (-1);
|
||
}
|
||
int
|
||
inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
|
||
socklen_t *lenp, void **databufp)
|
||
{
|
||
u_int8_t *optp, *lim;
|
||
int optlen;
|
||
/* Validate extlen. XXX: is the variable really necessary?? */
|
||
if (extlen == 0 || (extlen % 8))
|
||
return (-1);
|
||
lim = (u_int8_t *)extbuf + extlen;
|
||
/*
|
||
* If this is the first time this function called for this options
|
||
* header, simply return the 1st option.
|
||
* Otherwise, search the option list for the next option.
|
||
*/
|
||
if (offset == 0)
|
||
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
|
||
else
|
||
optp = (u_int8_t *)extbuf + offset;
|
||
/* Find the specified option */
|
||
while (optp < lim) {
|
||
if ((optlen = ip6optlen(optp, lim)) == 0)
|
||
goto optend;
|
||
if (*optp == type) { /* found */
|
||
*lenp = optlen - 2;
|
||
*databufp = optp + 2;
|
||
return (optp + optlen - (u_int8_t *)extbuf);
|
||
}
|
||
optp += optlen;
|
||
}
|
||
optend:
|
||
*databufp = NULL; /* for safety */
|
||
return (-1);
|
||
}
|
||
int
|
||
inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
|
||
{
|
||
/* we can't assume alignment here */
|
||
memcpy(val, (u_int8_t *)databuf + offset, vallen);
|
||
return (offset + vallen);
|
||
}
|
lib/libc/net/rthdr.c Wed May 23 21:42:13 2007 +0300 โ lib/libc/net/rthdr.c Fri May 25 06:12:44 2007 +0300 | ||
---|---|---|
return -1;
|
||
}
|
||
}
|
||
/*
|
||
* RFC3542 (2292bis) API
|
||
*/
|
||
socklen_t
|
||
inet6_rth_space(int type __unused, int segments __unused)
|
||
{
|
||
return (0); /* type not suppported */
|
||
}
|
||
void *
|
||
inet6_rth_init(void *bp __unused, socklen_t bp_len __unused, int type __unused,
|
||
int segments __unused)
|
||
{
|
||
return (NULL); /* type not supported */
|
||
}
|
||
int
|
||
inet6_rth_add(void *bp __unused, const struct in6_addr *addr __unused)
|
||
{
|
||
return (-1); /* type not supported */
|
||
}
|
||
int
|
||
inet6_rth_reverse(const void *in __unused, void *out __unused)
|
||
{
|
||
return (-1); /* type not supported */
|
||
}
|
||
int
|
||
inet6_rth_segments(const void *bp __unused)
|
||
{
|
||
return (-1); /* type not supported */
|
||
}
|
||
struct in6_addr *
|
||
inet6_rth_getaddr(const void *bp __unused, int idx __unused)
|
||
{
|
||
return (NULL); /* type not supported */
|
||
}
|
sys/netinet6/in6.h Wed May 23 21:42:13 2007 +0300 โ sys/netinet6/in6.h Fri May 25 06:12:44 2007 +0300 | ||
---|---|---|
*/
|
||
#define __KAME__
|
||
#define __KAME_VERSION "20010528/FreeBSD"
|
||
#ifndef _SOCKLEN_T_DECLARED
|
||
#define _SOCKLEN_T_DECLARED
|
||
typedef __socklen_t socklen_t;
|
||
#endif
|
||
/*
|
||
* Local port number conventions:
|
||
... | ... | |
int inet6_option_next (const struct cmsghdr *, uint8_t **);
|
||
int inet6_option_space (int);
|
||
int inet6_opt_append (void *, size_t, int, uint8_t, size_t, uint8_t, void **);
|
||
int inet6_opt_find (void *, size_t, int, uint8_t, size_t *, void **);
|
||
int inet6_opt_finish (void *, size_t, int);
|
||
int inet6_opt_get_val (void *, size_t, void *, int);
|
||
int inet6_opt_init (void *, size_t);
|
||
int inet6_opt_next (void *, size_t, int, uint8_t *, size_t *, void **);
|
||
int inet6_opt_set_val (void *, size_t, void *, int);
|
||
int inet6_opt_append (void *, socklen_t, int, uint8_t, size_t, uint8_t, void **);
|
||
int inet6_opt_find (void *, socklen_t, int, uint8_t, size_t *, void **);
|
||
int inet6_opt_finish (void *, socklen_t, int);
|
||
int inet6_opt_get_val (void *, int, void *, socklen_t);
|
||
int inet6_opt_init (void *, socklen_t);
|
||
int inet6_opt_next (void *, socklen_t, int, uint8_t *, socklen_t *, void **);
|
||
int inet6_opt_set_val (void *, int, void *, socklen_t);
|
||
int inet6_rth_add (void *, const struct in6_addr *);
|
||
struct in6_addr *inet6_rth_getaddr (const void *, int);
|
||
void *inet6_rth_init (void *, int, int, int);
|
||
void *inet6_rth_init (void *, socklen_t, int, int);
|
||
int inet6_rth_reverse (const void *, void *);
|
||
int inet6_rth_segments (const void *);
|
||
size_t inet6_rth_space (int, int);
|
||
socklen_t inet6_rth_space (int, int);
|
||
int inet6_rthdr_add (struct cmsghdr *, const struct in6_addr *,
|
||
unsigned int);
|