aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey V. Elsukov <ae@FreeBSD.org>2018-10-21 17:55:26 +0000
committerAndrey V. Elsukov <ae@FreeBSD.org>2018-10-21 17:55:26 +0000
commit8251c68d5c8f068fbf8462b8809517d45f8fed86 (patch)
treeb27d45b3977253546359784b6a7f6649827203d1
parent6ab6e9d3f48dcef22551e65d34e2c802ab1ac687 (diff)
downloadsrc-8251c68d5c8f068fbf8462b8809517d45f8fed86.tar.gz
src-8251c68d5c8f068fbf8462b8809517d45f8fed86.zip
Notes
-rw-r--r--sys/net/if.c12
-rw-r--r--sys/netinet/ip_encap.c152
-rw-r--r--sys/netinet/ip_encap.h11
3 files changed, 159 insertions, 16 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 3469f75f1354..2acea128cdfd 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -328,18 +328,6 @@ static MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals");
MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
-/*
- * Support for old ifaddr_event.
- */
-static void
-ifaddr_event_compat(void *arg __unused, struct ifnet *ifp,
- struct ifaddr *ifa __unused, int event __unused)
-{
-
- EVENTHANDLER_INVOKE(ifaddr_event, ifp);
-}
-EVENTHANDLER_DEFINE(ifaddr_event_ext, ifaddr_event_compat, NULL, 0);
-
struct ifnet *
ifnet_byindex_locked(u_short idx)
{
diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c
index 9d98fcfe9cff..bcae4691247e 100644
--- a/sys/netinet/ip_encap.c
+++ b/sys/netinet/ip_encap.c
@@ -100,22 +100,139 @@ struct encaptab {
encap_input_t input;
};
+struct srcaddrtab {
+ CK_LIST_ENTRY(srcaddrtab) chain;
+
+ encap_srcaddr_t srcaddr;
+ void *arg;
+};
+
CK_LIST_HEAD(encaptab_head, encaptab);
+CK_LIST_HEAD(srcaddrtab_head, srcaddrtab);
#ifdef INET
static struct encaptab_head ipv4_encaptab = CK_LIST_HEAD_INITIALIZER();
+static struct srcaddrtab_head ipv4_srcaddrtab = CK_LIST_HEAD_INITIALIZER();
#endif
#ifdef INET6
static struct encaptab_head ipv6_encaptab = CK_LIST_HEAD_INITIALIZER();
+static struct srcaddrtab_head ipv6_srcaddrtab = CK_LIST_HEAD_INITIALIZER();
#endif
-static struct mtx encapmtx;
+static struct mtx encapmtx, srcaddrmtx;
MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF);
+MTX_SYSINIT(srcaddrmtx, &srcaddrmtx, "srcaddrmtx", MTX_DEF);
#define ENCAP_WLOCK() mtx_lock(&encapmtx)
#define ENCAP_WUNLOCK() mtx_unlock(&encapmtx)
-#define ENCAP_RLOCK() struct epoch_tracker encap_et; epoch_enter_preempt(net_epoch_preempt, &encap_et)
-#define ENCAP_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &encap_et)
+#define ENCAP_RLOCK_TRACKER struct epoch_tracker encap_et
+#define ENCAP_RLOCK() \
+ epoch_enter_preempt(net_epoch_preempt, &encap_et)
+#define ENCAP_RUNLOCK() \
+ epoch_exit_preempt(net_epoch_preempt, &encap_et)
#define ENCAP_WAIT() epoch_wait_preempt(net_epoch_preempt)
+#define SRCADDR_WLOCK() mtx_lock(&srcaddrmtx)
+#define SRCADDR_WUNLOCK() mtx_unlock(&srcaddrmtx)
+#define SRCADDR_RLOCK_TRACKER struct epoch_tracker srcaddr_et
+#define SRCADDR_RLOCK() \
+ epoch_enter_preempt(net_epoch_preempt, &srcaddr_et)
+#define SRCADDR_RUNLOCK() \
+ epoch_exit_preempt(net_epoch_preempt, &srcaddr_et)
+#define SRCADDR_WAIT() epoch_wait_preempt(net_epoch_preempt)
+
+/*
+ * ifaddr_event_ext handler.
+ *
+ * Tunnelling interfaces may request the kernel to notify when
+ * some interface addresses appears or disappears. Usually tunnelling
+ * interface must use an address configured on the local machine as
+ * ingress address to be able receive datagramms and do not send
+ * spoofed packets.
+ */
+static void
+srcaddr_change_event(void *arg __unused, struct ifnet *ifp,
+ struct ifaddr *ifa, int event)
+{
+ SRCADDR_RLOCK_TRACKER;
+ struct srcaddrtab_head *head;
+ struct srcaddrtab *p;
+
+ /* Support for old ifaddr_event. */
+ EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ head = &ipv4_srcaddrtab;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ head = &ipv6_srcaddrtab;
+ break;
+#endif
+ default:
+ /* ignore event */
+ return;
+ }
+
+ SRCADDR_RLOCK();
+ CK_LIST_FOREACH(p, head, chain) {
+ (*p->srcaddr)(p->arg, ifa->ifa_addr, event);
+ }
+ SRCADDR_RUNLOCK();
+}
+EVENTHANDLER_DEFINE(ifaddr_event_ext, srcaddr_change_event, NULL, 0);
+
+static struct srcaddrtab *
+encap_register_srcaddr(struct srcaddrtab_head *head, encap_srcaddr_t func,
+ void *arg, int mflags)
+{
+ struct srcaddrtab *p, *tmp;
+
+ if (func == NULL)
+ return (NULL);
+ p = malloc(sizeof(*p), M_NETADDR, mflags);
+ if (p == NULL)
+ return (NULL);
+ p->srcaddr = func;
+ p->arg = arg;
+
+ SRCADDR_WLOCK();
+ CK_LIST_FOREACH(tmp, head, chain) {
+ if (func == tmp->srcaddr && arg == tmp->arg)
+ break;
+ }
+ if (tmp == NULL)
+ CK_LIST_INSERT_HEAD(head, p, chain);
+ SRCADDR_WUNLOCK();
+
+ if (tmp != NULL) {
+ free(p, M_NETADDR);
+ p = tmp;
+ }
+ return (p);
+}
+
+static int
+encap_unregister_srcaddr(struct srcaddrtab_head *head,
+ const struct srcaddrtab *cookie)
+{
+ struct srcaddrtab *p;
+
+ SRCADDR_WLOCK();
+ CK_LIST_FOREACH(p, head, chain) {
+ if (p == cookie) {
+ CK_LIST_REMOVE(p, chain);
+ SRCADDR_WUNLOCK();
+ SRCADDR_WAIT();
+ free(p, M_NETADDR);
+ return (0);
+ }
+ }
+ SRCADDR_WUNLOCK();
+ return (EINVAL);
+}
+
static struct encaptab *
encap_attach(struct encaptab_head *head, const struct encap_config *cfg,
void *arg, int mflags)
@@ -175,6 +292,7 @@ encap_detach(struct encaptab_head *head, const struct encaptab *cookie)
static int
encap_input(struct encaptab_head *head, struct mbuf *m, int off, int proto)
{
+ ENCAP_RLOCK_TRACKER;
struct encaptab *ep, *match;
void *arg;
int matchprio, ret;
@@ -220,6 +338,20 @@ encap_input(struct encaptab_head *head, struct mbuf *m, int off, int proto)
}
#ifdef INET
+const struct srcaddrtab *
+ip_encap_register_srcaddr(encap_srcaddr_t func, void *arg, int mflags)
+{
+
+ return (encap_register_srcaddr(&ipv4_srcaddrtab, func, arg, mflags));
+}
+
+int
+ip_encap_unregister_srcaddr(const struct srcaddrtab *cookie)
+{
+
+ return (encap_unregister_srcaddr(&ipv4_srcaddrtab, cookie));
+}
+
const struct encaptab *
ip_encap_attach(const struct encap_config *cfg, void *arg, int mflags)
{
@@ -245,6 +377,20 @@ encap4_input(struct mbuf **mp, int *offp, int proto)
#endif /* INET */
#ifdef INET6
+const struct srcaddrtab *
+ip6_encap_register_srcaddr(encap_srcaddr_t func, void *arg, int mflags)
+{
+
+ return (encap_register_srcaddr(&ipv6_srcaddrtab, func, arg, mflags));
+}
+
+int
+ip6_encap_unregister_srcaddr(const struct srcaddrtab *cookie)
+{
+
+ return (encap_unregister_srcaddr(&ipv6_srcaddrtab, cookie));
+}
+
const struct encaptab *
ip6_encap_attach(const struct encap_config *cfg, void *arg, int mflags)
{
diff --git a/sys/netinet/ip_encap.h b/sys/netinet/ip_encap.h
index 65ac922fc1bb..898114c2db58 100644
--- a/sys/netinet/ip_encap.h
+++ b/sys/netinet/ip_encap.h
@@ -43,7 +43,8 @@ int encap6_input(struct mbuf **, int *, int);
typedef int (*encap_lookup_t)(const struct mbuf *, int, int, void **);
typedef int (*encap_check_t)(const struct mbuf *, int, int, void *);
-typedef int (*encap_input_t)(struct mbuf *, int , int, void *);
+typedef int (*encap_input_t)(struct mbuf *, int, int, void *);
+typedef void (*encap_srcaddr_t)(void *, const struct sockaddr *, int);
struct encap_config {
int proto; /* protocol */
@@ -60,12 +61,20 @@ struct encap_config {
};
struct encaptab;
+struct srcaddrtab;
const struct encaptab *ip_encap_attach(const struct encap_config *,
void *arg, int mflags);
const struct encaptab *ip6_encap_attach(const struct encap_config *,
void *arg, int mflags);
+const struct srcaddrtab *ip_encap_register_srcaddr(encap_srcaddr_t,
+ void *arg, int mflags);
+const struct srcaddrtab *ip6_encap_register_srcaddr(encap_srcaddr_t,
+ void *arg, int mflags);
+
+int ip_encap_unregister_srcaddr(const struct srcaddrtab *);
+int ip6_encap_unregister_srcaddr(const struct srcaddrtab *);
int ip_encap_detach(const struct encaptab *);
int ip6_encap_detach(const struct encaptab *);
#endif