Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.17 retrieving revision 1.47 diff -u -p -r1.17 -r1.47 --- src/sys/netinet/udp_usrreq.c 1995/06/04 05:07:20 1.17 +++ src/sys/netinet/udp_usrreq.c 1999/01/19 23:03:22 1.47 @@ -1,7 +1,7 @@ -/* $NetBSD: udp_usrreq.c,v 1.17 1995/06/04 05:07:20 mycroft Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.47 1999/01/19 23:03:22 mycroft Exp $ */ /* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,8 +32,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 */ +#include "ipkdb.h" #include #include @@ -43,6 +44,11 @@ #include #include #include +#include +#include + +#include +#include #include #include @@ -57,6 +63,8 @@ #include #include +#include + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -67,23 +75,28 @@ int udpcksum = 1; int udpcksum = 0; /* XXX */ #endif -struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; -struct inpcb *udp_last_inpcb = &udb; - -static void udp_detach __P((struct inpcb *)); static void udp_notify __P((struct inpcb *, int)); -static struct mbuf *udp_saveopt __P((caddr_t, int, int)); + +#ifndef UDBHASHSIZE +#define UDBHASHSIZE 128 +#endif +int udbhashsize = UDBHASHSIZE; void udp_init() { - udb.inp_next = udb.inp_prev = &udb; + + in_pcbinit(&udbtable, udbhashsize, udbhashsize); } void -udp_input(m, iphlen) - register struct mbuf *m; - int iphlen; +#if __STDC__ +udp_input(struct mbuf *m, ...) +#else +udp_input(m, va_alist) + struct mbuf *m; + va_dcl +#endif { register struct ip *ip; register struct udphdr *uh; @@ -91,6 +104,13 @@ udp_input(m, iphlen) struct mbuf *opts = 0; int len; struct ip save_ip; + int iphlen; + va_list ap; + struct sockaddr_in udpsrc; + + va_start(ap, m); + iphlen = va_arg(ap, int); + va_end(ap); udpstat.udps_ipackets++; @@ -123,13 +143,12 @@ udp_input(m, iphlen) * If not enough data to reflect UDP length, drop. */ len = ntohs((u_int16_t)uh->uh_ulen); - if (ip->ip_len != len) { - if (len > ip->ip_len) { + if (ip->ip_len != iphlen + len) { + if (ip->ip_len < iphlen + len) { udpstat.udps_badlen++; goto bad; } - m_adj(m, len - ip->ip_len); - /* ip->ip_len = len; */ + m_adj(m, iphlen + len - ip->ip_len); } /* * Save a copy of the IP header in case we want restore it @@ -140,12 +159,11 @@ udp_input(m, iphlen) /* * Checksum extended UDP header and data. */ - if (udpcksum && uh->uh_sum) { - ((struct ipovly *)ip)->ih_next = 0; - ((struct ipovly *)ip)->ih_prev = 0; - ((struct ipovly *)ip)->ih_x1 = 0; + if (uh->uh_sum) { + bzero(((struct ipovly *)ip)->ih_x1, + sizeof ((struct ipovly *)ip)->ih_x1); ((struct ipovly *)ip)->ih_len = uh->uh_ulen; - if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { + if (in_cksum(m, len + sizeof (struct ip)) != 0) { udpstat.udps_badsum++; m_freem(m); return; @@ -154,7 +172,7 @@ udp_input(m, iphlen) if (IN_MULTICAST(ip->ip_dst.s_addr) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { - struct socket *last; + struct inpcb *last; /* * Deliver a multicast or broadcast datagram to *all* sockets * for which the local and remote addresses and ports match @@ -174,26 +192,32 @@ udp_input(m, iphlen) /* * Construct sockaddr format source address. */ - udp_in.sin_port = uh->uh_sport; - udp_in.sin_addr = ip->ip_src; - m->m_len -= sizeof (struct udpiphdr); - m->m_data += sizeof (struct udpiphdr); + udpsrc.sin_family = AF_INET; + udpsrc.sin_len = sizeof(struct sockaddr_in); + udpsrc.sin_addr = ip->ip_src; + udpsrc.sin_port = uh->uh_sport; + bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_pkthdr.len -= iphlen; + m->m_data += iphlen; /* * Locate pcb(s) for datagram. * (Algorithm copied from raw_intr().) */ last = NULL; - for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) { + for (inp = udbtable.inpt_queue.cqh_first; + inp != (struct inpcb *)&udbtable.inpt_queue; + inp = inp->inp_queue.cqe_next) { if (inp->inp_lport != uh->uh_dport) continue; - if (inp->inp_laddr.s_addr != INADDR_ANY) { - if (inp->inp_laddr.s_addr != - ip->ip_dst.s_addr) + if (!in_nullhost(inp->inp_laddr)) { + if (!in_hosteq(inp->inp_laddr, ip->ip_dst)) continue; } - if (inp->inp_faddr.s_addr != INADDR_ANY) { - if (inp->inp_faddr.s_addr != - ip->ip_src.s_addr || + if (!in_nullhost(inp->inp_faddr)) { + if (!in_hosteq(inp->inp_faddr, ip->ip_src) || inp->inp_fport != uh->uh_sport) continue; } @@ -202,16 +226,24 @@ udp_input(m, iphlen) struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { - if (sbappendaddr(&last->so_rcv, - sintosa(&udp_in), n, - (struct mbuf *)0) == 0) { + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & + SO_TIMESTAMP) { + ip_savecontrol(last, &opts, + ip, n); + } + if (sbappendaddr( + &last->inp_socket->so_rcv, + sintosa(&udpsrc), n, opts) == 0) { m_freem(n); - udpstat.udps_fullsock++; + if (opts) + m_freem(opts); } else - sorwakeup(last); + sorwakeup(last->inp_socket); + opts = 0; } } - last = inp->inp_socket; + last = inp; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR @@ -220,7 +252,8 @@ udp_input(m, iphlen) * port. It * assumes that an application will never * clear these options after setting them. */ - if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) + if ((last->inp_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } @@ -233,77 +266,65 @@ udp_input(m, iphlen) udpstat.udps_noportbcast++; goto bad; } - if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m, - (struct mbuf *)0) == 0) { + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + if (sbappendaddr(&last->inp_socket->so_rcv, + sintosa(&udpsrc), m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } - sorwakeup(last); + sorwakeup(last->inp_socket); return; } /* * Locate pcb for datagram. */ - inp = udp_last_inpcb; - if (inp->inp_lport != uh->uh_dport || - inp->inp_fport != uh->uh_sport || - inp->inp_faddr.s_addr != ip->ip_src.s_addr || - inp->inp_laddr.s_addr != ip->ip_dst.s_addr) { - inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); - if (inp) - udp_last_inpcb = inp; - udpstat.udpps_pcbcachemiss++; - } + inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport); if (inp == 0) { - udpstat.udps_noport++; - if (m->m_flags & (M_BCAST | M_MCAST)) { - udpstat.udps_noportbcast++; - goto bad; + ++udpstat.udps_pcbhashmiss; + inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport); + if (inp == 0) { + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } + *ip = save_ip; +#if NIPKDB > 0 + if (checkipkdb(&ip->ip_src, + uh->uh_sport, + uh->uh_dport, + m, + iphlen + sizeof(struct udphdr), + len - sizeof(struct udphdr))) + /* It was a debugger connect packet, just drop it now */ + goto bad; +#endif + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); + return; } - *ip = save_ip; - ip->ip_len += iphlen; - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); - return; } /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ - udp_in.sin_port = uh->uh_sport; - udp_in.sin_addr = ip->ip_src; - if (inp->inp_flags & INP_CONTROLOPTS) { - struct mbuf **mp = &opts; - - if (inp->inp_flags & INP_RECVDSTADDR) { - *mp = udp_saveopt((caddr_t) &ip->ip_dst, - sizeof(struct in_addr), IP_RECVDSTADDR); - if (*mp) - mp = &(*mp)->m_next; - } -#ifdef notyet - /* options were tossed above */ - if (inp->inp_flags & INP_RECVOPTS) { - *mp = udp_saveopt((caddr_t) opts_deleted_above, - sizeof(struct in_addr), IP_RECVOPTS); - if (*mp) - mp = &(*mp)->m_next; - } - /* ip_srcroute doesn't do what we want here, need to fix */ - if (inp->inp_flags & INP_RECVRETOPTS) { - *mp = udp_saveopt((caddr_t) ip_srcroute(), - sizeof(struct in_addr), IP_RECVRETOPTS); - if (*mp) - mp = &(*mp)->m_next; - } -#endif - } + udpsrc.sin_family = AF_INET; + udpsrc.sin_len = sizeof(struct sockaddr_in); + udpsrc.sin_addr = ip->ip_src; + udpsrc.sin_port = uh->uh_sport; + bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); + + if (inp->inp_flags & INP_CONTROLOPTS || + inp->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(inp, &opts, ip, m); iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_pkthdr.len -= iphlen; m->m_data += iphlen; - if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udp_in), m, + if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udpsrc), m, opts) == 0) { udpstat.udps_fullsock++; goto bad; @@ -317,31 +338,6 @@ bad: } /* - * Create a "control" mbuf containing the specified data - * with the specified type for presentation with a datagram. - */ -struct mbuf * -udp_saveopt(p, size, type) - caddr_t p; - register int size; - int type; -{ - register struct cmsghdr *cp; - struct mbuf *m; - - if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) - return ((struct mbuf *) NULL); - cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); - bcopy(p, CMSG_DATA(cp), size); - size += sizeof(*cp); - m->m_len = size; - cp->cmsg_len = size; - cp->cmsg_level = IPPROTO_IP; - cp->cmsg_type = type; - return (m); -} - -/* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. */ @@ -350,67 +346,62 @@ 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, ip) +void * +udp_ctlinput(cmd, sa, v) int cmd; struct sockaddr *sa; - register struct ip *ip; + void *v; { + register struct ip *ip = v; register struct udphdr *uh; - extern struct in_addr zeroin_addr; - extern u_char inetctlerrmap[]; + extern int inetctlerrmap[]; + void (*notify) __P((struct inpcb *, int)) = udp_notify; + int errno; - if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) - return; + if ((unsigned)cmd >= PRC_NCMDS) + return NULL; + errno = inetctlerrmap[cmd]; + if (PRC_IS_REDIRECT(cmd)) + notify = in_rtchange, ip = 0; + else if (cmd == PRC_HOSTDEAD) + ip = 0; + else if (errno == 0) + return NULL; if (ip) { uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); - in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, - cmd, udp_notify); + in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, + ip->ip_src, uh->uh_sport, errno, notify); } else - in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); + in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno, + notify); + return NULL; } int -udp_output(inp, m, addr, control) - register struct inpcb *inp; - register struct mbuf *m; - struct mbuf *addr, *control; +#if __STDC__ +udp_output(struct mbuf *m, ...) +#else +udp_output(m, va_alist) + struct mbuf *m; + va_dcl +#endif { + register struct inpcb *inp; register struct udpiphdr *ui; register int len = m->m_pkthdr.len; - struct in_addr laddr; - int s, error = 0; + int error = 0; + va_list ap; - if (control) - m_freem(control); /* XXX */ + va_start(ap, m); + inp = va_arg(ap, struct inpcb *); + va_end(ap); - if (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); - 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. @@ -422,12 +413,20 @@ udp_output(inp, m, addr, control) } /* + * Compute the packet length of the IP header, and + * punt if the length looks bogus. + */ + if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { + error = EMSGSIZE; + goto release; + } + + /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); - ui->ui_next = ui->ui_prev = 0; - ui->ui_x1 = 0; + bzero(ui->ui_x1, sizeof ui->ui_x1); ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); ui->ui_src = inp->inp_laddr; @@ -448,44 +447,46 @@ udp_output(inp, m, addr, control) ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ udpstat.udps_opackets++; - error = ip_output(m, inp->inp_options, &inp->inp_route, + return (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; - splx(s); - } - return (error); + inp->inp_moptions)); release: m_freem(m); return (error); } -u_long udp_sendspace = 9216; /* really max datagram size */ -u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); +int udp_sendspace = 9216; /* really max datagram size */ +int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); /* 40 1K datagrams */ /*ARGSUSED*/ int -udp_usrreq(so, req, m, addr, control) +udp_usrreq(so, req, m, nam, control, p) struct socket *so; int req; - struct mbuf *m, *addr, *control; + struct mbuf *m, *nam, *control; + struct proc *p; { - struct inpcb *inp = sotoinpcb(so); - int error = 0; + register struct inpcb *inp; int s; + register int error = 0; if (req == PRU_CONTROL) - return (in_control(so, (long)m, (caddr_t)addr, - (struct ifnet *)control)); - if (inp == NULL && req != PRU_ATTACH) { + return (in_control(so, (long)m, (caddr_t)nam, + (struct ifnet *)control, p)); + + s = splsoftnet(); + inp = sotoinpcb(so); +#ifdef DIAGNOSTIC + if (req != PRU_SEND && req != PRU_SENDOOB && control) + panic("udp_usrreq: unexpected control mbuf"); +#endif + if (inp == 0 && req != PRU_ATTACH) { error = EINVAL; goto release; } + /* * Note: need to block udp_input while changing * the udp pcb queue and/or pcb addresses. @@ -493,29 +494,28 @@ udp_usrreq(so, req, m, addr, control) switch (req) { case PRU_ATTACH: - if (inp != NULL) { - error = EINVAL; + if (inp != 0) { + error = EISCONN; break; } - s = splnet(); - error = in_pcballoc(so, &udb); - splx(s); - if (error) - break; - error = soreserve(so, udp_sendspace, udp_recvspace); + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + break; + } + error = in_pcballoc(so, &udbtable); if (error) break; - ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; + inp = sotoinpcb(so); + inp->inp_ip.ip_ttl = ip_defttl; break; case PRU_DETACH: - udp_detach(inp); + in_pcbdetach(inp); break; case PRU_BIND: - s = splnet(); - error = in_pcbbind(inp, addr); - splx(s); + error = in_pcbbind(inp, nam, p); break; case PRU_LISTEN: @@ -523,104 +523,107 @@ udp_usrreq(so, req, m, addr, control) break; case PRU_CONNECT: - if (inp->inp_faddr.s_addr != INADDR_ANY) { - error = EISCONN; + error = in_pcbconnect(inp, nam); + if (error) break; - } - s = splnet(); - error = in_pcbconnect(inp, addr); - splx(s); - if (error == 0) - soisconnected(so); + soisconnected(so); break; case PRU_CONNECT2: error = EOPNOTSUPP; break; - case PRU_ACCEPT: - error = EOPNOTSUPP; - break; - case PRU_DISCONNECT: - if (inp->inp_faddr.s_addr == INADDR_ANY) { - error = ENOTCONN; - break; - } - s = splnet(); + /*soisdisconnected(so);*/ + so->so_state &= ~SS_ISCONNECTED; /* XXX */ in_pcbdisconnect(inp); - inp->inp_laddr.s_addr = INADDR_ANY; - splx(s); - so->so_state &= ~SS_ISCONNECTED; /* XXX */ + inp->inp_laddr = zeroin_addr; /* XXX */ + in_pcbstate(inp, INP_BOUND); /* XXX */ break; case PRU_SHUTDOWN: socantsendmore(so); break; - case PRU_SEND: - return (udp_output(inp, m, addr, control)); - - case PRU_ABORT: - soisdisconnected(so); - udp_detach(inp); + case PRU_RCVD: + error = EOPNOTSUPP; break; - case PRU_SOCKADDR: - in_setsockaddr(inp, addr); - break; + case PRU_SEND: + if (control && control->m_len) { + m_freem(control); + m_freem(m); + error = EINVAL; + break; + } + { + struct in_addr laddr; /* XXX */ - case PRU_PEERADDR: - in_setpeeraddr(inp, addr); + if (nam) { + laddr = inp->inp_laddr; /* XXX */ + if ((so->so_state & SS_ISCONNECTED) != 0) { + error = EISCONN; + goto die; + } + error = in_pcbconnect(inp, nam); + if (error) { + die: + m_freem(m); + break; + } + } else { + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + goto die; + } + } + error = udp_output(m, inp); + if (nam) { + in_pcbdisconnect(inp); + inp->inp_laddr = laddr; /* XXX */ + in_pcbstate(inp, INP_BOUND); /* XXX */ + } + } break; case PRU_SENSE: /* * stat: don't bother with a blocksize. */ + splx(s); return (0); + case PRU_RCVOOB: + error = EOPNOTSUPP; + break; + case PRU_SENDOOB: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: + m_freem(control); + m_freem(m); error = EOPNOTSUPP; break; - case PRU_RCVD: - case PRU_RCVOOB: - return (EOPNOTSUPP); /* do not free mbuf's */ + case PRU_SOCKADDR: + in_setsockaddr(inp, nam); + break; + + case PRU_PEERADDR: + in_setpeeraddr(inp, nam); + break; default: panic("udp_usrreq"); } release: - if (control) { - printf("udp control data unexpectedly retained\n"); - m_freem(control); - } - if (m) - m_freem(m); - return (error); -} - -static void -udp_detach(inp) - struct inpcb *inp; -{ - int s = splnet(); - - if (inp == udp_last_inpcb) - udp_last_inpcb = &udb; - in_pcbdetach(inp); splx(s); + return (error); } /* * Sysctl for udp variables. */ +int udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) int *name; u_int namelen; @@ -636,6 +639,12 @@ udp_sysctl(name, namelen, oldp, oldlenp, switch (name[0]) { case UDPCTL_CHECKSUM: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); + case UDPCTL_SENDSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &udp_sendspace)); + case UDPCTL_RECVSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &udp_recvspace)); default: return (ENOPROTOOPT); }