123199Smckusick /* 223199Smckusick * Copyright (c) 1982 Regents of the University of California. 323199Smckusick * All rights reserved. The Berkeley software License Agreement 423199Smckusick * specifies the terms and conditions for redistribution. 523199Smckusick * 6*26426Skarels * @(#)udp_usrreq.c 6.21 (Berkeley) 02/25/86 723199Smckusick */ 84784Swnj 917065Sbloom #include "param.h" 1017065Sbloom #include "dir.h" 1117065Sbloom #include "user.h" 1217065Sbloom #include "mbuf.h" 1317065Sbloom #include "protosw.h" 1417065Sbloom #include "socket.h" 1517065Sbloom #include "socketvar.h" 1617065Sbloom #include "errno.h" 1717065Sbloom #include "stat.h" 1810897Ssam 196584Ssam #include "../net/if.h" 206354Ssam #include "../net/route.h" 2110897Ssam 2217065Sbloom #include "in.h" 2317065Sbloom #include "in_pcb.h" 2417065Sbloom #include "in_systm.h" 2517065Sbloom #include "ip.h" 2617065Sbloom #include "ip_var.h" 2717065Sbloom #include "ip_icmp.h" 2817065Sbloom #include "udp.h" 2917065Sbloom #include "udp_var.h" 304784Swnj 314926Swnj /* 324926Swnj * UDP protocol implementation. 334926Swnj * Per RFC 768, August, 1980. 344926Swnj */ 354805Swnj udp_init() 364805Swnj { 374805Swnj 384901Swnj udb.inp_next = udb.inp_prev = &udb; 394805Swnj } 404805Swnj 4126118Skarels #ifndef COMPAT_42 4219519Skarels int udpcksum = 1; 4326118Skarels #else 4426118Skarels int udpcksum = 0; /* XXX */ 4526118Skarels #endif 4626118Skarels 474926Swnj struct sockaddr_in udp_in = { AF_INET }; 484901Swnj 4926032Skarels udp_input(m0, ifp) 504926Swnj struct mbuf *m0; 5126032Skarels struct ifnet *ifp; 524784Swnj { 534901Swnj register struct udpiphdr *ui; 544887Swnj register struct inpcb *inp; 554926Swnj register struct mbuf *m; 567844Sroot int len; 5724823Skarels struct ip ip; 584784Swnj 594926Swnj /* 605246Sroot * Get IP and UDP header together in first mbuf. 614926Swnj */ 624926Swnj m = m0; 635308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 645308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 654926Swnj udpstat.udps_hdrops++; 665308Sroot return; 674926Swnj } 685050Swnj ui = mtod(m, struct udpiphdr *); 695246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 705220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 714926Swnj 724926Swnj /* 735246Sroot * Make mbuf data length reflect UDP length. 745246Sroot * If not enough data to reflect UDP length, drop. 754926Swnj */ 767844Sroot len = ntohs((u_short)ui->ui_ulen); 774926Swnj if (((struct ip *)ui)->ip_len != len) { 784926Swnj if (len > ((struct ip *)ui)->ip_len) { 794926Swnj udpstat.udps_badlen++; 804926Swnj goto bad; 814926Swnj } 8215539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 8324823Skarels /* ((struct ip *)ui)->ip_len = len; */ 844926Swnj } 8524823Skarels /* 8624823Skarels * Save a copy of the IP header in case we want restore it for ICMP. 8724823Skarels */ 8824823Skarels ip = *(struct ip*)ui; 894926Swnj 904926Swnj /* 915246Sroot * Checksum extended UDP header and data. 924926Swnj */ 9315539Skarels if (udpcksum && ui->ui_sum) { 944926Swnj ui->ui_next = ui->ui_prev = 0; 954926Swnj ui->ui_x1 = 0; 9621112Skarels ui->ui_len = ui->ui_ulen; 977844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 984926Swnj udpstat.udps_badsum++; 994901Swnj m_freem(m); 1004901Swnj return; 1014901Swnj } 1024901Swnj } 1034926Swnj 1044926Swnj /* 1057844Sroot * Locate pcb for datagram. 1064926Swnj */ 1074926Swnj inp = in_pcblookup(&udb, 1086029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1096029Sroot INPLOOKUP_WILDCARD); 1106584Ssam if (inp == 0) { 11110144Ssam /* don't send ICMP response for broadcast packet */ 11221112Skarels if (in_broadcast(ui->ui_dst)) 1136584Ssam goto bad; 11424823Skarels *(struct ip *)ui = ip; 11526032Skarels icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 11626032Skarels ifp); 1176584Ssam return; 1186584Ssam } 1196584Ssam 1204926Swnj /* 1214926Swnj * Construct sockaddr format source address. 1224926Swnj * Stuff source address and datagram in user buffer. 1234926Swnj */ 1244926Swnj udp_in.sin_port = ui->ui_sport; 1254926Swnj udp_in.sin_addr = ui->ui_src; 1265050Swnj m->m_len -= sizeof (struct udpiphdr); 1275050Swnj m->m_off += sizeof (struct udpiphdr); 12812767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 12912767Ssam m, (struct mbuf *)0) == 0) 1304926Swnj goto bad; 1315050Swnj sorwakeup(inp->inp_socket); 1324887Swnj return; 1334926Swnj bad: 1344887Swnj m_freem(m); 1354784Swnj } 1364784Swnj 137*26426Skarels /* 138*26426Skarels * Notify a udp user of an asynchronous error; 139*26426Skarels * just wake up so that he can collect error status. 140*26426Skarels */ 141*26426Skarels udp_notify(inp) 142*26426Skarels register struct inpcb *inp; 143*26426Skarels { 144*26426Skarels 145*26426Skarels sorwakeup(inp->inp_socket); 146*26426Skarels sowwakeup(inp->inp_socket); 147*26426Skarels } 148*26426Skarels 14924823Skarels udp_ctlinput(cmd, sa) 1506591Ssam int cmd; 15124823Skarels struct sockaddr *sa; 1526591Ssam { 1536591Ssam extern u_char inetctlerrmap[]; 15424823Skarels struct sockaddr_in *sin; 15521121Skarels int in_rtchange(); 1566591Ssam 15724823Skarels if ((unsigned)cmd > PRC_NCMDS) 1586591Ssam return; 15924823Skarels if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 16024823Skarels return; 16124823Skarels sin = (struct sockaddr_in *)sa; 16224823Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 16324823Skarels return; 16424823Skarels 1656591Ssam switch (cmd) { 1666591Ssam 16724823Skarels case PRC_QUENCH: 1686591Ssam break; 1696591Ssam 17024823Skarels case PRC_ROUTEDEAD: 17121121Skarels case PRC_REDIRECT_NET: 17221121Skarels case PRC_REDIRECT_HOST: 17324823Skarels case PRC_REDIRECT_TOSNET: 17424823Skarels case PRC_REDIRECT_TOSHOST: 17524823Skarels in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 1766591Ssam break; 1776591Ssam 1786591Ssam default: 17921121Skarels if (inetctlerrmap[cmd] == 0) 18021121Skarels return; /* XXX */ 18124823Skarels in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 182*26426Skarels udp_notify); 1836591Ssam } 1846591Ssam } 1856591Ssam 1864955Swnj udp_output(inp, m0) 18726060Skarels register struct inpcb *inp; 1884926Swnj struct mbuf *m0; 1894784Swnj { 1904926Swnj register struct mbuf *m; 1914926Swnj register struct udpiphdr *ui; 19217165Skarels register int len = 0; 1934784Swnj 1944926Swnj /* 1954926Swnj * Calculate data length and get a mbuf 1965246Sroot * for UDP and IP headers. 1974926Swnj */ 1984926Swnj for (m = m0; m; m = m->m_next) 1994926Swnj len += m->m_len; 20021112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 2016507Ssam if (m == 0) { 2026507Ssam m_freem(m0); 2036507Ssam return (ENOBUFS); 2046507Ssam } 2054784Swnj 2064926Swnj /* 2075246Sroot * Fill in mbuf with extended UDP header 2084926Swnj * and addresses and length put into network format. 2094926Swnj */ 2104926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 2114926Swnj m->m_len = sizeof (struct udpiphdr); 2124926Swnj m->m_next = m0; 2134926Swnj ui = mtod(m, struct udpiphdr *); 2144926Swnj ui->ui_next = ui->ui_prev = 0; 2154926Swnj ui->ui_x1 = 0; 2164926Swnj ui->ui_pr = IPPROTO_UDP; 21715226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2185050Swnj ui->ui_src = inp->inp_laddr; 2195050Swnj ui->ui_dst = inp->inp_faddr; 2205050Swnj ui->ui_sport = inp->inp_lport; 2215050Swnj ui->ui_dport = inp->inp_fport; 22215226Ssam ui->ui_ulen = ui->ui_len; 2234784Swnj 2244926Swnj /* 2254926Swnj * Stuff checksum and output datagram. 2264926Swnj */ 2274926Swnj ui->ui_sum = 0; 22819519Skarels if (udpcksum) { 22919519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 23015539Skarels ui->ui_sum = -1; 23121112Skarels } 2325050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 23326086Skarels ((struct ip *)ui)->ip_ttl = UDP_TTL; 23426060Skarels return (ip_output(m, inp->inp_options, &inp->inp_route, 23526060Skarels inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 2364784Swnj } 2374784Swnj 23818368Skarels int udp_sendspace = 2048; /* really max datagram size */ 23918368Skarels int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 24018368Skarels 2418602Sroot /*ARGSUSED*/ 24212767Ssam udp_usrreq(so, req, m, nam, rights) 2434887Swnj struct socket *so; 2444784Swnj int req; 24512767Ssam struct mbuf *m, *nam, *rights; 2464784Swnj { 2474887Swnj struct inpcb *inp = sotoinpcb(so); 2486507Ssam int error = 0; 2494784Swnj 25018368Skarels if (req == PRU_CONTROL) 25118368Skarels return (in_control(so, (int)m, (caddr_t)nam, 25218368Skarels (struct ifnet *)rights)); 25312767Ssam if (rights && rights->m_len) { 25412767Ssam error = EINVAL; 25512767Ssam goto release; 25612767Ssam } 25711080Ssam if (inp == NULL && req != PRU_ATTACH) { 25811080Ssam error = EINVAL; 25911080Ssam goto release; 26011080Ssam } 2614784Swnj switch (req) { 2624784Swnj 2634784Swnj case PRU_ATTACH: 26411080Ssam if (inp != NULL) { 26511080Ssam error = EINVAL; 26611080Ssam break; 26711080Ssam } 2688273Sroot error = in_pcballoc(so, &udb); 2698273Sroot if (error) 2708273Sroot break; 27118368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2728273Sroot if (error) 2738273Sroot break; 2744887Swnj break; 2754784Swnj 2764784Swnj case PRU_DETACH: 2775166Swnj in_pcbdetach(inp); 2784887Swnj break; 2794784Swnj 2808273Sroot case PRU_BIND: 2818273Sroot error = in_pcbbind(inp, nam); 2828273Sroot break; 2838273Sroot 2848273Sroot case PRU_LISTEN: 2858273Sroot error = EOPNOTSUPP; 2868273Sroot break; 2878273Sroot 2884784Swnj case PRU_CONNECT: 28911080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 29011080Ssam error = EISCONN; 29111080Ssam break; 29211080Ssam } 2938273Sroot error = in_pcbconnect(inp, nam); 2946507Ssam if (error == 0) 2956507Ssam soisconnected(so); 2964887Swnj break; 2974784Swnj 29813118Ssam case PRU_CONNECT2: 29913118Ssam error = EOPNOTSUPP; 30013118Ssam break; 30113118Ssam 3024926Swnj case PRU_ACCEPT: 30311080Ssam error = EOPNOTSUPP; 30411080Ssam break; 3054926Swnj 3064784Swnj case PRU_DISCONNECT: 30711080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 30811080Ssam error = ENOTCONN; 30911080Ssam break; 31011080Ssam } 3115166Swnj in_pcbdisconnect(inp); 31226404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 3134784Swnj break; 3144784Swnj 3154912Swnj case PRU_SHUTDOWN: 3164912Swnj socantsendmore(so); 3174912Swnj break; 3184912Swnj 3195996Swnj case PRU_SEND: { 3205996Swnj struct in_addr laddr; 32116799Skarels int s; 3225996Swnj 3238273Sroot if (nam) { 3245996Swnj laddr = inp->inp_laddr; 32511080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 32611080Ssam error = EISCONN; 32711080Ssam break; 32811080Ssam } 32916799Skarels /* 33016799Skarels * Must block input while temporarily connected. 33116799Skarels */ 33216799Skarels s = splnet(); 3338273Sroot error = in_pcbconnect(inp, nam); 33416799Skarels if (error) { 33516799Skarels splx(s); 3366507Ssam break; 33716799Skarels } 3384955Swnj } else { 33911080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 34011080Ssam error = ENOTCONN; 34111080Ssam break; 34211080Ssam } 3434955Swnj } 3446507Ssam error = udp_output(inp, m); 34511080Ssam m = NULL; 3468273Sroot if (nam) { 3475166Swnj in_pcbdisconnect(inp); 34818368Skarels inp->inp_laddr = laddr; 34916799Skarels splx(s); 3505996Swnj } 3515996Swnj } 3524784Swnj break; 3534784Swnj 3544784Swnj case PRU_ABORT: 3555166Swnj in_pcbdetach(inp); 3564887Swnj sofree(so); 3574887Swnj soisdisconnected(so); 3584784Swnj break; 3594784Swnj 3606511Ssam case PRU_SOCKADDR: 3618273Sroot in_setsockaddr(inp, nam); 3626511Ssam break; 3636511Ssam 36414124Ssam case PRU_PEERADDR: 36514124Ssam in_setpeeraddr(inp, nam); 36614124Ssam break; 36714124Ssam 36816988Skarels case PRU_SENSE: 36916988Skarels /* 37016988Skarels * stat: don't bother with a blocksize. 37116988Skarels */ 37216988Skarels return (0); 37316988Skarels 37412205Ssam case PRU_SENDOOB: 37512205Ssam case PRU_FASTTIMO: 37612205Ssam case PRU_SLOWTIMO: 37712205Ssam case PRU_PROTORCV: 37812205Ssam case PRU_PROTOSEND: 37912205Ssam error = EOPNOTSUPP; 38012205Ssam break; 38113118Ssam 38216799Skarels case PRU_RCVD: 38316799Skarels case PRU_RCVOOB: 38416799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 38516799Skarels 38613118Ssam default: 38713118Ssam panic("udp_usrreq"); 3884805Swnj } 38911080Ssam release: 39011080Ssam if (m != NULL) 39111080Ssam m_freem(m); 3926507Ssam return (error); 3934784Swnj } 394