X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/cce93e4b226012d5eebcf7f7bd01cde8a8a07f51..99d13dad0a8ca5c57c42f01db01b7f1b2535f24b:/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 cd4131f03a..7d1daddf7a 100644 --- a/usr/src/sys/netinet/udp_usrreq.c +++ b/usr/src/sys/netinet/udp_usrreq.c @@ -1,23 +1,32 @@ -/* udp_usrreq.c 4.41 82/12/14 */ - -#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 "../netinet/in.h" +/* + * Copyright (c) 1982 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)udp_usrreq.c 6.21 (Berkeley) %G% + */ + +#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 "../netinet/in_pcb.h" -#include "../netinet/in_systm.h" -#include "../netinet/ip.h" -#include "../netinet/ip_var.h" -#include "../netinet/ip_icmp.h" -#include "../netinet/udp.h" -#include "../netinet/udp_var.h" -#include + +#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. @@ -29,16 +38,23 @@ udp_init() udb.inp_next = udb.inp_prev = &udb; } -int udpcksum; +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif + struct sockaddr_in udp_in = { AF_INET }; -udp_input(m0) +udp_input(m0, ifp) struct mbuf *m0; + struct ifnet *ifp; { register struct udpiphdr *ui; register struct inpcb *inp; register struct mbuf *m; int len; + struct ip ip; /* * Get IP and UDP header together in first mbuf. @@ -63,20 +79,23 @@ udp_input(m0) 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. */ - if (udpcksum) { + if (udpcksum && ui->ui_sum) { ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; - ui->ui_len = htons((u_short)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; } @@ -89,13 +108,12 @@ udp_input(m0) ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, INPLOOKUP_WILDCARD); if (inp == 0) { - struct in_addr broadcastaddr; - - broadcastaddr = - if_makeaddr(in_netof(ui->ui_dst), INADDR_ANY); - if (ui->ui_dst.s_addr == broadcastaddr.s_addr) + /* 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); + *(struct ip *)ui = ip; + icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, + ifp); return; } @@ -107,61 +125,70 @@ udp_input(m0) udp_in.sin_addr = ui->ui_src; m->m_len -= sizeof (struct udpiphdr); m->m_off += sizeof (struct udpiphdr); -SBCHECK(&inp->inp_socket->so_rcv, "udpinput before"); - 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; -SBCHECK(&inp->inp_socket->so_rcv, "udpinput after"); sorwakeup(inp->inp_socket); return; bad: m_freem(m); } -udp_abort(inp) - struct inpcb *inp; +/* + * 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; { - struct socket *so = inp->inp_socket; - in_pcbdisconnect(inp); - soisdisconnected(so); + sorwakeup(inp->inp_socket); + sowwakeup(inp->inp_socket); } -udp_ctlinput(cmd, arg) +udp_ctlinput(cmd, sa) int cmd; - caddr_t arg; + struct sockaddr *sa; { - struct in_addr *sin; extern u_char inetctlerrmap[]; + struct sockaddr_in *sin; + int in_rtchange(); - if (cmd < 0 || cmd > PRC_NCMDS) + 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_ROUTEDEAD: - break; + switch (cmd) { case PRC_QUENCH: break; - /* these are handled by ip */ - case PRC_IFDOWN: - case PRC_HOSTDEAD: - case PRC_HOSTUNREACH: + 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: - sin = &((struct icmp *)arg)->icmp_ip.ip_dst; - in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); + if (inetctlerrmap[cmd] == 0) + return; /* XXX */ + in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], + udp_notify); } } udp_output(inp, m0) - struct inpcb *inp; + register struct inpcb *inp; struct mbuf *m0; { register struct mbuf *m; register struct udpiphdr *ui; - register struct socket *so; register int len = 0; /* @@ -170,7 +197,7 @@ udp_output(inp, m0) */ for (m = m0; m; m = m->m_next) len += m->m_len; - m = m_get(M_DONTWAIT, MT_HEADER); + MGET(m, M_DONTWAIT, MT_HEADER); if (m == 0) { m_freem(m0); return (ENOBUFS); @@ -187,54 +214,66 @@ udp_output(inp, m0) ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = len + sizeof (struct udphdr); + 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)ui->ui_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; - so = inp->inp_socket; - return (ip_output(m, (struct mbuf *)0, - (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, - so->so_state & SS_PRIV)); + ((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))); } +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, opt) +udp_usrreq(so, req, m, nam, rights) struct socket *so; int req; - struct mbuf *m, *nam; - struct socketopt *opt; + struct mbuf *m, *nam, *rights; { struct inpcb *inp = sotoinpcb(so); int error = 0; - 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); + if (inp != NULL) { + error = EINVAL; + break; + } error = in_pcballoc(so, &udb); if (error) break; - error = soreserve(so, 2048, 2048); + error = soreserve(so, udp_sendspace, udp_recvspace); if (error) break; break; case PRU_DETACH: - if (inp == 0) - return (ENOTCONN); in_pcbdetach(inp); break; @@ -247,21 +286,30 @@ udp_usrreq(so, req, m, nam, opt) break; case PRU_CONNECT: - if (inp->inp_faddr.s_addr) - return (EISCONN); + 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); + so->so_state &= ~SS_ISCONNECTED; /* XXX */ break; case PRU_SHUTDOWN: @@ -270,22 +318,35 @@ udp_usrreq(so, req, m, nam, opt) case PRU_SEND: { struct in_addr laddr; + int s; if (nam) { laddr = inp->inp_laddr; - if (inp->inp_faddr.s_addr) - return (EISCONN); + 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) + 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); } } break; @@ -296,15 +357,37 @@ udp_usrreq(so, req, m, nam, opt) 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"); } +release: + if (m != NULL) + m_freem(m); return (error); }