📄 udp_usrreq.c
字号:
* subroutine of udp_input(), mainly for source code readability.
* caller must properly init udp_ip6 and udp_in6 beforehand.
*/
static void
udp_append(last, ip, n, off)
struct inpcb *last;
struct ip *ip;
struct mbuf *n;
int off;
{
struct sockaddr *append_sa;
struct mbuf *opts = 0;
#ifdef INET6
struct ip6_recvpktopts opts6;
bzero(&opts6, sizeof(opts6));
#endif
if (last->inp_flags & INP_CONTROLOPTS ||
last->inp_socket->so_options & SO_TIMESTAMP) {
#ifdef INET6
if (last->inp_vflag & INP_IPV6) {
int savedflags;
if (udp_ip6.uip6_init_done == 0) {
ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
udp_ip6.uip6_init_done = 1;
}
savedflags = last->inp_flags;
last->inp_flags &= ~INP_UNMAPPABLEOPTS;
ip6_savecontrol(last, &udp_ip6.uip6_ip6, n,
&opts6, NULL);
last->inp_flags = savedflags;
} else
#endif
ip_savecontrol(last, &opts, ip, n);
}
#ifdef INET6
if (last->inp_vflag & INP_IPV6) {
if (udp_in6.uin6_init_done == 0) {
in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
udp_in6.uin6_init_done = 1;
}
append_sa = (struct sockaddr *)&udp_in6.uin6_sin;
opts = opts6.head;
} else
#endif
append_sa = (struct sockaddr *)&udp_in;
m_adj(n, off);
if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) {
m_freem(n);
if (opts)
m_freem(opts);
udpstat.udps_fullsock++;
} else
sorwakeup(last->inp_socket);
}
/*
* Notify a udp user of an asynchronous error;
* just wake up so that he can collect error status.
*/
void
udp_notify(inp, _errno)
register struct inpcb *inp;
int _errno;
{
inp->inp_socket->so_error = _errno;
sorwakeup(inp->inp_socket);
sowwakeup(inp->inp_socket);
}
void
udp_ctlinput(cmd, sa, vip)
int cmd;
struct sockaddr *sa;
void *vip;
{
struct ip *ip = vip;
struct udphdr *uh;
void (*notify) __P((struct inpcb *, int)) = udp_notify;
struct in_addr faddr;
struct inpcb *inp;
int s;
faddr = ((struct sockaddr_in *)sa)->sin_addr;
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
if (PRC_IS_REDIRECT(cmd)) {
ip = 0;
notify = in_rtchange;
} else if (cmd == PRC_HOSTDEAD)
ip = 0;
else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
return;
if (ip) {
s = splnet();
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport,
ip->ip_src, uh->uh_sport, 0, NULL);
if (inp != NULL && inp->inp_socket != NULL)
(*notify)(inp, inetctlerrmap[cmd]);
splx(s);
} else
in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify);
}
#ifdef CYGPKG_NET_FREEBSD_SYSCTL
static int
udp_pcblist(SYSCTL_HANDLER_ARGS)
{
int error, i, n, s;
struct inpcb *inp, **inp_list;
inp_gen_t gencnt;
struct xinpgen xig;
/*
* The process of preparing the TCB list is too time-consuming and
* resource-intensive to repeat twice on every request.
*/
if (req->oldptr == 0) {
n = udbinfo.ipi_count;
req->oldidx = 2 * (sizeof xig)
+ (n + n/8) * sizeof(struct xinpcb);
return 0;
}
if (req->newptr != 0)
return EPERM;
/*
* OK, now we're committed to doing something.
*/
s = splnet();
gencnt = udbinfo.ipi_gencnt;
n = udbinfo.ipi_count;
splx(s);
xig.xig_len = sizeof xig;
xig.xig_count = n;
xig.xig_gen = gencnt;
xig.xig_sogen = so_gencnt;
error = SYSCTL_OUT(req, &xig, sizeof xig);
if (error)
return error;
inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
if (inp_list == 0)
return ENOMEM;
s = splnet();
for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n;
inp = LIST_NEXT(inp, inp_list)) {
if (inp->inp_gencnt <= gencnt)
inp_list[i++] = inp;
}
splx(s);
n = i;
error = 0;
for (i = 0; i < n; i++) {
inp = inp_list[i];
if (inp->inp_gencnt <= gencnt) {
struct xinpcb xi;
xi.xi_len = sizeof xi;
/* XXX should avoid extra copy */
bcopy(inp, &xi.xi_inp, sizeof *inp);
if (inp->inp_socket)
sotoxsocket(inp->inp_socket, &xi.xi_socket);
error = SYSCTL_OUT(req, &xi, sizeof xi);
}
}
if (!error) {
/*
* Give the user an updated idea of our state.
* If the generation differs from what we told
* her before, she knows that something happened
* while we were processing this request, and it
* might be necessary to retry.
*/
s = splnet();
xig.xig_gen = udbinfo.ipi_gencnt;
xig.xig_sogen = so_gencnt;
xig.xig_count = udbinfo.ipi_count;
splx(s);
error = SYSCTL_OUT(req, &xig, sizeof xig);
}
free(inp_list, M_TEMP);
return error;
}
#endif
SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
udp_pcblist, "S,xinpcb", "List of active UDP sockets");
static int
udp_output(inp, m, addr, control, p)
register struct inpcb *inp;
struct mbuf *m;
struct sockaddr *addr;
struct mbuf *control;
struct proc *p;
{
register struct udpiphdr *ui;
register int len = m->m_pkthdr.len;
struct in_addr laddr;
struct sockaddr_in *sin;
int s = 0, error = 0;
if (control)
m_freem(control); /* XXX */
if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
error = EMSGSIZE;
goto release;
}
if (addr) {
sin = (struct sockaddr_in *)addr;
laddr = inp->inp_laddr;
if (inp->inp_faddr.s_addr != INADDR_ANY) {
error = EISCONN;
goto release;
}
/*
* Must block input while temporarily connected.
*/
s = splnet();
error = in_pcbconnect(inp, addr, p);
if (error) {
splx(s);
goto release;
}
} else {
if (inp->inp_faddr.s_addr == INADDR_ANY) {
error = ENOTCONN;
goto release;
}
}
/*
* Calculate data length and get a mbuf
* for UDP and IP headers.
*/
M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
if (m == 0) {
error = ENOBUFS;
if (addr)
splx(s);
goto release;
}
/*
* Fill in mbuf with extended UDP header
* and addresses and length put into network format.
*/
ui = mtod(m, struct udpiphdr *);
bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */
ui->ui_pr = IPPROTO_UDP;
ui->ui_src = inp->inp_laddr;
ui->ui_dst = inp->inp_faddr;
ui->ui_sport = inp->inp_lport;
ui->ui_dport = inp->inp_fport;
ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));
/*
* Set up checksum and output datagram.
*/
if (udpcksum) {
ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr,
htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP));
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 = sizeof (struct udpiphdr) + len;
((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
udpstat.udps_opackets++;
#ifdef IPSEC
if (ipsec_setsocket(m, inp->inp_socket) != 0) {
error = ENOBUFS;
goto release;
}
#endif /*IPSEC*/
error = ip_output(m, inp->inp_options, &inp->inp_route,
(inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)),
inp->inp_moptions);
if (addr) {
in_pcbdisconnect(inp);
inp->inp_laddr = laddr; /* XXX rehash? */
splx(s);
}
return (error);
release:
m_freem(m);
return (error);
}
u_long udp_sendspace = 9216; /* really max datagram size */
/* 40 1K datagrams */
SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
&udp_sendspace, 0, "Maximum outgoing UDP datagram size");
u_long udp_recvspace = 40 * (1024 +
#ifdef INET6
sizeof(struct sockaddr_in6)
#else
sizeof(struct sockaddr_in)
#endif
);
SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
&udp_recvspace, 0, "Maximum incoming UDP datagram size");
static int
udp_abort(struct socket *so)
{
struct inpcb *inp;
int s;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL; /* ??? possible? panic instead? */
soisdisconnected(so);
s = splnet();
in_pcbdetach(inp);
splx(s);
return 0;
}
static int
udp_attach(struct socket *so, int proto, struct proc *p)
{
struct inpcb *inp;
int s, error;
inp = sotoinpcb(so);
if (inp != 0)
return EINVAL;
error = soreserve(so, udp_sendspace, udp_recvspace);
if (error)
return error;
s = splnet();
error = in_pcballoc(so, &udbinfo, p);
splx(s);
if (error)
return error;
inp = (struct inpcb *)so->so_pcb;
inp->inp_vflag |= INP_IPV4;
inp->inp_ip_ttl = ip_defttl;
return 0;
}
static int
udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
{
struct inpcb *inp;
int s, error;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
s = splnet();
error = in_pcbbind(inp, nam, p);
splx(s);
return error;
}
static int
udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
{
struct inpcb *inp;
int s, error;
struct sockaddr_in *sin;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
if (inp->inp_faddr.s_addr != INADDR_ANY)
return EISCONN;
error = 0;
s = splnet();
if (error == 0) {
sin = (struct sockaddr_in *)nam;
error = in_pcbconnect(inp, nam, p);
}
splx(s);
if (error == 0)
soisconnected(so);
return error;
}
static int
udp_detach(struct socket *so)
{
struct inpcb *inp;
int s;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
s = splnet();
in_pcbdetach(inp);
splx(s);
return 0;
}
static int
udp_disconnect(struct socket *so)
{
struct inpcb *inp;
int s;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
if (inp->inp_faddr.s_addr == INADDR_ANY)
return ENOTCONN;
s = splnet();
in_pcbdisconnect(inp);
inp->inp_laddr.s_addr = INADDR_ANY;
splx(s);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
return 0;
}
static int
udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct proc *p)
{
struct inpcb *inp;
inp = sotoinpcb(so);
if (inp == 0) {
m_freem(m);
return EINVAL;
}
return udp_output(inp, m, addr, control, p);
}
int
udp_shutdown(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
socantsendmore(so);
return 0;
}
struct pr_usrreqs udp_usrreqs = {
udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
in_setsockaddr, sosend, soreceive, sopoll
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -