X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/4ad99baef19aa1d3c1c12bba63d689409256e66f..986fd057089c0c3c193084e22eee9f05c565b9bb:/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 85ef543c57..0edf4fa2b9 100644 --- a/usr/src/sys/netinet/udp_usrreq.c +++ b/usr/src/sys/netinet/udp_usrreq.c @@ -1,19 +1,44 @@ -/* udp_usrreq.c 4.7 81/11/20 */ - -#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/inet.h" -#include "../net/inet_pcb.h" -#include "../net/inet_systm.h" -#include "../net/ip.h" -#include "../net/ip_var.h" -#include "../net/udp.h" -#include "../net/udp_var.h" +/* + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)udp_usrreq.c 7.9 (Berkeley) %G% + */ + +#include "param.h" +#include "dir.h" +#include "user.h" +#include "malloc.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. @@ -25,72 +50,85 @@ udp_init() udb.inp_next = udb.inp_prev = &udb; } -int udpcksum; +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif +int udp_ttl = UDP_TTL; + struct sockaddr_in udp_in = { AF_INET }; -udp_input(m0) - struct mbuf *m0; +udp_input(m, iphlen) + register struct mbuf *m; + int iphlen; { register struct udpiphdr *ui; register struct inpcb *inp; - register struct mbuf *m; - int len, ulen; + int len; + struct ip ip; /* - * Get ip and udp header together in first mbuf. + * Get IP and UDP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. */ - m = m0; ui = mtod(m, struct udpiphdr *); - if (ui->ui_len > sizeof (struct ip)) - ip_stripoptions((struct ip *)ui, (char *)0); - if (m->m_len < sizeof (struct udpiphdr) && - m_pullup(m, sizeof (struct udpiphdr)) == 0) { - udpstat.udps_hdrops++; - goto bad; + if (iphlen > sizeof (struct ip)) + ip_stripoptions(m, (struct mbuf *)0); + if (m->m_len < sizeof (struct udpiphdr)) { + if ((m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { + udpstat.udps_hdrops++; + return; + } + ui = mtod(m, struct udpiphdr *); } /* - * Make mbuf data length reflect udp length. - * If not enough data to reflect udp length, drop. + * 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 udpiphdr) + 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); - /* (struct ip *)ui->ip_len = len; */ + m_adj(m, len - ((struct ip *)ui)->ip_len); + /* ((struct ip *)ui)->ip_len = len; */ } + /* + * Save a copy of the IP header in case we want restore it for ICMP. + */ + ip = *(struct ip *)ui; /* - * Checksum extended udp header and data. + * 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 udpiphdr) + ulen)); - if (ui->ui_sum = inet_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; } } /* - * Convert addresses and ports to host format. * Locate pcb for datagram. */ - ui->ui_src.s_addr = ntohl(ui->ui_src.s_addr); - ui->ui_dst.s_addr = ntohl(ui->ui_dst.s_addr); - ui->ui_sport = ntohs(ui->ui_sport); - ui->ui_dport = ntohs(ui->ui_dport); inp = in_pcblookup(&udb, - ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport); - if (inp == 0) - goto bad; + ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, + INPLOOKUP_WILDCARD); + if (inp == 0) { + /* don't send ICMP response for broadcast packet */ + if (m->m_flags & M_BCAST) + goto bad; + *(struct ip *)ui = ip; + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); + return; + } /* * Construct sockaddr format source address. @@ -98,153 +136,261 @@ udp_input(m0) */ udp_in.sin_port = ui->ui_sport; udp_in.sin_addr = ui->ui_src; - if (sbappendaddr(&inp->inp_socket->so_snd, (struct sockaddr *)&udp_in, m) == 0) + m->m_len -= sizeof (struct udpiphdr); + m->m_pkthdr.len -= sizeof (struct udpiphdr); + m->m_data += sizeof (struct udpiphdr); + if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, + m, (struct mbuf *)0) == 0) goto bad; + sorwakeup(inp->inp_socket); return; bad: m_freem(m); } -udp_ctlinput(m) - struct mbuf *m; +/* + * Notify a udp user of an asynchronous error; + * just wake up so that he can collect error status. + */ +udp_notify(inp) + register struct inpcb *inp; { - m_freem(m); + sorwakeup(inp->inp_socket); + sowwakeup(inp->inp_socket); } -/*ARGSUSED*/ -udp_output(inp, m0) - struct inpcb *inp; - struct mbuf *m0; +udp_ctlinput(cmd, sa) + int cmd; + struct sockaddr *sa; { + extern u_char inetctlerrmap[]; + struct sockaddr_in *sin; + int in_rtchange(); + + if ((unsigned)cmd > PRC_NCMDS) + return; + if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) + return; + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr == INADDR_ANY) + return; + + switch (cmd) { + + case PRC_QUENCH: + break; + + case PRC_ROUTEDEAD: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); + break; + + default: + if (inetctlerrmap[cmd] == 0) + return; /* XXX */ + in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], + udp_notify); + } +} + +udp_output(inp, m) + register struct inpcb *inp; register struct mbuf *m; +{ register struct udpiphdr *ui; - register int len = 0; + register int len = m->m_pkthdr.len; /* * Calculate data length and get a mbuf - * for udp and ip headers. + * for UDP and IP headers. */ - for (m = m0; m; m = m->m_next) - len += m->m_len; - m = m_get(0); - if (m == 0) - goto bad; + M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); /* - * Fill in mbuf with extended udp header + * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ - m->m_off = MMAXOFF - sizeof (struct udpiphdr); - m->m_len = sizeof (struct udpiphdr); - m->m_next = m0; ui = mtod(m, struct udpiphdr *); ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons((u_short)(sizeof (struct udphdr) + len)); - ui->ui_src.s_addr = htonl(inp->inp_laddr.s_addr); - ui->ui_dst.s_addr = htonl(inp->inp_faddr.s_addr); - ui->ui_sport = htons(inp->inp_lport); - ui->ui_dport = htons(inp->inp_fport); - ui->ui_ulen = htons((u_short)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 = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; - ui->ui_sum = inet_cksum(m, sizeof (struct udpiphdr) + len); - ip_output(m); - return; -bad: - m_freem(m); + if (udpcksum) { + if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; + ((struct ip *)ui)->ip_ttl = udp_ttl; + return (ip_output(m, inp->inp_options, &inp->inp_route, + inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); } +u_long udp_sendspace = 2048; /* really max datagram size */ +u_long udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ + /*ARGSUSED*/ -udp_usrreq(so, req, m, addr) +udp_usrreq(so, req, m, nam, rights, control) struct socket *so; int req; - struct mbuf *m; - caddr_t addr; + struct mbuf *m, *nam, *rights, *control; { struct inpcb *inp = sotoinpcb(so); - int error; + int error = 0; + 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_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); + if (inp != NULL) { + error = EINVAL; + break; + } + error = in_pcballoc(so, &udb); if (error) - return (error); - so->so_pcb = (caddr_t)inp; + break; + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + break; break; case PRU_DETACH: - if (inp == 0) - return (ENOTCONN); - in_pcbfree(inp); + 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_pcbsetpeer(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); - inp->inp_faddr.s_addr = 0; - soisdisconnected(so); + if (inp->inp_faddr.s_addr == INADDR_ANY) { + error = ENOTCONN; + break; + } + in_pcbdisconnect(inp); + so->so_state &= ~SS_ISCONNECTED; /* XXX */ break; case PRU_SHUTDOWN: socantsendmore(so); break; - case PRU_SEND: - if (addr) { - if (inp->inp_faddr.s_addr) - return (EISCONN); - error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); - if (error) - return (error); + case PRU_SEND: { + struct in_addr laddr; + int s; + + if (nam) { + laddr = inp->inp_laddr; + 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; + } + } + error = udp_output(inp, m); + m = NULL; + if (nam) { + in_pcbdisconnect(inp); + inp->inp_laddr = laddr; + splx(s); + } } - udp_output(inp, m); - if (addr) - inp->inp_faddr.s_addr = 0; break; case PRU_ABORT: - in_pcbfree(inp); - sofree(so); soisdisconnected(so); + in_pcbdetach(inp); + break; + + case PRU_SOCKADDR: + in_setsockaddr(inp, nam); + break; + + case PRU_PEERADDR: + in_setpeeraddr(inp, nam); break; - case PRU_CONTROL: - return (EOPNOTSUPP); + 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); -} - -/*ARGSUSED*/ -udp_sense(m) - struct mbuf *m; -{ - - return (EOPNOTSUPP); +release: + if (m != NULL) + m_freem(m); + return (error); }