Add support for UDP-Lite protocol (RFC 3828) to IPv4 and IPv6 stacks.
Tested with vlc and a test suite [1]. [1] http://www.erg.abdn.ac.uk/~gerrit/udp-lite/files/udplite_linux.tar.gz Reviewed by: jhb, glebius, adrian
This commit is contained in:
parent
212168f867
commit
e06e816f67
@ -170,12 +170,14 @@ static const struct explore explore[] = {
|
||||
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 },
|
||||
{ PF_INET6, SOCK_STREAM, IPPROTO_SCTP, 0x03 },
|
||||
{ PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 },
|
||||
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 },
|
||||
{ PF_INET6, SOCK_RAW, ANY, 0x05 },
|
||||
#endif
|
||||
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07 },
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07 },
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_SCTP, 0x03 },
|
||||
{ PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 },
|
||||
{ PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 },
|
||||
{ PF_INET, SOCK_RAW, ANY, 0x05 },
|
||||
{ -1, 0, 0, 0 },
|
||||
};
|
||||
@ -1477,6 +1479,9 @@ get_port(struct addrinfo *ai, const char *servname, int matchonly)
|
||||
case IPPROTO_SCTP:
|
||||
proto = "sctp";
|
||||
break;
|
||||
case IPPROTO_UDPLITE:
|
||||
proto = "udplite";
|
||||
break;
|
||||
default:
|
||||
proto = NULL;
|
||||
break;
|
||||
|
@ -859,6 +859,7 @@ in_ifdetach(struct ifnet *ifp)
|
||||
|
||||
in_pcbpurgeif0(&V_ripcbinfo, ifp);
|
||||
in_pcbpurgeif0(&V_udbinfo, ifp);
|
||||
in_pcbpurgeif0(&V_ulitecbinfo, ifp);
|
||||
in_purgemaddrs(ifp);
|
||||
}
|
||||
|
||||
|
@ -237,6 +237,7 @@ __END_DECLS
|
||||
#define IPPROTO_IPCOMP 108 /* payload compression (IPComp) */
|
||||
#define IPPROTO_SCTP 132 /* SCTP */
|
||||
#define IPPROTO_MH 135 /* IPv6 Mobility Header */
|
||||
#define IPPROTO_UDPLITE 136 /* UDP-Lite */
|
||||
#define IPPROTO_HIP 139 /* IP6 Host Identity Protocol */
|
||||
#define IPPROTO_SHIM6 140 /* IP6 Shim6 Protocol */
|
||||
/* 101-254: Partly Unassigned */
|
||||
|
@ -389,13 +389,14 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp,
|
||||
lastport = &pcbinfo->ipi_lastport;
|
||||
}
|
||||
/*
|
||||
* For UDP, use random port allocation as long as the user
|
||||
* For UDP(-Lite), use random port allocation as long as the user
|
||||
* allows it. For TCP (and as of yet unknown) connections,
|
||||
* use random port allocation only if the user allows it AND
|
||||
* ipport_tick() allows it.
|
||||
*/
|
||||
if (V_ipport_randomized &&
|
||||
(!V_ipport_stoprandom || pcbinfo == &V_udbinfo))
|
||||
(!V_ipport_stoprandom || pcbinfo == &V_udbinfo ||
|
||||
pcbinfo == &V_ulitecbinfo))
|
||||
dorandom = 1;
|
||||
else
|
||||
dorandom = 0;
|
||||
@ -405,8 +406,8 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp,
|
||||
*/
|
||||
if (first == last)
|
||||
dorandom = 0;
|
||||
/* Make sure to not include UDP packets in the count. */
|
||||
if (pcbinfo != &V_udbinfo)
|
||||
/* Make sure to not include UDP(-Lite) packets in the count. */
|
||||
if (pcbinfo != &V_udbinfo || pcbinfo != &V_ulitecbinfo)
|
||||
V_ipport_tcpallocs++;
|
||||
/*
|
||||
* Instead of having two loops further down counting up or down
|
||||
|
@ -183,6 +183,20 @@ struct protosw inetsw[] = {
|
||||
.pr_usrreqs = &sctp_usrreqs
|
||||
},
|
||||
#endif /* SCTP */
|
||||
{
|
||||
.pr_type = SOCK_DGRAM,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = IPPROTO_UDPLITE,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = udp_input,
|
||||
.pr_ctlinput = udplite_ctlinput,
|
||||
.pr_ctloutput = udp_ctloutput,
|
||||
.pr_init = udplite_init,
|
||||
#ifdef VIMAGE
|
||||
.pr_destroy = udplite_destroy,
|
||||
#endif
|
||||
.pr_usrreqs = &udp_usrreqs
|
||||
},
|
||||
{
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
|
@ -3,6 +3,7 @@
|
||||
* The Regents of the University of California.
|
||||
* Copyright (c) 2008 Robert N. M. Watson
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* Copyright (c) 2014 Kevin Lo
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Robert N. M. Watson under
|
||||
@ -87,6 +88,7 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/udp_var.h>
|
||||
#include <netinet/udplite.h>
|
||||
|
||||
#ifdef IPSEC
|
||||
#include <netipsec/ipsec.h>
|
||||
@ -98,8 +100,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
/*
|
||||
* UDP protocol implementation.
|
||||
* UDP and UDP-Lite protocols implementation.
|
||||
* Per RFC 768, August, 1980.
|
||||
* Per RFC 3828, July, 2004.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -139,6 +142,8 @@ SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
|
||||
|
||||
VNET_DEFINE(struct inpcbhead, udb); /* from udp_var.h */
|
||||
VNET_DEFINE(struct inpcbinfo, udbinfo);
|
||||
VNET_DEFINE(struct inpcbhead, ulitecb);
|
||||
VNET_DEFINE(struct inpcbinfo, ulitecbinfo);
|
||||
static VNET_DEFINE(uma_zone_t, udpcb_zone);
|
||||
#define V_udpcb_zone VNET(udpcb_zone)
|
||||
|
||||
@ -187,6 +192,16 @@ udp_inpcb_init(void *mem, int size, int flags)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udplite_inpcb_init(void *mem, int size, int flags)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
|
||||
inp = mem;
|
||||
INP_LOCK_INIT(inp, "inp", "udpliteinp");
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
udp_init(void)
|
||||
{
|
||||
@ -202,6 +217,15 @@ udp_init(void)
|
||||
EVENTHANDLER_PRI_ANY);
|
||||
}
|
||||
|
||||
void
|
||||
udplite_init(void)
|
||||
{
|
||||
|
||||
in_pcbinfo_init(&V_ulitecbinfo, "udplite", &V_ulitecb, UDBHASHSIZE,
|
||||
UDBHASHSIZE, "udplite_inpcb", udplite_inpcb_init, NULL,
|
||||
UMA_ZONE_NOFREE, IPI_HASHFIELDS_2TUPLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kernel module interface for updating udpstat. The argument is an index
|
||||
* into udpstat treated as an array of u_long. While this encodes the
|
||||
@ -243,6 +267,13 @@ udp_destroy(void)
|
||||
in_pcbinfo_destroy(&V_udbinfo);
|
||||
uma_zdestroy(V_udpcb_zone);
|
||||
}
|
||||
|
||||
void
|
||||
udplite_destroy(void)
|
||||
{
|
||||
|
||||
in_pcbinfo_destroy(&V_ulitecbinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
@ -346,10 +377,14 @@ udp_input(struct mbuf *m, int off)
|
||||
struct ifnet *ifp;
|
||||
struct inpcb *inp;
|
||||
uint16_t len, ip_len;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct ip save_ip;
|
||||
struct sockaddr_in udp_in;
|
||||
struct m_tag *fwd_tag;
|
||||
int cscov_partial;
|
||||
uint8_t pr;
|
||||
|
||||
iphlen = off;
|
||||
ifp = m->m_pkthdr.rcvif;
|
||||
UDPSTAT_INC(udps_ipackets);
|
||||
|
||||
@ -375,6 +410,8 @@ udp_input(struct mbuf *m, int off)
|
||||
ip = mtod(m, struct ip *);
|
||||
}
|
||||
uh = (struct udphdr *)((caddr_t)ip + iphlen);
|
||||
pr = ip->ip_p;
|
||||
cscov_partial = (pr == IPPROTO_UDPLITE) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Destination port of 0 is illegal, based on RFC768.
|
||||
@ -398,12 +435,18 @@ udp_input(struct mbuf *m, int off)
|
||||
*/
|
||||
len = ntohs((u_short)uh->uh_ulen);
|
||||
ip_len = ntohs(ip->ip_len) - iphlen;
|
||||
if (pr == IPPROTO_UDPLITE && len == 0) {
|
||||
/* Zero means checksum over the complete packet. */
|
||||
len = ip_len;
|
||||
cscov_partial = 0;
|
||||
}
|
||||
if (ip_len != len) {
|
||||
if (len > ip_len || len < sizeof(struct udphdr)) {
|
||||
UDPSTAT_INC(udps_badlen);
|
||||
goto badunlocked;
|
||||
}
|
||||
m_adj(m, len - ip_len);
|
||||
if (pr == IPPROTO_UDP)
|
||||
m_adj(m, len - ip_len);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -421,20 +464,22 @@ udp_input(struct mbuf *m, int off)
|
||||
if (uh->uh_sum) {
|
||||
u_short uh_sum;
|
||||
|
||||
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
|
||||
if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID) &&
|
||||
!cscov_partial) {
|
||||
if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
|
||||
uh_sum = m->m_pkthdr.csum_data;
|
||||
else
|
||||
uh_sum = in_pseudo(ip->ip_src.s_addr,
|
||||
ip->ip_dst.s_addr, htonl((u_short)len +
|
||||
m->m_pkthdr.csum_data + IPPROTO_UDP));
|
||||
m->m_pkthdr.csum_data + pr));
|
||||
uh_sum ^= 0xffff;
|
||||
} else {
|
||||
char b[9];
|
||||
|
||||
bcopy(((struct ipovly *)ip)->ih_x1, b, 9);
|
||||
bzero(((struct ipovly *)ip)->ih_x1, 9);
|
||||
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
|
||||
((struct ipovly *)ip)->ih_len = (pr == IPPROTO_UDP) ?
|
||||
uh->uh_ulen : htons(ip_len);
|
||||
uh_sum = in_cksum(m, len + sizeof (struct ip));
|
||||
bcopy(b, ((struct ipovly *)ip)->ih_x1, 9);
|
||||
}
|
||||
@ -446,14 +491,17 @@ udp_input(struct mbuf *m, int off)
|
||||
} else
|
||||
UDPSTAT_INC(udps_nosum);
|
||||
|
||||
pcbinfo = get_inpcbinfo(pr);
|
||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
|
||||
in_broadcast(ip->ip_dst, ifp)) {
|
||||
struct inpcb *last;
|
||||
struct inpcbhead *pcblist;
|
||||
struct ip_moptions *imo;
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
INP_INFO_RLOCK(pcbinfo);
|
||||
pcblist = get_pcblist(pr);
|
||||
last = NULL;
|
||||
LIST_FOREACH(inp, &V_udb, inp_list) {
|
||||
LIST_FOREACH(inp, pcblist, inp_list) {
|
||||
if (inp->inp_lport != uh->uh_dport)
|
||||
continue;
|
||||
#ifdef INET6
|
||||
@ -539,12 +587,12 @@ udp_input(struct mbuf *m, int off)
|
||||
UDPSTAT_INC(udps_noportbcast);
|
||||
if (inp)
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
goto badunlocked;
|
||||
}
|
||||
udp_append(last, ip, m, iphlen, &udp_in);
|
||||
INP_RUNLOCK(last);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -565,7 +613,7 @@ udp_input(struct mbuf *m, int off)
|
||||
* Transparently forwarded. Pretend to be the destination.
|
||||
* Already got one like this?
|
||||
*/
|
||||
inp = in_pcblookup_mbuf(&V_udbinfo, ip->ip_src, uh->uh_sport,
|
||||
inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport,
|
||||
ip->ip_dst, uh->uh_dport, INPLOOKUP_RLOCKPCB, ifp, m);
|
||||
if (!inp) {
|
||||
/*
|
||||
@ -573,7 +621,7 @@ udp_input(struct mbuf *m, int off)
|
||||
* Because we've rewritten the destination address,
|
||||
* any hardware-generated hash is ignored.
|
||||
*/
|
||||
inp = in_pcblookup(&V_udbinfo, ip->ip_src,
|
||||
inp = in_pcblookup(pcbinfo, ip->ip_src,
|
||||
uh->uh_sport, next_hop->sin_addr,
|
||||
next_hop->sin_port ? htons(next_hop->sin_port) :
|
||||
uh->uh_dport, INPLOOKUP_WILDCARD |
|
||||
@ -583,7 +631,7 @@ udp_input(struct mbuf *m, int off)
|
||||
m_tag_delete(m, fwd_tag);
|
||||
m->m_flags &= ~M_IP_NEXTHOP;
|
||||
} else
|
||||
inp = in_pcblookup_mbuf(&V_udbinfo, ip->ip_src, uh->uh_sport,
|
||||
inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport,
|
||||
ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_RLOCKPCB, ifp, m);
|
||||
if (inp == NULL) {
|
||||
@ -619,6 +667,16 @@ udp_input(struct mbuf *m, int off)
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
if (cscov_partial) {
|
||||
struct udpcb *up;
|
||||
|
||||
up = intoudpcb(inp);
|
||||
if (up->u_rxcslen > len) {
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UDP_PROBE(receive, NULL, inp, ip, inp, uh);
|
||||
udp_append(inp, ip, m, iphlen, &udp_in);
|
||||
@ -653,8 +711,9 @@ udp_notify(struct inpcb *inp, int errno)
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
void
|
||||
udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
static void
|
||||
udp_common_ctlinput(int cmd, struct sockaddr *sa, void *vip,
|
||||
struct inpcbinfo *pcbinfo)
|
||||
{
|
||||
struct ip *ip = vip;
|
||||
struct udphdr *uh;
|
||||
@ -683,7 +742,7 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
return;
|
||||
if (ip != NULL) {
|
||||
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
|
||||
inp = in_pcblookup(&V_udbinfo, faddr, uh->uh_dport,
|
||||
inp = in_pcblookup(pcbinfo, faddr, uh->uh_dport,
|
||||
ip->ip_src, uh->uh_sport, INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
@ -693,9 +752,22 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
} else
|
||||
in_pcbnotifyall(&V_udbinfo, faddr, inetctlerrmap[cmd],
|
||||
in_pcbnotifyall(pcbinfo, faddr, inetctlerrmap[cmd],
|
||||
udp_notify);
|
||||
}
|
||||
void
|
||||
udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
{
|
||||
|
||||
return (udp_common_ctlinput(cmd, sa, vip, &V_udbinfo));
|
||||
}
|
||||
|
||||
void
|
||||
udplite_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
{
|
||||
|
||||
return (udp_common_ctlinput(cmd, sa, vip, &V_ulitecbinfo));
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
static int
|
||||
@ -851,16 +923,16 @@ SYSCTL_PROC(_net_inet_udp, OID_AUTO, getcred,
|
||||
int
|
||||
udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
{
|
||||
int error = 0, optval;
|
||||
struct inpcb *inp;
|
||||
#ifdef IPSEC_NAT_T
|
||||
struct udpcb *up;
|
||||
#endif
|
||||
int isudplite, error, optval;
|
||||
|
||||
error = 0;
|
||||
isudplite = (so->so_proto->pr_protocol == IPPROTO_UDPLITE) ? 1 : 0;
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
|
||||
INP_WLOCK(inp);
|
||||
if (sopt->sopt_level != IPPROTO_UDP) {
|
||||
if (sopt->sopt_level != so->so_proto->pr_protocol) {
|
||||
#ifdef INET6
|
||||
if (INP_CHECK_SOCKAF(so, AF_INET6)) {
|
||||
INP_WUNLOCK(inp);
|
||||
@ -918,6 +990,34 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
break;
|
||||
case UDPLITE_SEND_CSCOV:
|
||||
case UDPLITE_RECV_CSCOV:
|
||||
if (!isudplite) {
|
||||
INP_WUNLOCK(inp);
|
||||
error = ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
error = sooptcopyin(sopt, &optval, sizeof(optval),
|
||||
sizeof(optval));
|
||||
if (error != 0)
|
||||
break;
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
|
||||
INP_WLOCK(inp);
|
||||
up = intoudpcb(inp);
|
||||
KASSERT(up != NULL, ("%s: up == NULL", __func__));
|
||||
if (optval != 0 && optval < 8) {
|
||||
INP_WUNLOCK(inp);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (sopt->sopt_name == UDPLITE_SEND_CSCOV)
|
||||
up->u_txcslen = optval;
|
||||
else
|
||||
up->u_rxcslen = optval;
|
||||
INP_WUNLOCK(inp);
|
||||
break;
|
||||
default:
|
||||
INP_WUNLOCK(inp);
|
||||
error = ENOPROTOOPT;
|
||||
@ -935,6 +1035,22 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
error = sooptcopyout(sopt, &optval, sizeof optval);
|
||||
break;
|
||||
#endif
|
||||
case UDPLITE_SEND_CSCOV:
|
||||
case UDPLITE_RECV_CSCOV:
|
||||
if (!isudplite) {
|
||||
INP_WUNLOCK(inp);
|
||||
error = ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
up = intoudpcb(inp);
|
||||
KASSERT(up != NULL, ("%s: up == NULL", __func__));
|
||||
if (sopt->sopt_name == UDPLITE_SEND_CSCOV)
|
||||
optval = up->u_txcslen;
|
||||
else
|
||||
optval = up->u_rxcslen;
|
||||
INP_WUNLOCK(inp);
|
||||
error = sooptcopyout(sopt, &optval, sizeof(optval));
|
||||
break;
|
||||
default:
|
||||
INP_WUNLOCK(inp);
|
||||
error = ENOPROTOOPT;
|
||||
@ -957,12 +1073,16 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
int len = m->m_pkthdr.len;
|
||||
struct in_addr faddr, laddr;
|
||||
struct cmsghdr *cm;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct sockaddr_in *sin, src;
|
||||
int cscov_partial = 0;
|
||||
int error = 0;
|
||||
int ipflags;
|
||||
u_short fport, lport;
|
||||
int unlock_udbinfo;
|
||||
u_char tos;
|
||||
uint8_t pr;
|
||||
uint16_t cscov = 0;
|
||||
|
||||
/*
|
||||
* udp_output() may need to temporarily bind or connect the current
|
||||
@ -1057,12 +1177,14 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
*
|
||||
* XXXRW: Check that hash locking update here is correct.
|
||||
*/
|
||||
pr = inp->inp_socket->so_proto->pr_protocol;
|
||||
pcbinfo = get_inpcbinfo(pr);
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
if (sin != NULL &&
|
||||
(inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) {
|
||||
INP_RUNLOCK(inp);
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
unlock_udbinfo = UH_WLOCKED;
|
||||
} else if ((sin != NULL && (
|
||||
(sin->sin_addr.s_addr == INADDR_ANY) ||
|
||||
@ -1070,7 +1192,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
(inp->inp_laddr.s_addr == INADDR_ANY) ||
|
||||
(inp->inp_lport == 0))) ||
|
||||
(src.sin_family == AF_INET)) {
|
||||
INP_HASH_RLOCK(&V_udbinfo);
|
||||
INP_HASH_RLOCK(pcbinfo);
|
||||
unlock_udbinfo = UH_RLOCKED;
|
||||
} else
|
||||
unlock_udbinfo = UH_UNLOCKED;
|
||||
@ -1083,7 +1205,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
laddr = inp->inp_laddr;
|
||||
lport = inp->inp_lport;
|
||||
if (src.sin_family == AF_INET) {
|
||||
INP_HASH_LOCK_ASSERT(&V_udbinfo);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
if ((lport == 0) ||
|
||||
(laddr.s_addr == INADDR_ANY &&
|
||||
src.sin_addr.s_addr == INADDR_ANY)) {
|
||||
@ -1134,7 +1256,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
inp->inp_lport == 0 ||
|
||||
sin->sin_addr.s_addr == INADDR_ANY ||
|
||||
sin->sin_addr.s_addr == INADDR_BROADCAST) {
|
||||
INP_HASH_LOCK_ASSERT(&V_udbinfo);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
error = in_pcbconnect_setup(inp, addr, &laddr.s_addr,
|
||||
&lport, &faddr.s_addr, &fport, NULL,
|
||||
td->td_ucred);
|
||||
@ -1149,7 +1271,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
if (inp->inp_laddr.s_addr == INADDR_ANY &&
|
||||
inp->inp_lport == 0) {
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(&V_udbinfo);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
/*
|
||||
* Remember addr if jailed, to prevent
|
||||
* rebinding.
|
||||
@ -1198,13 +1320,30 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
*/
|
||||
ui = mtod(m, struct udpiphdr *);
|
||||
bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */
|
||||
ui->ui_v = IPVERSION << 4;
|
||||
ui->ui_pr = IPPROTO_UDP;
|
||||
ui->ui_pr = pr;
|
||||
ui->ui_src = laddr;
|
||||
ui->ui_dst = faddr;
|
||||
ui->ui_sport = lport;
|
||||
ui->ui_dport = fport;
|
||||
ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));
|
||||
if (pr == IPPROTO_UDPLITE) {
|
||||
struct udpcb *up;
|
||||
uint16_t plen;
|
||||
|
||||
up = intoudpcb(inp);
|
||||
cscov = up->u_txcslen;
|
||||
plen = (u_short)len + sizeof(struct udphdr);
|
||||
if (cscov >= plen)
|
||||
cscov = 0;
|
||||
ui->ui_len = htons(plen);
|
||||
ui->ui_ulen = htons(cscov);
|
||||
/*
|
||||
* For UDP-Lite, checksum coverage length of zero means
|
||||
* the entire UDPLite packet is covered by the checksum.
|
||||
*/
|
||||
cscov_partial = (cscov == 0) ? 0 : 1;
|
||||
} else
|
||||
ui->ui_v = IPVERSION << 4;
|
||||
|
||||
/*
|
||||
* Set the Don't Fragment bit in the IP header.
|
||||
@ -1231,24 +1370,29 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
/*
|
||||
* Set up checksum and output datagram.
|
||||
*/
|
||||
if (V_udp_cksum) {
|
||||
ui->ui_sum = 0;
|
||||
if (cscov_partial) {
|
||||
if (inp->inp_flags & INP_ONESBCAST)
|
||||
faddr.s_addr = INADDR_BROADCAST;
|
||||
if ((ui->ui_sum = in_cksum(m, sizeof(struct ip) + cscov)) == 0)
|
||||
ui->ui_sum = 0xffff;
|
||||
} else if (V_udp_cksum || !cscov_partial) {
|
||||
if (inp->inp_flags & INP_ONESBCAST)
|
||||
faddr.s_addr = INADDR_BROADCAST;
|
||||
ui->ui_sum = in_pseudo(ui->ui_src.s_addr, faddr.s_addr,
|
||||
htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP));
|
||||
htons((u_short)len + sizeof(struct udphdr) + pr));
|
||||
m->m_pkthdr.csum_flags = CSUM_UDP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
|
||||
} else
|
||||
ui->ui_sum = 0;
|
||||
}
|
||||
((struct ip *)ui)->ip_len = htons(sizeof(struct udpiphdr) + len);
|
||||
((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
|
||||
((struct ip *)ui)->ip_tos = tos; /* XXX */
|
||||
UDPSTAT_INC(udps_opackets);
|
||||
|
||||
if (unlock_udbinfo == UH_WLOCKED)
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
else if (unlock_udbinfo == UH_RLOCKED)
|
||||
INP_HASH_RUNLOCK(&V_udbinfo);
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
|
||||
error = ip_output(m, inp->inp_options, NULL, ipflags,
|
||||
inp->inp_moptions, inp);
|
||||
@ -1260,10 +1404,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
|
||||
release:
|
||||
if (unlock_udbinfo == UH_WLOCKED) {
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
} else if (unlock_udbinfo == UH_RLOCKED) {
|
||||
INP_HASH_RUNLOCK(&V_udbinfo);
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
INP_RUNLOCK(inp);
|
||||
} else
|
||||
INP_RUNLOCK(inp);
|
||||
@ -1410,15 +1554,17 @@ static void
|
||||
udp_abort(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_abort: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@ -1428,17 +1574,19 @@ static int
|
||||
udp_attach(struct socket *so, int proto, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp == NULL, ("udp_attach: inp != NULL"));
|
||||
error = soreserve(so, udp_sendspace, udp_recvspace);
|
||||
if (error)
|
||||
return (error);
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
error = in_pcballoc(so, &V_udbinfo);
|
||||
INP_INFO_WLOCK(pcbinfo);
|
||||
error = in_pcballoc(so, pcbinfo);
|
||||
if (error) {
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1450,12 +1598,12 @@ udp_attach(struct socket *so, int proto, struct thread *td)
|
||||
if (error) {
|
||||
in_pcbdetach(inp);
|
||||
in_pcbfree(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (0);
|
||||
}
|
||||
#endif /* INET */
|
||||
@ -1486,14 +1634,16 @@ static int
|
||||
udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_bind: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = in_pcbbind(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
return (error);
|
||||
}
|
||||
@ -1502,15 +1652,17 @@ static void
|
||||
udp_close(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_close: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@ -1520,9 +1672,11 @@ static int
|
||||
udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
int error;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct sockaddr_in *sin;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_connect: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -1536,9 +1690,9 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
INP_WUNLOCK(inp);
|
||||
return (error);
|
||||
}
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = in_pcbconnect(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
INP_WUNLOCK(inp);
|
||||
@ -1549,20 +1703,22 @@ static void
|
||||
udp_detach(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct udpcb *up;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
|
||||
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
|
||||
("udp_detach: not disconnected"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_INFO_WLOCK(pcbinfo);
|
||||
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);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
udp_discardcb(up);
|
||||
}
|
||||
|
||||
@ -1570,7 +1726,9 @@ static int
|
||||
udp_disconnect(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_disconnect: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -1578,10 +1736,10 @@ udp_disconnect(struct socket *so)
|
||||
INP_WUNLOCK(inp);
|
||||
return (ENOTCONN);
|
||||
}
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
|
@ -63,6 +63,8 @@ typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
|
||||
struct udpcb {
|
||||
udp_tun_func_t u_tun_func; /* UDP kernel tunneling callback. */
|
||||
u_int u_flags; /* Generic UDP flags. */
|
||||
uint16_t u_rxcslen; /* Coverage for incoming datagrams. */
|
||||
uint16_t u_txcslen; /* Coverage for outgoing datagrams. */
|
||||
};
|
||||
|
||||
#define intoudpcb(ip) ((struct udpcb *)(ip)->inp_ppcb)
|
||||
@ -129,8 +131,12 @@ SYSCTL_DECL(_net_inet_udp);
|
||||
extern struct pr_usrreqs udp_usrreqs;
|
||||
VNET_DECLARE(struct inpcbhead, udb);
|
||||
VNET_DECLARE(struct inpcbinfo, udbinfo);
|
||||
VNET_DECLARE(struct inpcbhead, ulitecb);
|
||||
VNET_DECLARE(struct inpcbinfo, ulitecbinfo);
|
||||
#define V_udb VNET(udb)
|
||||
#define V_udbinfo VNET(udbinfo)
|
||||
#define V_ulitecb VNET(ulitecb)
|
||||
#define V_ulitecbinfo VNET(ulitecbinfo)
|
||||
|
||||
extern u_long udp_sendspace;
|
||||
extern u_long udp_recvspace;
|
||||
@ -140,20 +146,37 @@ VNET_DECLARE(int, udp_blackhole);
|
||||
#define V_udp_blackhole VNET(udp_blackhole)
|
||||
extern int udp_log_in_vain;
|
||||
|
||||
static __inline struct inpcbinfo *
|
||||
get_inpcbinfo(uint8_t protocol)
|
||||
{
|
||||
return (protocol == IPPROTO_UDP) ? &V_udbinfo : &V_ulitecbinfo;
|
||||
}
|
||||
|
||||
static __inline struct inpcbhead *
|
||||
get_pcblist(uint8_t protocol)
|
||||
{
|
||||
return (protocol == IPPROTO_UDP) ? &V_udb : &V_ulitecb;
|
||||
}
|
||||
|
||||
int udp_newudpcb(struct inpcb *);
|
||||
void udp_discardcb(struct udpcb *);
|
||||
|
||||
void udp_ctlinput(int, struct sockaddr *, void *);
|
||||
void udplite_ctlinput(int, struct sockaddr *, void *);
|
||||
int udp_ctloutput(struct socket *, struct sockopt *);
|
||||
void udp_init(void);
|
||||
void udplite_init(void);
|
||||
#ifdef VIMAGE
|
||||
void udp_destroy(void);
|
||||
void udplite_destroy(void);
|
||||
#endif
|
||||
void udp_input(struct mbuf *, int);
|
||||
void udplite_input(struct mbuf *, int);
|
||||
struct inpcb *udp_notify(struct inpcb *inp, int errno);
|
||||
int udp_shutdown(struct socket *so);
|
||||
|
||||
int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NETINET_UDP_VAR_H_ */
|
||||
|
38
sys/netinet/udplite.h
Normal file
38
sys/netinet/udplite.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*-
|
||||
* Copyright (c) 2014, Kevin Lo
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_UDPLITE_H_
|
||||
#define _NETINET_UDPLITE_H_
|
||||
|
||||
/*
|
||||
* User-settable options (used with setsockopt).
|
||||
*/
|
||||
#define UDPLITE_SEND_CSCOV 2 /* Sender checksum coverage. */
|
||||
#define UDPLITE_RECV_CSCOV 4 /* Receiver checksum coverage. */
|
||||
|
||||
#endif /* !_NETINET_UDPLITE_H_ */
|
@ -829,6 +829,7 @@ in6_ifdetach(struct ifnet *ifp)
|
||||
}
|
||||
|
||||
in6_pcbpurgeif0(&V_udbinfo, ifp);
|
||||
in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
|
||||
in6_pcbpurgeif0(&V_ripcbinfo, ifp);
|
||||
/* leave from all multicast groups joined */
|
||||
in6_purgemaddrs(ifp);
|
||||
|
@ -214,6 +214,19 @@ struct ip6protosw inet6sw[] = {
|
||||
.pr_usrreqs = &sctp6_usrreqs
|
||||
},
|
||||
#endif /* SCTP */
|
||||
{
|
||||
.pr_type = SOCK_DGRAM,
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = IPPROTO_UDPLITE,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = udp6_input,
|
||||
.pr_ctlinput = udplite6_ctlinput,
|
||||
.pr_ctloutput = udp_ctloutput,
|
||||
#ifndef INET /* Do not call initialization twice. */
|
||||
.pr_init = udplite_init,
|
||||
#endif
|
||||
.pr_usrreqs = &udp6_usrreqs,
|
||||
},
|
||||
{
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inet6domain,
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* Copyright (c) 2014 Kevin Lo
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Robert N. M. Watson under
|
||||
@ -109,6 +110,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/udp_var.h>
|
||||
#include <netinet/udplite.h>
|
||||
|
||||
#include <netinet6/ip6protosw.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
@ -181,12 +183,15 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
struct ip6_hdr *ip6;
|
||||
struct udphdr *uh;
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct udpcb *up;
|
||||
int off = *offp;
|
||||
int cscov_partial;
|
||||
int plen, ulen;
|
||||
struct sockaddr_in6 fromsa;
|
||||
struct m_tag *fwd_tag;
|
||||
uint16_t uh_sum;
|
||||
uint8_t nxt;
|
||||
|
||||
ifp = m->m_pkthdr.rcvif;
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
@ -218,6 +223,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
|
||||
ulen = ntohs((u_short)uh->uh_ulen);
|
||||
|
||||
nxt = ip6->ip6_nxt;
|
||||
cscov_partial = (nxt == IPPROTO_UDPLITE) ? 1 : 0;
|
||||
if (nxt == IPPROTO_UDPLITE && ulen == 0) {
|
||||
/* Zero means checksum over the complete packet. */
|
||||
ulen = plen;
|
||||
cscov_partial = 0;
|
||||
}
|
||||
if (plen != ulen) {
|
||||
UDPSTAT_INC(udps_badlen);
|
||||
goto badunlocked;
|
||||
@ -227,19 +239,22 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* Checksum extended UDP header and data.
|
||||
*/
|
||||
if (uh->uh_sum == 0) {
|
||||
UDPSTAT_INC(udps_nosum);
|
||||
goto badunlocked;
|
||||
if (ulen > plen || ulen < sizeof(struct udphdr)) {
|
||||
UDPSTAT_INC(udps_nosum);
|
||||
goto badunlocked;
|
||||
}
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) {
|
||||
if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) &&
|
||||
!cscov_partial) {
|
||||
if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
|
||||
uh_sum = m->m_pkthdr.csum_data;
|
||||
else
|
||||
uh_sum = in6_cksum_pseudo(ip6, ulen,
|
||||
IPPROTO_UDP, m->m_pkthdr.csum_data);
|
||||
uh_sum = in6_cksum_pseudo(ip6, ulen, nxt,
|
||||
m->m_pkthdr.csum_data);
|
||||
uh_sum ^= 0xffff;
|
||||
} else
|
||||
uh_sum = in6_cksum(m, IPPROTO_UDP, off, ulen);
|
||||
uh_sum = in6_cksum(m, nxt, off, ulen);
|
||||
|
||||
if (uh_sum != 0) {
|
||||
UDPSTAT_INC(udps_badsum);
|
||||
@ -252,11 +267,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
init_sin6(&fromsa, m);
|
||||
fromsa.sin6_port = uh->uh_sport;
|
||||
|
||||
pcbinfo = get_inpcbinfo(nxt);
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
||||
struct inpcb *last;
|
||||
struct inpcbhead *pcblist;
|
||||
struct ip6_moptions *imo;
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
INP_INFO_RLOCK(pcbinfo);
|
||||
/*
|
||||
* In the event that laddr should be set to the link-local
|
||||
* address (this happens in RIPng), the multicast address
|
||||
@ -272,8 +289,9 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* here. We need udphdr for IPsec processing so we do that
|
||||
* later.
|
||||
*/
|
||||
pcblist = get_pcblist(nxt);
|
||||
last = NULL;
|
||||
LIST_FOREACH(inp, &V_udb, inp_list) {
|
||||
LIST_FOREACH(inp, pcblist, inp_list) {
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (inp->inp_lport != uh->uh_dport)
|
||||
@ -378,7 +396,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badheadlocked;
|
||||
}
|
||||
INP_RLOCK(last);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
up = intoudpcb(last);
|
||||
UDP_PROBE(receive, NULL, last, ip6, last, uh);
|
||||
if (up->u_tun_func == NULL) {
|
||||
@ -409,8 +427,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* Transparently forwarded. Pretend to be the destination.
|
||||
* Already got one like this?
|
||||
*/
|
||||
inp = in6_pcblookup_mbuf(&V_udbinfo,
|
||||
&ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
|
||||
inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src,
|
||||
uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
|
||||
INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m);
|
||||
if (!inp) {
|
||||
/*
|
||||
@ -418,7 +436,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* Because we've rewritten the destination address,
|
||||
* any hardware-generated hash is ignored.
|
||||
*/
|
||||
inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src,
|
||||
inp = in6_pcblookup(pcbinfo, &ip6->ip6_src,
|
||||
uh->uh_sport, &next_hop6->sin6_addr,
|
||||
next_hop6->sin6_port ? htons(next_hop6->sin6_port) :
|
||||
uh->uh_dport, INPLOOKUP_WILDCARD |
|
||||
@ -428,7 +446,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
m_tag_delete(m, fwd_tag);
|
||||
m->m_flags &= ~M_IP6_NEXTHOP;
|
||||
} else
|
||||
inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src,
|
||||
inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src,
|
||||
uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
|
||||
INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
|
||||
m->m_pkthdr.rcvif, m);
|
||||
@ -459,6 +477,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
}
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
up = intoudpcb(inp);
|
||||
if (cscov_partial) {
|
||||
if (up->u_rxcslen > ulen) {
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
}
|
||||
UDP_PROBE(receive, NULL, inp, ip6, inp, uh);
|
||||
if (up->u_tun_func == NULL) {
|
||||
udp6_append(inp, m, off, &fromsa);
|
||||
@ -473,15 +498,16 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
return (IPPROTO_DONE);
|
||||
|
||||
badheadlocked:
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
badunlocked:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
|
||||
void
|
||||
udp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
static void
|
||||
udp6_common_ctlinput(int cmd, struct sockaddr *sa, void *d,
|
||||
struct inpcbinfo *pcbinfo)
|
||||
{
|
||||
struct udphdr uh;
|
||||
struct ip6_hdr *ip6;
|
||||
@ -537,14 +563,28 @@ udp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
bzero(&uh, sizeof(uh));
|
||||
m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
|
||||
|
||||
(void) in6_pcbnotify(&V_udbinfo, sa, uh.uh_dport,
|
||||
(void)in6_pcbnotify(pcbinfo, sa, uh.uh_dport,
|
||||
(struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd,
|
||||
cmdarg, notify);
|
||||
} else
|
||||
(void) in6_pcbnotify(&V_udbinfo, sa, 0,
|
||||
(void)in6_pcbnotify(pcbinfo, sa, 0,
|
||||
(const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
|
||||
}
|
||||
|
||||
void
|
||||
udp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
{
|
||||
|
||||
return (udp6_common_ctlinput(cmd, sa, d, &V_udbinfo));
|
||||
}
|
||||
|
||||
void
|
||||
udplite6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
{
|
||||
|
||||
return (udp6_common_ctlinput(cmd, sa, d, &V_ulitecbinfo));
|
||||
}
|
||||
|
||||
static int
|
||||
udp6_getcred(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
@ -602,9 +642,12 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
struct in6_addr *laddr, *faddr, in6a;
|
||||
struct sockaddr_in6 *sin6 = NULL;
|
||||
struct ifnet *oifp = NULL;
|
||||
int cscov_partial = 0;
|
||||
int scope_ambiguous = 0;
|
||||
u_short fport;
|
||||
int error = 0;
|
||||
uint8_t nxt;
|
||||
uint16_t cscov = 0;
|
||||
struct ip6_pktopts *optp, opt;
|
||||
int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
|
||||
int flags;
|
||||
@ -761,10 +804,25 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
/*
|
||||
* Stuff checksum and output datagram.
|
||||
*/
|
||||
nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ?
|
||||
IPPROTO_UDP : IPPROTO_UDPLITE;
|
||||
udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
|
||||
udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */
|
||||
udp6->uh_dport = fport;
|
||||
if (plen <= 0xffff)
|
||||
if (nxt == IPPROTO_UDPLITE) {
|
||||
struct udpcb *up;
|
||||
|
||||
up = intoudpcb(inp);
|
||||
cscov = up->u_txcslen;
|
||||
if (cscov >= plen)
|
||||
cscov = 0;
|
||||
udp6->uh_ulen = htons(cscov);
|
||||
/*
|
||||
* For UDP-Lite, checksum coverage length of zero means
|
||||
* the entire UDPLite packet is covered by the checksum.
|
||||
*/
|
||||
cscov_partial = (cscov == 0) ? 0 : 1;
|
||||
} else if (plen <= 0xffff)
|
||||
udp6->uh_ulen = htons((u_short)plen);
|
||||
else
|
||||
udp6->uh_ulen = 0;
|
||||
@ -777,14 +835,20 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
|
||||
ip6->ip6_vfc |= IPV6_VERSION;
|
||||
ip6->ip6_plen = htons((u_short)plen);
|
||||
ip6->ip6_nxt = IPPROTO_UDP;
|
||||
ip6->ip6_nxt = nxt;
|
||||
ip6->ip6_hlim = in6_selecthlim(inp, NULL);
|
||||
ip6->ip6_src = *laddr;
|
||||
ip6->ip6_dst = *faddr;
|
||||
|
||||
udp6->uh_sum = in6_cksum_pseudo(ip6, plen, IPPROTO_UDP, 0);
|
||||
m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
|
||||
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
|
||||
if (cscov_partial) {
|
||||
if ((udp6->uh_sum = in6_cksum(m, 0,
|
||||
sizeof(struct ip6_hdr), cscov)) == 0)
|
||||
udp6->uh_sum = 0xffff;
|
||||
} else {
|
||||
udp6->uh_sum = in6_cksum_pseudo(ip6, plen, nxt, 0);
|
||||
m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
|
||||
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
|
||||
@ -814,7 +878,9 @@ static void
|
||||
udp6_abort(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
|
||||
|
||||
@ -830,10 +896,10 @@ udp6_abort(struct socket *so)
|
||||
|
||||
INP_WLOCK(inp);
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@ -843,8 +909,10 @@ static int
|
||||
udp6_attach(struct socket *so, int proto, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp == NULL, ("udp6_attach: inp != NULL"));
|
||||
|
||||
@ -853,10 +921,10 @@ udp6_attach(struct socket *so, int proto, struct thread *td)
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
error = in_pcballoc(so, &V_udbinfo);
|
||||
INP_INFO_WLOCK(pcbinfo);
|
||||
error = in_pcballoc(so, pcbinfo);
|
||||
if (error) {
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (error);
|
||||
}
|
||||
inp = (struct inpcb *)so->so_pcb;
|
||||
@ -877,11 +945,11 @@ udp6_attach(struct socket *so, int proto, struct thread *td)
|
||||
if (error) {
|
||||
in_pcbdetach(inp);
|
||||
in_pcbfree(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (error);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -889,13 +957,15 @@ static int
|
||||
udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
|
||||
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
inp->inp_vflag &= ~INP_IPV4;
|
||||
inp->inp_vflag |= INP_IPV6;
|
||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
||||
@ -923,7 +993,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
#ifdef INET
|
||||
out:
|
||||
#endif
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
return (error);
|
||||
}
|
||||
@ -932,7 +1002,9 @@ static void
|
||||
udp6_close(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
|
||||
|
||||
@ -947,10 +1019,10 @@ udp6_close(struct socket *so)
|
||||
#endif
|
||||
INP_WLOCK(inp);
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@ -960,9 +1032,11 @@ static int
|
||||
udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct sockaddr_in6 *sin6;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
sin6 = (struct sockaddr_in6 *)nam;
|
||||
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
|
||||
@ -989,10 +1063,10 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
error = prison_remote_ip4(td->td_ucred, &sin.sin_addr);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = in_pcbconnect(inp, (struct sockaddr *)&sin,
|
||||
td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
goto out;
|
||||
@ -1007,9 +1081,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = in6_pcbconnect(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
out:
|
||||
@ -1021,18 +1095,20 @@ static void
|
||||
udp6_detach(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct udpcb *up;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_INFO_WLOCK(pcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
up = intoudpcb(inp);
|
||||
KASSERT(up != NULL, ("%s: up == NULL", __func__));
|
||||
in_pcbdetach(inp);
|
||||
in_pcbfree(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
udp_discardcb(up);
|
||||
}
|
||||
|
||||
@ -1040,8 +1116,10 @@ static int
|
||||
udp6_disconnect(struct socket *so)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
|
||||
|
||||
@ -1062,10 +1140,10 @@ udp6_disconnect(struct socket *so)
|
||||
goto out;
|
||||
}
|
||||
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
@ -1079,8 +1157,10 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
|
||||
struct sockaddr *addr, struct mbuf *control, struct thread *td)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
int error = 0;
|
||||
|
||||
pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
|
||||
|
||||
@ -1132,9 +1212,9 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
|
||||
#ifdef MAC
|
||||
mac_inpcb_create_mbuf(inp, m);
|
||||
#endif
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = udp6_output(inp, m, addr, control, td);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
#ifdef INET
|
||||
#endif
|
||||
INP_WUNLOCK(inp);
|
||||
|
@ -69,6 +69,7 @@ SYSCTL_DECL(_net_inet6_udp6);
|
||||
extern struct pr_usrreqs udp6_usrreqs;
|
||||
|
||||
void udp6_ctlinput(int, struct sockaddr *, void *);
|
||||
void udplite6_ctlinput(int, struct sockaddr *, void *);
|
||||
int udp6_input(struct mbuf **, int *, int);
|
||||
#endif
|
||||
|
||||
|
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1100017 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1100018 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
Loading…
Reference in New Issue
Block a user