123199Smckusick /* 235794Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332789Sbostic * All rights reserved. 423199Smckusick * 532789Sbostic * Redistribution and use in source and binary forms are permitted 634855Sbostic * provided that the above copyright notice and this paragraph are 734855Sbostic * duplicated in all such forms and that any documentation, 834855Sbostic * advertising materials, and other materials related to such 934855Sbostic * distribution and use acknowledge that the software was developed 1034855Sbostic * by the University of California, Berkeley. The name of the 1134855Sbostic * University may not be used to endorse or promote products derived 1234855Sbostic * from this software without specific prior written permission. 1334855Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434855Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534855Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632789Sbostic * 17*42184Skarels * @(#)udp_usrreq.c 7.14 (Berkeley) 05/17/90 1823199Smckusick */ 194784Swnj 2017065Sbloom #include "param.h" 2117065Sbloom #include "user.h" 2235794Skarels #include "malloc.h" 2317065Sbloom #include "mbuf.h" 2417065Sbloom #include "protosw.h" 2517065Sbloom #include "socket.h" 2617065Sbloom #include "socketvar.h" 2717065Sbloom #include "errno.h" 2817065Sbloom #include "stat.h" 2910897Ssam 306584Ssam #include "../net/if.h" 316354Ssam #include "../net/route.h" 3210897Ssam 3317065Sbloom #include "in.h" 3417065Sbloom #include "in_systm.h" 3517065Sbloom #include "ip.h" 3640688Skarels #include "in_pcb.h" 3717065Sbloom #include "ip_var.h" 3817065Sbloom #include "ip_icmp.h" 3917065Sbloom #include "udp.h" 4017065Sbloom #include "udp_var.h" 414784Swnj 424926Swnj /* 434926Swnj * UDP protocol implementation. 444926Swnj * Per RFC 768, August, 1980. 454926Swnj */ 464805Swnj udp_init() 474805Swnj { 484805Swnj 494901Swnj udb.inp_next = udb.inp_prev = &udb; 504805Swnj } 514805Swnj 5226118Skarels #ifndef COMPAT_42 5319519Skarels int udpcksum = 1; 5426118Skarels #else 5526118Skarels int udpcksum = 0; /* XXX */ 5626118Skarels #endif 5731398Skarels int udp_ttl = UDP_TTL; 5826118Skarels 5937324Skarels struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 604901Swnj 6135794Skarels udp_input(m, iphlen) 6235794Skarels register struct mbuf *m; 6335794Skarels int iphlen; 644784Swnj { 6540688Skarels register struct ip *ip; 6640688Skarels register struct udphdr *uh; 674887Swnj register struct inpcb *inp; 687844Sroot int len; 6940688Skarels struct ip save_ip; 704784Swnj 7140688Skarels #ifndef notyet 7240688Skarels if (iphlen > sizeof (struct ip)) 7340688Skarels ip_stripoptions(m, (struct mbuf *)0); 7440688Skarels #endif 754926Swnj /* 765246Sroot * Get IP and UDP header together in first mbuf. 774926Swnj */ 7840688Skarels ip = mtod(m, struct ip *); 7940688Skarels if (m->m_len < iphlen + sizeof(struct udphdr)) { 8040688Skarels if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 8135288Skarels udpstat.udps_hdrops++; 8235288Skarels return; 8335288Skarels } 8440688Skarels ip = mtod(m, struct ip *); 8535288Skarels } 8640688Skarels uh = (struct udphdr *)((caddr_t)ip + iphlen); 874926Swnj 884926Swnj /* 895246Sroot * Make mbuf data length reflect UDP length. 905246Sroot * If not enough data to reflect UDP length, drop. 914926Swnj */ 9240688Skarels len = ntohs((u_short)uh->uh_ulen); 9340688Skarels if (ip->ip_len != len) { 9440688Skarels if (len > ip->ip_len) { 954926Swnj udpstat.udps_badlen++; 964926Swnj goto bad; 974926Swnj } 9840688Skarels m_adj(m, len - ip->ip_len); 9940688Skarels /* ip->ip_len = len; */ 1004926Swnj } 10124823Skarels /* 10240688Skarels * Save a copy of the IP header in case we want restore it 10340688Skarels * for sending an ICMP error message in response. 10424823Skarels */ 10540688Skarels save_ip = *ip; 1064926Swnj 1074926Swnj /* 1085246Sroot * Checksum extended UDP header and data. 1094926Swnj */ 11040688Skarels if (udpcksum && uh->uh_sum) { 11140688Skarels ((struct ipovly *)ip)->ih_next = 0; 11240688Skarels ((struct ipovly *)ip)->ih_prev = 0; 11340688Skarels ((struct ipovly *)ip)->ih_x1 = 0; 11440688Skarels ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 11540688Skarels if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 1164926Swnj udpstat.udps_badsum++; 1174901Swnj m_freem(m); 1184901Swnj return; 1194901Swnj } 1204901Swnj } 1214926Swnj 1224926Swnj /* 1237844Sroot * Locate pcb for datagram. 1244926Swnj */ 1254926Swnj inp = in_pcblookup(&udb, 12640688Skarels ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, 12740688Skarels INPLOOKUP_WILDCARD); 1286584Ssam if (inp == 0) { 12910144Ssam /* don't send ICMP response for broadcast packet */ 13040688Skarels udpstat.udps_noport++; 13135794Skarels if (m->m_flags & M_BCAST) 1326584Ssam goto bad; 13340688Skarels *ip = save_ip; 13435794Skarels icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); 1356584Ssam return; 1366584Ssam } 1376584Ssam 1384926Swnj /* 1394926Swnj * Construct sockaddr format source address. 1404926Swnj * Stuff source address and datagram in user buffer. 1414926Swnj */ 14240688Skarels udp_in.sin_port = uh->uh_sport; 14340688Skarels udp_in.sin_addr = ip->ip_src; 14440688Skarels iphlen = sizeof(struct ip); 14540688Skarels iphlen += sizeof(struct udphdr); 14640688Skarels m->m_len -= iphlen; 14740688Skarels m->m_pkthdr.len -= iphlen; 14840688Skarels m->m_data += iphlen; 14912767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 15012767Ssam m, (struct mbuf *)0) == 0) 1514926Swnj goto bad; 15240688Skarels udpstat.udps_ipackets++; 1535050Swnj sorwakeup(inp->inp_socket); 1544887Swnj return; 1554926Swnj bad: 1564887Swnj m_freem(m); 1574784Swnj } 1584784Swnj 15926426Skarels /* 16026426Skarels * Notify a udp user of an asynchronous error; 16126426Skarels * just wake up so that he can collect error status. 16226426Skarels */ 16326426Skarels udp_notify(inp) 16426426Skarels register struct inpcb *inp; 16526426Skarels { 16626426Skarels 16726426Skarels sorwakeup(inp->inp_socket); 16826426Skarels sowwakeup(inp->inp_socket); 16926426Skarels } 17026426Skarels 17140688Skarels udp_ctlinput(cmd, sa, ip) 1726591Ssam int cmd; 17324823Skarels struct sockaddr *sa; 17440688Skarels register struct ip *ip; 1756591Ssam { 17640688Skarels register struct udphdr *uh; 17740688Skarels extern struct in_addr zeroin_addr; 1786591Ssam extern u_char inetctlerrmap[]; 1796591Ssam 18040688Skarels if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 1816591Ssam return; 18240688Skarels if (ip) { 18340688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 18440688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 18540688Skarels cmd, udp_notify); 18640688Skarels } else 18740688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 1886591Ssam } 1896591Ssam 190*42184Skarels udp_output(inp, m, addr, control) 19126060Skarels register struct inpcb *inp; 19235794Skarels register struct mbuf *m; 193*42184Skarels struct mbuf *addr, *control; 1944784Swnj { 1954926Swnj register struct udpiphdr *ui; 19635794Skarels register int len = m->m_pkthdr.len; 197*42184Skarels struct in_addr laddr; 198*42184Skarels int s, error = 0; 1994784Swnj 200*42184Skarels if (control) 201*42184Skarels m_freem(control); /* XXX */ 202*42184Skarels 203*42184Skarels if (addr) { 204*42184Skarels laddr = inp->inp_laddr; 205*42184Skarels if (inp->inp_faddr.s_addr != INADDR_ANY) { 206*42184Skarels error = EISCONN; 207*42184Skarels goto release; 208*42184Skarels } 209*42184Skarels /* 210*42184Skarels * Must block input while temporarily connected. 211*42184Skarels */ 212*42184Skarels s = splnet(); 213*42184Skarels error = in_pcbconnect(inp, addr); 214*42184Skarels if (error) { 215*42184Skarels splx(s); 216*42184Skarels goto release; 217*42184Skarels } 218*42184Skarels } else { 219*42184Skarels if (inp->inp_faddr.s_addr == INADDR_ANY) { 220*42184Skarels error = ENOTCONN; 221*42184Skarels goto release; 222*42184Skarels } 223*42184Skarels } 2244926Swnj /* 2254926Swnj * Calculate data length and get a mbuf 2265246Sroot * for UDP and IP headers. 2274926Swnj */ 22835794Skarels M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); 2294784Swnj 2304926Swnj /* 2315246Sroot * Fill in mbuf with extended UDP header 2324926Swnj * and addresses and length put into network format. 2334926Swnj */ 2344926Swnj ui = mtod(m, struct udpiphdr *); 2354926Swnj ui->ui_next = ui->ui_prev = 0; 2364926Swnj ui->ui_x1 = 0; 2374926Swnj ui->ui_pr = IPPROTO_UDP; 23815226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2395050Swnj ui->ui_src = inp->inp_laddr; 2405050Swnj ui->ui_dst = inp->inp_faddr; 2415050Swnj ui->ui_sport = inp->inp_lport; 2425050Swnj ui->ui_dport = inp->inp_fport; 24315226Ssam ui->ui_ulen = ui->ui_len; 2444784Swnj 2454926Swnj /* 2464926Swnj * Stuff checksum and output datagram. 2474926Swnj */ 2484926Swnj ui->ui_sum = 0; 24919519Skarels if (udpcksum) { 25019519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 25133715Skarels ui->ui_sum = 0xffff; 25221112Skarels } 2535050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 25431398Skarels ((struct ip *)ui)->ip_ttl = udp_ttl; 25540688Skarels udpstat.udps_opackets++; 256*42184Skarels error = ip_output(m, inp->inp_options, &inp->inp_route, 257*42184Skarels inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)); 258*42184Skarels 259*42184Skarels if (addr) { 260*42184Skarels in_pcbdisconnect(inp); 261*42184Skarels inp->inp_laddr = laddr; 262*42184Skarels splx(s); 263*42184Skarels } 264*42184Skarels return (error); 265*42184Skarels 266*42184Skarels release: 267*42184Skarels m_freem(m); 268*42184Skarels return (error); 2694784Swnj } 2704784Swnj 27138354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 27238354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 27338354Smckusick /* 40 1K datagrams */ 27418368Skarels 2758602Sroot /*ARGSUSED*/ 276*42184Skarels udp_usrreq(so, req, m, addr, control) 2774887Swnj struct socket *so; 2784784Swnj int req; 279*42184Skarels struct mbuf *m, *addr, *control; 2804784Swnj { 2814887Swnj struct inpcb *inp = sotoinpcb(so); 2826507Ssam int error = 0; 2834784Swnj 28418368Skarels if (req == PRU_CONTROL) 285*42184Skarels return (in_control(so, (int)m, (caddr_t)addr, 28640688Skarels (struct ifnet *)control)); 28711080Ssam if (inp == NULL && req != PRU_ATTACH) { 28811080Ssam error = EINVAL; 28911080Ssam goto release; 29011080Ssam } 2914784Swnj switch (req) { 2924784Swnj 2934784Swnj case PRU_ATTACH: 29411080Ssam if (inp != NULL) { 29511080Ssam error = EINVAL; 29611080Ssam break; 29711080Ssam } 2988273Sroot error = in_pcballoc(so, &udb); 2998273Sroot if (error) 3008273Sroot break; 30118368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 3028273Sroot if (error) 3038273Sroot break; 3044887Swnj break; 3054784Swnj 3064784Swnj case PRU_DETACH: 3075166Swnj in_pcbdetach(inp); 3084887Swnj break; 3094784Swnj 3108273Sroot case PRU_BIND: 311*42184Skarels error = in_pcbbind(inp, addr); 3128273Sroot break; 3138273Sroot 3148273Sroot case PRU_LISTEN: 3158273Sroot error = EOPNOTSUPP; 3168273Sroot break; 3178273Sroot 3184784Swnj case PRU_CONNECT: 31911080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 32011080Ssam error = EISCONN; 32111080Ssam break; 32211080Ssam } 323*42184Skarels error = in_pcbconnect(inp, addr); 3246507Ssam if (error == 0) 3256507Ssam soisconnected(so); 3264887Swnj break; 3274784Swnj 32813118Ssam case PRU_CONNECT2: 32913118Ssam error = EOPNOTSUPP; 33013118Ssam break; 33113118Ssam 3324926Swnj case PRU_ACCEPT: 33311080Ssam error = EOPNOTSUPP; 33411080Ssam break; 3354926Swnj 3364784Swnj case PRU_DISCONNECT: 33711080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 33811080Ssam error = ENOTCONN; 33911080Ssam break; 34011080Ssam } 3415166Swnj in_pcbdisconnect(inp); 34240688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 34326404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 3444784Swnj break; 3454784Swnj 3464912Swnj case PRU_SHUTDOWN: 3474912Swnj socantsendmore(so); 3484912Swnj break; 3494912Swnj 350*42184Skarels case PRU_SEND: 351*42184Skarels error = udp_output(inp, m, addr, control); 35211080Ssam m = NULL; 353*42184Skarels control = NULL; 3544784Swnj break; 3554784Swnj 3564784Swnj case PRU_ABORT: 35731750Skarels soisdisconnected(so); 3585166Swnj in_pcbdetach(inp); 3594784Swnj break; 3604784Swnj 3616511Ssam case PRU_SOCKADDR: 362*42184Skarels in_setsockaddr(inp, addr); 3636511Ssam break; 3646511Ssam 36514124Ssam case PRU_PEERADDR: 366*42184Skarels in_setpeeraddr(inp, addr); 36714124Ssam break; 36814124Ssam 36916988Skarels case PRU_SENSE: 37016988Skarels /* 37116988Skarels * stat: don't bother with a blocksize. 37216988Skarels */ 37316988Skarels return (0); 37416988Skarels 37512205Ssam case PRU_SENDOOB: 37612205Ssam case PRU_FASTTIMO: 37712205Ssam case PRU_SLOWTIMO: 37812205Ssam case PRU_PROTORCV: 37912205Ssam case PRU_PROTOSEND: 38012205Ssam error = EOPNOTSUPP; 38112205Ssam break; 38213118Ssam 38316799Skarels case PRU_RCVD: 38416799Skarels case PRU_RCVOOB: 38516799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 38616799Skarels 38713118Ssam default: 38813118Ssam panic("udp_usrreq"); 3894805Swnj } 39011080Ssam release: 391*42184Skarels if (control) { 392*42184Skarels printf("udp control data unexpectedly retained\n"); 393*42184Skarels m_freem(control); 394*42184Skarels } 395*42184Skarels if (m) 39611080Ssam m_freem(m); 3976507Ssam return (error); 3984784Swnj } 399