|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/malloc.h> ! 63: #include <sys/mbuf.h> ! 64: #include <sys/protosw.h> ! 65: #include <sys/socket.h> ! 66: #include <sys/socketvar.h> ! 67: #include <sys/errno.h> ! 68: #include <sys/stat.h> ! 69: ! 70: #include <net/if.h> ! 71: #include <net/route.h> ! 72: ! 73: #include <kernserv/machine/spl.h> ! 74: #include <netinet/in.h> ! 75: #include <netinet/in_systm.h> ! 76: #include <netinet/ip.h> ! 77: #include <netinet/in_pcb.h> ! 78: #include <netinet/ip_var.h> ! 79: #include <netinet/ip_icmp.h> ! 80: #include <netinet/udp.h> ! 81: #include <netinet/udp_var.h> ! 82: ! 83: #if NEXT ! 84: #import <kern/kdebug.h> ! 85: ! 86: #if KDEBUG ! 87: ! 88: #define DBG_LAYER_IN_BEG NETDBG_CODE(DBG_NETUDP, 0) ! 89: #define DBG_LAYER_IN_END NETDBG_CODE(DBG_NETUDP, 2) ! 90: #define DBG_LAYER_OUT_BEG NETDBG_CODE(DBG_NETUDP, 1) ! 91: #define DBG_LAYER_OUT_END NETDBG_CODE(DBG_NETUDP, 3) ! 92: #define DBG_FNC_UDP_INPUT NETDBG_CODE(DBG_NETUDP, (5 << 8)) ! 93: #define DBG_FNC_UDP_OUTPUT NETDBG_CODE(DBG_NETUDP, (6 << 8) | 1) ! 94: ! 95: #endif ! 96: ! 97: #endif ! 98: ! 99: ! 100: #define N_UDP_HASH_ELEMENTS (2 * 1024) /* must be power of 2 */ ! 101: #define UDP_HASH_MASK (N_UDP_HASH_ELEMENTS - 1) ! 102: #define N_UDP_LPORT_HASH_ELEMENTS (1024) ! 103: #define UDP_LPORT_HASH_MASK (N_UDP_LPORT_HASH_ELEMENTS - 1) ! 104: ! 105: ! 106: /* ! 107: * UDP protocol implementation. ! 108: * Per RFC 768, August, 1980. ! 109: */ ! 110: #ifndef COMPAT_42 ! 111: int udpcksum = 1; ! 112: #else ! 113: int udpcksum = 0; /* XXX */ ! 114: #endif ! 115: ! 116: struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; ! 117: struct inpcb udb; ! 118: struct udpstat udpstat; ! 119: ! 120: struct inpcb *udp_hash_array[N_UDP_HASH_ELEMENTS]; ! 121: struct inpcb *udp_lport_hash_array[N_UDP_LPORT_HASH_ELEMENTS]; ! 122: ! 123: struct inpcb_hash_str udp_hash_str = ! 124: {udp_hash_array, UDP_HASH_MASK, N_UDP_HASH_ELEMENTS}; ! 125: ! 126: struct inpcb_hash_str udp_lport_hash_str = ! 127: {udp_lport_hash_array, UDP_LPORT_HASH_MASK, N_UDP_LPORT_HASH_ELEMENTS}; ! 128: ! 129: static void udp_detach __P((struct inpcb *)); ! 130: static void udp_notify __P((struct inpcb *, int)); ! 131: static struct mbuf *udp_saveopt __P((caddr_t, int, int)); ! 132: static struct mbuf *udp_savesockopt __P((caddr_t, int, int, int)); ! 133: ! 134: #include <strings.h> ! 135: ! 136: static struct mbuf * ! 137: udp_insert_ifinfo(struct mbuf * m) ! 138: { ! 139: struct ifnet * ifp = m->m_pkthdr.rcvif; ! 140: ! 141: if (ifp) { ! 142: char buf[IFNAMSIZ * 2]; ! 143: struct mbuf * mp; ! 144: int len; ! 145: ! 146: bzero(buf, sizeof(buf)); ! 147: sprintf(buf, "%s%d", ifp->if_name, ifp->if_unit); ! 148: len = ALIGN(strlen(buf)); ! 149: mp = udp_savesockopt((caddr_t)buf, len, SOL_SOCKET, SO_RCVIF); ! 150: return (mp); ! 151: } ! 152: return (NULL); ! 153: } ! 154: ! 155: void ! 156: udp_init() ! 157: { ! 158: int i; ! 159: ! 160: udb.inp_next = udb.inp_prev = &udb; ! 161: ! 162: for (i=0; i < N_UDP_HASH_ELEMENTS; i++) ! 163: udp_hash_array[i] = 0; ! 164: ! 165: for (i=0; i < N_UDP_LPORT_HASH_ELEMENTS; i++) ! 166: udp_lport_hash_array[i] = 0; ! 167: } ! 168: ! 169: void ! 170: udp_input(m, iphlen) ! 171: register struct mbuf *m; ! 172: int iphlen; ! 173: { ! 174: register struct ip *ip; ! 175: register struct udphdr *uh; ! 176: register struct inpcb *inp; ! 177: struct mbuf *opts = 0; ! 178: int len; ! 179: struct ip save_ip; ! 180: ! 181: udpstat.udps_ipackets++; ! 182: ! 183: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_START, 0,0,0,0,0); ! 184: ! 185: /* ! 186: * Strip IP options, if any; should skip this, ! 187: * make available to user, and use on returned packets, ! 188: * but we don't yet have a way to check the checksum ! 189: * with options still present. ! 190: */ ! 191: if (iphlen > sizeof (struct ip)) { ! 192: ip_stripoptions(m, (struct mbuf *)0); ! 193: iphlen = sizeof(struct ip); ! 194: } ! 195: ! 196: /* ! 197: * Get IP and UDP header together in first mbuf. ! 198: */ ! 199: ip = mtod(m, struct ip *); ! 200: if (m->m_len < iphlen + sizeof(struct udphdr)) { ! 201: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { ! 202: udpstat.udps_hdrops++; ! 203: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 204: return; ! 205: } ! 206: ip = mtod(m, struct ip *); ! 207: } ! 208: uh = (struct udphdr *)((caddr_t)ip + iphlen); ! 209: ! 210: KERNEL_DEBUG(DBG_LAYER_IN_BEG, uh->uh_dport, uh->uh_sport, ! 211: ip->ip_src.s_addr, ip->ip_dst.s_addr, uh->uh_ulen); ! 212: ! 213: /* ! 214: * Make mbuf data length reflect UDP length. ! 215: * If not enough data to reflect UDP length, drop. ! 216: */ ! 217: len = ntohs((u_short)uh->uh_ulen); ! 218: if (ip->ip_len != len) { ! 219: if (len > ip->ip_len) { ! 220: udpstat.udps_badlen++; ! 221: goto bad; ! 222: } ! 223: m_adj(m, len - ip->ip_len); ! 224: /* ip->ip_len = len; */ ! 225: } ! 226: /* ! 227: * Save a copy of the IP header in case we want restore it ! 228: * for sending an ICMP error message in response. ! 229: */ ! 230: save_ip = *ip; ! 231: ! 232: /* ! 233: * Checksum extended UDP header and data. ! 234: */ ! 235: if (uh->uh_sum) { ! 236: ((struct ipovly *)ip)->ih_next = 0; ! 237: ((struct ipovly *)ip)->ih_prev = 0; ! 238: ((struct ipovly *)ip)->ih_x1 = 0; ! 239: ((struct ipovly *)ip)->ih_len = uh->uh_ulen; ! 240: if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip)))) { ! 241: udpstat.udps_badsum++; ! 242: m_freem(m); ! 243: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 244: return; ! 245: } ! 246: } ! 247: ! 248: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || ! 249: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { ! 250: struct socket *last; ! 251: /* ! 252: * Deliver a multicast or broadcast datagram to *all* sockets ! 253: * for which the local and remote addresses and ports match ! 254: * those of the incoming datagram. This allows more than ! 255: * one process to receive multi/broadcasts on the same port. ! 256: * (This really ought to be done for unicast datagrams as ! 257: * well, but that would cause problems with existing ! 258: * applications that open both address-specific sockets and ! 259: * a wildcard socket listening to the same port -- they would ! 260: * end up receiving duplicates of every unicast datagram. ! 261: * Those applications open the multiple sockets to overcome an ! 262: * inadequacy of the UDP socket interface, but for backwards ! 263: * compatibility we avoid the problem here rather than ! 264: * fixing the interface. Maybe 4.5BSD will remedy this?) ! 265: */ ! 266: ! 267: /* ! 268: * Construct sockaddr format source address. ! 269: */ ! 270: udp_in.sin_port = uh->uh_sport; ! 271: udp_in.sin_addr = ip->ip_src; ! 272: m->m_len -= sizeof (struct udpiphdr); ! 273: m->m_data += sizeof (struct udpiphdr); ! 274: /* ! 275: * Locate pcb(s) for datagram. ! 276: * (Algorithm copied from raw_intr().) ! 277: */ ! 278: last = NULL; ! 279: inp = inet_lport_hash1(&udp_lport_hash_str, uh->uh_dport); ! 280: for (; inp != 0; inp = inp->lport_hash_next) { ! 281: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 282: if (inp->inp_laddr.s_addr != ! 283: ip->ip_dst.s_addr) ! 284: continue; ! 285: } ! 286: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 287: if (inp->inp_faddr.s_addr != ! 288: ip->ip_src.s_addr || ! 289: inp->inp_fport != uh->uh_sport) ! 290: continue; ! 291: } ! 292: ! 293: if (last != NULL) { ! 294: struct mbuf *n; ! 295: ! 296: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { ! 297: struct mbuf * mp = 0; ! 298: KERNEL_DEBUG(DBG_LAYER_IN_END, uh->uh_dport, uh->uh_sport, ! 299: save_ip.ip_src.s_addr, save_ip.ip_dst.s_addr, uh->uh_ulen); ! 300: ! 301: if (last->so_options & SO_RCVIF) ! 302: mp = udp_insert_ifinfo(n); ! 303: ! 304: if (sbappendaddr(&last->so_rcv, ! 305: (struct sockaddr *)&udp_in, ! 306: n, mp) == 0) { ! 307: m_freem(n); ! 308: if (mp) ! 309: m_freem(mp); ! 310: udpstat.udps_fullsock++; ! 311: } else ! 312: sorwakeup(last); ! 313: } ! 314: } ! 315: last = inp->inp_socket; ! 316: /* ! 317: * Don't look for additional matches if this one does ! 318: * not have either the SO_REUSEPORT or SO_REUSEADDR ! 319: * socket options set. This heuristic avoids searching ! 320: * through all pcbs in the common case of a non-shared ! 321: * port. It * assumes that an application will never ! 322: * clear these options after setting them. ! 323: */ ! 324: if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) ! 325: break; ! 326: } ! 327: ! 328: if (last == NULL) { ! 329: /* ! 330: * No matching pcb found; discard datagram. ! 331: * (No need to send an ICMP Port Unreachable ! 332: * for a broadcast or multicast datgram.) ! 333: */ ! 334: udpstat.udps_noportbcast++; ! 335: goto bad; ! 336: } ! 337: ! 338: KERNEL_DEBUG(DBG_LAYER_IN_END, uh->uh_dport, uh->uh_sport, ! 339: save_ip.ip_src.s_addr, save_ip.ip_dst.s_addr, uh->uh_ulen); ! 340: ! 341: { ! 342: struct mbuf * mp = 0; ! 343: ! 344: if (last->so_options & SO_RCVIF) ! 345: mp = udp_insert_ifinfo(m); ! 346: if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, ! 347: m, mp) == 0) { ! 348: udpstat.udps_fullsock++; ! 349: if (mp) ! 350: m_freem(mp); ! 351: goto bad; ! 352: } ! 353: } ! 354: sorwakeup(last); ! 355: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 356: return; ! 357: } ! 358: /* ! 359: * Locate pcb for datagram. ! 360: */ ! 361: ! 362: inp = inet_hash1(&udp_hash_str, ip->ip_dst.s_addr, uh->uh_dport, ! 363: ip->ip_src.s_addr, uh->uh_sport); ! 364: ! 365: inp = hash_in_pcblookup(inp, ip->ip_src, uh->uh_sport, ! 366: ip->ip_dst, uh->uh_dport); ! 367: if (inp == 0) { ! 368: inp = inet_hash1(&udp_hash_str, 0, uh->uh_dport,0,0); ! 369: inp = hash_in_pcbwild(inp, ! 370: ip->ip_src, uh->uh_sport, ! 371: ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); ! 372: /* ! 373: if (inp == 0) ! 374: udpstat.udpps_pcbcachemiss++; ! 375: inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, ! 376: ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); ! 377: */ ! 378: } ! 379: ! 380: ! 381: if (inp == 0) { ! 382: udpstat.udps_noport++; ! 383: if (m->m_flags & (M_BCAST | M_MCAST)) { ! 384: udpstat.udps_noportbcast++; ! 385: goto bad; ! 386: } ! 387: *ip = save_ip; ! 388: ip->ip_len += iphlen; ! 389: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); ! 390: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 391: return; ! 392: } ! 393: ! 394: /* ! 395: * Construct sockaddr format source address. ! 396: * Stuff source address and datagram in user buffer. ! 397: */ ! 398: udp_in.sin_port = uh->uh_sport; ! 399: udp_in.sin_addr = ip->ip_src; ! 400: ! 401: { ! 402: struct mbuf **mp = &opts; ! 403: if (inp->inp_flags & INP_CONTROLOPTS) { ! 404: ! 405: if (inp->inp_flags & INP_RECVDSTADDR) { ! 406: *mp = udp_saveopt((caddr_t) &ip->ip_dst, ! 407: sizeof(struct in_addr), IP_RECVDSTADDR); ! 408: if (*mp) ! 409: mp = &(*mp)->m_next; ! 410: } ! 411: #ifdef notyet ! 412: /* options were tossed above */ ! 413: if (inp->inp_flags & INP_RECVOPTS) { ! 414: *mp = udp_saveopt((caddr_t) opts_deleted_above, ! 415: sizeof(struct in_addr), IP_RECVOPTS); ! 416: if (*mp) ! 417: mp = &(*mp)->m_next; ! 418: } ! 419: /* ip_srcroute doesn't do what we want here, need to fix */ ! 420: if (inp->inp_flags & INP_RECVRETOPTS) { ! 421: *mp = udp_saveopt((caddr_t) ip_srcroute(), ! 422: sizeof(struct in_addr), IP_RECVRETOPTS); ! 423: if (*mp) ! 424: mp = &(*mp)->m_next; ! 425: } ! 426: #endif ! 427: } ! 428: ! 429: if (inp->inp_socket->so_options & SO_RCVIF) { ! 430: /* insert receive interface info */ ! 431: *mp = udp_insert_ifinfo(m); ! 432: if (*mp) ! 433: mp = &(*mp)->m_next; ! 434: } ! 435: } ! 436: iphlen += sizeof(struct udphdr); ! 437: m->m_len -= iphlen; ! 438: m->m_pkthdr.len -= iphlen; ! 439: m->m_data += iphlen; ! 440: ! 441: KERNEL_DEBUG(DBG_LAYER_IN_END, uh->uh_dport, uh->uh_sport, ! 442: save_ip.ip_src.s_addr, save_ip.ip_dst.s_addr, uh->uh_ulen); ! 443: ! 444: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, ! 445: m, opts) == 0) { ! 446: udpstat.udps_fullsock++; ! 447: goto bad; ! 448: } ! 449: ! 450: sorwakeup(inp->inp_socket); ! 451: ! 452: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 453: return; ! 454: bad: ! 455: m_freem(m); ! 456: if (opts) ! 457: m_freem(opts); ! 458: ! 459: KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); ! 460: } ! 461: ! 462: /* ! 463: * Create a "control" mbuf containing the specified data ! 464: * with the specified type/level for presentation with a datagram. ! 465: */ ! 466: struct mbuf * ! 467: udp_savesockopt(p, size, level, type) ! 468: caddr_t p; ! 469: register int size; ! 470: int level; ! 471: int type; ! 472: { ! 473: register struct cmsghdr *cp; ! 474: struct mbuf *m; ! 475: ! 476: if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) ! 477: return ((struct mbuf *) NULL); ! 478: cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); ! 479: bcopy(p, CMSG_DATA(cp), size); ! 480: size += sizeof(*cp); ! 481: m->m_len = size; ! 482: cp->cmsg_len = size; ! 483: cp->cmsg_level = level; ! 484: cp->cmsg_type = type; ! 485: return (m); ! 486: } ! 487: ! 488: struct mbuf * ! 489: udp_saveopt(p, size, type) ! 490: caddr_t p; ! 491: register int size; ! 492: int type; ! 493: { ! 494: return (udp_savesockopt(p, size, IPPROTO_IP, type)); ! 495: } ! 496: ! 497: ! 498: /* ! 499: * Notify a udp user of an asynchronous error; ! 500: * just wake up so that he can collect error status. ! 501: */ ! 502: static void ! 503: udp_notify(inp, errno) ! 504: register struct inpcb *inp; ! 505: int errno; ! 506: { ! 507: inp->inp_socket->so_error = errno; ! 508: sorwakeup(inp->inp_socket); ! 509: sowwakeup(inp->inp_socket); ! 510: } ! 511: ! 512: void ! 513: udp_ctlinput(cmd, sa, ip) ! 514: int cmd; ! 515: struct sockaddr *sa; ! 516: register struct ip *ip; ! 517: { ! 518: register struct udphdr *uh; ! 519: extern struct in_addr zeroin_addr; ! 520: extern u_char inetctlerrmap[]; ! 521: ! 522: if (!PRC_IS_REDIRECT(cmd) && ! 523: ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) ! 524: return; ! 525: if (ip) { ! 526: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ! 527: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, ! 528: cmd, udp_notify); ! 529: } else ! 530: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); ! 531: } ! 532: ! 533: int ! 534: udp_output(inp, m, addr, control) ! 535: register struct inpcb *inp; ! 536: register struct mbuf *m; ! 537: struct mbuf *addr, *control; ! 538: { ! 539: register struct udpiphdr *ui; ! 540: register int len = m->m_pkthdr.len; ! 541: struct in_addr laddr; ! 542: int s, error = 0; ! 543: ! 544: ! 545: KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0); ! 546: ! 547: if (control) ! 548: m_freem(control); /* XXX */ ! 549: ! 550: ! 551: KERNEL_DEBUG(DBG_LAYER_OUT_BEG, inp->inp_fport, inp->inp_lport, ! 552: inp->inp_laddr.s_addr, inp->inp_faddr.s_addr, ! 553: (htons((u_short)len + sizeof (struct udphdr)))); ! 554: ! 555: if (addr) { ! 556: laddr = inp->inp_laddr; ! 557: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 558: error = EISCONN; ! 559: goto release; ! 560: } ! 561: /* ! 562: * Must block input while temporarily connected. ! 563: */ ! 564: s = splnet(); ! 565: error = in_pcbconnect(inp, addr); ! 566: if (error) { ! 567: splx(s); ! 568: goto release; ! 569: } ! 570: } else { ! 571: if (inp->inp_faddr.s_addr == INADDR_ANY) { ! 572: error = ENOTCONN; ! 573: goto release; ! 574: } ! 575: } ! 576: /* ! 577: * Calculate data length and get a mbuf ! 578: * for UDP and IP headers. ! 579: */ ! 580: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); ! 581: if (m == 0) { ! 582: error = ENOBUFS; ! 583: goto release; ! 584: } ! 585: ! 586: /* ! 587: * Fill in mbuf with extended UDP header ! 588: * and addresses and length put into network format. ! 589: */ ! 590: ui = mtod(m, struct udpiphdr *); ! 591: ui->ui_next = ui->ui_prev = 0; ! 592: ui->ui_x1 = 0; ! 593: ui->ui_pr = IPPROTO_UDP; ! 594: ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); ! 595: ui->ui_src = inp->inp_laddr; ! 596: ui->ui_dst = inp->inp_faddr; ! 597: ui->ui_sport = inp->inp_lport; ! 598: ui->ui_dport = inp->inp_fport; ! 599: ui->ui_ulen = ui->ui_len; ! 600: ! 601: /* ! 602: * Stuff checksum and output datagram. ! 603: */ ! 604: ui->ui_sum = 0; ! 605: if (udpcksum) { ! 606: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) ! 607: ui->ui_sum = 0xffff; ! 608: } ! 609: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ! 610: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ ! 611: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ ! 612: udpstat.udps_opackets++; ! 613: ! 614: ! 615: KERNEL_DEBUG(DBG_LAYER_OUT_END, ui->ui_dport, ui->ui_sport, ! 616: ui->ui_src.s_addr, ui->ui_dst.s_addr, ui->ui_ulen); ! 617: ! 618: error = ip_output(m, inp->inp_options, &inp->inp_route, ! 619: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), ! 620: inp->inp_moptions); ! 621: ! 622: if (addr) { ! 623: in_pcbdisconnect(inp); ! 624: inp->inp_laddr = laddr; ! 625: hash_insert(inp); ! 626: splx(s); ! 627: } ! 628: ! 629: KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_END, error, 0,0,0,0); ! 630: return (error); ! 631: ! 632: release: ! 633: m_freem(m); ! 634: KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_END, error, 0,0,0,0); ! 635: return (error); ! 636: } ! 637: ! 638: u_long udp_sendspace = 9216; /* really max datagram size */ ! 639: u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); ! 640: /* 40 1K datagrams */ ! 641: ! 642: /*ARGSUSED*/ ! 643: int ! 644: udp_usrreq(so, req, m, addr, control) ! 645: struct socket *so; ! 646: int req; ! 647: struct mbuf *m, *addr, *control; ! 648: { ! 649: struct inpcb *inp = sotoinpcb(so); ! 650: int error = 0; ! 651: int s; ! 652: ! 653: if (req == PRU_CONTROL) ! 654: return (in_control(so, (u_long)m, (caddr_t)addr, ! 655: (struct ifnet *)control)); ! 656: if (inp == NULL && req != PRU_ATTACH) { ! 657: error = EINVAL; ! 658: goto release; ! 659: } ! 660: /* ! 661: * Note: need to block udp_input while changing ! 662: * the udp pcb queue and/or pcb addresses. ! 663: */ ! 664: switch (req) { ! 665: ! 666: case PRU_ATTACH: ! 667: if (inp != NULL) { ! 668: error = EINVAL; ! 669: break; ! 670: } ! 671: s = splnet(); ! 672: error = in_pcballoc(so, &udb, &udp_hash_str, &udp_lport_hash_str); ! 673: splx(s); ! 674: if (error) ! 675: break; ! 676: error = soreserve(so, udp_sendspace, udp_recvspace); ! 677: if (error) ! 678: break; ! 679: ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; ! 680: break; ! 681: ! 682: case PRU_DETACH: ! 683: udp_detach(inp); ! 684: break; ! 685: ! 686: case PRU_BIND: ! 687: s = splnet(); ! 688: error = in_pcbbind(inp, addr); ! 689: if (error == 0) { ! 690: hash_insert(inp); ! 691: } ! 692: ! 693: splx(s); ! 694: break; ! 695: ! 696: case PRU_LISTEN: ! 697: error = EOPNOTSUPP; ! 698: break; ! 699: ! 700: case PRU_CONNECT: ! 701: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 702: error = EISCONN; ! 703: break; ! 704: } ! 705: s = splnet(); ! 706: ! 707: if (inp->hash_element >= 0) ! 708: hash_remove(inp); ! 709: ! 710: error = in_pcbconnect(inp, addr); ! 711: splx(s); ! 712: if (error == 0) ! 713: soisconnected(so); ! 714: break; ! 715: ! 716: case PRU_CONNECT2: ! 717: error = EOPNOTSUPP; ! 718: break; ! 719: ! 720: case PRU_ACCEPT: ! 721: error = EOPNOTSUPP; ! 722: break; ! 723: ! 724: case PRU_DISCONNECT: ! 725: if (inp->inp_faddr.s_addr == INADDR_ANY) { ! 726: error = ENOTCONN; ! 727: break; ! 728: } ! 729: s = splnet(); ! 730: in_pcbdisconnect(inp); ! 731: inp->inp_laddr.s_addr = INADDR_ANY; ! 732: hash_insert(inp); ! 733: splx(s); ! 734: so->so_state &= ~SS_ISCONNECTED; /* XXX */ ! 735: break; ! 736: ! 737: case PRU_SHUTDOWN: ! 738: socantsendmore(so); ! 739: break; ! 740: ! 741: case PRU_SEND: ! 742: return (udp_output(inp, m, addr, control)); ! 743: ! 744: case PRU_ABORT: ! 745: soisdisconnected(so); ! 746: udp_detach(inp); ! 747: break; ! 748: ! 749: case PRU_SOCKADDR: ! 750: in_setsockaddr(inp, addr); ! 751: break; ! 752: ! 753: case PRU_PEERADDR: ! 754: in_setpeeraddr(inp, addr); ! 755: break; ! 756: ! 757: case PRU_SENSE: ! 758: /* ! 759: * stat: don't bother with a blocksize. ! 760: */ ! 761: return (0); ! 762: ! 763: case PRU_SENDOOB: ! 764: case PRU_FASTTIMO: ! 765: case PRU_SLOWTIMO: ! 766: case PRU_PROTORCV: ! 767: case PRU_PROTOSEND: ! 768: error = EOPNOTSUPP; ! 769: break; ! 770: ! 771: case PRU_RCVD: ! 772: case PRU_RCVOOB: ! 773: return (EOPNOTSUPP); /* do not free mbuf's */ ! 774: ! 775: default: ! 776: panic("udp_usrreq"); ! 777: } ! 778: ! 779: release: ! 780: if (control) { ! 781: printf("udp control data unexpectedly retained\n"); ! 782: m_freem(control); ! 783: } ! 784: if (m) ! 785: m_freem(m); ! 786: return (error); ! 787: } ! 788: ! 789: static void ! 790: udp_detach(inp) ! 791: struct inpcb *inp; ! 792: { ! 793: int s = splnet(); ! 794: ! 795: in_pcbdetach(inp); ! 796: splx(s); ! 797: } ! 798: ! 799: /* ! 800: * Sysctl for udp variables. ! 801: */ ! 802: int ! 803: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) ! 804: int *name; ! 805: u_int namelen; ! 806: void *oldp; ! 807: size_t *oldlenp; ! 808: void *newp; ! 809: size_t newlen; ! 810: { ! 811: /* All sysctl names at this level are terminal. */ ! 812: if (namelen != 1) ! 813: return (ENOTDIR); ! 814: ! 815: switch (name[0]) { ! 816: case UDPCTL_CHECKSUM: ! 817: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); ! 818: default: ! 819: return (ENOPROTOOPT); ! 820: } ! 821: /* NOTREACHED */ ! 822: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.