diff options
Diffstat (limited to 'sys/netinet')
| -rw-r--r-- | sys/netinet/igmp.c | 3 | ||||
| -rw-r--r-- | sys/netinet/in.c | 99 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.c | 6 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.h | 7 | ||||
| -rw-r--r-- | sys/netinet/in_var.h | 2 | ||||
| -rw-r--r-- | sys/netinet/ip_fw2.c | 16 | ||||
| -rw-r--r-- | sys/netinet/ip_ipsec.c | 11 | ||||
| -rw-r--r-- | sys/netinet/ip_output.c | 19 | ||||
| -rw-r--r-- | sys/netinet/sctp_crc32.c | 1 | ||||
| -rw-r--r-- | sys/netinet/sctp_uio.h | 6 | ||||
| -rw-r--r-- | sys/netinet/tcp_hostcache.c | 2 | ||||
| -rw-r--r-- | sys/netinet/tcp_reass.c | 3 | ||||
| -rw-r--r-- | sys/netinet/tcp_subr.c | 2 | ||||
| -rw-r--r-- | sys/netinet/udp_usrreq.c | 102 | ||||
| -rw-r--r-- | sys/netinet/udp_var.h | 18 | ||||
| -rw-r--r-- | sys/netinet/vinet.h | 2 |
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) |
