2008-04-23 10:09:04 +04:00
|
|
|
/* $NetBSD: ip6_output.c,v 1.129 2008/04/23 06:09:05 thorpej Exp $ */
|
2001-03-25 13:58:43 +04:00
|
|
|
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 1982, 1986, 1988, 1990, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1999-06-28 10:36:47 +04:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:56:55 +03:00
|
|
|
#include <sys/cdefs.h>
|
2008-04-23 10:09:04 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.129 2008/04/23 06:09:05 thorpej Exp $");
|
2001-11-13 03:56:55 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include "opt_inet.h"
|
2006-05-05 04:03:21 +04:00
|
|
|
#include "opt_inet6.h"
|
1999-07-10 02:57:15 +04:00
|
|
|
#include "opt_ipsec.h"
|
2000-02-17 13:59:32 +03:00
|
|
|
#include "opt_pfil_hooks.h"
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/proc.h>
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
2000-02-17 13:59:32 +03:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
#include <net/pfil.h>
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
|
|
|
#include <netinet/icmp6.h>
|
2005-08-10 17:08:11 +04:00
|
|
|
#include <netinet/in_offload.h>
|
2006-11-23 22:41:58 +03:00
|
|
|
#include <netinet6/in6_offload.h>
|
2000-01-06 09:41:18 +03:00
|
|
|
#include <netinet6/ip6_var.h>
|
2008-04-15 07:57:04 +04:00
|
|
|
#include <netinet6/ip6_private.h>
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <netinet6/in6_pcb.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/nd6.h>
|
2004-02-04 08:17:28 +03:00
|
|
|
#include <netinet6/ip6protosw.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef IPSEC
|
|
|
|
#include <netinet6/ipsec.h>
|
2008-04-23 10:09:04 +04:00
|
|
|
#include <netinet6/ipsec_private.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netkey/key.h>
|
|
|
|
#endif /* IPSEC */
|
|
|
|
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
#include <netipsec/ipsec.h>
|
|
|
|
#include <netipsec/ipsec6.h>
|
|
|
|
#include <netipsec/key.h>
|
|
|
|
#include <netipsec/xform.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
|
|
|
|
Restructure the PFIL_HOOKS mechanism a bit:
- All packets are passed to PFIL_HOOKS as they come off the wire, i.e.
fields in protocol headers in network order, etc.
- Allow for multiple hooks to be registered, using a "key" and a "dlt".
The "dlt" is a BPF data link type, indicating what type of header is
present.
- INET and INET6 register with key == AF_INET or AF_INET6, and
dlt == DLT_RAW.
- PFIL_HOOKS now take an argument for the filter hook, and mbuf **,
an ifnet *, and a direction (PFIL_IN or PFIL_OUT), thus making them
less IP (really, IP Filter) centric.
Maintain compatibility with IP Filter by adding wrapper functions for
IP Filter.
2000-11-11 03:52:36 +03:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
extern struct pfil_head inet6_pfil_hook; /* XXX */
|
|
|
|
#endif
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip6_exthdrs {
|
|
|
|
struct mbuf *ip6e_ip6;
|
|
|
|
struct mbuf *ip6e_hbh;
|
|
|
|
struct mbuf *ip6e_dest1;
|
|
|
|
struct mbuf *ip6e_rthdr;
|
|
|
|
struct mbuf *ip6e_dest2;
|
|
|
|
};
|
|
|
|
|
2007-11-01 23:33:56 +03:00
|
|
|
static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **,
|
|
|
|
int, int);
|
|
|
|
static int ip6_getpcbopt(struct ip6_pktopts *, int, struct mbuf **);
|
|
|
|
static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, int,
|
|
|
|
int, int, int);
|
|
|
|
static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
|
|
|
|
static int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf **);
|
|
|
|
static int ip6_copyexthdr(struct mbuf **, void *, int);
|
|
|
|
static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
|
|
|
|
struct ip6_frag **);
|
|
|
|
static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
|
|
|
|
static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
static int ip6_getpmtu(struct route *, struct route *, struct ifnet *,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct in6_addr *, u_long *, int *);
|
2007-11-01 23:33:56 +03:00
|
|
|
static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
|
2006-05-05 04:03:21 +04:00
|
|
|
|
|
|
|
#ifdef RFC2292
|
2007-11-01 23:33:56 +03:00
|
|
|
static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *,
|
|
|
|
struct socket *);
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2005-08-10 17:08:11 +04:00
|
|
|
#define IN6_NEED_CHECKSUM(ifp, csum_flags) \
|
|
|
|
(__predict_true(((ifp)->if_flags & IFF_LOOPBACK) == 0 || \
|
|
|
|
(((csum_flags) & M_CSUM_UDPv6) != 0 && udp_do_loopback_cksum) || \
|
|
|
|
(((csum_flags) & M_CSUM_TCPv6) != 0 && tcp_do_loopback_cksum)))
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IP6 output. The packet in mbuf chain m contains a skeletal IP6
|
|
|
|
* header (with pri, len, nxt, hlim, src, dst).
|
|
|
|
* This function may modify ver and hlim only.
|
|
|
|
* The mbuf chain containing the packet will be freed.
|
|
|
|
* The mbuf opt, if present, will not be freed.
|
2002-06-07 21:13:56 +04:00
|
|
|
*
|
|
|
|
* type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
|
|
|
|
* nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one,
|
|
|
|
* which is rt_rmx.rmx_mtu.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
int
|
2006-10-12 05:30:41 +04:00
|
|
|
ip6_output(
|
|
|
|
struct mbuf *m0,
|
|
|
|
struct ip6_pktopts *opt,
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route *ro,
|
2006-10-12 05:30:41 +04:00
|
|
|
int flags,
|
|
|
|
struct ip6_moptions *im6o,
|
2006-11-16 04:32:37 +03:00
|
|
|
struct socket *so,
|
2006-10-12 05:30:41 +04:00
|
|
|
struct ifnet **ifpp /* XXX: just for statistics */
|
|
|
|
)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6, *mhip6;
|
2000-05-19 05:40:18 +04:00
|
|
|
struct ifnet *ifp, *origifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m = m0;
|
|
|
|
int hlen, tlen, len, off;
|
2007-02-22 01:59:35 +03:00
|
|
|
bool tso;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route ip6route;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct rtentry *rt = NULL;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
const struct sockaddr_in6 *dst = NULL;
|
|
|
|
struct sockaddr_in6 src_sa, dst_sa;
|
1999-06-28 10:36:47 +04:00
|
|
|
int error = 0;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct in6_ifaddr *ia = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
u_long mtu;
|
2004-02-04 08:17:28 +03:00
|
|
|
int alwaysfrag, dontfrag;
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
|
|
|
|
struct ip6_exthdrs exthdrs;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct in6_addr finaldst, src0, dst0;
|
|
|
|
u_int32_t zone;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route *ro_pmtu = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
int hdrsplit = 0;
|
|
|
|
int needipsec = 0;
|
|
|
|
#ifdef IPSEC
|
|
|
|
int needipsectun = 0;
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int s;
|
|
|
|
#endif
|
|
|
|
|
2007-12-20 22:53:29 +03:00
|
|
|
memset(&ip6route, 0, sizeof(ip6route));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-07-12 17:11:27 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if ((m->m_flags & M_PKTHDR) == 0)
|
|
|
|
panic("ip6_output: no HDR");
|
|
|
|
|
|
|
|
if ((m->m_pkthdr.csum_flags &
|
|
|
|
(M_CSUM_TCPv4|M_CSUM_UDPv4|M_CSUM_TSOv4)) != 0) {
|
|
|
|
panic("ip6_output: IPv4 checksum offload flags: %d",
|
|
|
|
m->m_pkthdr.csum_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) ==
|
|
|
|
(M_CSUM_TCPv6|M_CSUM_UDPv6)) {
|
|
|
|
panic("ip6_output: conflicting checksum offload flags: %d",
|
|
|
|
m->m_pkthdr.csum_flags);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-08-10 16:58:37 +04:00
|
|
|
M_CSUM_DATA_IPv6_HL_SET(m->m_pkthdr.csum_data, sizeof(struct ip6_hdr));
|
|
|
|
|
2000-06-03 18:36:32 +04:00
|
|
|
#define MAKE_EXTHDR(hp, mp) \
|
|
|
|
do { \
|
1999-06-28 10:36:47 +04:00
|
|
|
if (hp) { \
|
|
|
|
struct ip6_ext *eh = (struct ip6_ext *)(hp); \
|
2007-03-04 08:59:00 +03:00
|
|
|
error = ip6_copyexthdr((mp), (void *)(hp), \
|
2002-06-07 18:29:10 +04:00
|
|
|
((eh)->ip6e_len + 1) << 3); \
|
1999-06-28 10:36:47 +04:00
|
|
|
if (error) \
|
|
|
|
goto freehdrs; \
|
|
|
|
} \
|
2002-11-02 10:30:55 +03:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
2002-06-07 18:48:56 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
bzero(&exthdrs, sizeof(exthdrs));
|
|
|
|
if (opt) {
|
|
|
|
/* Hop-by-Hop options header */
|
|
|
|
MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
|
|
|
|
/* Destination options header(1st part) */
|
|
|
|
MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
|
|
|
|
/* Routing header */
|
|
|
|
MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
|
|
|
|
/* Destination options header(2nd part) */
|
|
|
|
MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef IPSEC
|
2004-01-19 08:14:58 +03:00
|
|
|
if ((flags & IPV6_FORWARDING) != 0) {
|
|
|
|
needipsec = 0;
|
|
|
|
goto skippolicycheck;
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* get a security policy for this packet */
|
|
|
|
if (so == NULL)
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
|
2004-03-02 05:28:28 +03:00
|
|
|
else {
|
|
|
|
if (IPSEC_PCB_SKIP_IPSEC(sotoinpcb_hdr(so)->inph_sp,
|
|
|
|
IPSEC_DIR_OUTBOUND)) {
|
|
|
|
needipsec = 0;
|
|
|
|
goto skippolicycheck;
|
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
|
2004-03-02 05:28:28 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (sp == NULL) {
|
2008-04-23 10:09:04 +04:00
|
|
|
IPSEC6_STATINC(IPSEC_STAT_OUT_INVAL);
|
2000-06-20 06:24:42 +04:00
|
|
|
goto freehdrs;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
/* check policy */
|
|
|
|
switch (sp->policy) {
|
|
|
|
case IPSEC_POLICY_DISCARD:
|
|
|
|
/*
|
|
|
|
* This packet is just discarded.
|
|
|
|
*/
|
2008-04-23 10:09:04 +04:00
|
|
|
IPSEC6_STATINC(IPSEC_STAT_OUT_POLVIO);
|
2000-06-20 06:24:42 +04:00
|
|
|
goto freehdrs;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
/* no need to do IPsec. */
|
|
|
|
needipsec = 0;
|
|
|
|
break;
|
2002-06-07 18:48:56 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
|
|
|
if (sp->req == NULL) {
|
|
|
|
/* XXX should be panic ? */
|
|
|
|
printf("ip6_output: No IPsec request specified.\n");
|
|
|
|
error = EINVAL;
|
2000-06-20 06:24:42 +04:00
|
|
|
goto freehdrs;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
needipsec = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
|
|
|
default:
|
|
|
|
printf("ip6_output: Invalid policy found. %d\n", sp->policy);
|
|
|
|
}
|
2004-01-19 08:14:58 +03:00
|
|
|
|
|
|
|
skippolicycheck:;
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif /* IPSEC */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the total length of the extension header chain.
|
|
|
|
* Keep the length of the unfragmentable part for fragmentation.
|
|
|
|
*/
|
1999-12-13 18:17:17 +03:00
|
|
|
optlen = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len;
|
|
|
|
if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len;
|
|
|
|
if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len;
|
1999-12-13 18:17:17 +03:00
|
|
|
unfragpartlen = optlen + sizeof(struct ip6_hdr);
|
1999-06-28 10:36:47 +04:00
|
|
|
/* NOTE: we don't add AH/ESP length here. do that later. */
|
|
|
|
if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len;
|
|
|
|
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
/* Check the security policy (SP) for the packet */
|
|
|
|
|
|
|
|
/* XXX For moment, we doesn't support packet with extented action */
|
|
|
|
if (optlen !=0)
|
|
|
|
goto freehdrs;
|
|
|
|
|
|
|
|
sp = ipsec6_check_policy(m,so,flags,&needipsec,&error);
|
|
|
|
if (error != 0) {
|
|
|
|
/*
|
|
|
|
* Hack: -EINVAL is used to signal that a packet
|
|
|
|
* should be silently discarded. This is typically
|
|
|
|
* because we asked key management for an SA and
|
|
|
|
* it was delayed (e.g. kicked up to IKE).
|
|
|
|
*/
|
|
|
|
if (error == -EINVAL)
|
|
|
|
error = 0;
|
|
|
|
goto freehdrs;
|
|
|
|
}
|
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
|
|
|
|
|
|
|
if (needipsec &&
|
|
|
|
(m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
|
|
|
|
in6_delayed_cksum(m);
|
|
|
|
m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* If we need IPsec, or there is at least one extension header,
|
|
|
|
* separate IP6 header from the payload.
|
|
|
|
*/
|
|
|
|
if ((needipsec || optlen) && !hdrsplit) {
|
|
|
|
if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
|
|
|
|
m = NULL;
|
|
|
|
goto freehdrs;
|
|
|
|
}
|
|
|
|
m = exthdrs.ip6e_ip6;
|
|
|
|
hdrsplit++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust pointer */
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
|
|
|
|
/* adjust mbuf packet header length */
|
|
|
|
m->m_pkthdr.len += optlen;
|
|
|
|
plen = m->m_pkthdr.len - sizeof(*ip6);
|
|
|
|
|
|
|
|
/* If this is a jumbo payload, insert a jumbo payload option. */
|
|
|
|
if (plen > IPV6_MAXPACKET) {
|
|
|
|
if (!hdrsplit) {
|
|
|
|
if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
|
|
|
|
m = NULL;
|
|
|
|
goto freehdrs;
|
|
|
|
}
|
|
|
|
m = exthdrs.ip6e_ip6;
|
|
|
|
hdrsplit++;
|
|
|
|
}
|
|
|
|
/* adjust pointer */
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
|
|
|
|
goto freehdrs;
|
2005-08-10 16:58:37 +04:00
|
|
|
optlen += 8; /* XXX JUMBOOPTLEN */
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6->ip6_plen = 0;
|
|
|
|
} else
|
|
|
|
ip6->ip6_plen = htons(plen);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Concatenate headers and fill in next header fields.
|
|
|
|
* Here we have, on "m"
|
1999-12-13 18:17:17 +03:00
|
|
|
* IPv6 payload
|
1999-06-28 10:36:47 +04:00
|
|
|
* and we insert headers accordingly. Finally, we should be getting:
|
|
|
|
* IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
|
1999-12-13 18:17:17 +03:00
|
|
|
*
|
|
|
|
* during the header composing process, "m" points to IPv6 header.
|
|
|
|
* "mprev" points to an extension header prior to esp.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
u_char *nexthdrp = &ip6->ip6_nxt;
|
|
|
|
struct mbuf *mprev = m;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we treat dest2 specially. this makes IPsec processing
|
2004-02-04 08:17:28 +03:00
|
|
|
* much easier. the goal here is to make mprev point the
|
|
|
|
* mbuf prior to dest2.
|
1999-12-13 18:17:17 +03:00
|
|
|
*
|
|
|
|
* result: IPv6 dest2 payload
|
|
|
|
* m and mprev will point to IPv6 header.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
if (exthdrs.ip6e_dest2) {
|
|
|
|
if (!hdrsplit)
|
|
|
|
panic("assumption failed: hdr not split");
|
1999-12-13 18:17:17 +03:00
|
|
|
exthdrs.ip6e_dest2->m_next = m->m_next;
|
|
|
|
m->m_next = exthdrs.ip6e_dest2;
|
1999-06-28 10:36:47 +04:00
|
|
|
*mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
|
|
|
|
ip6->ip6_nxt = IPPROTO_DSTOPTS;
|
|
|
|
}
|
|
|
|
|
2000-06-03 18:36:32 +04:00
|
|
|
#define MAKE_CHAIN(m, mp, p, i)\
|
|
|
|
do {\
|
1999-06-28 10:36:47 +04:00
|
|
|
if (m) {\
|
|
|
|
if (!hdrsplit) \
|
|
|
|
panic("assumption failed: hdr not split"); \
|
|
|
|
*mtod((m), u_char *) = *(p);\
|
|
|
|
*(p) = (i);\
|
|
|
|
p = mtod((m), u_char *);\
|
|
|
|
(m)->m_next = (mp)->m_next;\
|
|
|
|
(mp)->m_next = (m);\
|
|
|
|
(mp) = (m);\
|
|
|
|
}\
|
2002-11-02 10:30:55 +03:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* result: IPv6 hbh dest1 rthdr dest2 payload
|
|
|
|
* m will point to IPv6 header. mprev will point to the
|
|
|
|
* extension header prior to dest2 (rthdr in the above case).
|
|
|
|
*/
|
2002-06-07 18:29:10 +04:00
|
|
|
MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS);
|
|
|
|
MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp,
|
|
|
|
IPPROTO_DSTOPTS);
|
|
|
|
MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp,
|
|
|
|
IPPROTO_ROUTING);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2005-08-10 16:58:37 +04:00
|
|
|
M_CSUM_DATA_IPv6_HL_SET(m->m_pkthdr.csum_data,
|
|
|
|
sizeof(struct ip6_hdr) + optlen);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
if (!needipsec)
|
|
|
|
goto skip_ipsec2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pointers after IPsec headers are not valid any more.
|
|
|
|
* other pointers need a great care too.
|
|
|
|
* (IPsec routines should not mangle mbufs prior to AH/ESP)
|
|
|
|
*/
|
|
|
|
exthdrs.ip6e_dest2 = NULL;
|
|
|
|
|
|
|
|
{
|
|
|
|
struct ip6_rthdr *rh = NULL;
|
|
|
|
int segleft_org = 0;
|
|
|
|
struct ipsec_output_state state;
|
|
|
|
|
|
|
|
if (exthdrs.ip6e_rthdr) {
|
|
|
|
rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
|
|
|
|
segleft_org = rh->ip6r_segleft;
|
|
|
|
rh->ip6r_segleft = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bzero(&state, sizeof(state));
|
|
|
|
state.m = m;
|
|
|
|
error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags,
|
2004-02-04 08:17:28 +03:00
|
|
|
&needipsectun);
|
1999-06-28 10:36:47 +04:00
|
|
|
m = state.m;
|
|
|
|
if (error) {
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
|
1999-06-28 10:36:47 +04:00
|
|
|
/* mbuf is already reclaimed in ipsec6_output_trans. */
|
|
|
|
m = NULL;
|
|
|
|
switch (error) {
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETUNREACH:
|
|
|
|
case EMSGSIZE:
|
|
|
|
case ENOBUFS:
|
|
|
|
case ENOMEM:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("ip6_output (ipsec): error code %d\n", error);
|
2002-06-07 08:18:11 +04:00
|
|
|
/* FALLTHROUGH */
|
1999-06-28 10:36:47 +04:00
|
|
|
case ENOENT:
|
|
|
|
/* don't show these error codes to the user */
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (exthdrs.ip6e_rthdr) {
|
|
|
|
/* ah6_output doesn't modify mbuf chain */
|
|
|
|
rh->ip6r_segleft = segleft_org;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_ipsec2:;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is a routing header, replace destination address field
|
|
|
|
* with the first hop of the routing header.
|
|
|
|
*/
|
|
|
|
if (exthdrs.ip6e_rthdr) {
|
2002-06-07 18:29:10 +04:00
|
|
|
struct ip6_rthdr *rh;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip6_rthdr0 *rh0;
|
2003-06-06 12:13:43 +04:00
|
|
|
struct in6_addr *addr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct sockaddr_in6 sa;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-07 18:29:10 +04:00
|
|
|
rh = (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr,
|
|
|
|
struct ip6_rthdr *));
|
1999-06-28 10:36:47 +04:00
|
|
|
finaldst = ip6->ip6_dst;
|
2001-02-10 07:14:26 +03:00
|
|
|
switch (rh->ip6r_type) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPV6_RTHDR_TYPE_0:
|
|
|
|
rh0 = (struct ip6_rthdr0 *)rh;
|
2003-06-06 12:13:43 +04:00
|
|
|
addr = (struct in6_addr *)(rh0 + 1);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* construct a sockaddr_in6 form of
|
|
|
|
* the first hop.
|
|
|
|
*
|
|
|
|
* XXX: we may not have enough
|
|
|
|
* information about its scope zone;
|
|
|
|
* there is no standard API to pass
|
|
|
|
* the information from the
|
|
|
|
* application.
|
|
|
|
*/
|
2007-11-07 02:48:24 +03:00
|
|
|
sockaddr_in6_init(&sa, addr, 0, 0, 0);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if ((error = sa6_embedscope(&sa,
|
|
|
|
ip6_use_defzone)) != 0) {
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip6->ip6_dst = sa.sin6_addr;
|
2005-09-24 01:21:58 +04:00
|
|
|
(void)memmove(&addr[0], &addr[1],
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
sizeof(struct in6_addr) *
|
|
|
|
(rh0->ip6r0_segleft - 1));
|
2003-06-06 12:13:43 +04:00
|
|
|
addr[rh0->ip6r0_segleft - 1] = finaldst;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/* XXX */
|
|
|
|
in6_clearscope(addr + rh0->ip6r0_segleft - 1);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
default: /* is it possible? */
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Source address validation */
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
|
2002-06-09 01:22:29 +04:00
|
|
|
(flags & IPV6_UNSPECSRC) == 0) {
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EOPNOTSUPP;
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_BADSCOPE);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
|
|
|
|
error = EOPNOTSUPP;
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_BADSCOPE);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_LOCALOUT);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Route packet.
|
|
|
|
*/
|
2004-02-04 08:17:28 +03:00
|
|
|
/* initialize cached route */
|
2007-01-29 09:13:58 +03:00
|
|
|
if (ro == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ro = &ip6route;
|
|
|
|
}
|
|
|
|
ro_pmtu = ro;
|
|
|
|
if (opt && opt->ip6po_rthdr)
|
|
|
|
ro = &opt->ip6po_route;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if specified, try to fill in the traffic class field.
|
|
|
|
* do not override if a non-zero value is already set.
|
|
|
|
* we check the diffserv field and the ecn field separately.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (opt && opt->ip6po_tclass >= 0) {
|
|
|
|
int mask = 0;
|
|
|
|
|
|
|
|
if ((ip6->ip6_flow & htonl(0xfc << 20)) == 0)
|
|
|
|
mask |= 0xfc;
|
|
|
|
if ((ip6->ip6_flow & htonl(0x03 << 20)) == 0)
|
|
|
|
mask |= 0x03;
|
|
|
|
if (mask != 0)
|
|
|
|
ip6->ip6_flow |= htonl((opt->ip6po_tclass & mask) << 20);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/* fill in or override the hop limit field, if necessary. */
|
|
|
|
if (opt && opt->ip6po_hlim != -1)
|
|
|
|
ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
|
|
|
|
else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
|
|
|
if (im6o != NULL)
|
|
|
|
ip6->ip6_hlim = im6o->im6o_multicast_hlim;
|
|
|
|
else
|
|
|
|
ip6->ip6_hlim = ip6_defmcasthlim;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
if (needipsec && needipsectun) {
|
|
|
|
struct ipsec_output_state state;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All the extension headers will become inaccessible
|
|
|
|
* (since they can be encrypted).
|
|
|
|
* Don't panic, we need no more updates to extension headers
|
|
|
|
* on inner IPv6 packet (since they are now encapsulated).
|
|
|
|
*
|
|
|
|
* IPv6 [ESP|AH] IPv6 [extension headers] payload
|
|
|
|
*/
|
|
|
|
bzero(&exthdrs, sizeof(exthdrs));
|
|
|
|
exthdrs.ip6e_ip6 = m;
|
|
|
|
|
|
|
|
bzero(&state, sizeof(state));
|
|
|
|
state.m = m;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
state.ro = ro;
|
|
|
|
state.dst = rtcache_getdst(ro);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
error = ipsec6_output_tunnel(&state, sp, flags);
|
|
|
|
|
|
|
|
m = state.m;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
ro_pmtu = ro = state.ro;
|
|
|
|
dst = satocsin6(state.dst);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (error) {
|
|
|
|
/* mbuf is already reclaimed in ipsec6_output_tunnel. */
|
|
|
|
m0 = m = NULL;
|
|
|
|
m = NULL;
|
|
|
|
switch (error) {
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETUNREACH:
|
|
|
|
case EMSGSIZE:
|
|
|
|
case ENOBUFS:
|
|
|
|
case ENOMEM:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("ip6_output (ipsec): error code %d\n", error);
|
2002-06-07 08:18:11 +04:00
|
|
|
/* FALLTHROUGH */
|
1999-06-28 10:36:47 +04:00
|
|
|
case ENOENT:
|
|
|
|
/* don't show these error codes to the user */
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
exthdrs.ip6e_ip6 = m;
|
|
|
|
}
|
2001-10-24 10:36:37 +04:00
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
if (needipsec) {
|
|
|
|
s = splsoftnet();
|
|
|
|
error = ipsec6_process_packet(m,sp->req);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Preserve KAME behaviour: ENOENT can be returned
|
|
|
|
* when an SA acquire is in progress. Don't propagate
|
|
|
|
* this to user-level; it confuses applications.
|
|
|
|
* XXX this will go away when the SADB is redone.
|
|
|
|
*/
|
|
|
|
if (error == ENOENT)
|
|
|
|
error = 0;
|
|
|
|
splx(s);
|
|
|
|
goto done;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
}
|
2007-02-10 12:43:05 +03:00
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/* adjust pointer */
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2007-11-07 02:48:24 +03:00
|
|
|
sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if ((error = in6_selectroute(&dst_sa, opt, im6o, ro,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
&ifp, &rt, 0)) != 0) {
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (ifp != NULL)
|
|
|
|
in6_ifstat_inc(ifp, ifs6_out_discard);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (rt == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
* If in6_selectroute() does not return a route entry,
|
|
|
|
* dst may not have been updated.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_setdst(ro, sin6tosa(&dst_sa));
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* then rt (for unicast) and ifp must be non-NULL valid values.
|
|
|
|
*/
|
|
|
|
if ((flags & IPV6_FORWARDING) == 0) {
|
|
|
|
/* XXX: the FORWARDING flag can be set for mrouting. */
|
|
|
|
in6_ifstat_inc(ifp, ifs6_out_request);
|
|
|
|
}
|
|
|
|
if (rt != NULL) {
|
|
|
|
ia = (struct in6_ifaddr *)(rt->rt_ifa);
|
|
|
|
rt->rt_use++;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* The outgoing interface must be in the zone of source and
|
|
|
|
* destination addresses. We should use ia_ifp to support the
|
|
|
|
* case of sending packets to an address of our own.
|
|
|
|
*/
|
|
|
|
if (ia != NULL && ia->ia_ifp)
|
|
|
|
origifp = ia->ia_ifp;
|
|
|
|
else
|
|
|
|
origifp = ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
src0 = ip6->ip6_src;
|
|
|
|
if (in6_setscope(&src0, origifp, &zone))
|
|
|
|
goto badscope;
|
2007-11-07 02:48:24 +03:00
|
|
|
sockaddr_in6_init(&src_sa, &ip6->ip6_src, 0, 0, 0);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (sa6_recoverscope(&src_sa) || zone != src_sa.sin6_scope_id)
|
|
|
|
goto badscope;
|
|
|
|
|
|
|
|
dst0 = ip6->ip6_dst;
|
|
|
|
if (in6_setscope(&dst0, origifp, &zone))
|
|
|
|
goto badscope;
|
|
|
|
/* re-initialize to be sure */
|
2007-11-07 02:48:24 +03:00
|
|
|
sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (sa6_recoverscope(&dst_sa) || zone != dst_sa.sin6_scope_id)
|
|
|
|
goto badscope;
|
|
|
|
|
|
|
|
/* scope check is done. */
|
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if (rt == NULL || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
|
|
|
if (dst == NULL)
|
|
|
|
dst = satocsin6(rtcache_getdst(ro));
|
|
|
|
KASSERT(dst != NULL);
|
2008-01-14 07:16:45 +03:00
|
|
|
} else if (opt && rtcache_validate(&opt->ip6po_nextroute) != NULL) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
/*
|
|
|
|
* The nexthop is explicitly specified by the
|
|
|
|
* application. We assume the next hop is an IPv6
|
|
|
|
* address.
|
|
|
|
*/
|
|
|
|
dst = (struct sockaddr_in6 *)opt->ip6po_nexthop;
|
|
|
|
} else if ((rt->rt_flags & RTF_GATEWAY))
|
|
|
|
dst = (struct sockaddr_in6 *)rt->rt_gateway;
|
|
|
|
else if (dst == NULL)
|
|
|
|
dst = satocsin6(rtcache_getdst(ro));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* XXXXXX: original code follows:
|
|
|
|
*/
|
|
|
|
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
|
|
|
|
m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
|
|
|
|
else {
|
|
|
|
struct in6_multi *in6m;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
in6_ifstat_inc(ifp, ifs6_out_mcast);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Confirm that the outgoing interface supports multicast.
|
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (!(ifp->if_flags & IFF_MULTICAST)) {
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_NOROUTE);
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(ifp, ifs6_out_discard);
|
1999-06-28 10:36:47 +04:00
|
|
|
error = ENETUNREACH;
|
|
|
|
goto bad;
|
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
|
|
|
|
if (in6m != NULL &&
|
|
|
|
(im6o == NULL || im6o->im6o_multicast_loop)) {
|
|
|
|
/*
|
|
|
|
* If we belong to the destination multicast group
|
|
|
|
* on the outgoing interface, and the caller did not
|
|
|
|
* forbid loopback, loop back a copy.
|
|
|
|
*/
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
KASSERT(dst != NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6_mloopback(ifp, m, dst);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If we are acting as a multicast router, perform
|
|
|
|
* multicast forwarding as if the packet had just
|
|
|
|
* arrived on the interface to which we are about
|
|
|
|
* to send. The multicast forwarding function
|
|
|
|
* recursively calls this function, using the
|
|
|
|
* IPV6_FORWARDING flag to prevent infinite recursion.
|
|
|
|
*
|
|
|
|
* Multicasts that are looped back by ip6_mloopback(),
|
|
|
|
* above, will be forwarded by the ip6_input() routine,
|
|
|
|
* if necessary.
|
|
|
|
*/
|
|
|
|
if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
|
2000-05-19 08:34:39 +04:00
|
|
|
if (ip6_mforward(ip6, ifp, m) != 0) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Multicasts with a hoplimit of zero may be looped back,
|
|
|
|
* above, but must not be transmitted on a network.
|
|
|
|
* Also, multicasts addressed to the loopback interface
|
|
|
|
* are not sent -- the above call to ip6_mloopback() will
|
|
|
|
* loop back a copy if this host actually belongs to the
|
|
|
|
* destination group on the loopback interface.
|
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) ||
|
|
|
|
IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Fill the outgoing inteface to tell the upper layer
|
|
|
|
* to increment per-interface statistics.
|
|
|
|
*/
|
|
|
|
if (ifpp)
|
|
|
|
*ifpp = ifp;
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
/* Determine path MTU. */
|
2004-02-04 08:17:28 +03:00
|
|
|
if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
|
|
|
|
&alwaysfrag)) != 0)
|
2002-05-29 11:53:39 +04:00
|
|
|
goto bad;
|
2004-07-14 07:06:08 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
if (needipsectun)
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
#endif
|
2002-05-29 11:53:39 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2002-05-29 11:53:39 +04:00
|
|
|
* The caller of this function may specify to use the minimum MTU
|
|
|
|
* in some cases.
|
2006-05-05 04:03:21 +04:00
|
|
|
* An advanced API option (IPV6_USE_MIN_MTU) can also override MTU
|
|
|
|
* setting. The logic is a bit complicated; by default, unicast
|
|
|
|
* packets will follow path MTU while multicast packets will be sent at
|
|
|
|
* the minimum MTU. If IP6PO_MINMTU_ALL is specified, all packets
|
|
|
|
* including unicast ones will be sent at the minimum MTU. Multicast
|
|
|
|
* packets will always be sent at the minimum MTU unless
|
|
|
|
* IP6PO_MINMTU_DISABLE is explicitly specified.
|
|
|
|
* See RFC 3542 for more details.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-05-29 11:53:39 +04:00
|
|
|
if (mtu > IPV6_MMTU) {
|
|
|
|
if ((flags & IPV6_MINMTU))
|
|
|
|
mtu = IPV6_MMTU;
|
2006-05-05 04:03:21 +04:00
|
|
|
else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL)
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
|
|
|
|
(opt == NULL ||
|
|
|
|
opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) {
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
}
|
2001-12-20 10:26:36 +03:00
|
|
|
}
|
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* clear embedded scope identifiers if necessary.
|
|
|
|
* in6_clearscope will touch the addresses only when necessary.
|
|
|
|
*/
|
|
|
|
in6_clearscope(&ip6->ip6_src);
|
|
|
|
in6_clearscope(&ip6->ip6_dst);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the outgoing packet contains a hop-by-hop options header,
|
|
|
|
* it must be examined and processed even by the source node.
|
|
|
|
* (RFC 2460, section 4.)
|
|
|
|
*/
|
|
|
|
if (exthdrs.ip6e_hbh) {
|
2001-02-10 07:14:26 +03:00
|
|
|
struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
|
1999-07-22 07:59:42 +04:00
|
|
|
u_int32_t dummy1; /* XXX unused */
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int32_t dummy2; /* XXX unused */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: if we have to send an ICMPv6 error to the sender,
|
|
|
|
* we need the M_LOOP flag since icmp6_error() expects
|
|
|
|
* the IPv6 and the hop-by-hop options header are
|
|
|
|
* continuous unless the flag is set.
|
|
|
|
*/
|
|
|
|
m->m_flags |= M_LOOP;
|
|
|
|
m->m_pkthdr.rcvif = ifp;
|
2002-06-07 18:29:10 +04:00
|
|
|
if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1),
|
|
|
|
((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh),
|
|
|
|
&dummy1, &dummy2) < 0) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/* m was already freed at this point */
|
|
|
|
error = EINVAL;/* better error? */
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
m->m_flags &= ~M_LOOP; /* XXX */
|
|
|
|
m->m_pkthdr.rcvif = NULL;
|
|
|
|
}
|
|
|
|
|
2000-02-17 13:59:32 +03:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
/*
|
|
|
|
* Run through list of hooks for output packets.
|
|
|
|
*/
|
2002-06-07 18:29:10 +04:00
|
|
|
if ((error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT)) != 0)
|
Restructure the PFIL_HOOKS mechanism a bit:
- All packets are passed to PFIL_HOOKS as they come off the wire, i.e.
fields in protocol headers in network order, etc.
- Allow for multiple hooks to be registered, using a "key" and a "dlt".
The "dlt" is a BPF data link type, indicating what type of header is
present.
- INET and INET6 register with key == AF_INET or AF_INET6, and
dlt == DLT_RAW.
- PFIL_HOOKS now take an argument for the filter hook, and mbuf **,
an ifnet *, and a direction (PFIL_IN or PFIL_OUT), thus making them
less IP (really, IP Filter) centric.
Maintain compatibility with IP Filter by adding wrapper functions for
IP Filter.
2000-11-11 03:52:36 +03:00
|
|
|
goto done;
|
|
|
|
if (m == NULL)
|
|
|
|
goto done;
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
2000-02-17 13:59:32 +03:00
|
|
|
#endif /* PFIL_HOOKS */
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Send the packet to the outgoing interface.
|
2000-05-19 05:40:18 +04:00
|
|
|
* If necessary, do IPv6 fragmentation before sending.
|
2004-02-04 08:17:28 +03:00
|
|
|
*
|
|
|
|
* the logic here is rather complex:
|
|
|
|
* 1: normal case (dontfrag == 0, alwaysfrag == 0)
|
|
|
|
* 1-a: send as is if tlen <= path mtu
|
|
|
|
* 1-b: fragment if tlen > path mtu
|
|
|
|
*
|
|
|
|
* 2: if user asks us not to fragment (dontfrag == 1)
|
|
|
|
* 2-a: send as is if tlen <= interface mtu
|
|
|
|
* 2-b: error if tlen > interface mtu
|
|
|
|
*
|
|
|
|
* 3: if we always need to attach fragment header (alwaysfrag == 1)
|
|
|
|
* always fragment
|
|
|
|
*
|
|
|
|
* 4: if dontfrag == 1 && alwaysfrag == 1
|
|
|
|
* error, as we cannot handle this conflicting request
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
tlen = m->m_pkthdr.len;
|
2006-11-23 22:41:58 +03:00
|
|
|
tso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv6) != 0;
|
2006-05-05 04:03:21 +04:00
|
|
|
if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
|
|
|
|
dontfrag = 1;
|
|
|
|
else
|
|
|
|
dontfrag = 0;
|
|
|
|
|
2004-02-04 08:17:28 +03:00
|
|
|
if (dontfrag && alwaysfrag) { /* case 4 */
|
|
|
|
/* conflicting request - can't transmit */
|
|
|
|
error = EMSGSIZE;
|
|
|
|
goto bad;
|
|
|
|
}
|
2006-11-23 22:41:58 +03:00
|
|
|
if (dontfrag && (!tso && tlen > IN6_LINKMTU(ifp))) { /* case 2-b */
|
2004-02-04 08:17:28 +03:00
|
|
|
/*
|
|
|
|
* Even if the DONTFRAG option is specified, we cannot send the
|
|
|
|
* packet when the data length is larger than the MTU of the
|
|
|
|
* outgoing interface.
|
|
|
|
* Notify the error by sending IPV6_PATHMTU ancillary data as
|
|
|
|
* well as returning an error code (the latter is not described
|
|
|
|
* in the API spec.)
|
|
|
|
*/
|
|
|
|
u_int32_t mtu32;
|
|
|
|
struct ip6ctlparam ip6cp;
|
|
|
|
|
|
|
|
mtu32 = (u_int32_t)mtu;
|
|
|
|
bzero(&ip6cp, sizeof(ip6cp));
|
|
|
|
ip6cp.ip6c_cmdarg = (void *)&mtu32;
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
pfctlinput2(PRC_MSGSIZE,
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_getdst(ro_pmtu), &ip6cp);
|
2004-02-04 08:17:28 +03:00
|
|
|
|
|
|
|
error = EMSGSIZE;
|
|
|
|
goto bad;
|
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
|
2004-02-04 08:17:28 +03:00
|
|
|
/*
|
|
|
|
* transmit packet without fragmentation
|
|
|
|
*/
|
2006-11-23 22:41:58 +03:00
|
|
|
if (dontfrag || (!alwaysfrag && (tlen <= mtu || tso))) {
|
|
|
|
/* case 1-a and 2-a */
|
2000-10-23 07:45:25 +04:00
|
|
|
struct in6_ifaddr *ia6;
|
2005-08-10 16:58:37 +04:00
|
|
|
int sw_csum;
|
2004-02-04 08:17:28 +03:00
|
|
|
|
2000-10-23 07:45:25 +04:00
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
|
|
|
|
if (ia6) {
|
2001-12-18 06:04:02 +03:00
|
|
|
/* Record statistics for this interface address. */
|
2004-02-04 08:17:28 +03:00
|
|
|
ia6->ia_ifa.ifa_data.ifad_outbytes += m->m_pkthdr.len;
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
2001-01-24 12:04:15 +03:00
|
|
|
#ifdef IPSEC
|
|
|
|
/* clean ipsec history once it goes out of the node */
|
|
|
|
ipsec_delaux(m);
|
|
|
|
#endif
|
2005-08-10 16:58:37 +04:00
|
|
|
|
|
|
|
sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
|
|
|
|
if ((sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
|
2005-08-10 17:08:11 +04:00
|
|
|
if (IN6_NEED_CHECKSUM(ifp,
|
|
|
|
sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6))) {
|
|
|
|
in6_delayed_cksum(m);
|
|
|
|
}
|
2005-08-10 16:58:37 +04:00
|
|
|
m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
|
|
|
|
}
|
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
KASSERT(dst != NULL);
|
2006-11-23 22:41:58 +03:00
|
|
|
if (__predict_true(!tso ||
|
|
|
|
(ifp->if_capenable & IFCAP_TSOv6) != 0)) {
|
|
|
|
error = nd6_output(ifp, origifp, m, dst, rt);
|
|
|
|
} else {
|
|
|
|
error = ip6_tso_output(ifp, origifp, m, dst, rt);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
goto done;
|
2004-02-04 08:17:28 +03:00
|
|
|
}
|
|
|
|
|
2006-11-23 22:41:58 +03:00
|
|
|
if (tso) {
|
|
|
|
error = EINVAL; /* XXX */
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2004-02-04 08:17:28 +03:00
|
|
|
/*
|
|
|
|
* try to fragment the packet. case 1-b and 3
|
|
|
|
*/
|
|
|
|
if (mtu < IPV6_MMTU) {
|
|
|
|
/* path MTU cannot be less than IPV6_MMTU */
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EMSGSIZE;
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(ifp, ifs6_out_fragfail);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
2004-02-04 08:17:28 +03:00
|
|
|
} else if (ip6->ip6_plen == 0) {
|
|
|
|
/* jumbo payload cannot be fragmented */
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EMSGSIZE;
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(ifp, ifs6_out_fragfail);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
} else {
|
|
|
|
struct mbuf **mnext, *m_frgpart;
|
|
|
|
struct ip6_frag *ip6f;
|
2003-09-06 07:36:30 +04:00
|
|
|
u_int32_t id = htonl(ip6_randomid());
|
1999-06-28 10:36:47 +04:00
|
|
|
u_char nextproto;
|
2006-07-08 23:58:40 +04:00
|
|
|
#if 0 /* see below */
|
2004-02-04 08:17:28 +03:00
|
|
|
struct ip6ctlparam ip6cp;
|
|
|
|
u_int32_t mtu32;
|
2006-07-08 23:58:40 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Too large for the destination or interface;
|
|
|
|
* fragment if possible.
|
|
|
|
* Must be able to put at least 8 bytes per fragment.
|
|
|
|
*/
|
|
|
|
hlen = unfragpartlen;
|
|
|
|
if (mtu > IPV6_MAXPACKET)
|
|
|
|
mtu = IPV6_MAXPACKET;
|
2004-02-04 08:17:28 +03:00
|
|
|
|
2006-07-08 23:58:40 +04:00
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* It is believed this code is a leftover from the
|
|
|
|
* development of the IPV6_RECVPATHMTU sockopt and
|
|
|
|
* associated work to implement RFC3542.
|
|
|
|
* It's not entirely clear what the intent of the API
|
|
|
|
* is at this point, so disable this code for now.
|
|
|
|
* The IPV6_RECVPATHMTU sockopt and/or IPV6_DONTFRAG
|
|
|
|
* will send notifications if the application requests.
|
|
|
|
*/
|
|
|
|
|
2004-02-04 08:17:28 +03:00
|
|
|
/* Notify a proper path MTU to applications. */
|
|
|
|
mtu32 = (u_int32_t)mtu;
|
|
|
|
bzero(&ip6cp, sizeof(ip6cp));
|
|
|
|
ip6cp.ip6c_cmdarg = (void *)&mtu32;
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
pfctlinput2(PRC_MSGSIZE,
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_getdst(ro_pmtu), &ip6cp);
|
2006-07-08 23:58:40 +04:00
|
|
|
#endif
|
2004-02-04 08:17:28 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
|
|
|
|
if (len < 8) {
|
|
|
|
error = EMSGSIZE;
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(ifp, ifs6_out_fragfail);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
mnext = &m->m_nextpkt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change the next header field of the last header in the
|
|
|
|
* unfragmentable part.
|
|
|
|
*/
|
|
|
|
if (exthdrs.ip6e_rthdr) {
|
|
|
|
nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *);
|
|
|
|
*mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else if (exthdrs.ip6e_dest1) {
|
1999-06-28 10:36:47 +04:00
|
|
|
nextproto = *mtod(exthdrs.ip6e_dest1, u_char *);
|
|
|
|
*mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else if (exthdrs.ip6e_hbh) {
|
1999-06-28 10:36:47 +04:00
|
|
|
nextproto = *mtod(exthdrs.ip6e_hbh, u_char *);
|
|
|
|
*mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else {
|
1999-06-28 10:36:47 +04:00
|
|
|
nextproto = ip6->ip6_nxt;
|
|
|
|
ip6->ip6_nxt = IPPROTO_FRAGMENT;
|
|
|
|
}
|
|
|
|
|
2005-08-10 16:58:37 +04:00
|
|
|
if ((m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6))
|
|
|
|
!= 0) {
|
2005-08-10 17:08:11 +04:00
|
|
|
if (IN6_NEED_CHECKSUM(ifp,
|
|
|
|
m->m_pkthdr.csum_flags &
|
|
|
|
(M_CSUM_UDPv6|M_CSUM_TCPv6))) {
|
|
|
|
in6_delayed_cksum(m);
|
|
|
|
}
|
2005-08-10 16:58:37 +04:00
|
|
|
m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Loop through length of segment after first fragment,
|
2001-12-18 06:04:02 +03:00
|
|
|
* make new header and copy data of each part and link onto
|
|
|
|
* chain.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
m0 = m;
|
|
|
|
for (off = hlen; off < tlen; off += len) {
|
2003-09-04 07:07:33 +04:00
|
|
|
struct mbuf *mlast;
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
MGETHDR(m, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (!m) {
|
|
|
|
error = ENOBUFS;
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_ODROPPED);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto sendorfree;
|
|
|
|
}
|
2004-02-04 08:17:28 +03:00
|
|
|
m->m_pkthdr.rcvif = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
m->m_flags = m0->m_flags & M_COPYFLAGS;
|
|
|
|
*mnext = m;
|
|
|
|
mnext = &m->m_nextpkt;
|
|
|
|
m->m_data += max_linkhdr;
|
|
|
|
mhip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
*mhip6 = *ip6;
|
|
|
|
m->m_len = sizeof(*mhip6);
|
2001-12-18 06:04:02 +03:00
|
|
|
error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
|
|
|
|
if (error) {
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_ODROPPED);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto sendorfree;
|
|
|
|
}
|
2003-09-06 03:20:48 +04:00
|
|
|
ip6f->ip6f_offlg = htons((u_int16_t)((off - hlen) & ~7));
|
1999-06-28 10:36:47 +04:00
|
|
|
if (off + len >= tlen)
|
|
|
|
len = tlen - off;
|
|
|
|
else
|
|
|
|
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
|
2003-09-06 03:20:48 +04:00
|
|
|
mhip6->ip6_plen = htons((u_int16_t)(len + hlen +
|
2002-06-07 18:29:10 +04:00
|
|
|
sizeof(*ip6f) - sizeof(struct ip6_hdr)));
|
1999-06-28 10:36:47 +04:00
|
|
|
if ((m_frgpart = m_copy(m0, off, len)) == 0) {
|
|
|
|
error = ENOBUFS;
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_ODROPPED);
|
1999-06-28 10:36:47 +04:00
|
|
|
goto sendorfree;
|
|
|
|
}
|
2003-09-04 07:07:33 +04:00
|
|
|
for (mlast = m; mlast->m_next; mlast = mlast->m_next)
|
|
|
|
;
|
|
|
|
mlast->m_next = m_frgpart;
|
1999-06-28 10:36:47 +04:00
|
|
|
m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
|
|
|
|
m->m_pkthdr.rcvif = (struct ifnet *)0;
|
|
|
|
ip6f->ip6f_reserved = 0;
|
|
|
|
ip6f->ip6f_ident = id;
|
|
|
|
ip6f->ip6f_nxt = nextproto;
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_OFRAGMENTS);
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(ifp, ifs6_out_fragcreat);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
in6_ifstat_inc(ifp, ifs6_out_fragok);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove leading garbages.
|
|
|
|
*/
|
|
|
|
sendorfree:
|
|
|
|
m = m0->m_nextpkt;
|
|
|
|
m0->m_nextpkt = 0;
|
|
|
|
m_freem(m0);
|
|
|
|
for (m0 = m; m; m = m0) {
|
|
|
|
m0 = m->m_nextpkt;
|
|
|
|
m->m_nextpkt = 0;
|
|
|
|
if (error == 0) {
|
2000-10-23 07:45:25 +04:00
|
|
|
struct in6_ifaddr *ia6;
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
|
|
|
|
if (ia6) {
|
2001-12-18 06:04:02 +03:00
|
|
|
/*
|
|
|
|
* Record statistics for this interface
|
|
|
|
* address.
|
|
|
|
*/
|
2000-10-23 07:45:25 +04:00
|
|
|
ia6->ia_ifa.ifa_data.ifad_outbytes +=
|
2004-02-04 08:17:28 +03:00
|
|
|
m->m_pkthdr.len;
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
2001-01-24 12:04:15 +03:00
|
|
|
#ifdef IPSEC
|
|
|
|
/* clean ipsec history once it goes out of the node */
|
|
|
|
ipsec_delaux(m);
|
|
|
|
#endif
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
KASSERT(dst != NULL);
|
2006-05-05 04:03:21 +04:00
|
|
|
error = nd6_output(ifp, origifp, m, dst, rt);
|
2000-05-19 05:40:18 +04:00
|
|
|
} else
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error == 0)
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_FRAGMENTED);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
done:
|
2007-12-20 22:53:29 +03:00
|
|
|
rtcache_free(&ip6route);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef IPSEC
|
|
|
|
if (sp != NULL)
|
|
|
|
key_freesp(sp);
|
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
if (sp != NULL)
|
|
|
|
KEY_FREESP(&sp);
|
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
freehdrs:
|
|
|
|
m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */
|
|
|
|
m_freem(exthdrs.ip6e_dest1);
|
|
|
|
m_freem(exthdrs.ip6e_rthdr);
|
|
|
|
m_freem(exthdrs.ip6e_dest2);
|
2002-06-07 08:18:11 +04:00
|
|
|
/* FALLTHROUGH */
|
1999-06-28 10:36:47 +04:00
|
|
|
bad:
|
|
|
|
m_freem(m);
|
|
|
|
goto done;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
badscope:
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_BADSCOPE);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
in6_ifstat_inc(origifp, ifs6_out_discard);
|
|
|
|
if (error == 0)
|
|
|
|
error = EHOSTUNREACH; /* XXX */
|
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_copyexthdr(struct mbuf **mp, void *hdr, int hlen)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct mbuf *m;
|
|
|
|
|
|
|
|
if (hlen > MCLBYTES)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS); /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
MGET(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (!m)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (hlen > MLEN) {
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
if ((m->m_flags & M_EXT) == 0) {
|
|
|
|
m_free(m);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
m->m_len = hlen;
|
|
|
|
if (hdr)
|
2007-03-04 08:59:00 +03:00
|
|
|
bcopy(hdr, mtod(m, void *), hlen);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
*mp = m;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2005-08-10 16:58:37 +04:00
|
|
|
/*
|
|
|
|
* Process a delayed payload checksum calculation.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
in6_delayed_cksum(struct mbuf *m)
|
|
|
|
{
|
|
|
|
uint16_t csum, offset;
|
|
|
|
|
|
|
|
KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0);
|
|
|
|
KASSERT((~m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0);
|
|
|
|
KASSERT((m->m_pkthdr.csum_flags
|
|
|
|
& (M_CSUM_UDPv4|M_CSUM_TCPv4|M_CSUM_TSOv4)) == 0);
|
|
|
|
|
|
|
|
offset = M_CSUM_DATA_IPv6_HL(m->m_pkthdr.csum_data);
|
|
|
|
csum = in6_cksum(m, 0, offset, m->m_pkthdr.len - offset);
|
|
|
|
if (csum == 0 && (m->m_pkthdr.csum_flags & M_CSUM_UDPv6) != 0) {
|
|
|
|
csum = 0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += M_CSUM_DATA_IPv6_OFFSET(m->m_pkthdr.csum_data);
|
|
|
|
if ((offset + sizeof(csum)) > m->m_len) {
|
|
|
|
m_copyback(m, offset, sizeof(csum), &csum);
|
|
|
|
} else {
|
2007-03-04 08:59:00 +03:00
|
|
|
*(uint16_t *)(mtod(m, char *) + offset) = csum;
|
2005-08-10 16:58:37 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2000-05-19 05:40:18 +04:00
|
|
|
* Insert jumbo payload option.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct mbuf *mopt;
|
2002-09-11 06:41:19 +04:00
|
|
|
u_int8_t *optbuf;
|
2000-08-19 12:15:53 +04:00
|
|
|
u_int32_t v;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is no hop-by-hop options header, allocate new one.
|
|
|
|
* If there is one but it doesn't have enough space to store the
|
|
|
|
* jumbo payload option, allocate a cluster to store the whole options.
|
|
|
|
* Otherwise, use it to store the options.
|
|
|
|
*/
|
|
|
|
if (exthdrs->ip6e_hbh == 0) {
|
|
|
|
MGET(mopt, M_DONTWAIT, MT_DATA);
|
|
|
|
if (mopt == 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
mopt->m_len = JUMBOOPTLEN;
|
2002-09-11 06:41:19 +04:00
|
|
|
optbuf = mtod(mopt, u_int8_t *);
|
1999-06-28 10:36:47 +04:00
|
|
|
optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */
|
|
|
|
exthdrs->ip6e_hbh = mopt;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else {
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip6_hbh *hbh;
|
|
|
|
|
|
|
|
mopt = exthdrs->ip6e_hbh;
|
|
|
|
if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
|
2000-08-19 12:15:53 +04:00
|
|
|
/*
|
|
|
|
* XXX assumption:
|
|
|
|
* - exthdrs->ip6e_hbh is not referenced from places
|
|
|
|
* other than exthdrs.
|
|
|
|
* - exthdrs->ip6e_hbh is not an mbuf chain.
|
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
int oldoptlen = mopt->m_len;
|
2000-08-19 12:15:53 +04:00
|
|
|
struct mbuf *n;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-08-19 12:15:53 +04:00
|
|
|
/*
|
|
|
|
* XXX: give up if the whole (new) hbh header does
|
|
|
|
* not fit even in an mbuf cluster.
|
|
|
|
*/
|
|
|
|
if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-08-19 12:15:53 +04:00
|
|
|
/*
|
|
|
|
* As a consequence, we must always prepare a cluster
|
|
|
|
* at this point.
|
|
|
|
*/
|
|
|
|
MGET(n, M_DONTWAIT, MT_DATA);
|
|
|
|
if (n) {
|
|
|
|
MCLGET(n, M_DONTWAIT);
|
|
|
|
if ((n->m_flags & M_EXT) == 0) {
|
|
|
|
m_freem(n);
|
|
|
|
n = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!n)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
2000-08-19 12:15:53 +04:00
|
|
|
n->m_len = oldoptlen + JUMBOOPTLEN;
|
2007-03-04 08:59:00 +03:00
|
|
|
bcopy(mtod(mopt, void *), mtod(n, void *),
|
2004-02-04 08:17:28 +03:00
|
|
|
oldoptlen);
|
2002-09-11 06:41:19 +04:00
|
|
|
optbuf = mtod(n, u_int8_t *) + oldoptlen;
|
2000-08-19 12:15:53 +04:00
|
|
|
m_freem(mopt);
|
2001-03-25 13:58:43 +04:00
|
|
|
mopt = exthdrs->ip6e_hbh = n;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else {
|
2002-09-11 06:41:19 +04:00
|
|
|
optbuf = mtod(mopt, u_int8_t *) + mopt->m_len;
|
1999-06-28 10:36:47 +04:00
|
|
|
mopt->m_len += JUMBOOPTLEN;
|
|
|
|
}
|
|
|
|
optbuf[0] = IP6OPT_PADN;
|
2002-09-23 17:28:55 +04:00
|
|
|
optbuf[1] = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust the header length according to the pad and
|
|
|
|
* the jumbo payload option.
|
|
|
|
*/
|
|
|
|
hbh = mtod(mopt, struct ip6_hbh *);
|
|
|
|
hbh->ip6h_len += (JUMBOOPTLEN >> 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill in the option. */
|
|
|
|
optbuf[2] = IP6OPT_JUMBO;
|
|
|
|
optbuf[3] = 4;
|
2000-08-19 12:15:53 +04:00
|
|
|
v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
|
|
|
|
bcopy(&v, &optbuf[4], sizeof(u_int32_t));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* finally, adjust the packet header length */
|
|
|
|
exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
#undef JUMBOOPTLEN
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert fragment header and copy unfragmentable header portions.
|
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen,
|
|
|
|
struct ip6_frag **frghdrp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct mbuf *n, *mlast;
|
|
|
|
|
|
|
|
if (hlen > sizeof(struct ip6_hdr)) {
|
|
|
|
n = m_copym(m0, sizeof(struct ip6_hdr),
|
2002-06-07 18:29:10 +04:00
|
|
|
hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (n == 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
m->m_next = n;
|
2000-05-19 05:40:18 +04:00
|
|
|
} else
|
1999-06-28 10:36:47 +04:00
|
|
|
n = m;
|
|
|
|
|
|
|
|
/* Search for the last mbuf of unfragmentable part. */
|
|
|
|
for (mlast = n; mlast->m_next; mlast = mlast->m_next)
|
|
|
|
;
|
|
|
|
|
|
|
|
if ((mlast->m_flags & M_EXT) == 0 &&
|
2000-06-03 18:36:32 +04:00
|
|
|
M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/* use the trailing space of the last mbuf for the fragment hdr */
|
2007-03-04 08:59:00 +03:00
|
|
|
*frghdrp = (struct ip6_frag *)(mtod(mlast, char *) +
|
2002-06-07 18:29:10 +04:00
|
|
|
mlast->m_len);
|
1999-06-28 10:36:47 +04:00
|
|
|
mlast->m_len += sizeof(struct ip6_frag);
|
|
|
|
m->m_pkthdr.len += sizeof(struct ip6_frag);
|
2000-05-19 05:40:18 +04:00
|
|
|
} else {
|
1999-06-28 10:36:47 +04:00
|
|
|
/* allocate a new mbuf for the fragment header */
|
|
|
|
struct mbuf *mfrg;
|
|
|
|
|
|
|
|
MGET(mfrg, M_DONTWAIT, MT_DATA);
|
|
|
|
if (mfrg == 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
mfrg->m_len = sizeof(struct ip6_frag);
|
|
|
|
*frghdrp = mtod(mfrg, struct ip6_frag *);
|
|
|
|
mlast->m_next = mfrg;
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2005-02-28 12:27:07 +03:00
|
|
|
static int
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
ip6_getpmtu(struct route *ro_pmtu, struct route *ro, struct ifnet *ifp,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct in6_addr *dst, u_long *mtup, int *alwaysfragp)
|
2002-05-29 11:53:39 +04:00
|
|
|
{
|
2007-12-20 22:53:29 +03:00
|
|
|
struct rtentry *rt;
|
2002-05-29 11:53:39 +04:00
|
|
|
u_int32_t mtu = 0;
|
2004-02-04 08:17:28 +03:00
|
|
|
int alwaysfrag = 0;
|
2002-05-29 11:53:39 +04:00
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (ro_pmtu != ro) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
union {
|
|
|
|
struct sockaddr dst;
|
|
|
|
struct sockaddr_in6 dst6;
|
|
|
|
} u;
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
/* The first hop and the final destination may differ. */
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
sockaddr_in6_init(&u.dst6, dst, 0, 0, 0);
|
2008-01-14 07:16:45 +03:00
|
|
|
rt = rtcache_lookup(ro_pmtu, &u.dst);
|
|
|
|
} else
|
|
|
|
rt = rtcache_validate(ro_pmtu);
|
|
|
|
if (rt != NULL) {
|
2002-05-29 11:53:39 +04:00
|
|
|
u_int32_t ifmtu;
|
|
|
|
|
|
|
|
if (ifp == NULL)
|
2007-12-20 22:53:29 +03:00
|
|
|
ifp = rt->rt_ifp;
|
2002-05-29 11:53:39 +04:00
|
|
|
ifmtu = IN6_LINKMTU(ifp);
|
2007-12-20 22:53:29 +03:00
|
|
|
mtu = rt->rt_rmx.rmx_mtu;
|
2002-05-31 07:18:54 +04:00
|
|
|
if (mtu == 0)
|
|
|
|
mtu = ifmtu;
|
2004-02-04 08:17:28 +03:00
|
|
|
else if (mtu < IPV6_MMTU) {
|
|
|
|
/*
|
|
|
|
* RFC2460 section 5, last paragraph:
|
|
|
|
* if we record ICMPv6 too big message with
|
|
|
|
* mtu < IPV6_MMTU, transmit packets sized IPV6_MMTU
|
|
|
|
* or smaller, with fragment header attached.
|
|
|
|
* (fragment header is needed regardless from the
|
|
|
|
* packet size, for translators to identify packets)
|
|
|
|
*/
|
|
|
|
alwaysfrag = 1;
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
} else if (mtu > ifmtu) {
|
2002-05-29 11:53:39 +04:00
|
|
|
/*
|
|
|
|
* The MTU on the route is larger than the MTU on
|
|
|
|
* the interface! This shouldn't happen, unless the
|
|
|
|
* MTU of the interface has been changed after the
|
|
|
|
* interface was brought up. Change the MTU in the
|
|
|
|
* route to match the interface MTU (as long as the
|
|
|
|
* field isn't locked).
|
|
|
|
*/
|
|
|
|
mtu = ifmtu;
|
2007-12-20 22:53:29 +03:00
|
|
|
if (!(rt->rt_rmx.rmx_locks & RTV_MTU))
|
|
|
|
rt->rt_rmx.rmx_mtu = mtu;
|
2002-05-29 11:53:39 +04:00
|
|
|
}
|
|
|
|
} else if (ifp) {
|
|
|
|
mtu = IN6_LINKMTU(ifp);
|
|
|
|
} else
|
|
|
|
error = EHOSTUNREACH; /* XXX */
|
|
|
|
|
|
|
|
*mtup = mtu;
|
2004-02-04 08:17:28 +03:00
|
|
|
if (alwaysfragp)
|
|
|
|
*alwaysfragp = alwaysfrag;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
2002-05-29 11:53:39 +04:00
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IP6 socket option processing.
|
|
|
|
*/
|
|
|
|
int
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
ip6_ctloutput(int op, struct socket *so, int level, int optname,
|
|
|
|
struct mbuf **mp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2006-05-05 04:03:21 +04:00
|
|
|
int privileged, optdatalen, uproto;
|
|
|
|
void *optdata;
|
2001-02-10 07:14:26 +03:00
|
|
|
struct in6pcb *in6p = sotoin6pcb(so);
|
|
|
|
struct mbuf *m = *mp;
|
2006-05-05 04:03:21 +04:00
|
|
|
int error, optval;
|
|
|
|
int optlen;
|
2006-07-24 02:06:03 +04:00
|
|
|
struct lwp *l = curlwp; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
optlen = m ? m->m_len : 0;
|
|
|
|
error = optval = 0;
|
2006-07-24 02:06:03 +04:00
|
|
|
privileged = (l == 0 || kauth_authorize_generic(l->l_cred,
|
2007-01-04 22:07:03 +03:00
|
|
|
KAUTH_GENERIC_ISSUSER, NULL)) ? 0 : 1;
|
2006-05-05 04:03:21 +04:00
|
|
|
uproto = (int)so->so_proto->pr_protocol;
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (level != IPPROTO_IPV6) {
|
|
|
|
if (op == PRCO_SETOPT && *mp)
|
|
|
|
(void)m_free(*mp);
|
|
|
|
return ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
switch (op) {
|
|
|
|
case PRCO_SETOPT:
|
|
|
|
switch (optname) {
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
|
|
|
/* m is freed in ip6_pcbopts */
|
|
|
|
error = ip6_pcbopts(&in6p->in6p_outputopts,
|
|
|
|
m, so);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/*
|
|
|
|
* Use of some Hop-by-Hop options or some
|
|
|
|
* Destination options, might require special
|
|
|
|
* privilege. That is, normal applications
|
|
|
|
* (without special privilege) might be forbidden
|
|
|
|
* from setting certain options in outgoing packets,
|
|
|
|
* and might never see certain options in received
|
|
|
|
* packets. [RFC 2292 Section 6]
|
|
|
|
* KAME specific note:
|
|
|
|
* KAME prevents non-privileged users from sending or
|
|
|
|
* receiving ANY hbh/dst options in order to avoid
|
|
|
|
* overhead of parsing options in the kernel.
|
|
|
|
*/
|
|
|
|
case IPV6_RECVHOPOPTS:
|
|
|
|
case IPV6_RECVDSTOPTS:
|
|
|
|
case IPV6_RECVRTHDRDSTOPTS:
|
|
|
|
if (!privileged) {
|
|
|
|
error = EPERM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
case IPV6_HOPLIMIT:
|
|
|
|
case IPV6_FAITH:
|
|
|
|
|
|
|
|
case IPV6_RECVPKTINFO:
|
|
|
|
case IPV6_RECVHOPLIMIT:
|
|
|
|
case IPV6_RECVRTHDR:
|
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
case IPV6_RECVTCLASS:
|
|
|
|
case IPV6_V6ONLY:
|
|
|
|
if (optlen != sizeof(int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optval = *mtod(m, int *);
|
|
|
|
switch (optname) {
|
2006-05-05 04:03:21 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
if (optval < -1 || optval >= 256)
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EINVAL;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
else {
|
|
|
|
/* -1 = kernel default */
|
|
|
|
in6p->in6p_hops = optval;
|
2001-10-15 13:51:15 +04:00
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
#define OPTSET(bit) \
|
2002-06-07 18:29:10 +04:00
|
|
|
do { \
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (optval) \
|
|
|
|
in6p->in6p_flags |= (bit); \
|
|
|
|
else \
|
|
|
|
in6p->in6p_flags &= ~(bit); \
|
2002-11-02 10:30:55 +03:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
|
|
|
#define OPTSET2292(bit) \
|
|
|
|
do { \
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
in6p->in6p_flags |= IN6P_RFC2292; \
|
|
|
|
if (optval) \
|
|
|
|
in6p->in6p_flags |= (bit); \
|
|
|
|
else \
|
|
|
|
in6p->in6p_flags &= ~(bit); \
|
2006-05-05 04:03:21 +04:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVPKTINFO:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_PKTINFO);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_HOPLIMIT:
|
|
|
|
{
|
|
|
|
struct ip6_pktopts **optp;
|
2006-05-05 04:03:21 +04:00
|
|
|
|
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
#endif
|
|
|
|
optp = &in6p->in6p_outputopts;
|
|
|
|
error = ip6_pcbopt(IPV6_HOPLIMIT,
|
|
|
|
(u_char *)&optval,
|
|
|
|
sizeof(optval),
|
|
|
|
optp,
|
|
|
|
privileged, uproto);
|
|
|
|
break;
|
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVHOPLIMIT:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_HOPLIMIT);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVHOPOPTS:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_HOPOPTS);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVDSTOPTS:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_DSTOPTS);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVRTHDRDSTOPTS:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_RTHDRDSTOPTS);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVRTHDR:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_RTHDR);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_FAITH:
|
|
|
|
OPTSET(IN6P_FAITH);
|
|
|
|
break;
|
2000-01-06 09:41:18 +03:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
/*
|
|
|
|
* We ignore this option for TCP
|
|
|
|
* sockets.
|
|
|
|
* (RFC3542 leaves this case
|
|
|
|
* unspecified.)
|
|
|
|
*/
|
|
|
|
if (uproto != IPPROTO_TCP)
|
|
|
|
OPTSET(IN6P_MTU);
|
|
|
|
break;
|
2004-06-11 08:10:10 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_V6ONLY:
|
|
|
|
/*
|
|
|
|
* make setsockopt(IPV6_V6ONLY)
|
|
|
|
* available only prior to bind(2).
|
|
|
|
* see ipng mailing list, Jun 22 2001.
|
|
|
|
*/
|
|
|
|
if (in6p->in6p_lport ||
|
|
|
|
!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2001-10-15 13:51:15 +04:00
|
|
|
#ifdef INET6_BINDV6ONLY
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (!optval)
|
|
|
|
error = EINVAL;
|
2001-10-15 13:51:15 +04:00
|
|
|
#else
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
OPTSET(IN6P_IPV6_V6ONLY);
|
2001-10-15 13:51:15 +04:00
|
|
|
#endif
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
break;
|
|
|
|
case IPV6_RECVTCLASS:
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 XXX */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
#endif
|
|
|
|
OPTSET(IN6P_TCLASS);
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_OTCLASS:
|
|
|
|
{
|
|
|
|
struct ip6_pktopts **optp;
|
|
|
|
u_int8_t tclass;
|
|
|
|
|
|
|
|
if (optlen != sizeof(tclass)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
tclass = *mtod(m, u_int8_t *);
|
|
|
|
optp = &in6p->in6p_outputopts;
|
|
|
|
error = ip6_pcbopt(optname,
|
|
|
|
(u_char *)&tclass,
|
|
|
|
sizeof(tclass),
|
|
|
|
optp,
|
|
|
|
privileged, uproto);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_TCLASS:
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
case IPV6_USE_MIN_MTU:
|
|
|
|
if (optlen != sizeof(optval)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optval = *mtod(m, int *);
|
2006-05-05 04:03:21 +04:00
|
|
|
{
|
|
|
|
struct ip6_pktopts **optp;
|
|
|
|
optp = &in6p->in6p_outputopts;
|
|
|
|
error = ip6_pcbopt(optname,
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
(u_char *)&optval,
|
|
|
|
sizeof(optval),
|
2006-05-05 04:03:21 +04:00
|
|
|
optp,
|
|
|
|
privileged, uproto);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
/* RFC 2292 */
|
|
|
|
if (optlen != sizeof(int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optval = *mtod(m, int *);
|
|
|
|
switch (optname) {
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292PKTINFO:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
OPTSET2292(IN6P_PKTINFO);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292HOPLIMIT:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
OPTSET2292(IN6P_HOPLIMIT);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292HOPOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/*
|
|
|
|
* Check super-user privilege.
|
|
|
|
* See comments for IPV6_RECVHOPOPTS.
|
|
|
|
*/
|
|
|
|
if (!privileged)
|
|
|
|
return (EPERM);
|
|
|
|
OPTSET2292(IN6P_HOPOPTS);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292DSTOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (!privileged)
|
|
|
|
return (EPERM);
|
|
|
|
OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292RTHDR:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
OPTSET2292(IN6P_RTHDR);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PKTINFO:
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_NEXTHOP:
|
|
|
|
{
|
|
|
|
/* new advanced API (RFC3542) */
|
|
|
|
u_char *optbuf;
|
|
|
|
int optbuflen;
|
|
|
|
struct ip6_pktopts **optp;
|
|
|
|
if (!m) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
|
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
/* cannot mix with RFC2292 */
|
|
|
|
if (OPTBIT(IN6P_RFC2292)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (m && m->m_next) {
|
|
|
|
error = EINVAL; /* XXX */
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
|
|
|
|
optbuf = mtod(m, u_char *);
|
|
|
|
optbuflen = m->m_len;
|
|
|
|
optp = &in6p->in6p_outputopts;
|
|
|
|
error = ip6_pcbopt(optname, optbuf, optbuflen,
|
|
|
|
optp, privileged, uproto);
|
|
|
|
break;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
#undef OPTSET
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
case IPV6_JOIN_GROUP:
|
|
|
|
case IPV6_LEAVE_GROUP:
|
|
|
|
error = ip6_setmoptions(optname,
|
|
|
|
&in6p->in6p_moptions, m);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PORTRANGE:
|
|
|
|
if (!m) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optval = *mtod(m, int *);
|
2000-01-26 20:06:36 +03:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
switch (optval) {
|
|
|
|
case IPV6_PORTRANGE_DEFAULT:
|
|
|
|
in6p->in6p_flags &= ~(IN6P_LOWPORT);
|
|
|
|
in6p->in6p_flags &= ~(IN6P_HIGHPORT);
|
|
|
|
break;
|
2000-01-26 20:06:36 +03:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PORTRANGE_HIGH:
|
|
|
|
in6p->in6p_flags &= ~(IN6P_LOWPORT);
|
|
|
|
in6p->in6p_flags |= IN6P_HIGHPORT;
|
|
|
|
break;
|
2000-01-26 20:06:36 +03:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PORTRANGE_LOW:
|
|
|
|
in6p->in6p_flags &= ~(IN6P_HIGHPORT);
|
|
|
|
in6p->in6p_flags |= IN6P_LOWPORT;
|
|
|
|
break;
|
2000-01-26 20:06:36 +03:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
default:
|
|
|
|
error = EINVAL;
|
2000-01-26 20:06:36 +03:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
break;
|
2000-01-26 20:06:36 +03:00
|
|
|
|
2007-02-10 12:43:05 +03:00
|
|
|
|
|
|
|
#if defined(IPSEC) || defined(FAST_IPSEC)
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_IPSEC_POLICY:
|
|
|
|
{
|
|
|
|
void *req = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
if (m) {
|
|
|
|
req = mtod(m, void *);
|
|
|
|
len = m->m_len;
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
error = ipsec6_set_policy(in6p, optname, req,
|
|
|
|
len, privileged);
|
|
|
|
}
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif /* IPSEC */
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
default:
|
|
|
|
error = ENOPROTOOPT;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
if (m)
|
|
|
|
(void)m_free(m);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case PRCO_GETOPT:
|
|
|
|
switch (optname) {
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
|
|
|
/*
|
|
|
|
* RFC3542 (effectively) deprecated the
|
|
|
|
* semantics of the 2292-style pktoptions.
|
|
|
|
* Since it was not reliable in nature (i.e.,
|
|
|
|
* applications had to expect the lack of some
|
|
|
|
* information after all), it would make sense
|
|
|
|
* to simplify this part by always returning
|
|
|
|
* empty data.
|
|
|
|
*/
|
|
|
|
*mp = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
(*mp)->m_len = 0;
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_RECVHOPOPTS:
|
|
|
|
case IPV6_RECVDSTOPTS:
|
|
|
|
case IPV6_RECVRTHDRDSTOPTS:
|
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
case IPV6_RECVPKTINFO:
|
|
|
|
case IPV6_RECVHOPLIMIT:
|
|
|
|
case IPV6_RECVRTHDR:
|
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
|
|
|
|
case IPV6_FAITH:
|
|
|
|
case IPV6_V6ONLY:
|
|
|
|
case IPV6_PORTRANGE:
|
|
|
|
case IPV6_RECVTCLASS:
|
|
|
|
switch (optname) {
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVHOPOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_HOPOPTS);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVDSTOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_DSTOPTS);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVRTHDRDSTOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_RTHDRDSTOPTS);
|
|
|
|
break;
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPV6_UNICAST_HOPS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = in6p->in6p_hops;
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVPKTINFO:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_PKTINFO);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVHOPLIMIT:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_HOPLIMIT);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVRTHDR:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_RTHDR);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVPATHMTU:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_MTU);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPV6_FAITH:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_FAITH);
|
|
|
|
break;
|
|
|
|
|
2001-10-15 13:51:15 +04:00
|
|
|
case IPV6_V6ONLY:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_IPV6_V6ONLY);
|
|
|
|
break;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_PORTRANGE:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
flags = in6p->in6p_flags;
|
|
|
|
if (flags & IN6P_HIGHPORT)
|
|
|
|
optval = IPV6_PORTRANGE_HIGH;
|
|
|
|
else if (flags & IN6P_LOWPORT)
|
|
|
|
optval = IPV6_PORTRANGE_LOW;
|
|
|
|
else
|
|
|
|
optval = 0;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RECVTCLASS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_TCLASS);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
if (error)
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
*mp = m = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
m->m_len = sizeof(int);
|
|
|
|
*mtod(m, int *) = optval;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PATHMTU:
|
|
|
|
{
|
|
|
|
u_long pmtu = 0;
|
|
|
|
struct ip6_mtuinfo mtuinfo;
|
|
|
|
struct route *ro = &in6p->in6p_route;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (!(so->so_state & SS_ISCONNECTED))
|
|
|
|
return (ENOTCONN);
|
|
|
|
/*
|
|
|
|
* XXX: we dot not consider the case of source
|
|
|
|
* routing, or optional information to specify
|
|
|
|
* the outgoing interface.
|
|
|
|
*/
|
|
|
|
error = ip6_getpmtu(ro, NULL, NULL,
|
|
|
|
&in6p->in6p_faddr, &pmtu, NULL);
|
|
|
|
if (error)
|
2006-05-05 04:03:21 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
if (pmtu > IPV6_MAXPACKET)
|
|
|
|
pmtu = IPV6_MAXPACKET;
|
|
|
|
|
|
|
|
memset(&mtuinfo, 0, sizeof(mtuinfo));
|
|
|
|
mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
|
|
|
|
optdata = (void *)&mtuinfo;
|
|
|
|
optdatalen = sizeof(mtuinfo);
|
|
|
|
if (optdatalen > MCLBYTES)
|
|
|
|
return (EMSGSIZE); /* XXX */
|
|
|
|
*mp = m = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
if (optdatalen > MLEN)
|
|
|
|
MCLGET(m, M_WAIT);
|
|
|
|
m->m_len = optdatalen;
|
|
|
|
memcpy(mtod(m, void *), optdata, optdatalen);
|
|
|
|
break;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
switch (optname) {
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292PKTINFO:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_PKTINFO);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292HOPLIMIT:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_HOPLIMIT);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292HOPOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_HOPOPTS);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292RTHDR:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_RTHDR);
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_2292DSTOPTS:
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
}
|
|
|
|
*mp = m = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
m->m_len = sizeof(int);
|
|
|
|
*mtod(m, int *) = optval;
|
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_PKTINFO:
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_NEXTHOP:
|
|
|
|
case IPV6_OTCLASS:
|
|
|
|
case IPV6_TCLASS:
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
case IPV6_USE_MIN_MTU:
|
|
|
|
error = ip6_getpcbopt(in6p->in6p_outputopts,
|
|
|
|
optname, mp);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
case IPV6_JOIN_GROUP:
|
|
|
|
case IPV6_LEAVE_GROUP:
|
|
|
|
error = ip6_getmoptions(optname,
|
|
|
|
in6p->in6p_moptions, mp);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2007-02-10 12:43:05 +03:00
|
|
|
#if defined(IPSEC) || defined(FAST_IPSEC)
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
case IPV6_IPSEC_POLICY:
|
|
|
|
{
|
|
|
|
void *req = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
if (m) {
|
|
|
|
req = mtod(m, void *);
|
|
|
|
len = m->m_len;
|
|
|
|
}
|
|
|
|
error = ipsec6_get_policy(in6p, req, len, mp);
|
|
|
|
break;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif /* IPSEC */
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
default:
|
|
|
|
error = ENOPROTOOPT;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-08 02:03:02 +04:00
|
|
|
int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_raw_ctloutput(int op, struct socket *so, int level, int optname,
|
|
|
|
struct mbuf **mp)
|
2002-06-08 02:03:02 +04:00
|
|
|
{
|
|
|
|
int error = 0, optval, optlen;
|
|
|
|
const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
|
|
|
|
struct in6pcb *in6p = sotoin6pcb(so);
|
|
|
|
struct mbuf *m = *mp;
|
|
|
|
|
|
|
|
optlen = m ? m->m_len : 0;
|
|
|
|
|
|
|
|
if (level != IPPROTO_IPV6) {
|
|
|
|
if (op == PRCO_SETOPT && *mp)
|
|
|
|
(void)m_free(*mp);
|
1) Introduce a new socket option, (SOL_SOCKET, SO_NOHEADER), that
tells a socket that it should both add a protocol header to tx'd
datagrams and remove the header from rx'd datagrams:
int onoff = 1, s = socket(...);
setsockopt(s, SOL_SOCKET, SO_NOHEADER, &onoff);
2) Add an implementation of (SOL_SOCKET, SO_NOHEADER) for raw IPv4
sockets.
3) Reorganize the protocols' pr_ctloutput implementations a bit.
Consistently return ENOPROTOOPT when an option is unsupported,
and EINVAL if a supported option's arguments are incorrect.
Reorganize the flow of code so that it's more clear how/when
options are passed down the stack until they are handled.
Shorten some pr_ctloutput staircases for readability.
4) Extract common mbuf code into subroutines, add new sockaddr
methods, and introduce a new subroutine, fsocreate(), for reuse
later; use it first in sys_socket():
struct mbuf *m_getsombuf(struct socket *so)
Create an mbuf and make its owner the socket `so'.
struct mbuf *m_intopt(struct socket *so, int val)
Create an mbuf, make its owner the socket `so', put the
int `val' into it, and set its length to sizeof(int).
int fsocreate(..., int *fd)
Create a socket, a la socreate(9), put the socket into the
given LWP's descriptor table, return the descriptor at `fd'
on success.
void *sockaddr_addr(struct sockaddr *sa, socklen_t *slenp)
const void *sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp)
Extract a pointer to the address part of a sockaddr. Write
the length of the address part at `slenp', if `slenp' is
not NULL.
socklen_t sockaddr_getlen(const struct sockaddr *sa)
Return the length of a sockaddr. This just evaluates to
sa->sa_len. I only add this for consistency with code that
appears in a portable userland library that I am going to
import.
const struct sockaddr *sockaddr_any(const struct sockaddr *sa)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
const void *sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp)
Return the "don't care" sockaddr in the same family as
`sa'. This is the address a client should sobind(9) if it
does not care the source address and, if applicable, the
port et cetera that it uses.
2007-09-19 08:33:42 +04:00
|
|
|
return ENOPROTOOPT;
|
2002-06-08 02:03:02 +04:00
|
|
|
}
|
2002-06-09 18:43:10 +04:00
|
|
|
|
2002-06-08 02:03:02 +04:00
|
|
|
switch (optname) {
|
|
|
|
case IPV6_CHECKSUM:
|
|
|
|
/*
|
|
|
|
* For ICMPv6 sockets, no modification allowed for checksum
|
|
|
|
* offset, permit "no change" values to help existing apps.
|
|
|
|
*
|
2006-05-05 04:03:21 +04:00
|
|
|
* XXX RFC3542 says: "An attempt to set IPV6_CHECKSUM
|
|
|
|
* for an ICMPv6 socket will fail." The current
|
|
|
|
* behavior does not meet RFC3542.
|
2002-06-08 02:03:02 +04:00
|
|
|
*/
|
|
|
|
switch (op) {
|
|
|
|
case PRCO_SETOPT:
|
|
|
|
if (optlen != sizeof(int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optval = *mtod(m, int *);
|
|
|
|
if ((optval % 2) != 0) {
|
|
|
|
/* the API assumes even offset values */
|
|
|
|
error = EINVAL;
|
|
|
|
} else if (so->so_proto->pr_protocol ==
|
|
|
|
IPPROTO_ICMPV6) {
|
|
|
|
if (optval != icmp6off)
|
|
|
|
error = EINVAL;
|
|
|
|
} else
|
|
|
|
in6p->in6p_cksum = optval;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PRCO_GETOPT:
|
|
|
|
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
|
|
|
|
optval = icmp6off;
|
|
|
|
else
|
|
|
|
optval = in6p->in6p_cksum;
|
|
|
|
|
|
|
|
*mp = m = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
m->m_len = sizeof(int);
|
|
|
|
*mtod(m, int *) = optval;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op == PRCO_SETOPT && m)
|
|
|
|
(void)m_free(m);
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
2002-06-08 02:03:02 +04:00
|
|
|
}
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2006-05-05 04:03:21 +04:00
|
|
|
* Set up IP6 options in pcb for insertion in output packets or
|
|
|
|
* specifying behavior of outgoing packets.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2001-02-10 07:14:26 +03:00
|
|
|
struct ip6_pktopts *opt = *pktopt;
|
1999-06-28 10:36:47 +04:00
|
|
|
int error = 0;
|
2006-07-24 02:06:03 +04:00
|
|
|
struct lwp *l = curlwp; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
int priv = 0;
|
|
|
|
|
|
|
|
/* turn off any old options. */
|
|
|
|
if (opt) {
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
|
|
|
|
opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
|
|
|
|
opt->ip6po_rhinfo.ip6po_rhi_rthdr)
|
|
|
|
printf("ip6_pcbopts: all specified options are cleared.\n");
|
|
|
|
#endif
|
|
|
|
ip6_clearpktopts(opt, -1);
|
2000-05-19 05:40:18 +04:00
|
|
|
} else
|
1999-06-28 10:36:47 +04:00
|
|
|
opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
|
2006-05-05 04:03:21 +04:00
|
|
|
*pktopt = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (!m || m->m_len == 0) {
|
|
|
|
/*
|
2006-05-05 04:03:21 +04:00
|
|
|
* Only turning off any previous options, regardless of
|
|
|
|
* whether the opt is just created or given.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-10-31 20:36:16 +03:00
|
|
|
free(opt, M_IP6OPT);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set options specified by user. */
|
2006-07-24 02:06:03 +04:00
|
|
|
if (l && !kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
|
2007-01-04 22:07:03 +03:00
|
|
|
NULL))
|
1999-06-28 10:36:47 +04:00
|
|
|
priv = 1;
|
2006-05-05 04:03:21 +04:00
|
|
|
if ((error = ip6_setpktopts(m, opt, NULL, priv,
|
|
|
|
so->so_proto->pr_protocol)) != 0) {
|
|
|
|
ip6_clearpktopts(opt, -1); /* XXX: discard all options */
|
2002-10-31 20:36:16 +03:00
|
|
|
free(opt, M_IP6OPT);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
*pktopt = opt;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize ip6_pktopts. beware that there are non-zero default values in
|
|
|
|
* the struct.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ip6_initpktopts(struct ip6_pktopts *opt)
|
|
|
|
{
|
|
|
|
|
|
|
|
memset(opt, 0, sizeof(*opt));
|
|
|
|
opt->ip6po_hlim = -1; /* -1 means default hop limit */
|
|
|
|
opt->ip6po_tclass = -1; /* -1 means default traffic class */
|
|
|
|
opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define sin6tosa(sin6) ((struct sockaddr *)(sin6)) /* XXX */
|
|
|
|
static int
|
|
|
|
ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
|
|
|
|
int priv, int uproto)
|
|
|
|
{
|
|
|
|
struct ip6_pktopts *opt;
|
|
|
|
|
|
|
|
if (*pktopt == NULL) {
|
|
|
|
*pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT,
|
|
|
|
M_WAITOK);
|
|
|
|
ip6_initpktopts(*pktopt);
|
|
|
|
}
|
|
|
|
opt = *pktopt;
|
|
|
|
|
|
|
|
return (ip6_setpktopt(optname, buf, len, opt, priv, 1, 0, uproto));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct mbuf **mp)
|
|
|
|
{
|
|
|
|
void *optdata = NULL;
|
|
|
|
int optdatalen = 0;
|
|
|
|
struct ip6_ext *ip6e;
|
|
|
|
int error = 0;
|
|
|
|
struct in6_pktinfo null_pktinfo;
|
|
|
|
int deftclass = 0, on;
|
|
|
|
int defminmtu = IP6PO_MINMTU_MCASTONLY;
|
|
|
|
struct mbuf *m;
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_PKTINFO:
|
|
|
|
if (pktopt && pktopt->ip6po_pktinfo)
|
|
|
|
optdata = (void *)pktopt->ip6po_pktinfo;
|
|
|
|
else {
|
|
|
|
/* XXX: we don't have to do this every time... */
|
|
|
|
memset(&null_pktinfo, 0, sizeof(null_pktinfo));
|
|
|
|
optdata = (void *)&null_pktinfo;
|
|
|
|
}
|
|
|
|
optdatalen = sizeof(struct in6_pktinfo);
|
|
|
|
break;
|
|
|
|
case IPV6_OTCLASS:
|
|
|
|
/* XXX */
|
|
|
|
return (EINVAL);
|
|
|
|
case IPV6_TCLASS:
|
|
|
|
if (pktopt && pktopt->ip6po_tclass >= 0)
|
|
|
|
optdata = (void *)&pktopt->ip6po_tclass;
|
|
|
|
else
|
|
|
|
optdata = (void *)&deftclass;
|
|
|
|
optdatalen = sizeof(int);
|
|
|
|
break;
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
if (pktopt && pktopt->ip6po_hbh) {
|
|
|
|
optdata = (void *)pktopt->ip6po_hbh;
|
|
|
|
ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
|
|
|
|
optdatalen = (ip6e->ip6e_len + 1) << 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
if (pktopt && pktopt->ip6po_rthdr) {
|
|
|
|
optdata = (void *)pktopt->ip6po_rthdr;
|
|
|
|
ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
|
|
|
|
optdatalen = (ip6e->ip6e_len + 1) << 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
if (pktopt && pktopt->ip6po_dest1) {
|
|
|
|
optdata = (void *)pktopt->ip6po_dest1;
|
|
|
|
ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
|
|
|
|
optdatalen = (ip6e->ip6e_len + 1) << 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
if (pktopt && pktopt->ip6po_dest2) {
|
|
|
|
optdata = (void *)pktopt->ip6po_dest2;
|
|
|
|
ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
|
|
|
|
optdatalen = (ip6e->ip6e_len + 1) << 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV6_NEXTHOP:
|
|
|
|
if (pktopt && pktopt->ip6po_nexthop) {
|
|
|
|
optdata = (void *)pktopt->ip6po_nexthop;
|
|
|
|
optdatalen = pktopt->ip6po_nexthop->sa_len;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV6_USE_MIN_MTU:
|
|
|
|
if (pktopt)
|
|
|
|
optdata = (void *)&pktopt->ip6po_minmtu;
|
|
|
|
else
|
|
|
|
optdata = (void *)&defminmtu;
|
|
|
|
optdatalen = sizeof(int);
|
|
|
|
break;
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG))
|
|
|
|
on = 1;
|
|
|
|
else
|
|
|
|
on = 0;
|
|
|
|
optdata = (void *)&on;
|
|
|
|
optdatalen = sizeof(on);
|
|
|
|
break;
|
|
|
|
default: /* should not happen */
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
panic("ip6_getpcbopt: unexpected option\n");
|
|
|
|
#endif
|
|
|
|
return (ENOPROTOOPT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (optdatalen > MCLBYTES)
|
|
|
|
return (EMSGSIZE); /* XXX */
|
|
|
|
*mp = m = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
if (optdatalen > MLEN)
|
|
|
|
MCLGET(m, M_WAIT);
|
|
|
|
m->m_len = optdatalen;
|
|
|
|
if (optdatalen)
|
|
|
|
memcpy(mtod(m, void *), optdata, optdatalen);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname)
|
|
|
|
{
|
|
|
|
if (optname == -1 || optname == IPV6_PKTINFO) {
|
|
|
|
if (pktopt->ip6po_pktinfo)
|
|
|
|
free(pktopt->ip6po_pktinfo, M_IP6OPT);
|
|
|
|
pktopt->ip6po_pktinfo = NULL;
|
|
|
|
}
|
|
|
|
if (optname == -1 || optname == IPV6_HOPLIMIT)
|
|
|
|
pktopt->ip6po_hlim = -1;
|
|
|
|
if (optname == -1 || optname == IPV6_TCLASS)
|
|
|
|
pktopt->ip6po_tclass = -1;
|
|
|
|
if (optname == -1 || optname == IPV6_NEXTHOP) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_free(&pktopt->ip6po_nextroute);
|
2006-05-05 04:03:21 +04:00
|
|
|
if (pktopt->ip6po_nexthop)
|
|
|
|
free(pktopt->ip6po_nexthop, M_IP6OPT);
|
|
|
|
pktopt->ip6po_nexthop = NULL;
|
|
|
|
}
|
|
|
|
if (optname == -1 || optname == IPV6_HOPOPTS) {
|
|
|
|
if (pktopt->ip6po_hbh)
|
|
|
|
free(pktopt->ip6po_hbh, M_IP6OPT);
|
|
|
|
pktopt->ip6po_hbh = NULL;
|
|
|
|
}
|
|
|
|
if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
|
|
|
|
if (pktopt->ip6po_dest1)
|
|
|
|
free(pktopt->ip6po_dest1, M_IP6OPT);
|
|
|
|
pktopt->ip6po_dest1 = NULL;
|
|
|
|
}
|
|
|
|
if (optname == -1 || optname == IPV6_RTHDR) {
|
|
|
|
if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
|
|
|
|
free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
|
|
|
|
pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_free(&pktopt->ip6po_route);
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
|
|
|
if (optname == -1 || optname == IPV6_DSTOPTS) {
|
|
|
|
if (pktopt->ip6po_dest2)
|
|
|
|
free(pktopt->ip6po_dest2, M_IP6OPT);
|
|
|
|
pktopt->ip6po_dest2 = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PKTOPT_EXTHDRCPY(type) \
|
|
|
|
do { \
|
|
|
|
if (src->type) { \
|
|
|
|
int hlen = (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
|
|
|
|
dst->type = malloc(hlen, M_IP6OPT, canwait); \
|
|
|
|
if (dst->type == NULL && canwait == M_NOWAIT) \
|
|
|
|
goto bad; \
|
|
|
|
memcpy(dst->type, src->type, hlen); \
|
|
|
|
} \
|
|
|
|
} while (/*CONSTCOND*/ 0)
|
|
|
|
|
|
|
|
static int
|
|
|
|
copypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait)
|
|
|
|
{
|
|
|
|
dst->ip6po_hlim = src->ip6po_hlim;
|
|
|
|
dst->ip6po_tclass = src->ip6po_tclass;
|
|
|
|
dst->ip6po_flags = src->ip6po_flags;
|
|
|
|
if (src->ip6po_pktinfo) {
|
|
|
|
dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo),
|
|
|
|
M_IP6OPT, canwait);
|
|
|
|
if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT)
|
|
|
|
goto bad;
|
|
|
|
*dst->ip6po_pktinfo = *src->ip6po_pktinfo;
|
|
|
|
}
|
|
|
|
if (src->ip6po_nexthop) {
|
|
|
|
dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len,
|
|
|
|
M_IP6OPT, canwait);
|
|
|
|
if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT)
|
|
|
|
goto bad;
|
|
|
|
memcpy(dst->ip6po_nexthop, src->ip6po_nexthop,
|
|
|
|
src->ip6po_nexthop->sa_len);
|
|
|
|
}
|
|
|
|
PKTOPT_EXTHDRCPY(ip6po_hbh);
|
|
|
|
PKTOPT_EXTHDRCPY(ip6po_dest1);
|
|
|
|
PKTOPT_EXTHDRCPY(ip6po_dest2);
|
|
|
|
PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
bad:
|
|
|
|
if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT);
|
|
|
|
if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT);
|
|
|
|
if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT);
|
|
|
|
if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT);
|
|
|
|
if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT);
|
|
|
|
if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT);
|
|
|
|
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
#undef PKTOPT_EXTHDRCPY
|
|
|
|
|
|
|
|
struct ip6_pktopts *
|
|
|
|
ip6_copypktopts(struct ip6_pktopts *src, int canwait)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct ip6_pktopts *dst;
|
|
|
|
|
|
|
|
dst = malloc(sizeof(*dst), M_IP6OPT, canwait);
|
|
|
|
if (dst == NULL && canwait == M_NOWAIT)
|
|
|
|
return (NULL);
|
|
|
|
ip6_initpktopts(dst);
|
|
|
|
|
|
|
|
if ((error = copypktopts(dst, src, canwait)) != 0) {
|
|
|
|
free(dst, M_IP6OPT);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ip6_freepcbopts(struct ip6_pktopts *pktopt)
|
|
|
|
{
|
|
|
|
if (pktopt == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip6_clearpktopts(pktopt, -1);
|
|
|
|
|
|
|
|
free(pktopt, M_IP6OPT);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the IP6 multicast options in response to user setsockopt().
|
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
u_int loop, ifindex;
|
|
|
|
struct ipv6_mreq *mreq;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ip6_moptions *im6o = *im6op;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route ro;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6_multi_mship *imm;
|
2006-07-24 02:06:03 +04:00
|
|
|
struct lwp *l = curlwp; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (im6o == NULL) {
|
|
|
|
/*
|
|
|
|
* No multicast option buffer attached to the pcb;
|
|
|
|
* allocate one and initialize to default values.
|
|
|
|
*/
|
|
|
|
im6o = (struct ip6_moptions *)
|
|
|
|
malloc(sizeof(*im6o), M_IPMOPTS, M_WAITOK);
|
|
|
|
|
|
|
|
if (im6o == NULL)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ENOBUFS);
|
1999-06-28 10:36:47 +04:00
|
|
|
*im6op = im6o;
|
|
|
|
im6o->im6o_multicast_ifp = NULL;
|
|
|
|
im6o->im6o_multicast_hlim = ip6_defmcasthlim;
|
|
|
|
im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
|
|
|
|
LIST_INIT(&im6o->im6o_memberships);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
/*
|
|
|
|
* Select the interface for outgoing multicast packets.
|
|
|
|
*/
|
|
|
|
if (m == NULL || m->m_len != sizeof(u_int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2000-08-19 12:15:53 +04:00
|
|
|
bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex));
|
2004-12-21 14:37:47 +03:00
|
|
|
if (ifindex != 0) {
|
2006-08-30 21:15:22 +04:00
|
|
|
if (if_indexlim <= ifindex || !ifindex2ifnet[ifindex]) {
|
2004-12-21 14:37:47 +03:00
|
|
|
error = ENXIO; /* XXX EINVAL? */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ifp = ifindex2ifnet[ifindex];
|
|
|
|
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
ifp = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
im6o->im6o_multicast_ifp = ifp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Set the IP6 hoplimit for outgoing multicast packets.
|
|
|
|
*/
|
|
|
|
int optval;
|
|
|
|
if (m == NULL || m->m_len != sizeof(int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2000-08-19 12:15:53 +04:00
|
|
|
bcopy(mtod(m, u_int *), &optval, sizeof(optval));
|
1999-06-28 10:36:47 +04:00
|
|
|
if (optval < -1 || optval >= 256)
|
|
|
|
error = EINVAL;
|
|
|
|
else if (optval == -1)
|
|
|
|
im6o->im6o_multicast_hlim = ip6_defmcasthlim;
|
|
|
|
else
|
|
|
|
im6o->im6o_multicast_hlim = optval;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
/*
|
|
|
|
* Set the loopback flag for outgoing multicast packets.
|
|
|
|
* Must be zero or one.
|
|
|
|
*/
|
2000-08-19 12:15:53 +04:00
|
|
|
if (m == NULL || m->m_len != sizeof(u_int)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bcopy(mtod(m, u_int *), &loop, sizeof(loop));
|
|
|
|
if (loop > 1) {
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
im6o->im6o_multicast_loop = loop;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_JOIN_GROUP:
|
|
|
|
/*
|
|
|
|
* Add a multicast group membership.
|
|
|
|
* Group must be a valid IP6 multicast address.
|
|
|
|
*/
|
|
|
|
if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mreq = mtod(m, struct ipv6_mreq *);
|
1999-12-13 18:17:17 +03:00
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* We use the unspecified address to specify to accept
|
|
|
|
* all multicast addresses. Only super user is allowed
|
|
|
|
* to do this.
|
|
|
|
*/
|
2006-07-24 02:06:03 +04:00
|
|
|
if (kauth_authorize_generic(l->l_cred,
|
2007-01-04 22:07:03 +03:00
|
|
|
KAUTH_GENERIC_ISSUSER, NULL))
|
2001-02-10 07:14:26 +03:00
|
|
|
{
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EACCES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If no interface was explicitly specified, choose an
|
|
|
|
* appropriate one according to the given multicast address.
|
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (mreq->ipv6mr_interface == 0) {
|
2007-12-20 22:53:29 +03:00
|
|
|
struct rtentry *rt;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
union {
|
|
|
|
struct sockaddr dst;
|
|
|
|
struct sockaddr_in6 dst6;
|
|
|
|
} u;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the routing table for the
|
|
|
|
* address, and choose the outgoing interface.
|
|
|
|
* XXX: is it a good approach?
|
|
|
|
*/
|
2007-01-29 09:13:58 +03:00
|
|
|
memset(&ro, 0, sizeof(ro));
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
sockaddr_in6_init(&u.dst6, &mreq->ipv6mr_multiaddr, 0,
|
|
|
|
0, 0);
|
|
|
|
rtcache_setdst(&ro, &u.dst);
|
2008-01-10 11:06:11 +03:00
|
|
|
ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp
|
2007-12-20 22:53:29 +03:00
|
|
|
: NULL;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_free(&ro);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If the interface is specified, validate it.
|
|
|
|
*/
|
2006-08-30 21:15:22 +04:00
|
|
|
if (if_indexlim <= mreq->ipv6mr_interface ||
|
2004-12-21 14:37:47 +03:00
|
|
|
!ifindex2ifnet[mreq->ipv6mr_interface]) {
|
|
|
|
error = ENXIO; /* XXX EINVAL? */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ifp = ifindex2ifnet[mreq->ipv6mr_interface];
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* See if we found an interface, and confirm that it
|
|
|
|
* supports multicast
|
|
|
|
*/
|
|
|
|
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
if (in6_setscope(&mreq->ipv6mr_multiaddr, ifp, NULL)) {
|
|
|
|
error = EADDRNOTAVAIL; /* XXX: should not happen */
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* See if the membership already exists.
|
|
|
|
*/
|
|
|
|
for (imm = im6o->im6o_memberships.lh_first;
|
|
|
|
imm != NULL; imm = imm->i6mm_chain.le_next)
|
|
|
|
if (imm->i6mm_maddr->in6m_ifp == ifp &&
|
|
|
|
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
|
2002-06-07 18:29:10 +04:00
|
|
|
&mreq->ipv6mr_multiaddr))
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
if (imm != NULL) {
|
|
|
|
error = EADDRINUSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Everything looks good; add a new record to the multicast
|
|
|
|
* address list for the given interface.
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
imm = in6_joingroup(ifp, &mreq->ipv6mr_multiaddr, &error, 0);
|
|
|
|
if (imm == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_LEAVE_GROUP:
|
|
|
|
/*
|
|
|
|
* Drop a multicast group membership.
|
|
|
|
* Group must be a valid IP6 multicast address.
|
|
|
|
*/
|
|
|
|
if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mreq = mtod(m, struct ipv6_mreq *);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* If an interface address was specified, get a pointer
|
|
|
|
* to its ifnet structure.
|
|
|
|
*/
|
2004-12-21 14:37:47 +03:00
|
|
|
if (mreq->ipv6mr_interface != 0) {
|
2006-08-30 21:15:22 +04:00
|
|
|
if (if_indexlim <= mreq->ipv6mr_interface ||
|
2004-12-21 14:37:47 +03:00
|
|
|
!ifindex2ifnet[mreq->ipv6mr_interface]) {
|
|
|
|
error = ENXIO; /* XXX EINVAL? */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ifp = ifindex2ifnet[mreq->ipv6mr_interface];
|
|
|
|
} else
|
|
|
|
ifp = NULL;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/* Fill in the scope zone ID */
|
|
|
|
if (ifp) {
|
|
|
|
if (in6_setscope(&mreq->ipv6mr_multiaddr, ifp, NULL)) {
|
|
|
|
/* XXX: should not happen */
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (mreq->ipv6mr_interface != 0) {
|
|
|
|
/*
|
|
|
|
* XXX: This case would happens when the (positive)
|
|
|
|
* index is in the valid range, but the corresponding
|
|
|
|
* interface has been detached dynamically. The above
|
|
|
|
* check probably avoids such case to happen here, but
|
|
|
|
* we check it explicitly for safety.
|
|
|
|
*/
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
} else { /* ipv6mr_interface == 0 */
|
|
|
|
struct sockaddr_in6 sa6_mc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The API spec says as follows:
|
|
|
|
* If the interface index is specified as 0, the
|
|
|
|
* system may choose a multicast group membership to
|
|
|
|
* drop by matching the multicast address only.
|
|
|
|
* On the other hand, we cannot disambiguate the scope
|
|
|
|
* zone unless an interface is provided. Thus, we
|
|
|
|
* check if there's ambiguity with the default scope
|
|
|
|
* zone as the last resort.
|
|
|
|
*/
|
2007-11-07 02:48:24 +03:00
|
|
|
sockaddr_in6_init(&sa6_mc, &mreq->ipv6mr_multiaddr,
|
|
|
|
0, 0, 0);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
error = sa6_embedscope(&sa6_mc, ip6_use_defzone);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
mreq->ipv6mr_multiaddr = sa6_mc.sin6_addr;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Find the membership in the membership list.
|
|
|
|
*/
|
|
|
|
for (imm = im6o->im6o_memberships.lh_first;
|
|
|
|
imm != NULL; imm = imm->i6mm_chain.le_next) {
|
2002-06-07 18:29:10 +04:00
|
|
|
if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) &&
|
1999-06-28 10:36:47 +04:00
|
|
|
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
|
2002-06-07 18:29:10 +04:00
|
|
|
&mreq->ipv6mr_multiaddr))
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (imm == NULL) {
|
|
|
|
/* Unable to resolve interface */
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Give up the multicast address record to which the
|
|
|
|
* membership points.
|
|
|
|
*/
|
|
|
|
LIST_REMOVE(imm, i6mm_chain);
|
2001-12-20 10:26:36 +03:00
|
|
|
in6_leavegroup(imm);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If all options have default values, no need to keep the mbuf.
|
|
|
|
*/
|
|
|
|
if (im6o->im6o_multicast_ifp == NULL &&
|
|
|
|
im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
|
|
|
|
im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
|
|
|
|
im6o->im6o_memberships.lh_first == NULL) {
|
|
|
|
free(*im6op, M_IPMOPTS);
|
|
|
|
*im6op = NULL;
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the IP6 multicast options in response to user getsockopt().
|
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_getmoptions(int optname, struct ip6_moptions *im6o, struct mbuf **mp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
u_int *hlim, *loop, *ifindex;
|
|
|
|
|
|
|
|
*mp = m_get(M_WAIT, MT_SOOPTS);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
ifindex = mtod(*mp, u_int *);
|
|
|
|
(*mp)->m_len = sizeof(u_int);
|
|
|
|
if (im6o == NULL || im6o->im6o_multicast_ifp == NULL)
|
|
|
|
*ifindex = 0;
|
|
|
|
else
|
|
|
|
*ifindex = im6o->im6o_multicast_ifp->if_index;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
hlim = mtod(*mp, u_int *);
|
|
|
|
(*mp)->m_len = sizeof(u_int);
|
|
|
|
if (im6o == NULL)
|
|
|
|
*hlim = ip6_defmcasthlim;
|
|
|
|
else
|
|
|
|
*hlim = im6o->im6o_multicast_hlim;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
loop = mtod(*mp, u_int *);
|
|
|
|
(*mp)->m_len = sizeof(u_int);
|
|
|
|
if (im6o == NULL)
|
|
|
|
*loop = ip6_defmcasthlim;
|
|
|
|
else
|
|
|
|
*loop = im6o->im6o_multicast_loop;
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EOPNOTSUPP);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Discard the IP6 multicast options.
|
|
|
|
*/
|
|
|
|
void
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_freemoptions(struct ip6_moptions *im6o)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct in6_multi_mship *imm;
|
|
|
|
|
|
|
|
if (im6o == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
|
|
|
|
LIST_REMOVE(imm, i6mm_chain);
|
2001-12-20 10:26:36 +03:00
|
|
|
in6_leavegroup(imm);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
free(im6o, M_IPMOPTS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set IPv6 outgoing packet options based on advanced API.
|
|
|
|
*/
|
|
|
|
int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
|
|
|
|
struct ip6_pktopts *stickyopt, int priv, int uproto)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2001-02-10 07:14:26 +03:00
|
|
|
struct cmsghdr *cm = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
if (control == NULL || opt == NULL)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
ip6_initpktopts(opt);
|
|
|
|
if (stickyopt) {
|
|
|
|
int error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If stickyopt is provided, make a local copy of the options
|
|
|
|
* for this particular packet, then override them by ancillary
|
|
|
|
* objects.
|
|
|
|
* XXX: copypktopts() does not copy the cached route to a next
|
|
|
|
* hop (if any). This is not very good in terms of efficiency,
|
|
|
|
* but we can allow this since this option should be rarely
|
|
|
|
* used.
|
|
|
|
*/
|
|
|
|
if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0)
|
|
|
|
return (error);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: Currently, we assume all the optional information is stored
|
|
|
|
* in a single mbuf.
|
|
|
|
*/
|
|
|
|
if (control->m_next)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
|
2002-06-07 18:29:10 +04:00
|
|
|
control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
|
2006-05-05 04:03:21 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
if (control->m_len < CMSG_LEN(0))
|
|
|
|
return (EINVAL);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
cm = mtod(control, struct cmsghdr *);
|
|
|
|
if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (cm->cmsg_level != IPPROTO_IPV6)
|
|
|
|
continue;
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
|
|
|
|
cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set a particular packet option, as a sticky option or an ancillary data
|
|
|
|
* item. "len" can be 0 only when it's a sticky option.
|
|
|
|
* We have 4 cases of combination of "sticky" and "cmsg":
|
|
|
|
* "sticky=0, cmsg=0": impossible
|
|
|
|
* "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data
|
|
|
|
* "sticky=1, cmsg=0": RFC3542 socket option
|
|
|
|
* "sticky=1, cmsg=1": RFC2292 socket option
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
|
|
|
|
int priv, int sticky, int cmsg, int uproto)
|
|
|
|
{
|
|
|
|
int minmtupolicy;
|
|
|
|
|
|
|
|
if (!sticky && !cmsg) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
printf("ip6_setpktopt: impossible case\n");
|
|
|
|
#endif
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IPV6_2292xxx is for backward compatibility to RFC2292, and should
|
|
|
|
* not be specified in the context of RFC3542. Conversely,
|
|
|
|
* RFC3542 types should not be specified in the context of RFC2292.
|
|
|
|
*/
|
|
|
|
if (!cmsg) {
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
case IPV6_2292NEXTHOP:
|
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
case IPV6_2292PKTOPTIONS:
|
|
|
|
return (ENOPROTOOPT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sticky && cmsg) {
|
|
|
|
switch (optname) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPV6_PKTINFO:
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_HOPLIMIT:
|
|
|
|
case IPV6_NEXTHOP:
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_USE_MIN_MTU:
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
case IPV6_OTCLASS:
|
|
|
|
case IPV6_TCLASS:
|
|
|
|
return (ENOPROTOOPT);
|
|
|
|
}
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
switch (optname) {
|
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
#endif
|
|
|
|
case IPV6_PKTINFO:
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = NULL;
|
|
|
|
struct in6_pktinfo *pktinfo;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
if (len != sizeof(struct in6_pktinfo))
|
|
|
|
return (EINVAL);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
pktinfo = (struct in6_pktinfo *)buf;
|
2001-04-11 08:57:53 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/*
|
|
|
|
* An application can clear any sticky IPV6_PKTINFO option by
|
|
|
|
* doing a "regular" setsockopt with ipi6_addr being
|
|
|
|
* in6addr_any and ipi6_ifindex being zero.
|
|
|
|
* [RFC 3542, Section 6]
|
|
|
|
*/
|
|
|
|
if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo &&
|
|
|
|
pktinfo->ipi6_ifindex == 0 &&
|
|
|
|
IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
|
|
|
|
ip6_clearpktopts(opt, optname);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO &&
|
|
|
|
sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/* validate the interface index if specified. */
|
2006-08-30 21:15:22 +04:00
|
|
|
if (pktinfo->ipi6_ifindex >= if_indexlim) {
|
2006-05-05 04:03:21 +04:00
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
if (pktinfo->ipi6_ifindex) {
|
|
|
|
ifp = ifindex2ifnet[pktinfo->ipi6_ifindex];
|
|
|
|
if (ifp == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/*
|
|
|
|
* We store the address anyway, and let in6_selectsrc()
|
|
|
|
* validate the specified address. This is because ipi6_addr
|
|
|
|
* may not have enough information about its scope zone, and
|
|
|
|
* we may need additional information (such as outgoing
|
|
|
|
* interface or the scope zone of a destination address) to
|
|
|
|
* disambiguate the scope.
|
|
|
|
* XXX: the delay of the validation may confuse the
|
|
|
|
* application when it is used as a sticky option.
|
|
|
|
*/
|
|
|
|
if (opt->ip6po_pktinfo == NULL) {
|
|
|
|
opt->ip6po_pktinfo = malloc(sizeof(*pktinfo),
|
|
|
|
M_IP6OPT, M_NOWAIT);
|
|
|
|
if (opt->ip6po_pktinfo == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
memcpy(opt->ip6po_pktinfo, pktinfo, sizeof(*pktinfo));
|
|
|
|
break;
|
|
|
|
}
|
2001-02-10 07:14:26 +03:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
#endif
|
|
|
|
case IPV6_HOPLIMIT:
|
|
|
|
{
|
|
|
|
int *hlimp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT
|
|
|
|
* to simplify the ordering among hoplimit options.
|
|
|
|
*/
|
|
|
|
if (optname == IPV6_HOPLIMIT && sticky)
|
|
|
|
return (ENOPROTOOPT);
|
|
|
|
|
|
|
|
if (len != sizeof(int))
|
|
|
|
return (EINVAL);
|
|
|
|
hlimp = (int *)buf;
|
|
|
|
if (*hlimp < -1 || *hlimp > 255)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
opt->ip6po_hlim = *hlimp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_OTCLASS:
|
|
|
|
if (len != sizeof(u_int8_t))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
opt->ip6po_tclass = *(u_int8_t *)buf;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_TCLASS:
|
|
|
|
{
|
|
|
|
int tclass;
|
|
|
|
|
|
|
|
if (len != sizeof(int))
|
|
|
|
return (EINVAL);
|
|
|
|
tclass = *(int *)buf;
|
|
|
|
if (tclass < -1 || tclass > 255)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
opt->ip6po_tclass = tclass;
|
|
|
|
break;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292NEXTHOP:
|
|
|
|
#endif
|
|
|
|
case IPV6_NEXTHOP:
|
|
|
|
if (!priv)
|
|
|
|
return (EPERM);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
if (len == 0) { /* just remove the option */
|
|
|
|
ip6_clearpktopts(opt, IPV6_NEXTHOP);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/* check if cmsg_len is large enough for sa_len */
|
|
|
|
if (len < sizeof(struct sockaddr) || len < *buf)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
switch (((struct sockaddr *)buf)->sa_family) {
|
|
|
|
case AF_INET6:
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (sa6->sin6_len != sizeof(struct sockaddr_in6))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
|
|
|
|
IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
|
|
|
if ((error = sa6_embedscope(sa6, ip6_use_defzone))
|
|
|
|
!= 0) {
|
|
|
|
return (error);
|
2003-08-25 04:10:27 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
}
|
|
|
|
case AF_LINK: /* eventually be supported? */
|
|
|
|
default:
|
|
|
|
return (EAFNOSUPPORT);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/* turn off the previous option, then set the new option. */
|
|
|
|
ip6_clearpktopts(opt, IPV6_NEXTHOP);
|
|
|
|
opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_NOWAIT);
|
|
|
|
if (opt->ip6po_nexthop == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
memcpy(opt->ip6po_nexthop, buf, *buf);
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
#endif
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
{
|
|
|
|
struct ip6_hbh *hbh;
|
|
|
|
int hbhlen;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: We don't allow a non-privileged user to set ANY HbH
|
|
|
|
* options, since per-option restriction has too much
|
|
|
|
* overhead.
|
|
|
|
*/
|
|
|
|
if (!priv)
|
|
|
|
return (EPERM);
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
ip6_clearpktopts(opt, IPV6_HOPOPTS);
|
|
|
|
break; /* just remove the option */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* message length validation */
|
|
|
|
if (len < sizeof(struct ip6_hbh))
|
|
|
|
return (EINVAL);
|
|
|
|
hbh = (struct ip6_hbh *)buf;
|
|
|
|
hbhlen = (hbh->ip6h_len + 1) << 3;
|
|
|
|
if (len != hbhlen)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/* turn off the previous option, then set the new option. */
|
|
|
|
ip6_clearpktopts(opt, IPV6_HOPOPTS);
|
|
|
|
opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_NOWAIT);
|
|
|
|
if (opt->ip6po_hbh == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
memcpy(opt->ip6po_hbh, hbh, hbhlen);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
#endif
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
{
|
|
|
|
struct ip6_dest *dest, **newdest = NULL;
|
|
|
|
int destlen;
|
|
|
|
|
|
|
|
if (!priv) /* XXX: see the comment for IPV6_HOPOPTS */
|
|
|
|
return (EPERM);
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
ip6_clearpktopts(opt, optname);
|
|
|
|
break; /* just remove the option */
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/* message length validation */
|
|
|
|
if (len < sizeof(struct ip6_dest))
|
|
|
|
return (EINVAL);
|
|
|
|
dest = (struct ip6_dest *)buf;
|
|
|
|
destlen = (dest->ip6d_len + 1) << 3;
|
|
|
|
if (len != destlen)
|
|
|
|
return (EINVAL);
|
|
|
|
/*
|
|
|
|
* Determine the position that the destination options header
|
|
|
|
* should be inserted; before or after the routing header.
|
|
|
|
*/
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_2292DSTOPTS:
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2006-05-05 04:03:21 +04:00
|
|
|
* The old advanced API is ambiguous on this point.
|
|
|
|
* Our approach is to determine the position based
|
|
|
|
* according to the existence of a routing header.
|
|
|
|
* Note, however, that this depends on the order of the
|
|
|
|
* extension headers in the ancillary data; the 1st
|
|
|
|
* part of the destination options header must appear
|
|
|
|
* before the routing header in the ancillary data,
|
|
|
|
* too.
|
|
|
|
* RFC3542 solved the ambiguity by introducing
|
|
|
|
* separate ancillary data or option types.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2006-05-05 04:03:21 +04:00
|
|
|
if (opt->ip6po_rthdr == NULL)
|
|
|
|
newdest = &opt->ip6po_dest1;
|
|
|
|
else
|
|
|
|
newdest = &opt->ip6po_dest2;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
newdest = &opt->ip6po_dest1;
|
|
|
|
break;
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
newdest = &opt->ip6po_dest2;
|
|
|
|
break;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
/* turn off the previous option, then set the new option. */
|
|
|
|
ip6_clearpktopts(opt, optname);
|
|
|
|
*newdest = malloc(destlen, M_IP6OPT, M_NOWAIT);
|
|
|
|
if (*newdest == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
memcpy(*newdest, dest, destlen);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef RFC2292
|
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
#endif
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
{
|
|
|
|
struct ip6_rthdr *rth;
|
|
|
|
int rthlen;
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
ip6_clearpktopts(opt, IPV6_RTHDR);
|
|
|
|
break; /* just remove the option */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* message length validation */
|
|
|
|
if (len < sizeof(struct ip6_rthdr))
|
|
|
|
return (EINVAL);
|
|
|
|
rth = (struct ip6_rthdr *)buf;
|
|
|
|
rthlen = (rth->ip6r_len + 1) << 3;
|
|
|
|
if (len != rthlen)
|
|
|
|
return (EINVAL);
|
|
|
|
switch (rth->ip6r_type) {
|
|
|
|
case IPV6_RTHDR_TYPE_0:
|
|
|
|
if (rth->ip6r_len == 0) /* must contain one addr */
|
|
|
|
return (EINVAL);
|
|
|
|
if (rth->ip6r_len % 2) /* length must be even */
|
|
|
|
return (EINVAL);
|
|
|
|
if (rth->ip6r_len / 2 != rth->ip6r_segleft)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
default:
|
2006-05-05 04:03:21 +04:00
|
|
|
return (EINVAL); /* not supported */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2006-05-05 04:03:21 +04:00
|
|
|
/* turn off the previous option */
|
|
|
|
ip6_clearpktopts(opt, IPV6_RTHDR);
|
|
|
|
opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_NOWAIT);
|
|
|
|
if (opt->ip6po_rthdr == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
memcpy(opt->ip6po_rthdr, rth, rthlen);
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2006-05-05 04:03:21 +04:00
|
|
|
case IPV6_USE_MIN_MTU:
|
|
|
|
if (len != sizeof(int))
|
|
|
|
return (EINVAL);
|
|
|
|
minmtupolicy = *(int *)buf;
|
|
|
|
if (minmtupolicy != IP6PO_MINMTU_MCASTONLY &&
|
|
|
|
minmtupolicy != IP6PO_MINMTU_DISABLE &&
|
|
|
|
minmtupolicy != IP6PO_MINMTU_ALL) {
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
opt->ip6po_minmtu = minmtupolicy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
if (len != sizeof(int))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (uproto == IPPROTO_TCP || *(int *)buf == 0) {
|
|
|
|
/*
|
|
|
|
* we ignore this option for TCP sockets.
|
|
|
|
* (RFC3542 leaves this case unspecified.)
|
|
|
|
*/
|
|
|
|
opt->ip6po_flags &= ~IP6PO_DONTFRAG;
|
|
|
|
} else
|
|
|
|
opt->ip6po_flags |= IP6PO_DONTFRAG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (ENOPROTOOPT);
|
|
|
|
} /* end of switch */
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routine called from ip6_output() to loop back a copy of an IP6 multicast
|
|
|
|
* packet to the input queue of a specified interface. Note that this
|
|
|
|
* calls the output routine of the loopback "driver", but with an interface
|
2004-12-04 19:10:25 +03:00
|
|
|
* pointer that might NOT be lo0ifp -- easier than replicating that code here.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
void
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_mloopback(struct ifnet *ifp, struct mbuf *m,
|
|
|
|
const struct sockaddr_in6 *dst)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-06-03 18:36:32 +04:00
|
|
|
struct mbuf *copym;
|
|
|
|
struct ip6_hdr *ip6;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
copym = m_copy(m, 0, M_COPYALL);
|
2000-06-03 18:36:32 +04:00
|
|
|
if (copym == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure to deep-copy IPv6 header portion in case the data
|
|
|
|
* is in an mbuf cluster, so that we can safely override the IPv6
|
|
|
|
* header portion later.
|
|
|
|
*/
|
|
|
|
if ((copym->m_flags & M_EXT) != 0 ||
|
|
|
|
copym->m_len < sizeof(struct ip6_hdr)) {
|
|
|
|
copym = m_pullup(copym, sizeof(struct ip6_hdr));
|
|
|
|
if (copym == NULL)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (copym->m_len < sizeof(*ip6)) {
|
|
|
|
m_freem(copym);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-03-30 15:08:56 +04:00
|
|
|
ip6 = mtod(copym, struct ip6_hdr *);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* clear embedded scope identifiers if necessary.
|
|
|
|
* in6_clearscope will touch the addresses only when necessary.
|
|
|
|
*/
|
|
|
|
in6_clearscope(&ip6->ip6_src);
|
|
|
|
in6_clearscope(&ip6->ip6_dst);
|
2000-06-03 18:36:32 +04:00
|
|
|
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
(void)looutput(ifp, copym, (const struct sockaddr *)dst, NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Chop IPv6 header off from the payload.
|
|
|
|
*/
|
|
|
|
static int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct mbuf *mh;
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
if (m->m_len > sizeof(*ip6)) {
|
|
|
|
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (mh == 0) {
|
|
|
|
m_freem(m);
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
2005-08-18 04:30:58 +04:00
|
|
|
M_MOVE_PKTHDR(mh, m);
|
1999-06-28 10:36:47 +04:00
|
|
|
MH_ALIGN(mh, sizeof(*ip6));
|
|
|
|
m->m_len -= sizeof(*ip6);
|
|
|
|
m->m_data += sizeof(*ip6);
|
|
|
|
mh->m_next = m;
|
|
|
|
m = mh;
|
|
|
|
m->m_len = sizeof(*ip6);
|
2007-03-04 08:59:00 +03:00
|
|
|
bcopy((void *)ip6, mtod(m, void *), sizeof(*ip6));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
exthdrs->ip6e_ip6 = m;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute IPv6 extension header length.
|
|
|
|
*/
|
|
|
|
int
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_optlen(struct in6pcb *in6p)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!in6p->in6p_outputopts)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
#define elen(x) \
|
|
|
|
(((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
|
|
|
|
|
|
|
|
len += elen(in6p->in6p_outputopts->ip6po_hbh);
|
|
|
|
len += elen(in6p->in6p_outputopts->ip6po_dest1);
|
|
|
|
len += elen(in6p->in6p_outputopts->ip6po_rthdr);
|
|
|
|
len += elen(in6p->in6p_outputopts->ip6po_dest2);
|
|
|
|
return len;
|
|
|
|
#undef elen
|
|
|
|
}
|