summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-30 15:29:17 +0000
committerume <ume@FreeBSD.org>2003-10-30 15:29:17 +0000
commitf06677c31d30ff047ed2e60d7ac2736e110b6a6c (patch)
tree6c106b7b2386f566c9111704d70041ccb3f63778
parent8ca63b7ab79f326e932107b3ead77217e1529349 (diff)
downloadFreeBSD-src-f06677c31d30ff047ed2e60d7ac2736e110b6a6c.zip
FreeBSD-src-f06677c31d30ff047ed2e60d7ac2736e110b6a6c.tar.gz
add management part of address selection policy described in
RFC3484. Obtained from: KAME
-rw-r--r--sys/netinet6/in6.c8
-rw-r--r--sys/netinet6/in6.h3
-rw-r--r--sys/netinet6/in6_src.c202
-rw-r--r--sys/netinet6/in6_var.h13
-rw-r--r--sys/netinet6/ip6_input.c1
5 files changed, 227 insertions, 0 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index ea01b1f..46ec23a 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -346,6 +346,14 @@ in6_control(so, cmd, data, ifp, td)
return (mrt6_ioctl(cmd, data));
}
+ switch(cmd) {
+ case SIOCAADDRCTL_POLICY:
+ case SIOCDADDRCTL_POLICY:
+ if (!privileged)
+ return (EPERM);
+ return (in6_src_ioctl(cmd, data));
+ }
+
if (ifp == NULL)
return (EOPNOTSUPP);
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index af3711d..5f3da0e 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -593,6 +593,8 @@ struct ip6_mtuinfo {
#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */
#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */
+#define IPV6CTL_ADDRCTLPOLICY 38 /* get/set address selection policy */
+
#define IPV6CTL_MAXFRAGS 41 /* max fragments */
/* New entries should be added here from current IPV6CTL_MAXID value. */
@@ -626,6 +628,7 @@ void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin,
struct sockaddr_in6 *sin6));
void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam));
void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam));
+extern void addrsel_policy_init __P((void));
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 4780f0f..cf10c93 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -75,6 +75,8 @@
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
#include <sys/errno.h>
#include <sys/time.h>
@@ -97,6 +99,22 @@
#include <net/net_osdep.h>
+static struct mtx addrsel_lock;
+#define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF)
+#define ADDRSEL_LOCK() mtx_lock(&addrsel_lock)
+#define ADDRSEL_UNLOCK() mtx_unlock(&addrsel_lock)
+#define ADDRSEL_LOCK_ASSERT() mtx_assert(&addrsel_lock, MA_OWNED)
+
+#define ADDR_LABEL_NOTAPP (-1)
+struct in6_addrpolicy defaultaddrpolicy;
+
+static void init_policy_queue __P((void));
+static int add_addrsel_policyent __P((struct in6_addrpolicy *));
+static int delete_addrsel_policyent __P((struct in6_addrpolicy *));
+static int walk_addrsel_policy __P((int (*)(struct in6_addrpolicy *, void *),
+ void *));
+static int dump_addrsel_policyent __P((struct in6_addrpolicy *, void *));
+
/*
* Return an IPv6 address, which is the most appropriate for a given
* destination and user specified options.
@@ -528,3 +546,187 @@ in6_clearscope(addr)
if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
addr->s6_addr16[1] = 0;
}
+
+void
+addrsel_policy_init()
+{
+ ADDRSEL_LOCK_INIT();
+
+ init_policy_queue();
+
+ /* initialize the "last resort" policy */
+ bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
+ defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
+}
+
+/*
+ * Subroutines to manage the address selection policy table via sysctl.
+ */
+struct walkarg {
+ struct sysctl_req *w_req;
+};
+
+static int in6_src_sysctl(SYSCTL_HANDLER_ARGS);
+SYSCTL_DECL(_net_inet6_ip6);
+SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
+ CTLFLAG_RD, in6_src_sysctl, "");
+
+static int
+in6_src_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct walkarg w;
+
+ if (req->newptr)
+ return EPERM;
+
+ bzero(&w, sizeof(w));
+ w.w_req = req;
+
+ return (walk_addrsel_policy(dump_addrsel_policyent, &w));
+}
+
+int
+in6_src_ioctl(cmd, data)
+ u_long cmd;
+ caddr_t data;
+{
+ int i;
+ struct in6_addrpolicy ent0;
+
+ if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY)
+ return (EOPNOTSUPP); /* check for safety */
+
+ ent0 = *(struct in6_addrpolicy *)data;
+
+ if (ent0.label == ADDR_LABEL_NOTAPP)
+ return (EINVAL);
+ /* check if the prefix mask is consecutive. */
+ if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0)
+ return (EINVAL);
+ /* clear trailing garbages (if any) of the prefix address. */
+ for (i = 0; i < 4; i++) {
+ ent0.addr.sin6_addr.s6_addr32[i] &=
+ ent0.addrmask.sin6_addr.s6_addr32[i];
+ }
+ ent0.use = 0;
+
+ switch (cmd) {
+ case SIOCAADDRCTL_POLICY:
+ return (add_addrsel_policyent(&ent0));
+ case SIOCDADDRCTL_POLICY:
+ return (delete_addrsel_policyent(&ent0));
+ }
+
+ return (0); /* XXX: compromise compilers */
+}
+
+/*
+ * The followings are implementation of the policy table using a
+ * simple tail queue.
+ * XXX such details should be hidden.
+ * XXX implementation using binary tree should be more efficient.
+ */
+struct addrsel_policyent {
+ TAILQ_ENTRY(addrsel_policyent) ape_entry;
+ struct in6_addrpolicy ape_policy;
+};
+
+TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
+
+struct addrsel_policyhead addrsel_policytab;
+
+static void
+init_policy_queue()
+{
+ TAILQ_INIT(&addrsel_policytab);
+}
+
+static int
+add_addrsel_policyent(newpolicy)
+ struct in6_addrpolicy *newpolicy;
+{
+ struct addrsel_policyent *new, *pol;
+
+ ADDRSEL_LOCK();
+
+ /* duplication check */
+ for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
+ pol = TAILQ_NEXT(pol, ape_entry)) {
+ if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr,
+ &pol->ape_policy.addr) &&
+ SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask,
+ &pol->ape_policy.addrmask)) {
+ return (EEXIST); /* or override it? */
+ }
+ }
+
+ MALLOC(new, struct addrsel_policyent *, sizeof(*new), M_IFADDR,
+ M_WAITOK);
+ bzero(new, sizeof(*new));
+
+ /* XXX: should validate entry */
+ new->ape_policy = *newpolicy;
+
+ TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
+ ADDRSEL_UNLOCK();
+
+ return (0);
+}
+
+static int
+delete_addrsel_policyent(key)
+ struct in6_addrpolicy *key;
+{
+ struct addrsel_policyent *pol;
+
+ ADDRSEL_LOCK();
+
+ /* search for the entry in the table */
+ for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
+ pol = TAILQ_NEXT(pol, ape_entry)) {
+ if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) &&
+ SA6_ARE_ADDR_EQUAL(&key->addrmask,
+ &pol->ape_policy.addrmask)) {
+ break;
+ }
+ }
+ if (pol == NULL)
+ return (ESRCH);
+
+ TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry);
+ ADDRSEL_UNLOCK();
+
+ return (0);
+}
+
+static int
+walk_addrsel_policy(callback, w)
+ int (*callback) __P((struct in6_addrpolicy *, void *));
+ void *w;
+{
+ struct addrsel_policyent *pol;
+ int error = 0;
+
+ ADDRSEL_LOCK();
+ for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
+ pol = TAILQ_NEXT(pol, ape_entry)) {
+ if ((error = (*callback)(&pol->ape_policy, w)) != 0)
+ return (error);
+ }
+ ADDRSEL_UNLOCK();
+
+ return (error);
+}
+
+static int
+dump_addrsel_policyent(pol, arg)
+ struct in6_addrpolicy *pol;
+ void *arg;
+{
+ int error = 0;
+ struct walkarg *w = arg;
+
+ error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol));
+
+ return (error);
+}
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index b481b04..bc06d0f 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -118,6 +118,15 @@ struct in6_ifaddr {
struct nd_prefix *ia6_ndpr;
};
+/* control structure to manage address selection policy */
+struct in6_addrpolicy {
+ struct sockaddr_in6 addr; /* prefix address */
+ struct sockaddr_in6 addrmask; /* prefix mask */
+ int preced; /* precedence */
+ int label; /* matching label */
+ u_quad_t use; /* statistics */
+};
+
/*
* IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12).
*/
@@ -432,6 +441,9 @@ struct in6_rrenumreq {
#define SIOCGETMIFCNT_IN6 _IOWR('u', 107, \
struct sioc_mif_req6) /* get pkt cnt per if */
+#define SIOCAADDRCTL_POLICY _IOW('u', 108, struct in6_addrpolicy)
+#define SIOCDADDRCTL_POLICY _IOW('u', 109, struct in6_addrpolicy)
+
#define IN6_IFF_ANYCAST 0x01 /* anycast address */
#define IN6_IFF_TENTATIVE 0x02 /* tentative address */
#define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */
@@ -604,6 +616,7 @@ int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *,
int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *,
struct ifnet *));
void in6_clearscope __P((struct in6_addr *));
+int in6_src_ioctl __P((u_long, caddr_t));
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_VAR_H_ */
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index adc9e87..c02d76e 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -198,6 +198,7 @@ ip6_init()
mtx_init(&ip6intrq.ifq_mtx, "ip6_inq", NULL, MTX_DEF);
netisr_register(NETISR_IPV6, ip6_input, &ip6intrq);
scope6_init();
+ addrsel_policy_init();
nd6_init();
frag6_init();
#ifndef RANDOM_IP_ID
OpenPOWER on IntegriCloud