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*40688Skarels * @(#)udp_usrreq.c 7.13 (Berkeley) 04/03/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" 36*40688Skarels #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 { 65*40688Skarels register struct ip *ip; 66*40688Skarels register struct udphdr *uh; 674887Swnj register struct inpcb *inp; 687844Sroot int len; 69*40688Skarels struct ip save_ip; 704784Swnj 71*40688Skarels #ifndef notyet 72*40688Skarels if (iphlen > sizeof (struct ip)) 73*40688Skarels ip_stripoptions(m, (struct mbuf *)0); 74*40688Skarels #endif 754926Swnj /* 765246Sroot * Get IP and UDP header together in first mbuf. 774926Swnj */ 78*40688Skarels ip = mtod(m, struct ip *); 79*40688Skarels if (m->m_len < iphlen + sizeof(struct udphdr)) { 80*40688Skarels if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 8135288Skarels udpstat.udps_hdrops++; 8235288Skarels return; 8335288Skarels } 84*40688Skarels ip = mtod(m, struct ip *); 8535288Skarels } 86*40688Skarels 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 */ 92*40688Skarels len = ntohs((u_short)uh->uh_ulen); 93*40688Skarels if (ip->ip_len != len) { 94*40688Skarels if (len > ip->ip_len) { 954926Swnj udpstat.udps_badlen++; 964926Swnj goto bad; 974926Swnj } 98*40688Skarels m_adj(m, len - ip->ip_len); 99*40688Skarels /* ip->ip_len = len; */ 1004926Swnj } 10124823Skarels /* 102*40688Skarels * Save a copy of the IP header in case we want restore it 103*40688Skarels * for sending an ICMP error message in response. 10424823Skarels */ 105*40688Skarels save_ip = *ip; 1064926Swnj 1074926Swnj /* 1085246Sroot * Checksum extended UDP header and data. 1094926Swnj */ 110*40688Skarels if (udpcksum && uh->uh_sum) { 111*40688Skarels ((struct ipovly *)ip)->ih_next = 0; 112*40688Skarels ((struct ipovly *)ip)->ih_prev = 0; 113*40688Skarels ((struct ipovly *)ip)->ih_x1 = 0; 114*40688Skarels ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 115*40688Skarels 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, 126*40688Skarels ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, 127*40688Skarels INPLOOKUP_WILDCARD); 1286584Ssam if (inp == 0) { 12910144Ssam /* don't send ICMP response for broadcast packet */ 130*40688Skarels udpstat.udps_noport++; 13135794Skarels if (m->m_flags & M_BCAST) 1326584Ssam goto bad; 133*40688Skarels *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 */ 142*40688Skarels udp_in.sin_port = uh->uh_sport; 143*40688Skarels udp_in.sin_addr = ip->ip_src; 144*40688Skarels iphlen = sizeof(struct ip); 145*40688Skarels iphlen += sizeof(struct udphdr); 146*40688Skarels m->m_len -= iphlen; 147*40688Skarels m->m_pkthdr.len -= iphlen; 148*40688Skarels 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; 152*40688Skarels 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 171*40688Skarels udp_ctlinput(cmd, sa, ip) 1726591Ssam int cmd; 17324823Skarels struct sockaddr *sa; 174*40688Skarels register struct ip *ip; 1756591Ssam { 176*40688Skarels register struct udphdr *uh; 177*40688Skarels extern struct in_addr zeroin_addr; 1786591Ssam extern u_char inetctlerrmap[]; 1796591Ssam 180*40688Skarels if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 1816591Ssam return; 182*40688Skarels if (ip) { 183*40688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 184*40688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 185*40688Skarels cmd, udp_notify); 186*40688Skarels } else 187*40688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 1886591Ssam } 1896591Ssam 19035794Skarels udp_output(inp, m) 19126060Skarels register struct inpcb *inp; 19235794Skarels register struct mbuf *m; 1934784Swnj { 1944926Swnj register struct udpiphdr *ui; 19535794Skarels register int len = m->m_pkthdr.len; 1964784Swnj 1974926Swnj /* 1984926Swnj * Calculate data length and get a mbuf 1995246Sroot * for UDP and IP headers. 2004926Swnj */ 20135794Skarels M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); 2024784Swnj 2034926Swnj /* 2045246Sroot * Fill in mbuf with extended UDP header 2054926Swnj * and addresses and length put into network format. 2064926Swnj */ 2074926Swnj ui = mtod(m, struct udpiphdr *); 2084926Swnj ui->ui_next = ui->ui_prev = 0; 2094926Swnj ui->ui_x1 = 0; 2104926Swnj ui->ui_pr = IPPROTO_UDP; 21115226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2125050Swnj ui->ui_src = inp->inp_laddr; 2135050Swnj ui->ui_dst = inp->inp_faddr; 2145050Swnj ui->ui_sport = inp->inp_lport; 2155050Swnj ui->ui_dport = inp->inp_fport; 21615226Ssam ui->ui_ulen = ui->ui_len; 2174784Swnj 2184926Swnj /* 2194926Swnj * Stuff checksum and output datagram. 2204926Swnj */ 2214926Swnj ui->ui_sum = 0; 22219519Skarels if (udpcksum) { 22319519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 22433715Skarels ui->ui_sum = 0xffff; 22521112Skarels } 2265050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 22731398Skarels ((struct ip *)ui)->ip_ttl = udp_ttl; 228*40688Skarels udpstat.udps_opackets++; 22926060Skarels return (ip_output(m, inp->inp_options, &inp->inp_route, 23026060Skarels inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 2314784Swnj } 2324784Swnj 23338354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 23438354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 23538354Smckusick /* 40 1K datagrams */ 23618368Skarels 2378602Sroot /*ARGSUSED*/ 238*40688Skarels udp_usrreq(so, req, m, nam, control) 2394887Swnj struct socket *so; 2404784Swnj int req; 241*40688Skarels struct mbuf *m, *nam, *control; 2424784Swnj { 2434887Swnj struct inpcb *inp = sotoinpcb(so); 2446507Ssam int error = 0; 2454784Swnj 24618368Skarels if (req == PRU_CONTROL) 24718368Skarels return (in_control(so, (int)m, (caddr_t)nam, 248*40688Skarels (struct ifnet *)control)); 24911080Ssam if (inp == NULL && req != PRU_ATTACH) { 25011080Ssam error = EINVAL; 25111080Ssam goto release; 25211080Ssam } 2534784Swnj switch (req) { 2544784Swnj 2554784Swnj case PRU_ATTACH: 25611080Ssam if (inp != NULL) { 25711080Ssam error = EINVAL; 25811080Ssam break; 25911080Ssam } 2608273Sroot error = in_pcballoc(so, &udb); 2618273Sroot if (error) 2628273Sroot break; 26318368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2648273Sroot if (error) 2658273Sroot break; 2664887Swnj break; 2674784Swnj 2684784Swnj case PRU_DETACH: 2695166Swnj in_pcbdetach(inp); 2704887Swnj break; 2714784Swnj 2728273Sroot case PRU_BIND: 2738273Sroot error = in_pcbbind(inp, nam); 2748273Sroot break; 2758273Sroot 2768273Sroot case PRU_LISTEN: 2778273Sroot error = EOPNOTSUPP; 2788273Sroot break; 2798273Sroot 2804784Swnj case PRU_CONNECT: 28111080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 28211080Ssam error = EISCONN; 28311080Ssam break; 28411080Ssam } 2858273Sroot error = in_pcbconnect(inp, nam); 2866507Ssam if (error == 0) 2876507Ssam soisconnected(so); 2884887Swnj break; 2894784Swnj 29013118Ssam case PRU_CONNECT2: 29113118Ssam error = EOPNOTSUPP; 29213118Ssam break; 29313118Ssam 2944926Swnj case PRU_ACCEPT: 29511080Ssam error = EOPNOTSUPP; 29611080Ssam break; 2974926Swnj 2984784Swnj case PRU_DISCONNECT: 29911080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 30011080Ssam error = ENOTCONN; 30111080Ssam break; 30211080Ssam } 3035166Swnj in_pcbdisconnect(inp); 304*40688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 30526404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 3064784Swnj break; 3074784Swnj 3084912Swnj case PRU_SHUTDOWN: 3094912Swnj socantsendmore(so); 3104912Swnj break; 3114912Swnj 3125996Swnj case PRU_SEND: { 3135996Swnj struct in_addr laddr; 31416799Skarels int s; 3155996Swnj 3168273Sroot if (nam) { 3175996Swnj laddr = inp->inp_laddr; 31811080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 31911080Ssam error = EISCONN; 32011080Ssam break; 32111080Ssam } 32216799Skarels /* 32316799Skarels * Must block input while temporarily connected. 32416799Skarels */ 32516799Skarels s = splnet(); 3268273Sroot error = in_pcbconnect(inp, nam); 32716799Skarels if (error) { 32816799Skarels splx(s); 3296507Ssam break; 33016799Skarels } 3314955Swnj } else { 33211080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 33311080Ssam error = ENOTCONN; 33411080Ssam break; 33511080Ssam } 3364955Swnj } 3376507Ssam error = udp_output(inp, m); 33811080Ssam m = NULL; 3398273Sroot if (nam) { 3405166Swnj in_pcbdisconnect(inp); 34118368Skarels inp->inp_laddr = laddr; 34216799Skarels splx(s); 3435996Swnj } 3445996Swnj } 3454784Swnj break; 3464784Swnj 3474784Swnj case PRU_ABORT: 34831750Skarels soisdisconnected(so); 3495166Swnj in_pcbdetach(inp); 3504784Swnj break; 3514784Swnj 3526511Ssam case PRU_SOCKADDR: 3538273Sroot in_setsockaddr(inp, nam); 3546511Ssam break; 3556511Ssam 35614124Ssam case PRU_PEERADDR: 35714124Ssam in_setpeeraddr(inp, nam); 35814124Ssam break; 35914124Ssam 36016988Skarels case PRU_SENSE: 36116988Skarels /* 36216988Skarels * stat: don't bother with a blocksize. 36316988Skarels */ 36416988Skarels return (0); 36516988Skarels 36612205Ssam case PRU_SENDOOB: 36712205Ssam case PRU_FASTTIMO: 36812205Ssam case PRU_SLOWTIMO: 36912205Ssam case PRU_PROTORCV: 37012205Ssam case PRU_PROTOSEND: 37112205Ssam error = EOPNOTSUPP; 37212205Ssam break; 37313118Ssam 37416799Skarels case PRU_RCVD: 37516799Skarels case PRU_RCVOOB: 37616799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 37716799Skarels 37813118Ssam default: 37913118Ssam panic("udp_usrreq"); 3804805Swnj } 38111080Ssam release: 38211080Ssam if (m != NULL) 38311080Ssam m_freem(m); 3846507Ssam return (error); 3854784Swnj } 386