1*5094Swnj /* udp_usrreq.c 4.11 81/11/26 */ 24784Swnj 34784Swnj #include "../h/param.h" 44887Swnj #include "../h/dir.h" 54887Swnj #include "../h/user.h" 64784Swnj #include "../h/mbuf.h" 74805Swnj #include "../h/protosw.h" 84887Swnj #include "../h/socket.h" 94887Swnj #include "../h/socketvar.h" 10*5094Swnj #include "../net/in.h" 11*5094Swnj #include "../net/in_pcb.h" 12*5094Swnj #include "../net/in_systm.h" 134901Swnj #include "../net/ip.h" 144901Swnj #include "../net/ip_var.h" 154887Swnj #include "../net/udp.h" 164887Swnj #include "../net/udp_var.h" 174784Swnj 184926Swnj /* 194926Swnj * UDP protocol implementation. 204926Swnj * Per RFC 768, August, 1980. 214926Swnj */ 224805Swnj udp_init() 234805Swnj { 244805Swnj 25*5094Swnj COUNT(UDP_INIT); 264901Swnj udb.inp_next = udb.inp_prev = &udb; 274805Swnj } 284805Swnj 294901Swnj int udpcksum; 304926Swnj struct sockaddr_in udp_in = { AF_INET }; 314901Swnj 324926Swnj udp_input(m0) 334926Swnj struct mbuf *m0; 344784Swnj { 354901Swnj register struct udpiphdr *ui; 364887Swnj register struct inpcb *inp; 374926Swnj register struct mbuf *m; 384926Swnj int len, ulen; 394784Swnj 40*5094Swnj COUNT(UDP_INPUT); 414926Swnj /* 424926Swnj * Get ip and udp header together in first mbuf. 434926Swnj */ 444926Swnj m = m0; 454926Swnj if (m->m_len < sizeof (struct udpiphdr) && 464926Swnj m_pullup(m, sizeof (struct udpiphdr)) == 0) { 474926Swnj udpstat.udps_hdrops++; 484926Swnj goto bad; 494926Swnj } 505050Swnj ui = mtod(m, struct udpiphdr *); 515050Swnj if (ui->ui_len > sizeof (struct ip)) 525050Swnj ip_stripoptions((struct ip *)ui, (char *)0); 534926Swnj 544926Swnj /* 554926Swnj * Make mbuf data length reflect udp length. 564926Swnj * If not enough data to reflect udp length, drop. 574926Swnj */ 584955Swnj ulen = ntohs((u_short)ui->ui_ulen); 594926Swnj len = sizeof (struct udpiphdr) + ulen; 604926Swnj if (((struct ip *)ui)->ip_len != len) { 614926Swnj if (len > ((struct ip *)ui)->ip_len) { 624926Swnj udpstat.udps_badlen++; 634926Swnj goto bad; 644926Swnj } 654926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 664926Swnj /* (struct ip *)ui->ip_len = len; */ 674926Swnj } 684926Swnj 694926Swnj /* 704926Swnj * Checksum extended udp header and data. 714926Swnj */ 724901Swnj if (udpcksum) { 734926Swnj ui->ui_next = ui->ui_prev = 0; 744926Swnj ui->ui_x1 = 0; 754955Swnj ui->ui_len = htons((u_short)(sizeof (struct udpiphdr) + ulen)); 76*5094Swnj if ((ui->ui_sum = in_cksum(m, len)) != 0xffff) { 774926Swnj udpstat.udps_badsum++; 784901Swnj printf("udp cksum %x\n", ui->ui_sum); 794901Swnj m_freem(m); 804901Swnj return; 814901Swnj } 824901Swnj } 834926Swnj 844926Swnj /* 854926Swnj * Convert addresses and ports to host format. 864926Swnj * Locate pcb for datagram. 874926Swnj */ 884926Swnj inp = in_pcblookup(&udb, 894926Swnj ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport); 905051Swnj if (inp == 0) 914926Swnj goto bad; 924926Swnj 934926Swnj /* 944926Swnj * Construct sockaddr format source address. 954926Swnj * Stuff source address and datagram in user buffer. 964926Swnj */ 974926Swnj udp_in.sin_port = ui->ui_sport; 984926Swnj udp_in.sin_addr = ui->ui_src; 995050Swnj m->m_len -= sizeof (struct udpiphdr); 1005050Swnj m->m_off += sizeof (struct udpiphdr); 1015050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1024926Swnj goto bad; 1035050Swnj sorwakeup(inp->inp_socket); 1044887Swnj return; 1054926Swnj bad: 1064887Swnj m_freem(m); 1074784Swnj } 1084784Swnj 1094887Swnj udp_ctlinput(m) 1104887Swnj struct mbuf *m; 1114887Swnj { 1124887Swnj 113*5094Swnj COUNT(UDP_CTLINPUT); 1145050Swnj printf("udp_ctlinput\n"); 1154887Swnj m_freem(m); 1164887Swnj } 1174887Swnj 1184926Swnj /*ARGSUSED*/ 1194955Swnj udp_output(inp, m0) 1204926Swnj struct inpcb *inp; 1214926Swnj struct mbuf *m0; 1224784Swnj { 1234926Swnj register struct mbuf *m; 1244926Swnj register struct udpiphdr *ui; 1254926Swnj register int len = 0; 1264784Swnj 127*5094Swnj COUNT(UDP_OUTPUT); 1284926Swnj /* 1294926Swnj * Calculate data length and get a mbuf 1304926Swnj * for udp and ip headers. 1314926Swnj */ 1324926Swnj for (m = m0; m; m = m->m_next) 1334926Swnj len += m->m_len; 1344926Swnj m = m_get(0); 1355051Swnj if (m == 0) 1364926Swnj goto bad; 1374784Swnj 1384926Swnj /* 1394926Swnj * Fill in mbuf with extended udp header 1404926Swnj * and addresses and length put into network format. 1414926Swnj */ 1424926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1434926Swnj m->m_len = sizeof (struct udpiphdr); 1444926Swnj m->m_next = m0; 1454926Swnj ui = mtod(m, struct udpiphdr *); 1464926Swnj ui->ui_next = ui->ui_prev = 0; 1474926Swnj ui->ui_x1 = 0; 1484926Swnj ui->ui_pr = IPPROTO_UDP; 1495050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1505050Swnj ui->ui_src = inp->inp_laddr; 1515050Swnj ui->ui_dst = inp->inp_faddr; 1525050Swnj ui->ui_sport = inp->inp_lport; 1535050Swnj ui->ui_dport = inp->inp_fport; 1544955Swnj ui->ui_ulen = htons((u_short)len); 1554784Swnj 1564926Swnj /* 1574926Swnj * Stuff checksum and output datagram. 1584926Swnj */ 1594926Swnj ui->ui_sum = 0; 160*5094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1615050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1625050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 163*5094Swnj ip_output(m, (struct mbuf *)0); 1644926Swnj return; 1654926Swnj bad: 1664926Swnj m_freem(m); 1674784Swnj } 1684784Swnj 1694912Swnj /*ARGSUSED*/ 1704887Swnj udp_usrreq(so, req, m, addr) 1714887Swnj struct socket *so; 1724784Swnj int req; 1734784Swnj struct mbuf *m; 1744912Swnj caddr_t addr; 1754784Swnj { 1764887Swnj struct inpcb *inp = sotoinpcb(so); 1774887Swnj int error; 1784784Swnj 179*5094Swnj COUNT(UDP_USRREQ); 1805051Swnj if (inp == 0 && req != PRU_ATTACH) 1815050Swnj return (EINVAL); 1824784Swnj switch (req) { 1834784Swnj 1844784Swnj case PRU_ATTACH: 1854887Swnj if (inp != 0) 1864887Swnj return (EINVAL); 1874955Swnj error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1885051Swnj if (error) 1894955Swnj return (error); 1904887Swnj break; 1914784Swnj 1924784Swnj case PRU_DETACH: 1934887Swnj if (inp == 0) 1944887Swnj return (ENOTCONN); 1954912Swnj in_pcbfree(inp); 1964887Swnj break; 1974784Swnj 1984784Swnj case PRU_CONNECT: 1994955Swnj if (inp->inp_faddr.s_addr) 2004887Swnj return (EISCONN); 2014955Swnj error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 2025051Swnj if (error) 2034887Swnj return (error); 2044887Swnj soisconnected(so); 2054887Swnj break; 2064784Swnj 2074926Swnj case PRU_ACCEPT: 2084926Swnj return (EOPNOTSUPP); 2094926Swnj 2104784Swnj case PRU_DISCONNECT: 2114955Swnj if (inp->inp_faddr.s_addr == 0) 2124887Swnj return (ENOTCONN); 2134955Swnj inp->inp_faddr.s_addr = 0; 2144887Swnj soisdisconnected(so); 2154784Swnj break; 2164784Swnj 2174912Swnj case PRU_SHUTDOWN: 2184912Swnj socantsendmore(so); 2194912Swnj break; 2204912Swnj 2214784Swnj case PRU_SEND: 2224887Swnj if (addr) { 2234955Swnj if (inp->inp_faddr.s_addr) 2244887Swnj return (EISCONN); 2254955Swnj error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 2265051Swnj if (error) 2274955Swnj return (error); 2284955Swnj } else { 2294955Swnj if (inp->inp_faddr.s_addr == 0) 2304955Swnj return (ENOTCONN); 2314955Swnj } 2324955Swnj udp_output(inp, m); 2334955Swnj if (addr) 2344955Swnj inp->inp_faddr.s_addr = 0; 2354784Swnj break; 2364784Swnj 2374784Swnj case PRU_ABORT: 2384887Swnj in_pcbfree(inp); 2394887Swnj sofree(so); 2404887Swnj soisdisconnected(so); 2414784Swnj break; 2424784Swnj 2434784Swnj case PRU_CONTROL: 2444887Swnj return (EOPNOTSUPP); 2454784Swnj 2464784Swnj default: 2474784Swnj panic("udp_usrreq"); 2484805Swnj } 2494887Swnj return (0); 2504784Swnj } 2514805Swnj 2524955Swnj /*ARGSUSED*/ 2534926Swnj udp_sense(m) 2544926Swnj struct mbuf *m; 2554805Swnj { 2564955Swnj 257*5094Swnj COUNT(UDP_SENSE); 2585050Swnj printf("udp_sense\n"); 2594926Swnj return (EOPNOTSUPP); 2604805Swnj } 261