X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ee7873401e686a0eb45d334385c26708ef8a23f0..336240bf0e007e9903b3f288bd222473e9b09095:/usr/src/sys/netinet/udp_usrreq.c diff --git a/usr/src/sys/netinet/udp_usrreq.c b/usr/src/sys/netinet/udp_usrreq.c index 9a5fb9c36b..568437cbde 100644 --- a/usr/src/sys/netinet/udp_usrreq.c +++ b/usr/src/sys/netinet/udp_usrreq.c @@ -1,21 +1,27 @@ -/* udp_usrreq.c 4.23 82/03/28 */ - -#include "../h/param.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/mbuf.h" -#include "../h/protosw.h" -#include "../h/socket.h" -#include "../h/socketvar.h" -#include "../net/in.h" -#include "../net/in_pcb.h" -#include "../net/in_systm.h" -#include "../net/ip.h" -#include "../net/ip_var.h" -#include "../net/udp.h" -#include "../net/udp_var.h" +/* udp_usrreq.c 6.13 85/05/28 */ + +#include "param.h" +#include "dir.h" +#include "user.h" +#include "mbuf.h" +#include "protosw.h" +#include "socket.h" +#include "socketvar.h" +#include "errno.h" +#include "stat.h" + +#include "../net/if.h" #include "../net/route.h" +#include "in.h" +#include "in_pcb.h" +#include "in_systm.h" +#include "ip.h" +#include "ip_var.h" +#include "ip_icmp.h" +#include "udp.h" +#include "udp_var.h" + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -23,11 +29,10 @@ udp_init() { -COUNT(UDP_INIT); udb.inp_next = udb.inp_prev = &udb; } -int udpcksum; +int udpcksum = 1; struct sockaddr_in udp_in = { AF_INET }; udp_input(m0) @@ -36,9 +41,8 @@ udp_input(m0) register struct udpiphdr *ui; register struct inpcb *inp; register struct mbuf *m; - int len, ulen; + int len; -COUNT(UDP_INPUT); /* * Get IP and UDP header together in first mbuf. */ @@ -56,41 +60,43 @@ COUNT(UDP_INPUT); * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ - ulen = ntohs((u_short)ui->ui_ulen); - len = sizeof (struct udphdr) + ulen; + len = ntohs((u_short)ui->ui_ulen); if (((struct ip *)ui)->ip_len != len) { if (len > ((struct ip *)ui)->ip_len) { udpstat.udps_badlen++; goto bad; } - m_adj(m, ((struct ip *)ui)->ip_len - len); + m_adj(m, len - ((struct ip *)ui)->ip_len); /* (struct ip *)ui->ip_len = len; */ } /* * Checksum extended UDP header and data. */ - if (udpcksum) { + if (udpcksum && ui->ui_sum) { ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; - ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); - if (ui->ui_sum = in_cksum(m, len)) { + ui->ui_len = ui->ui_ulen; + if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { udpstat.udps_badsum++; - printf("udp cksum %x\n", ui->ui_sum); m_freem(m); return; } } /* - * Locate pcb for datagram. On wildcard match, update - * control block to anchor network and host address. + * Locate pcb for datagram. */ inp = in_pcblookup(&udb, ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, INPLOOKUP_WILDCARD); - if (inp == 0) - goto bad; + if (inp == 0) { + /* don't send ICMP response for broadcast packet */ + if (in_broadcast(ui->ui_dst)) + goto bad; + icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); + return; + } /* * Construct sockaddr format source address. @@ -100,7 +106,8 @@ COUNT(UDP_INPUT); udp_in.sin_addr = ui->ui_src; m->m_len -= sizeof (struct udpiphdr); m->m_off += sizeof (struct udpiphdr); - if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) + if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, + m, (struct mbuf *)0) == 0) goto bad; sorwakeup(inp->inp_socket); return; @@ -108,12 +115,52 @@ bad: m_freem(m); } -udp_ctlinput(m) - struct mbuf *m; +udp_abort(inp) + struct inpcb *inp; { + struct socket *so = inp->inp_socket; -COUNT(UDP_CTLINPUT); - m_freem(m); + in_pcbdisconnect(inp); + soisdisconnected(so); +} + +udp_ctlinput(cmd, arg) + int cmd; + caddr_t arg; +{ + struct in_addr *in; + extern u_char inetctlerrmap[]; + int in_rtchange(); + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + switch (cmd) { + + case PRC_ROUTEDEAD: + break; + + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + in = &((struct icmp *)arg)->icmp_ip.ip_dst; + in_pcbnotify(&udb, in, 0, in_rtchange); + break; + + case PRC_IFDOWN: + in = &((struct sockaddr_in *)arg)->sin_addr; + goto notify; + + case PRC_HOSTDEAD: + case PRC_HOSTUNREACH: + in = (struct in_addr *)arg; + goto notify; + + default: + if (inetctlerrmap[cmd] == 0) + return; /* XXX */ + in = &((struct icmp *)arg)->icmp_ip.ip_dst; +notify: + in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); + } } udp_output(inp, m0) @@ -122,18 +169,21 @@ udp_output(inp, m0) { register struct mbuf *m; register struct udpiphdr *ui; + register struct socket *so; register int len = 0; + register struct route *ro; -COUNT(UDP_OUTPUT); /* * Calculate data length and get a mbuf * for UDP and IP headers. */ for (m = m0; m; m = m->m_next) len += m->m_len; - m = m_get(M_DONTWAIT); - if (m == 0) - goto bad; + MGET(m, M_DONTWAIT, MT_HEADER); + if (m == 0) { + m_freem(m0); + return (ENOBUFS); + } /* * Fill in mbuf with extended UDP header @@ -146,70 +196,122 @@ COUNT(UDP_OUTPUT); ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = sizeof (struct udpiphdr) + len; + ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 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); + ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; - ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); + if (udpcksum) { + if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) + ui->ui_sum = -1; + } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ((struct ip *)ui)->ip_ttl = MAXTTL; - (void) ip_output(m, (struct mbuf *)0, 0, - inp->inp_socket->so_state & SS_PRIV); - return; -bad: - m_freem(m); + so = inp->inp_socket; + if (so->so_options & SO_DONTROUTE) + return (ip_output(m, (struct mbuf *)0, (struct route *)0, + (so->so_options & SO_BROADCAST) | IP_ROUTETOIF)); + /* + * Use cached route for previous datagram if + * this is also to the same destination. + * + * NB: We don't handle broadcasts because that + * would require 3 subroutine calls. + */ + ro = &inp->inp_route; +#define satosin(sa) ((struct sockaddr_in *)(sa)) + if (ro->ro_rt && + satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + return (ip_output(m, (struct mbuf *)0, ro, + so->so_options & SO_BROADCAST)); } -udp_usrreq(so, req, m, addr) +int udp_sendspace = 2048; /* really max datagram size */ +int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ + +/*ARGSUSED*/ +udp_usrreq(so, req, m, nam, rights) struct socket *so; int req; - struct mbuf *m; - caddr_t addr; + struct mbuf *m, *nam, *rights; { struct inpcb *inp = sotoinpcb(so); - int error; + int error = 0; -COUNT(UDP_USRREQ); - if (inp == 0 && req != PRU_ATTACH) - return (EINVAL); + if (req == PRU_CONTROL) + return (in_control(so, (int)m, (caddr_t)nam, + (struct ifnet *)rights)); + if (rights && rights->m_len) { + error = EINVAL; + goto release; + } + if (inp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } switch (req) { case PRU_ATTACH: - if (inp != 0) - return (EINVAL); - error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); + if (inp != NULL) { + error = EINVAL; + break; + } + error = in_pcballoc(so, &udb); if (error) - return (error); + break; + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + break; break; case PRU_DETACH: - if (inp == 0) - return (ENOTCONN); + if (inp == NULL) { + error = ENOTCONN; + break; + } in_pcbdetach(inp); break; + case PRU_BIND: + error = in_pcbbind(inp, nam); + break; + + case PRU_LISTEN: + error = EOPNOTSUPP; + break; + case PRU_CONNECT: - if (inp->inp_faddr.s_addr) - return (EISCONN); - error = in_pcbconnect(inp, (struct sockaddr_in *)addr); - if (error) - return (error); - soisconnected(so); + if (inp->inp_faddr.s_addr != INADDR_ANY) { + error = EISCONN; + break; + } + error = in_pcbconnect(inp, nam); + if (error == 0) + soisconnected(so); + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; break; case PRU_ACCEPT: - return (EOPNOTSUPP); + error = EOPNOTSUPP; + break; case PRU_DISCONNECT: - if (inp->inp_faddr.s_addr == 0) - return (ENOTCONN); + if (inp->inp_faddr.s_addr == INADDR_ANY) { + error = ENOTCONN; + break; + } in_pcbdisconnect(inp); soisdisconnected(so); break; @@ -220,23 +322,35 @@ COUNT(UDP_USRREQ); case PRU_SEND: { struct in_addr laddr; + int s; - if (addr) { + if (nam) { laddr = inp->inp_laddr; - if (inp->inp_faddr.s_addr) - return (EISCONN); - error = in_pcbconnect(inp, (struct sockaddr_in *)addr); - if (error) - return (error); + if (inp->inp_faddr.s_addr != INADDR_ANY) { + error = EISCONN; + break; + } + /* + * Must block input while temporarily connected. + */ + s = splnet(); + error = in_pcbconnect(inp, nam); + if (error) { + splx(s); + break; + } } else { - if (inp->inp_faddr.s_addr == 0) - return (ENOTCONN); + if (inp->inp_faddr.s_addr == INADDR_ANY) { + error = ENOTCONN; + break; + } } - udp_output(inp, m); - if (addr) { + error = udp_output(inp, m); + m = NULL; + if (nam) { in_pcbdisconnect(inp); inp->inp_laddr = laddr; - in_setsockaddr(inp); + splx(s); } } break; @@ -247,11 +361,37 @@ COUNT(UDP_USRREQ); soisdisconnected(so); break; - case PRU_CONTROL: - return (EOPNOTSUPP); + case PRU_SOCKADDR: + in_setsockaddr(inp, nam); + break; + + case PRU_PEERADDR: + in_setpeeraddr(inp, nam); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + return (EOPNOTSUPP); /* do not free mbuf's */ default: panic("udp_usrreq"); } - return (0); +release: + if (m != NULL) + m_freem(m); + return (error); }