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.10 retrieving revision 1.26 diff -u -p -r1.10 -r1.26 --- src/sys/netinet/udp_usrreq.c 1994/01/10 20:14:34 1.10 +++ src/sys/netinet/udp_usrreq.c 1996/01/31 03:49:38 1.26 @@ -1,6 +1,8 @@ +/* $NetBSD: udp_usrreq.c,v 1.26 1996/01/31 03:49:38 mycroft Exp $ */ + /* - * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. - * All rights reserved. + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,8 +32,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91 - * $Id: udp_usrreq.c,v 1.10 1994/01/10 20:14:34 mycroft Exp $ + * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 */ #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include @@ -47,6 +49,7 @@ #include #include +#include #include #include #include @@ -63,21 +66,23 @@ int udpcksum = 1; #else int udpcksum = 0; /* XXX */ #endif -int udp_ttl = UDP_TTL; 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)); +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); } void @@ -122,7 +127,7 @@ udp_input(m, iphlen) * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ - len = ntohs((u_short)uh->uh_ulen); + len = ntohs((u_int16_t)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len) { udpstat.udps_badlen++; @@ -141,9 +146,8 @@ 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; + 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))) { udpstat.udps_badsum++; @@ -151,9 +155,9 @@ udp_input(m, iphlen) return; } } -#ifdef MULTICAST - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || - in_broadcast(ip->ip_dst)) { + + if (IN_MULTICAST(ip->ip_dst.s_addr) || + in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { struct socket *last; /* * Deliver a multicast or broadcast datagram to *all* sockets @@ -168,8 +172,9 @@ udp_input(m, iphlen) * Those applications open the multiple sockets to overcome an * inadequacy of the UDP socket interface, but for backwards * compatibility we avoid the problem here rather than - * fixing the interface. Maybe 4.4BSD will remedy this?) + * fixing the interface. Maybe 4.5BSD will remedy this?) */ + /* * Construct sockaddr format source address. */ @@ -182,7 +187,9 @@ udp_input(m, iphlen) * (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) { @@ -202,23 +209,24 @@ udp_input(m, iphlen) if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { if (sbappendaddr(&last->so_rcv, - (struct sockaddr *)&udp_in, - n, (struct mbuf *)0) == 0) + sintosa(&udp_in), n, + (struct mbuf *)0) == 0) { m_freem(n); - else + udpstat.udps_fullsock++; + } else sorwakeup(last); } } last = inp->inp_socket; /* - * Don't look for additional matches if this one - * does not have the SO_REUSEADDR socket option set. - * This heuristic avoids searching through all pcbs - * in the common case of a non-shared port. It - * assumes that an application will never clear - * the SO_REUSEADDR option after setting it. + * Don't look for additional matches if this one does + * not have either the SO_REUSEPORT or SO_REUSEADDR + * socket options set. This heuristic avoids searching + * through all pcbs in the common case of a non-shared + * port. It * assumes that an application will never + * clear these options after setting them. */ - if ((last->so_options & SO_REUSEADDR) == 0) + if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) break; } @@ -228,46 +236,37 @@ udp_input(m, iphlen) * (No need to send an ICMP Port Unreachable * for a broadcast or multicast datgram.) */ + udpstat.udps_noportbcast++; goto bad; } - if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, - m, (struct mbuf *)0) == 0) + if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m, + (struct mbuf *)0) == 0) { + udpstat.udps_fullsock++; goto bad; + } sorwakeup(last); return; } -#endif /* * 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_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport); if (inp == 0) { - /* don't send ICMP response for broadcast packet */ - udpstat.udps_noport++; -#ifndef MULTICAST - /* XXX why don't we do this with MULTICAST? */ - if (m->m_flags & (M_BCAST | M_MCAST)) { - udpstat.udps_noportbcast++; - goto bad; + ++udpstat.udps_pcbhashmiss; + inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); + if (inp == 0) { + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } + *ip = save_ip; + ip->ip_len += iphlen; + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); + return; } -#endif - *ip = save_ip; - ip->ip_len += iphlen; - { - register struct in_addr foo = {}; - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, foo); - } - return; } /* @@ -306,8 +305,8 @@ udp_input(m, iphlen) m->m_len -= iphlen; m->m_pkthdr.len -= iphlen; m->m_data += iphlen; - if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, - m, opts) == 0) { + if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udp_in), m, + opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -323,7 +322,7 @@ bad: * Create a "control" mbuf containing the specified data * with the specified type for presentation with a datagram. */ -static struct mbuf * +struct mbuf * udp_saveopt(p, size, type) caddr_t p; register int size; @@ -335,7 +334,7 @@ udp_saveopt(p, size, type) if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) return ((struct mbuf *) NULL); cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); - bcopy(p, (caddr_t)(cp + 1), size); + bcopy(p, CMSG_DATA(cp), size); size += sizeof(*cp); m->m_len = size; cp->cmsg_len = size; @@ -353,7 +352,6 @@ udp_notify(inp, errno) register struct inpcb *inp; int errno; { - inp->inp_socket->so_error = errno; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); @@ -367,16 +365,25 @@ udp_ctlinput(cmd, sa, ip) { 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 ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) + if ((unsigned)cmd >= PRC_NCMDS) + return; + 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; 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, sa, 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, sa, errno, notify); } int @@ -402,7 +409,7 @@ udp_output(inp, m, addr, control) /* * Must block input while temporarily connected. */ - s = splnet(); + s = splsoftnet(); error = in_pcbconnect(inp, addr); if (error) { splx(s); @@ -418,17 +425,20 @@ udp_output(inp, m, addr, control) * Calculate data length and get a mbuf * for UDP and IP headers. */ - M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); + M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); + if (m == 0) { + error = ENOBUFS; + 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_short)len + sizeof (struct udphdr)); + ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); ui->ui_src = inp->inp_laddr; ui->ui_dst = inp->inp_faddr; ui->ui_sport = inp->inp_lport; @@ -448,13 +458,8 @@ udp_output(inp, m, addr, control) ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ udpstat.udps_opackets++; error = ip_output(m, inp->inp_options, &inp->inp_route, - inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST) -#ifdef MULTICAST - , inp->inp_moptions -#else - , NULL -#endif - ); + inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), + inp->inp_moptions); if (addr) { in_pcbdisconnect(inp); @@ -484,7 +489,7 @@ udp_usrreq(so, req, m, addr, control) int s; if (req == PRU_CONTROL) - return (in_control(so, (int)m, (caddr_t)addr, + return (in_control(so, (long)m, (caddr_t)addr, (struct ifnet *)control)); if (inp == NULL && req != PRU_ATTACH) { error = EINVAL; @@ -501,15 +506,15 @@ udp_usrreq(so, req, m, addr, control) error = EINVAL; break; } - s = splnet(); - error = in_pcballoc(so, &udb); + s = splsoftnet(); + error = in_pcballoc(so, &udbtable); splx(s); if (error) break; error = soreserve(so, udp_sendspace, udp_recvspace); if (error) break; - ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl; + ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; break; case PRU_DETACH: @@ -517,7 +522,7 @@ udp_usrreq(so, req, m, addr, control) break; case PRU_BIND: - s = splnet(); + s = splsoftnet(); error = in_pcbbind(inp, addr); splx(s); break; @@ -531,7 +536,7 @@ udp_usrreq(so, req, m, addr, control) error = EISCONN; break; } - s = splnet(); + s = splsoftnet(); error = in_pcbconnect(inp, addr); splx(s); if (error == 0) @@ -551,7 +556,7 @@ udp_usrreq(so, req, m, addr, control) error = ENOTCONN; break; } - s = splnet(); + s = splsoftnet(); in_pcbdisconnect(inp); inp->inp_laddr.s_addr = INADDR_ANY; splx(s); @@ -614,10 +619,32 @@ static void udp_detach(inp) struct inpcb *inp; { - int s = splnet(); + int s = splsoftnet(); - if (inp == udp_last_inpcb) - udp_last_inpcb = &udb; in_pcbdetach(inp); splx(s); } + +/* + * Sysctl for udp variables. + */ +udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case UDPCTL_CHECKSUM: + return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); + default: + return (ENOPROTOOPT); + } + /* NOTREACHED */ +}