aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/igmp.c3
-rw-r--r--sys/netinet/in.c99
-rw-r--r--sys/netinet/in_pcb.c6
-rw-r--r--sys/netinet/in_pcb.h7
-rw-r--r--sys/netinet/in_var.h2
-rw-r--r--sys/netinet/ip_fw2.c16
-rw-r--r--sys/netinet/ip_ipsec.c11
-rw-r--r--sys/netinet/ip_output.c19
-rw-r--r--sys/netinet/sctp_crc32.c1
-rw-r--r--sys/netinet/sctp_uio.h6
-rw-r--r--sys/netinet/tcp_hostcache.c2
-rw-r--r--sys/netinet/tcp_reass.c3
-rw-r--r--sys/netinet/tcp_subr.c2
-rw-r--r--sys/netinet/udp_usrreq.c102
-rw-r--r--sys/netinet/udp_var.h18
-rw-r--r--sys/netinet/vinet.h2
16 files changed, 225 insertions, 74 deletions
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index 34390a0532d4..1a311f2ee408 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -1100,9 +1100,6 @@ igmp_input_v3_group_query(struct in_multi *inm, struct igmp_ifinfo *igi,
nsrc = ntohs(igmpv3->igmp_numsrc);
- if (!IS_DEFAULT_VNET(curvnet))
- return (retval);
-
/*
* Deal with group-specific queries upfront.
* If any group query is already pending, purge any recorded
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 81803265398f..a656102da0e7 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -34,6 +34,7 @@
__FBSDID("$FreeBSD$");
#include "opt_carp.h"
+#include "opt_route.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -45,12 +46,15 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <sys/syslog.h>
#include <sys/vimage.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_llatbl.h>
#include <net/if_types.h>
#include <net/route.h>
+#include <net/vnet.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@@ -811,9 +815,13 @@ static int
in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
int scrub)
{
+ INIT_VNET_NET(ifp->if_vnet);
INIT_VNET_INET(ifp->if_vnet);
register u_long i = ntohl(sin->sin_addr.s_addr);
struct sockaddr_in oldaddr;
+ struct rtentry *rt = NULL;
+ struct rt_addrinfo info;
+ static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
int s = splimp(), flags = RTF_UP, error = 0;
oldaddr = ia->ia_addr;
@@ -900,6 +908,32 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
if ((error = in_addprefix(ia, flags)) != 0)
return (error);
+ if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY)
+ return (0);
+
+ /*
+ * add a loopback route to self
+ */
+ if (!(ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+ bzero(&info, sizeof(info));
+ info.rti_ifp = V_loif;
+ info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC;
+ info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr;
+ info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
+ error = rtrequest1_fib(RTM_ADD, &info, &rt, 0);
+
+ if (error == 0 && rt != NULL) {
+ RT_LOCK(rt);
+ ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
+ rt->rt_ifp->if_type;
+ ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
+ rt->rt_ifp->if_index;
+ RT_REMREF(rt);
+ RT_UNLOCK(rt);
+ } else if (error != 0)
+ log(LOG_INFO, "in_ifinit: insertion failed\n");
+ }
+
return (error);
}
@@ -975,14 +1009,35 @@ extern void arp_ifscrub(struct ifnet *ifp, uint32_t addr);
static int
in_scrubprefix(struct in_ifaddr *target)
{
+ INIT_VNET_NET(curvnet);
INIT_VNET_INET(curvnet);
struct in_ifaddr *ia;
struct in_addr prefix, mask, p;
int error;
+ struct sockaddr_in prefix0, mask0;
+ struct rt_addrinfo info;
+ struct sockaddr_dl null_sdl;
if ((target->ia_flags & IFA_ROUTE) == 0)
return (0);
+ if ((target->ia_addr.sin_addr.s_addr != INADDR_ANY) &&
+ !(target->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+ bzero(&null_sdl, sizeof(null_sdl));
+ null_sdl.sdl_len = sizeof(null_sdl);
+ null_sdl.sdl_family = AF_LINK;
+ null_sdl.sdl_type = V_loif->if_type;
+ null_sdl.sdl_index = V_loif->if_index;
+ bzero(&info, sizeof(info));
+ info.rti_flags = target->ia_flags | RTF_HOST | RTF_STATIC;
+ info.rti_info[RTAX_DST] = (struct sockaddr *)&target->ia_addr;
+ info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
+ error = rtrequest1_fib(RTM_DELETE, &info, NULL, 0);
+
+ if (error != 0)
+ log(LOG_INFO, "in_scrubprefix: deletion failed\n");
+ }
+
if (rtinitflags(target))
prefix = target->ia_dstaddr.sin_addr;
else {
@@ -1029,6 +1084,20 @@ in_scrubprefix(struct in_ifaddr *target)
}
/*
+ * remove all L2 entries on the given prefix
+ */
+ bzero(&prefix0, sizeof(prefix0));
+ prefix0.sin_len = sizeof(prefix0);
+ prefix0.sin_family = AF_INET;
+ prefix0.sin_addr.s_addr = target->ia_subnet;
+ bzero(&mask0, sizeof(mask0));
+ mask0.sin_len = sizeof(mask0);
+ mask0.sin_family = AF_INET;
+ mask0.sin_addr.s_addr = target->ia_subnetmask;
+ lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
+ (struct sockaddr *)&mask0);
+
+ /*
* As no-one seem to have this prefix, we can remove the route.
*/
rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
@@ -1136,7 +1205,6 @@ in_purgemaddrs(struct ifnet *ifp)
IN_MULTI_UNLOCK();
}
-#include <sys/syslog.h>
#include <net/if_dl.h>
#include <netinet/if_ether.h>
@@ -1180,6 +1248,34 @@ in_lltable_free(struct lltable *llt, struct llentry *lle)
free(lle, M_LLTABLE);
}
+
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
+ (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
+
+static void
+in_lltable_prefix_free(struct lltable *llt,
+ const struct sockaddr *prefix,
+ const struct sockaddr *mask)
+{
+ const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
+ const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+ struct llentry *lle, *next;
+ register int i;
+
+ for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+ LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+
+ if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in *)L3_ADDR(lle),
+ pfx, msk)) {
+ callout_drain(&lle->la_timer);
+ LLE_WLOCK(lle);
+ llentry_free(lle);
+ }
+ }
+ }
+}
+
+
static int
in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
{
@@ -1370,6 +1466,7 @@ in_domifattach(struct ifnet *ifp)
if (llt != NULL) {
llt->llt_new = in_lltable_new;
llt->llt_free = in_lltable_free;
+ llt->llt_prefix_free = in_lltable_prefix_free;
llt->llt_rtcheck = in_lltable_rtcheck;
llt->llt_lookup = in_lltable_lookup;
llt->llt_dump = in_lltable_dump;
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index dbc5ca844fba..94460bb0fc14 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -120,6 +120,8 @@ int ipport_tcplastcount;
if ((var) < (min)) { (var) = (min); } \
else if ((var) > (max)) { (var) = (max); }
+static void in_pcbremlists(struct inpcb *inp);
+
static int
sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS)
{
@@ -1512,7 +1514,7 @@ in_pcbrehash(struct inpcb *inp)
/*
* Remove PCB from various lists.
*/
-void
+static void
in_pcbremlists(struct inpcb *inp)
{
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
@@ -1878,7 +1880,7 @@ db_print_inpvflag(u_char inp_vflag)
}
}
-void
+static void
db_print_inpcb(struct inpcb *inp, const char *name, int indent)
{
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index c86f1abc318d..aa30e43d7460 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -501,14 +501,7 @@ int in_getsockaddr(struct socket *so, struct sockaddr **nam);
struct sockaddr *
in_sockaddr(in_port_t port, struct in_addr *addr);
void in_pcbsosetlabel(struct socket *so);
-void in_pcbremlists(struct inpcb *inp);
void ipport_tick(void *xtp);
-
-/*
- * Debugging routines compiled in when DDB is present.
- */
-void db_print_inpcb(struct inpcb *inp, const char *name, int indent);
-
#endif /* _KERNEL */
#endif /* !_NETINET_IN_PCB_H_ */
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index 84eb8ebb8371..2b59e929b5f4 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -336,7 +336,7 @@ SYSCTL_DECL(_net_inet_raw);
LIST_HEAD(in_multihead, in_multi); /* XXX unused */
#ifdef VIMAGE_GLOBALS
extern struct in_multihead in_multihead;
-#endif /* BURN_BRIDGES */
+#endif
/*
* Lock macros for IPv4 layer multicast address lists. IPv4 lock goes
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index ab65f3515c21..965cddb32cf3 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -127,6 +127,11 @@ static struct callout ipfw_timeout;
static int verbose_limit;
#endif
+#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
+static int default_to_accept = 1;
+#else
+static int default_to_accept;
+#endif
static uma_zone_t ipfw_dyn_rule_zone;
/*
@@ -176,7 +181,7 @@ SYSCTL_V_PROC(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, enable,
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, fw_enable, 0,
ipfw_chg_hook, "I", "Enable ipfw");
SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, autoinc_step,
- CTLFLAG_RW, autoinc_step, 0, "Rule number autincrement step");
+ CTLFLAG_RW, autoinc_step, 0, "Rule number auto-increment step");
SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_fw, OID_AUTO, one_pass,
CTLFLAG_RW | CTLFLAG_SECURE3, fw_one_pass, 0,
"Only do a single pass through ipfw when using dummynet(4)");
@@ -190,6 +195,9 @@ SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
NULL, IPFW_DEFAULT_RULE, "The default/max possible rule number.");
SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
NULL, IPFW_TABLES_MAX, "The maximum number of tables.");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
+ &default_to_accept, 0, "Make the default rule accept all packets.");
+TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
#endif /* SYSCTL_NODE */
/*
@@ -4636,11 +4644,7 @@ ipfw_init(void)
default_rule.set = RESVD_SET;
default_rule.cmd[0].len = 1;
- default_rule.cmd[0].opcode =
-#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
- 1 ? O_ACCEPT :
-#endif
- O_DENY;
+ default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
error = add_rule(&V_layer3_chain, &default_rule);
if (error != 0) {
diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c
index 45364a8ae312..ab5d22d88a7f 100644
--- a/sys/netinet/ip_ipsec.c
+++ b/sys/netinet/ip_ipsec.c
@@ -71,6 +71,10 @@ __FBSDID("$FreeBSD$");
extern struct protosw inetsw[];
+#ifdef VIMAGE_GLOBALS
+int ip4_ipsec_filtertunnel;
+#endif
+
/*
* Check if we have to jump over firewall processing for this packet.
* Called from ip_input().
@@ -79,11 +83,14 @@ extern struct protosw inetsw[];
int
ip_ipsec_filtertunnel(struct mbuf *m)
{
-#if defined(IPSEC) && !defined(IPSEC_FILTERTUNNEL)
+#if defined(IPSEC)
+ INIT_VNET_IPSEC(curvnet);
+
/*
* Bypass packet filtering for packets from a tunnel.
*/
- if (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
+ if (!V_ip4_ipsec_filtertunnel &&
+ m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
return 1;
#endif
return 0;
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 35905e80d42b..6e4f8792aad0 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -150,20 +150,25 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
#endif
M_ASSERTPKTHDR(m);
- if (ro == NULL) {
- ro = &iproute;
- bzero(ro, sizeof (*ro));
- }
-
if (inp != NULL) {
- M_SETFIB(m, inp->inp_inc.inc_fibnum);
INP_LOCK_ASSERT(inp);
+ M_SETFIB(m, inp->inp_inc.inc_fibnum);
if (inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
m->m_pkthdr.flowid = inp->inp_flowid;
m->m_flags |= M_FLOWID;
}
}
- if ((ro == &iproute) && (ro->ro_rt == NULL) && (ro->ro_lle == NULL)) {
+
+ if (ro == NULL) {
+ ro = &iproute;
+ bzero(ro, sizeof (*ro));
+
+ /*
+ * The flow table returns route entries valid for up to 30
+ * seconds; we rely on the remainder of ip_output() taking no
+ * longer than that long for the stability of ro_rt. The
+ * flow ID assignment must have happened before this point.
+ */
if (flowtable_lookup(ip_ft, m, ro) == 0)
nortfree = 1;
}
diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c
index 9594369a8b12..aeb97153855c 100644
--- a/sys/netinet/sctp_crc32.c
+++ b/sys/netinet/sctp_crc32.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_crc32.h>
#include <netinet/sctp_pcb.h>
+
#if !defined(SCTP_WITH_NO_CSUM)
static uint32_t
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index efcd2c4e4fa8..e58325d75933 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -764,6 +764,8 @@ struct sctp_timeval {
};
struct sctpstat {
+ struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18
+ * (TimeStamp) */
/* MIB according to RFC 3873 */
uint32_t sctps_currestab; /* sctpStats 1 (Gauge32) */
uint32_t sctps_activeestab; /* sctpStats 2 (Counter32) */
@@ -948,8 +950,8 @@ struct sctpstat {
uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via
* fwd-tsn's */
- struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18
- * (TimeStamp) */
+ uint32_t sctps_reserved[32]; /* Future ABI compat - remove int's
+ * from here when adding new */
};
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
diff --git a/sys/netinet/tcp_hostcache.c b/sys/netinet/tcp_hostcache.c
index 84586dbf6ea8..93367c5e16a1 100644
--- a/sys/netinet/tcp_hostcache.c
+++ b/sys/netinet/tcp_hostcache.c
@@ -637,7 +637,7 @@ tcp_hc_purge(void *arg)
CURVNET_SET((struct vnet *) arg);
INIT_VNET_INET(curvnet);
struct hc_metrics *hc_entry, *hc_next;
- int all = 0; /* XXX was: (intptr_t)arg - makes no sense? */
+ int all = 0;
int i;
if (V_tcp_hostcache.purgeall) {
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 080bb02c40bf..0849c25161c3 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -150,8 +150,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
/*
* XXX: tcp_reass() is rather inefficient with its data structures
- * and should be rewritten (see NetBSD for optimizations). While
- * doing that it should move to its own file tcp_reass.c.
+ * and should be rewritten (see NetBSD for optimizations).
*/
/*
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index c1dc4b3caac5..3c65a5412998 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -373,7 +373,7 @@ tcp_init(void)
&V_tcbinfo.ipi_hashmask);
V_tcbinfo.ipi_porthashbase = hashinit(hashsize, M_PCB,
&V_tcbinfo.ipi_porthashmask);
- V_tcbinfo.ipi_zone = uma_zcreate("inpcb", sizeof(struct inpcb),
+ V_tcbinfo.ipi_zone = uma_zcreate("tcp_inpcb", sizeof(struct inpcb),
NULL, NULL, tcp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(V_tcbinfo.ipi_zone, maxsockets);
/*
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 9aa83dd1f9fc..a49240c14b0c 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -137,6 +137,7 @@ SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
#ifdef VIMAGE_GLOBALS
struct inpcbhead udb; /* from udp_var.h */
struct inpcbinfo udbinfo;
+static uma_zone_t udpcb_zone;
struct udpstat udpstat; /* from udp_var.h */
#endif
@@ -158,6 +159,7 @@ udp_zone_change(void *tag)
INIT_VNET_INET(curvnet);
uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+ uma_zone_set_max(V_udpcb_zone, maxsockets);
}
static int
@@ -187,13 +189,39 @@ udp_init(void)
&V_udbinfo.ipi_hashmask);
V_udbinfo.ipi_porthashbase = hashinit(UDBHASHSIZE, M_PCB,
&V_udbinfo.ipi_porthashmask);
- V_udbinfo.ipi_zone = uma_zcreate("udpcb", sizeof(struct inpcb), NULL,
- NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ V_udbinfo.ipi_zone = uma_zcreate("udp_inpcb", sizeof(struct inpcb),
+ NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+
+ V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ uma_zone_set_max(V_udpcb_zone, maxsockets);
+
EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL,
EVENTHANDLER_PRI_ANY);
}
+int
+udp_newudpcb(struct inpcb *inp)
+{
+ INIT_VNET_INET(curvnet);
+ struct udpcb *up;
+
+ up = uma_zalloc(V_udpcb_zone, M_NOWAIT | M_ZERO);
+ if (up == NULL)
+ return (ENOBUFS);
+ inp->inp_ppcb = up;
+ return (0);
+}
+
+void
+udp_discardcb(struct udpcb *up)
+{
+ INIT_VNET_INET(curvnet);
+
+ uma_zfree(V_udpcb_zone, up);
+}
+
/*
* Subroutine of udp_input(), which appends the provided mbuf chain to the
* passed pcb/socket. The caller must provide a sockaddr_in via udp_in that
@@ -272,6 +300,7 @@ udp_input(struct mbuf *m, int off)
struct udphdr *uh;
struct ifnet *ifp;
struct inpcb *inp;
+ struct udpcb *up;
int len;
struct ip save_ip;
struct sockaddr_in udp_in;
@@ -455,28 +484,25 @@ udp_input(struct mbuf *m, int off)
struct mbuf *n;
n = m_copy(m, 0, M_COPYALL);
- if (last->inp_ppcb == NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == NULL) {
if (n != NULL)
udp_append(last,
ip, n,
iphlen +
sizeof(struct udphdr),
&udp_in);
- INP_RUNLOCK(last);
} else {
/*
* Engage the tunneling protocol we
* will have to leave the info_lock
* up, since we are hunting through
* multiple UDP's.
- *
*/
- udp_tun_func_t tunnel_func;
- tunnel_func = (udp_tun_func_t)last->inp_ppcb;
- tunnel_func(n, iphlen, last);
- INP_RUNLOCK(last);
+ (*up->u_tun_func)(n, iphlen, last);
}
+ INP_RUNLOCK(last);
}
last = inp;
/*
@@ -501,22 +527,18 @@ udp_input(struct mbuf *m, int off)
UDPSTAT_INC(udps_noportbcast);
goto badheadlocked;
}
- if (last->inp_ppcb == NULL) {
+ up = intoudpcb(last);
+ if (up->u_tun_func == NULL) {
udp_append(last, ip, m, iphlen + sizeof(struct udphdr),
&udp_in);
- INP_RUNLOCK(last);
- INP_INFO_RUNLOCK(&V_udbinfo);
} else {
/*
* Engage the tunneling protocol.
*/
- udp_tun_func_t tunnel_func;
-
- tunnel_func = (udp_tun_func_t)last->inp_ppcb;
- tunnel_func(m, iphlen, last);
- INP_RUNLOCK(last);
- INP_INFO_RUNLOCK(&V_udbinfo);
+ (*up->u_tun_func)(m, iphlen, last);
}
+ INP_RUNLOCK(last);
+ INP_INFO_RUNLOCK(&V_udbinfo);
return;
}
@@ -560,18 +582,16 @@ udp_input(struct mbuf *m, int off)
INP_RUNLOCK(inp);
goto badunlocked;
}
- if (inp->inp_ppcb != NULL) {
+ up = intoudpcb(inp);
+ if (up->u_tun_func == NULL) {
+ udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
+ } else {
/*
* Engage the tunneling protocol.
*/
- udp_tun_func_t tunnel_func;
- tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
- tunnel_func(m, iphlen, inp);
- INP_RUNLOCK(inp);
- return;
+ (*up->u_tun_func)(m, iphlen, inp);
}
- udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
INP_RUNLOCK(inp);
return;
@@ -1142,18 +1162,19 @@ udp_attach(struct socket *so, int proto, struct thread *td)
}
inp = (struct inpcb *)so->so_pcb;
- INP_INFO_WUNLOCK(&V_udbinfo);
inp->inp_vflag |= INP_IPV4;
inp->inp_ip_ttl = V_ip_defttl;
- /*
- * UDP does not have a per-protocol pcb (inp->inp_ppcb).
- * We use this pointer for kernel tunneling pointer.
- * If we ever need to have a protocol block we will
- * need to move this function pointer there. Null
- * in this pointer means "do the normal thing".
- */
- inp->inp_ppcb = NULL;
+
+ error = udp_newudpcb(inp);
+ if (error) {
+ in_pcbdetach(inp);
+ in_pcbfree(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
+ return (error);
+ }
+
INP_WUNLOCK(inp);
+ INP_INFO_WUNLOCK(&V_udbinfo);
return (0);
}
@@ -1161,24 +1182,26 @@ int
udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f)
{
struct inpcb *inp;
+ struct udpcb *up;
- inp = (struct inpcb *)so->so_pcb;
KASSERT(so->so_type == SOCK_DGRAM, ("udp_set_kernel_tunneling: !dgram"));
KASSERT(so->so_pcb != NULL, ("udp_set_kernel_tunneling: NULL inp"));
if (so->so_type != SOCK_DGRAM) {
/* Not UDP socket... sorry! */
return (ENOTSUP);
}
+ inp = (struct inpcb *)so->so_pcb;
if (inp == NULL) {
/* NULL INP? */
return (EINVAL);
}
INP_WLOCK(inp);
- if (inp->inp_ppcb != NULL) {
+ up = intoudpcb(inp);
+ if (up->u_tun_func != NULL) {
INP_WUNLOCK(inp);
return (EBUSY);
}
- inp->inp_ppcb = f;
+ up->u_tun_func = f;
INP_WUNLOCK(inp);
return (0);
}
@@ -1256,6 +1279,7 @@ udp_detach(struct socket *so)
{
INIT_VNET_INET(so->so_vnet);
struct inpcb *inp;
+ struct udpcb *up;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
@@ -1263,9 +1287,13 @@ udp_detach(struct socket *so)
("udp_detach: not disconnected"));
INP_INFO_WLOCK(&V_udbinfo);
INP_WLOCK(inp);
+ up = intoudpcb(inp);
+ KASSERT(up != NULL, ("%s: up == NULL", __func__));
+ inp->inp_ppcb = NULL;
in_pcbdetach(inp);
in_pcbfree(inp);
INP_INFO_WUNLOCK(&V_udbinfo);
+ udp_discardcb(up);
}
static int
diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h
index d83f705f58a6..e4298191e090 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -51,6 +51,19 @@ struct udpiphdr {
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
+typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
+
+/*
+ * UDP control block; one per udp.
+ */
+struct udpcb {
+ udp_tun_func_t u_tun_func; /* UDP kernel tunneling callback. */
+ u_int u_flags; /* Generic UDP flags. */
+};
+
+#define intoudpcb(ip) ((struct udpcb *)(ip)->inp_ppcb)
+#define sotoudpcb(so) (intoudpcb(sotoinpcb(so)))
+
struct udpstat {
/* input statistics: */
u_long udps_ipackets; /* total input packets */
@@ -110,14 +123,15 @@ extern u_long udp_sendspace;
extern u_long udp_recvspace;
extern int udp_log_in_vain;
+int udp_newudpcb(struct inpcb *);
+void udp_discardcb(struct udpcb *);
+
void udp_ctlinput(int, struct sockaddr *, void *);
void udp_init(void);
void udp_input(struct mbuf *, int);
struct inpcb *udp_notify(struct inpcb *inp, int errno);
int udp_shutdown(struct socket *so);
-
-typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f);
#endif
diff --git a/sys/netinet/vinet.h b/sys/netinet/vinet.h
index 6dcb685b98eb..026869326e28 100644
--- a/sys/netinet/vinet.h
+++ b/sys/netinet/vinet.h
@@ -149,6 +149,7 @@ struct vnet_inet {
struct inpcbhead _udb;
struct inpcbinfo _udbinfo;
+ uma_zone_t _udpcb_zone;
struct udpstat _udpstat;
int _udp_blackhole;
@@ -373,6 +374,7 @@ extern struct vnet_inet vnet_inet_0;
#define V_twq_2msl VNET_INET(twq_2msl)
#define V_udb VNET_INET(udb)
#define V_udbinfo VNET_INET(udbinfo)
+#define V_udpcb_zone VNET_INET(udpcb_zone)
#define V_udp_blackhole VNET_INET(udp_blackhole)
#define V_udpstat VNET_INET(udpstat)
#define V_useloopback VNET_INET(useloopback)