|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "malloc.h" ! 38: #include "mbuf.h" ! 39: #include "protosw.h" ! 40: #include "socket.h" ! 41: #include "socketvar.h" ! 42: #include "stat.h" ! 43: ! 44: #include "../net/if.h" ! 45: #include "../net/route.h" ! 46: ! 47: #include "in.h" ! 48: #include "in_systm.h" ! 49: #include "ip.h" ! 50: #include "in_pcb.h" ! 51: #include "ip_var.h" ! 52: #include "ip_icmp.h" ! 53: #include "udp.h" ! 54: #include "udp_var.h" ! 55: ! 56: struct inpcb *udp_last_inpcb = &udb; ! 57: ! 58: /* ! 59: * UDP protocol implementation. ! 60: * Per RFC 768, August, 1980. ! 61: */ ! 62: udp_init() ! 63: { ! 64: ! 65: udb.inp_next = udb.inp_prev = &udb; ! 66: } ! 67: ! 68: #ifndef COMPAT_42 ! 69: int udpcksum = 1; ! 70: #else ! 71: int udpcksum = 0; /* XXX */ ! 72: #endif ! 73: int udp_ttl = UDP_TTL; ! 74: ! 75: struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; ! 76: ! 77: udp_input(m, iphlen) ! 78: register struct mbuf *m; ! 79: int iphlen; ! 80: { ! 81: register struct ip *ip; ! 82: register struct udphdr *uh; ! 83: register struct inpcb *inp; ! 84: struct mbuf *opts = 0; ! 85: int len; ! 86: struct ip save_ip; ! 87: ! 88: udpstat.udps_ipackets++; ! 89: ! 90: /* ! 91: * Strip IP options, if any; should skip this, ! 92: * make available to user, and use on returned packets, ! 93: * but we don't yet have a way to check the checksum ! 94: * with options still present. ! 95: */ ! 96: if (iphlen > sizeof (struct ip)) { ! 97: ip_stripoptions(m, (struct mbuf *)0); ! 98: iphlen = sizeof(struct ip); ! 99: } ! 100: ! 101: /* ! 102: * Get IP and UDP header together in first mbuf. ! 103: */ ! 104: ip = mtod(m, struct ip *); ! 105: if (m->m_len < iphlen + sizeof(struct udphdr)) { ! 106: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { ! 107: udpstat.udps_hdrops++; ! 108: return; ! 109: } ! 110: ip = mtod(m, struct ip *); ! 111: } ! 112: uh = (struct udphdr *)((caddr_t)ip + iphlen); ! 113: ! 114: /* ! 115: * Make mbuf data length reflect UDP length. ! 116: * If not enough data to reflect UDP length, drop. ! 117: */ ! 118: len = ntohs((u_short)uh->uh_ulen); ! 119: if (ip->ip_len != len) { ! 120: if (len > ip->ip_len) { ! 121: udpstat.udps_badlen++; ! 122: goto bad; ! 123: } ! 124: m_adj(m, len - ip->ip_len); ! 125: /* ip->ip_len = len; */ ! 126: } ! 127: /* ! 128: * Save a copy of the IP header in case we want restore it ! 129: * for sending an ICMP error message in response. ! 130: */ ! 131: save_ip = *ip; ! 132: ! 133: /* ! 134: * Checksum extended UDP header and data. ! 135: */ ! 136: if (udpcksum && uh->uh_sum) { ! 137: ((struct ipovly *)ip)->ih_next = 0; ! 138: ((struct ipovly *)ip)->ih_prev = 0; ! 139: ((struct ipovly *)ip)->ih_x1 = 0; ! 140: ((struct ipovly *)ip)->ih_len = uh->uh_ulen; ! 141: if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { ! 142: udpstat.udps_badsum++; ! 143: m_freem(m); ! 144: return; ! 145: } ! 146: } ! 147: ! 148: /* ! 149: * Locate pcb for datagram. ! 150: */ ! 151: inp = udp_last_inpcb; ! 152: if (inp->inp_lport != uh->uh_dport || ! 153: inp->inp_fport != uh->uh_sport || ! 154: inp->inp_faddr.s_addr != ip->ip_src.s_addr || ! 155: inp->inp_laddr.s_addr != ip->ip_dst.s_addr) { ! 156: inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, ! 157: ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); ! 158: if (inp) ! 159: udp_last_inpcb = inp; ! 160: udpstat.udpps_pcbcachemiss++; ! 161: } ! 162: if (inp == 0) { ! 163: /* don't send ICMP response for broadcast packet */ ! 164: udpstat.udps_noport++; ! 165: if (m->m_flags & M_BCAST) { ! 166: udpstat.udps_noportbcast++; ! 167: goto bad; ! 168: } ! 169: *ip = save_ip; ! 170: ip->ip_len += iphlen; ! 171: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); ! 172: return; ! 173: } ! 174: ! 175: /* ! 176: * Construct sockaddr format source address. ! 177: * Stuff source address and datagram in user buffer. ! 178: */ ! 179: udp_in.sin_port = uh->uh_sport; ! 180: udp_in.sin_addr = ip->ip_src; ! 181: if (inp->inp_flags & INP_CONTROLOPTS) { ! 182: struct mbuf **mp = &opts; ! 183: struct mbuf *udp_saveopt(); ! 184: ! 185: if (inp->inp_flags & INP_RECVDSTADDR) { ! 186: *mp = udp_saveopt((caddr_t) &ip->ip_dst, ! 187: sizeof(struct in_addr), IP_RECVDSTADDR); ! 188: if (*mp) ! 189: mp = &(*mp)->m_next; ! 190: } ! 191: #ifdef notyet ! 192: /* options were tossed above */ ! 193: if (inp->inp_flags & INP_RECVOPTS) { ! 194: *mp = udp_saveopt((caddr_t) opts_deleted_above, ! 195: sizeof(struct in_addr), IP_RECVOPTS); ! 196: if (*mp) ! 197: mp = &(*mp)->m_next; ! 198: } ! 199: /* ip_srcroute doesn't do what we want here, need to fix */ ! 200: if (inp->inp_flags & INP_RECVRETOPTS) { ! 201: *mp = udp_saveopt((caddr_t) ip_srcroute(), ! 202: sizeof(struct in_addr), IP_RECVRETOPTS); ! 203: if (*mp) ! 204: mp = &(*mp)->m_next; ! 205: } ! 206: #endif ! 207: } ! 208: iphlen += sizeof(struct udphdr); ! 209: m->m_len -= iphlen; ! 210: m->m_pkthdr.len -= iphlen; ! 211: m->m_data += iphlen; ! 212: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, ! 213: m, opts) == 0) { ! 214: udpstat.udps_fullsock++; ! 215: goto bad; ! 216: } ! 217: sorwakeup(inp->inp_socket); ! 218: return; ! 219: bad: ! 220: m_freem(m); ! 221: if (opts) ! 222: m_freem(opts); ! 223: } ! 224: ! 225: /* ! 226: * Create a "control" mbuf containing the specified data ! 227: * with the specified type for presentation with a datagram. ! 228: */ ! 229: struct mbuf * ! 230: udp_saveopt(p, size, type) ! 231: caddr_t p; ! 232: register int size; ! 233: int type; ! 234: { ! 235: register struct cmsghdr *cp; ! 236: struct mbuf *m; ! 237: ! 238: if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) ! 239: return ((struct mbuf *) NULL); ! 240: cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); ! 241: bcopy(p, (caddr_t)(cp + 1), size); ! 242: size += sizeof(*cp); ! 243: m->m_len = size; ! 244: cp->cmsg_len = size; ! 245: cp->cmsg_level = IPPROTO_IP; ! 246: cp->cmsg_type = type; ! 247: return (m); ! 248: } ! 249: ! 250: /* ! 251: * Notify a udp user of an asynchronous error; ! 252: * just wake up so that he can collect error status. ! 253: */ ! 254: udp_notify(inp, errno) ! 255: register struct inpcb *inp; ! 256: { ! 257: ! 258: inp->inp_socket->so_error = errno; ! 259: sorwakeup(inp->inp_socket); ! 260: sowwakeup(inp->inp_socket); ! 261: } ! 262: ! 263: udp_ctlinput(cmd, sa, ip) ! 264: int cmd; ! 265: struct sockaddr *sa; ! 266: register struct ip *ip; ! 267: { ! 268: register struct udphdr *uh; ! 269: extern struct in_addr zeroin_addr; ! 270: extern u_char inetctlerrmap[]; ! 271: ! 272: if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) ! 273: return; ! 274: if (ip) { ! 275: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ! 276: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, ! 277: cmd, udp_notify); ! 278: } else ! 279: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); ! 280: } ! 281: ! 282: udp_output(inp, m, addr, control) ! 283: register struct inpcb *inp; ! 284: register struct mbuf *m; ! 285: struct mbuf *addr, *control; ! 286: { ! 287: register struct udpiphdr *ui; ! 288: register int len = m->m_pkthdr.len; ! 289: struct in_addr laddr; ! 290: int s, error = 0; ! 291: ! 292: if (control) ! 293: m_freem(control); /* XXX */ ! 294: ! 295: if (addr) { ! 296: laddr = inp->inp_laddr; ! 297: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 298: error = EISCONN; ! 299: goto release; ! 300: } ! 301: /* ! 302: * Must block input while temporarily connected. ! 303: */ ! 304: s = splnet(); ! 305: error = in_pcbconnect(inp, addr); ! 306: if (error) { ! 307: splx(s); ! 308: goto release; ! 309: } ! 310: } else { ! 311: if (inp->inp_faddr.s_addr == INADDR_ANY) { ! 312: error = ENOTCONN; ! 313: goto release; ! 314: } ! 315: } ! 316: /* ! 317: * Calculate data length and get a mbuf ! 318: * for UDP and IP headers. ! 319: */ ! 320: M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); ! 321: ! 322: /* ! 323: * Fill in mbuf with extended UDP header ! 324: * and addresses and length put into network format. ! 325: */ ! 326: ui = mtod(m, struct udpiphdr *); ! 327: ui->ui_next = ui->ui_prev = 0; ! 328: ui->ui_x1 = 0; ! 329: ui->ui_pr = IPPROTO_UDP; ! 330: ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); ! 331: ui->ui_src = inp->inp_laddr; ! 332: ui->ui_dst = inp->inp_faddr; ! 333: ui->ui_sport = inp->inp_lport; ! 334: ui->ui_dport = inp->inp_fport; ! 335: ui->ui_ulen = ui->ui_len; ! 336: ! 337: /* ! 338: * Stuff checksum and output datagram. ! 339: */ ! 340: ui->ui_sum = 0; ! 341: if (udpcksum) { ! 342: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) ! 343: ui->ui_sum = 0xffff; ! 344: } ! 345: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ! 346: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ ! 347: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ ! 348: udpstat.udps_opackets++; ! 349: error = ip_output(m, inp->inp_options, &inp->inp_route, ! 350: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)); ! 351: ! 352: if (addr) { ! 353: in_pcbdisconnect(inp); ! 354: inp->inp_laddr = laddr; ! 355: splx(s); ! 356: } ! 357: return (error); ! 358: ! 359: release: ! 360: m_freem(m); ! 361: return (error); ! 362: } ! 363: ! 364: u_long udp_sendspace = 9216; /* really max datagram size */ ! 365: u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); ! 366: /* 40 1K datagrams */ ! 367: ! 368: /*ARGSUSED*/ ! 369: udp_usrreq(so, req, m, addr, control) ! 370: struct socket *so; ! 371: int req; ! 372: struct mbuf *m, *addr, *control; ! 373: { ! 374: struct inpcb *inp = sotoinpcb(so); ! 375: int error = 0; ! 376: int s; ! 377: ! 378: if (req == PRU_CONTROL) ! 379: return (in_control(so, (int)m, (caddr_t)addr, ! 380: (struct ifnet *)control)); ! 381: if (inp == NULL && req != PRU_ATTACH) { ! 382: error = EINVAL; ! 383: goto release; ! 384: } ! 385: /* ! 386: * Note: need to block udp_input while changing ! 387: * the udp pcb queue and/or pcb addresses. ! 388: */ ! 389: switch (req) { ! 390: ! 391: case PRU_ATTACH: ! 392: if (inp != NULL) { ! 393: error = EINVAL; ! 394: break; ! 395: } ! 396: s = splnet(); ! 397: error = in_pcballoc(so, &udb); ! 398: splx(s); ! 399: if (error) ! 400: break; ! 401: error = soreserve(so, udp_sendspace, udp_recvspace); ! 402: if (error) ! 403: break; ! 404: ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl; ! 405: break; ! 406: ! 407: case PRU_DETACH: ! 408: udp_detach(inp); ! 409: break; ! 410: ! 411: case PRU_BIND: ! 412: s = splnet(); ! 413: error = in_pcbbind(inp, addr); ! 414: splx(s); ! 415: break; ! 416: ! 417: case PRU_LISTEN: ! 418: error = EOPNOTSUPP; ! 419: break; ! 420: ! 421: case PRU_CONNECT: ! 422: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 423: error = EISCONN; ! 424: break; ! 425: } ! 426: s = splnet(); ! 427: error = in_pcbconnect(inp, addr); ! 428: splx(s); ! 429: if (error == 0) ! 430: soisconnected(so); ! 431: break; ! 432: ! 433: case PRU_CONNECT2: ! 434: error = EOPNOTSUPP; ! 435: break; ! 436: ! 437: case PRU_ACCEPT: ! 438: error = EOPNOTSUPP; ! 439: break; ! 440: ! 441: case PRU_DISCONNECT: ! 442: if (inp->inp_faddr.s_addr == INADDR_ANY) { ! 443: error = ENOTCONN; ! 444: break; ! 445: } ! 446: s = splnet(); ! 447: in_pcbdisconnect(inp); ! 448: inp->inp_laddr.s_addr = INADDR_ANY; ! 449: splx(s); ! 450: so->so_state &= ~SS_ISCONNECTED; /* XXX */ ! 451: break; ! 452: ! 453: case PRU_SHUTDOWN: ! 454: socantsendmore(so); ! 455: break; ! 456: ! 457: case PRU_SEND: ! 458: return (udp_output(inp, m, addr, control)); ! 459: ! 460: case PRU_ABORT: ! 461: soisdisconnected(so); ! 462: udp_detach(inp); ! 463: break; ! 464: ! 465: case PRU_SOCKADDR: ! 466: in_setsockaddr(inp, addr); ! 467: break; ! 468: ! 469: case PRU_PEERADDR: ! 470: in_setpeeraddr(inp, addr); ! 471: break; ! 472: ! 473: case PRU_SENSE: ! 474: /* ! 475: * stat: don't bother with a blocksize. ! 476: */ ! 477: return (0); ! 478: ! 479: case PRU_SENDOOB: ! 480: case PRU_FASTTIMO: ! 481: case PRU_SLOWTIMO: ! 482: case PRU_PROTORCV: ! 483: case PRU_PROTOSEND: ! 484: error = EOPNOTSUPP; ! 485: break; ! 486: ! 487: case PRU_RCVD: ! 488: case PRU_RCVOOB: ! 489: return (EOPNOTSUPP); /* do not free mbuf's */ ! 490: ! 491: default: ! 492: panic("udp_usrreq"); ! 493: } ! 494: ! 495: release: ! 496: if (control) { ! 497: printf("udp control data unexpectedly retained\n"); ! 498: m_freem(control); ! 499: } ! 500: if (m) ! 501: m_freem(m); ! 502: return (error); ! 503: } ! 504: ! 505: udp_detach(inp) ! 506: struct inpcb *inp; ! 507: { ! 508: int s = splnet(); ! 509: ! 510: if (inp == udp_last_inpcb) ! 511: udp_last_inpcb = &udb; ! 512: in_pcbdetach(inp); ! 513: splx(s); ! 514: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.