1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * @(#)udp_usrreq.c 7.5.2 (2.11BSD GTE) 1995/10/09 13: */ 14: 15: #include "param.h" 16: #include "user.h" 17: #include "mbuf.h" 18: #include "protosw.h" 19: #include "socket.h" 20: #include "socketvar.h" 21: #include "errno.h" 22: 23: #include "../net/if.h" 24: #include "../net/route.h" 25: 26: #include "domain.h" 27: #include "in.h" 28: #include "in_pcb.h" 29: #include "in_systm.h" 30: #include "ip.h" 31: #include "ip_var.h" 32: #include "ip_icmp.h" 33: #include "udp.h" 34: #include "udp_var.h" 35: 36: struct inpcb *udp_last_inpcb = &udb; 37: 38: /* 39: * UDP protocol implementation. 40: * Per RFC 768, August, 1980. 41: */ 42: udp_init() 43: { 44: 45: udb.inp_next = udb.inp_prev = &udb; 46: } 47: 48: #ifndef COMPAT_42 49: int udpcksum = 1; 50: #else 51: int udpcksum = 0; /* XXX */ 52: #endif 53: 54: struct sockaddr_in udp_in = { AF_INET }; 55: 56: udp_input(m0, ifp) 57: struct mbuf *m0; 58: struct ifnet *ifp; 59: { 60: register struct udpiphdr *ui; 61: register struct inpcb *inp; 62: register struct mbuf *m; 63: int len; 64: struct ip ip; 65: 66: udpstat.udps_ipackets++; 67: 68: /* 69: * Get IP and UDP header together in first mbuf. 70: */ 71: m = m0; 72: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 73: (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 74: udpstat.udps_hdrops++; 75: return; 76: } 77: ui = mtod(m, struct udpiphdr *); 78: if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 79: ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 80: 81: /* 82: * Make mbuf data length reflect UDP length. 83: * If not enough data to reflect UDP length, drop. 84: */ 85: len = ntohs((u_short)ui->ui_ulen); 86: if (((struct ip *)ui)->ip_len != len) { 87: if (len > ((struct ip *)ui)->ip_len) { 88: udpstat.udps_badlen++; 89: goto bad; 90: } 91: m_adj(m, len - ((struct ip *)ui)->ip_len); 92: /* ((struct ip *)ui)->ip_len = len; */ 93: } 94: /* 95: * Save a copy of the IP header in case we want restore it for ICMP. 96: */ 97: ip = *(struct ip*)ui; 98: 99: /* 100: * Checksum extended UDP header and data. 101: */ 102: if (udpcksum && ui->ui_sum) { 103: ui->ui_next = ui->ui_prev = 0; 104: ui->ui_pad = 0; 105: ui->ui_x1 = 0; 106: ui->ui_len = ui->ui_ulen; 107: if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 108: udpstat.udps_badsum++; 109: m_freem(m); 110: return; 111: } 112: } 113: 114: /* 115: * Locate pcb for datagram. 116: */ 117: inp = udp_last_inpcb; 118: if (inp->inp_lport != ui->ui_dport || 119: inp->inp_fport != ui->ui_sport || 120: inp->inp_faddr.s_addr != ui->ui_src.s_addr || 121: inp->inp_laddr.s_addr != ui->ui_dst.s_addr) { 122: inp = in_pcblookup(&udb, ui->ui_src, ui->ui_sport, 123: ui->ui_dst, ui->ui_dport, INPLOOKUP_WILDCARD); 124: if (inp) 125: udp_last_inpcb = inp; 126: udpstat.udpps_pcbcachemiss++; 127: } 128: if (inp == 0) { 129: udpstat.udps_noport++; 130: /* don't send ICMP response for broadcast packet */ 131: if (in_broadcast(ui->ui_dst)) { 132: udpstat.udps_noportbcast++; 133: goto bad; 134: } 135: *(struct ip *)ui = ip; 136: icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 137: ifp); 138: return; 139: } 140: 141: /* 142: * Construct sockaddr format source address. 143: * Stuff source address and datagram in user buffer. 144: */ 145: udp_in.sin_port = ui->ui_sport; 146: udp_in.sin_addr = ui->ui_src; 147: m->m_len -= sizeof (struct udpiphdr); 148: m->m_off += sizeof (struct udpiphdr); 149: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 150: m, (struct mbuf *)0) == 0) { 151: udpstat.udps_fullsock++; 152: goto bad; 153: } 154: sorwakeup(inp->inp_socket); 155: return; 156: bad: 157: m_freem(m); 158: } 159: 160: /* 161: * Notify a udp user of an asynchronous error; 162: * just wake up so that he can collect error status. 163: */ 164: udp_notify(inp, errno) 165: register struct inpcb *inp; 166: int errno; 167: { 168: 169: inp->inp_socket->so_error = errno; 170: sorwakeup(inp->inp_socket); 171: sowwakeup(inp->inp_socket); 172: } 173: 174: udp_ctlinput(cmd, sa, ip) 175: register int cmd; 176: struct sockaddr *sa; 177: register struct ip *ip; 178: { 179: register struct udphdr *uh; 180: extern struct in_addr zeroin_addr; 181: extern u_char inetctlerrmap[]; 182: 183: if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 184: return; 185: if (ip) { 186: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 187: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 188: cmd, udp_notify); 189: } else 190: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 191: } 192: 193: udp_output(inp, m0, addr, control) 194: register struct inpcb *inp; 195: struct mbuf *m0; 196: struct mbuf *addr, *control; 197: { 198: register struct mbuf *m = m0; 199: register struct udpiphdr *ui; 200: register int len = 0; 201: struct in_addr laddr; 202: int s, error = 0; 203: 204: if (addr) { 205: laddr = inp->inp_laddr; 206: if (inp->inp_faddr.s_addr != INADDR_ANY) { 207: error = EISCONN; 208: goto release; 209: } 210: /* 211: * Must block input while temporarily connected. 212: */ 213: s = splnet(); 214: error = in_pcbconnect(inp, addr); 215: if (error) { 216: splx(s); 217: goto release; 218: } 219: } else { 220: if (inp->inp_faddr.s_addr == INADDR_ANY) { 221: error = ENOTCONN; 222: goto release; 223: } 224: } 225: 226: /* 227: * Calculate data length and get a mbuf 228: * for UDP and IP headers. 229: */ 230: for (m = m0; m; m = m->m_next) 231: len += m->m_len; 232: MGET(m, M_WAIT, MT_HEADER); 233: 234: /* 235: * Fill in mbuf with extended UDP header 236: * and addresses and length put into network format. 237: */ 238: m->m_off = MMAXOFF - sizeof (struct udpiphdr); 239: m->m_len = sizeof (struct udpiphdr); 240: m->m_next = m0; 241: ui = mtod(m, struct udpiphdr *); 242: ui->ui_next = ui->ui_prev = 0; 243: ui->ui_pad = 0; 244: ui->ui_x1 = 0; 245: ui->ui_pr = IPPROTO_UDP; 246: ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 247: ui->ui_src = inp->inp_laddr; 248: ui->ui_dst = inp->inp_faddr; 249: ui->ui_sport = inp->inp_lport; 250: ui->ui_dport = inp->inp_fport; 251: ui->ui_ulen = ui->ui_len; 252: 253: /* 254: * Stuff checksum and output datagram. 255: */ 256: ui->ui_sum = 0; 257: if (udpcksum) { 258: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 259: ui->ui_sum = 0xffff; 260: } 261: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 262: ((struct ip *)ui)->ip_ttl = ip_defttl; 263: udpstat.udps_opackets++; 264: error = ip_output(m, inp->inp_options, &inp->inp_route, 265: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)); 266: 267: if (addr) { 268: in_pcbdisconnect(inp); 269: inp->inp_laddr = laddr; 270: splx(s); 271: } 272: return(error); 273: 274: release: 275: m_freem(m); 276: return(error); 277: } 278: 279: int udp_sendspace = 2048; /* really max datagram size */ 280: int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 281: 282: /*ARGSUSED*/ 283: udp_usrreq(so, req, m, nam, rights) 284: struct socket *so; 285: int req; 286: struct mbuf *m, *nam, *rights; 287: { 288: register struct inpcb *inp = sotoinpcb(so); 289: int error = 0; 290: register int s; 291: 292: if (req == PRU_CONTROL) 293: return (in_control(so, (int)m, (caddr_t)nam, 294: (struct ifnet *)rights)); 295: if (rights && rights->m_len) { 296: error = EINVAL; 297: goto release; 298: } 299: if (inp == NULL && req != PRU_ATTACH) { 300: error = EINVAL; 301: goto release; 302: } 303: switch (req) { 304: 305: case PRU_ATTACH: 306: if (inp != NULL) { 307: error = EINVAL; 308: break; 309: } 310: s = splnet(); 311: error = in_pcballoc(so, &udb); 312: splx(s); 313: if (error) 314: break; 315: error = soreserve(so, udp_sendspace, udp_recvspace); 316: if (error) 317: break; 318: break; 319: 320: case PRU_DETACH: 321: udp_detach(inp); 322: break; 323: 324: case PRU_BIND: 325: s = splnet(); 326: error = in_pcbbind(inp, nam); 327: splx(s); 328: break; 329: 330: case PRU_LISTEN: 331: error = EOPNOTSUPP; 332: break; 333: 334: case PRU_CONNECT: 335: if (inp->inp_faddr.s_addr != INADDR_ANY) { 336: error = EISCONN; 337: break; 338: } 339: s = splnet(); 340: error = in_pcbconnect(inp, nam); 341: splx(s); 342: if (error == 0) 343: soisconnected(so); 344: break; 345: 346: case PRU_CONNECT2: 347: error = EOPNOTSUPP; 348: break; 349: 350: case PRU_ACCEPT: 351: error = EOPNOTSUPP; 352: break; 353: 354: case PRU_DISCONNECT: 355: if (inp->inp_faddr.s_addr == INADDR_ANY) { 356: error = ENOTCONN; 357: break; 358: } 359: s = splnet(); 360: in_pcbdisconnect(inp); 361: inp->inp_laddr.s_addr = INADDR_ANY; 362: splx(s); 363: so->so_state &= ~SS_ISCONNECTED; /* XXX */ 364: break; 365: 366: case PRU_SHUTDOWN: 367: socantsendmore(so); 368: break; 369: 370: case PRU_SEND: 371: return(udp_output(inp, m, nam, rights)); 372: 373: case PRU_ABORT: 374: soisdisconnected(so); 375: udp_detach(inp); 376: break; 377: 378: case PRU_SOCKADDR: 379: in_setsockaddr(inp, nam); 380: break; 381: 382: case PRU_PEERADDR: 383: in_setpeeraddr(inp, nam); 384: break; 385: 386: case PRU_SENSE: 387: /* 388: * stat: don't bother with a blocksize. 389: */ 390: return (0); 391: 392: case PRU_SENDOOB: 393: case PRU_FASTTIMO: 394: case PRU_SLOWTIMO: 395: case PRU_PROTORCV: 396: case PRU_PROTOSEND: 397: error = EOPNOTSUPP; 398: break; 399: 400: case PRU_RCVD: 401: case PRU_RCVOOB: 402: return (EOPNOTSUPP); /* do not free mbuf's */ 403: 404: default: 405: panic("udp_usrreq"); 406: } 407: release: 408: if (m != NULL) 409: m_freem(m); 410: return (error); 411: } 412: 413: udp_detach(inp) 414: register struct inpcb *inp; 415: { 416: register int s = splnet(); 417: 418: if (inp == udp_last_inpcb) 419: udp_last_inpcb = &udb; 420: in_pcbdetach(inp); 421: splx(s); 422: } 423: 424: /* 425: * Sysctl for udp variables. 426: */ 427: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 428: int *name; 429: u_int namelen; 430: void *oldp; 431: size_t *oldlenp; 432: void *newp; 433: size_t newlen; 434: { 435: /* All sysctl names at this level are terminal. */ 436: if (namelen != 1) 437: return (ENOTDIR); 438: 439: switch (name[0]) { 440: case UDPCTL_CHECKSUM: 441: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 442: default: 443: return (ENOPROTOOPT); 444: } 445: /* NOTREACHED */ 446: }