|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 ! 55: */ ! 56: ! 57: #include <sys/param.h> ! 58: #include <sys/systm.h> ! 59: #include <sys/kernel.h> ! 60: #include <sys/malloc.h> ! 61: #include <sys/mbuf.h> ! 62: #include <sys/protosw.h> ! 63: #include <sys/socket.h> ! 64: #include <sys/socketvar.h> ! 65: #include <sys/sysctl.h> ! 66: #include <sys/syslog.h> ! 67: ! 68: #if ISFB31 ! 69: #include <vm/vm_zone.h> ! 70: #endif ! 71: ! 72: ! 73: #include <net/if.h> ! 74: #include <net/route.h> ! 75: ! 76: #include <netinet/in.h> ! 77: #include <netinet/in_systm.h> ! 78: #include <netinet/ip.h> ! 79: #include <netinet/in_pcb.h> ! 80: #include <netinet/in_var.h> ! 81: #include <netinet/ip_var.h> ! 82: #include <netinet/ip_icmp.h> ! 83: #include <netinet/icmp_var.h> ! 84: #include <netinet/udp.h> ! 85: #include <netinet/udp_var.h> ! 86: ! 87: #define __STDC__ 1 ! 88: /* ! 89: * UDP protocol implementation. ! 90: * Per RFC 768, August, 1980. ! 91: */ ! 92: #ifndef COMPAT_42 ! 93: static int udpcksum = 1; ! 94: #else ! 95: static int udpcksum = 0; /* XXX */ ! 96: #endif ! 97: SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, ! 98: &udpcksum, 0, ""); ! 99: ! 100: static int log_in_vain = 0; ! 101: SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, ! 102: &log_in_vain, 0, ""); ! 103: ! 104: static struct inpcbhead udb; /* from udp_var.h */ ! 105: struct inpcbinfo udbinfo; ! 106: ! 107: #ifndef UDBHASHSIZE ! 108: #define UDBHASHSIZE 16 ! 109: #endif ! 110: ! 111: static struct udpstat udpstat; /* from udp_var.h */ ! 112: SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, ! 113: &udpstat, udpstat, ""); ! 114: ! 115: static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; ! 116: ! 117: static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, ! 118: struct mbuf *, struct proc *)); ! 119: static void udp_notify __P((struct inpcb *, int)); ! 120: ! 121: void ! 122: udp_init() ! 123: { ! 124: vm_size_t str_size; ! 125: int stat; ! 126: u_char fake_owner; ! 127: struct in_addr laddr; ! 128: struct in_addr faddr; ! 129: u_short lport; ! 130: ! 131: LIST_INIT(&udb); ! 132: udbinfo.listhead = &udb; ! 133: udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); ! 134: udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB, ! 135: &udbinfo.porthashmask); ! 136: #if ISFB31 ! 137: udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets, ! 138: ZONE_INTERRUPT, 0); ! 139: #else ! 140: str_size = (vm_size_t) sizeof(struct inpcb); ! 141: udbinfo.ipi_zone = (void *) zinit(str_size, 80000*str_size, 8192, "inpcb_zone"); ! 142: #endif ! 143: ! 144: udbinfo.last_pcb = 0; ! 145: in_pcb_nat_init(&udbinfo, AF_INET, IPPROTO_UDP, SOCK_DGRAM); ! 146: ! 147: #if 0 ! 148: stat = in_pcb_new_share_client(&udbinfo, &fake_owner); ! 149: kprintf("udp_init in_pcb_new_share_client - stat = %d\n", stat); ! 150: ! 151: laddr.s_addr = 0x11646464; ! 152: faddr.s_addr = 0x11646465; ! 153: ! 154: lport = 1500; ! 155: in_pcb_grab_port(&udbinfo, 0, laddr, &lport, faddr, 1600, 0, fake_owner); ! 156: kprintf("udp_init in_pcb_grab_port - stat = %d\n", stat); ! 157: ! 158: stat = in_pcb_rem_share_client(&udbinfo, fake_owner); ! 159: kprintf("udp_init in_pcb_rem_share_client - stat = %d\n", stat); ! 160: ! 161: stat = in_pcb_new_share_client(&udbinfo, &fake_owner); ! 162: kprintf("udp_init in_pcb_new_share_client(2) - stat = %d\n", stat); ! 163: ! 164: laddr.s_addr = 0x11646464; ! 165: faddr.s_addr = 0x11646465; ! 166: ! 167: lport = 1500; ! 168: stat = in_pcb_grab_port(&udbinfo, 0, laddr, &lport, faddr, 1600, 0, fake_owner); ! 169: kprintf("udp_init in_pcb_grab_port(2) - stat = %d\n", stat); ! 170: #endif ! 171: } ! 172: ! 173: void ! 174: udp_input(m, iphlen) ! 175: register struct mbuf *m; ! 176: int iphlen; ! 177: { ! 178: register struct ip *ip; ! 179: register struct udphdr *uh; ! 180: register struct inpcb *inp; ! 181: struct mbuf *opts = 0; ! 182: int len; ! 183: struct ip save_ip; ! 184: ! 185: udpstat.udps_ipackets++; ! 186: ! 187: /* ! 188: * Strip IP options, if any; should skip this, ! 189: * make available to user, and use on returned packets, ! 190: * but we don't yet have a way to check the checksum ! 191: * with options still present. ! 192: */ ! 193: if (iphlen > sizeof (struct ip)) { ! 194: ip_stripoptions(m, (struct mbuf *)0); ! 195: iphlen = sizeof(struct ip); ! 196: } ! 197: ! 198: /* ! 199: * Get IP and UDP header together in first mbuf. ! 200: */ ! 201: ip = mtod(m, struct ip *); ! 202: if (m->m_len < iphlen + sizeof(struct udphdr)) { ! 203: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { ! 204: udpstat.udps_hdrops++; ! 205: return; ! 206: } ! 207: ip = mtod(m, struct ip *); ! 208: } ! 209: uh = (struct udphdr *)((caddr_t)ip + iphlen); ! 210: ! 211: /* ! 212: * Make mbuf data length reflect UDP length. ! 213: * If not enough data to reflect UDP length, drop. ! 214: */ ! 215: len = ntohs((u_short)uh->uh_ulen); ! 216: if (ip->ip_len != len) { ! 217: if (len > ip->ip_len || len < sizeof(struct udphdr)) { ! 218: udpstat.udps_badlen++; ! 219: goto bad; ! 220: } ! 221: m_adj(m, len - ip->ip_len); ! 222: /* ip->ip_len = len; */ ! 223: } ! 224: /* ! 225: * Save a copy of the IP header in case we want restore it ! 226: * for sending an ICMP error message in response. ! 227: */ ! 228: save_ip = *ip; ! 229: ! 230: /* ! 231: * Checksum extended UDP header and data. ! 232: */ ! 233: if (uh->uh_sum) { ! 234: bzero(((struct ipovly *)ip)->ih_x1, 9); ! 235: ((struct ipovly *)ip)->ih_len = uh->uh_ulen; ! 236: uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); ! 237: if (uh->uh_sum) { ! 238: udpstat.udps_badsum++; ! 239: m_freem(m); ! 240: return; ! 241: } ! 242: } ! 243: ! 244: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || ! 245: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { ! 246: struct inpcb *last; ! 247: /* ! 248: * Deliver a multicast or broadcast datagram to *all* sockets ! 249: * for which the local and remote addresses and ports match ! 250: * those of the incoming datagram. This allows more than ! 251: * one process to receive multi/broadcasts on the same port. ! 252: * (This really ought to be done for unicast datagrams as ! 253: * well, but that would cause problems with existing ! 254: * applications that open both address-specific sockets and ! 255: * a wildcard socket listening to the same port -- they would ! 256: * end up receiving duplicates of every unicast datagram. ! 257: * Those applications open the multiple sockets to overcome an ! 258: * inadequacy of the UDP socket interface, but for backwards ! 259: * compatibility we avoid the problem here rather than ! 260: * fixing the interface. Maybe 4.5BSD will remedy this?) ! 261: */ ! 262: ! 263: /* ! 264: * Construct sockaddr format source address. ! 265: */ ! 266: udp_in.sin_port = uh->uh_sport; ! 267: udp_in.sin_addr = ip->ip_src; ! 268: m->m_len -= sizeof (struct udpiphdr); ! 269: m->m_data += sizeof (struct udpiphdr); ! 270: /* ! 271: * Locate pcb(s) for datagram. ! 272: * (Algorithm copied from raw_intr().) ! 273: */ ! 274: last = NULL; ! 275: for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { ! 276: if (inp->inp_lport != uh->uh_dport) ! 277: continue; ! 278: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 279: if (inp->inp_laddr.s_addr != ! 280: ip->ip_dst.s_addr) ! 281: continue; ! 282: } ! 283: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 284: if (inp->inp_faddr.s_addr != ! 285: ip->ip_src.s_addr || ! 286: inp->inp_fport != uh->uh_sport) ! 287: continue; ! 288: } ! 289: ! 290: if (last != NULL) { ! 291: struct mbuf *n; ! 292: ! 293: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { ! 294: if (last->inp_flags & INP_CONTROLOPTS ! 295: || last->inp_socket->so_options & SO_TIMESTAMP) ! 296: ip_savecontrol(last, &opts, ip, n); ! 297: if (sbappendaddr(&last->inp_socket->so_rcv, ! 298: (struct sockaddr *)&udp_in, ! 299: n, opts) == 0) { ! 300: m_freem(n); ! 301: if (opts) ! 302: m_freem(opts); ! 303: udpstat.udps_fullsock++; ! 304: } else ! 305: sorwakeup(last->inp_socket); ! 306: opts = 0; ! 307: } ! 308: } ! 309: last = inp; ! 310: /* ! 311: * Don't look for additional matches if this one does ! 312: * not have either the SO_REUSEPORT or SO_REUSEADDR ! 313: * socket options set. This heuristic avoids searching ! 314: * through all pcbs in the common case of a non-shared ! 315: * port. It * assumes that an application will never ! 316: * clear these options after setting them. ! 317: */ ! 318: if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) ! 319: break; ! 320: } ! 321: ! 322: if (last == NULL) { ! 323: /* ! 324: * No matching pcb found; discard datagram. ! 325: * (No need to send an ICMP Port Unreachable ! 326: * for a broadcast or multicast datgram.) ! 327: */ ! 328: udpstat.udps_noportbcast++; ! 329: goto bad; ! 330: } ! 331: if (last->inp_flags & INP_CONTROLOPTS ! 332: || last->inp_socket->so_options & SO_TIMESTAMP) ! 333: ip_savecontrol(last, &opts, ip, m); ! 334: if (sbappendaddr(&last->inp_socket->so_rcv, ! 335: (struct sockaddr *)&udp_in, ! 336: m, opts) == 0) { ! 337: udpstat.udps_fullsock++; ! 338: goto bad; ! 339: } ! 340: sorwakeup(last->inp_socket); ! 341: return; ! 342: } ! 343: /* ! 344: * Locate pcb for datagram. ! 345: */ ! 346: inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport, ! 347: ip->ip_dst, uh->uh_dport, 1); ! 348: if (inp == NULL) { ! 349: if (log_in_vain) { ! 350: char buf[4*sizeof "123"]; ! 351: ! 352: strcpy(buf, inet_ntoa(ip->ip_dst)); ! 353: log(LOG_INFO, ! 354: "Connection attempt to UDP %s:%d from %s:%d\n", ! 355: buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), ! 356: ntohs(uh->uh_sport)); ! 357: } ! 358: udpstat.udps_noport++; ! 359: if (m->m_flags & (M_BCAST | M_MCAST)) { ! 360: udpstat.udps_noportbcast++; ! 361: goto bad; ! 362: } ! 363: *ip = save_ip; ! 364: #if ICMP_BANDLIM ! 365: if (badport_bandlim(0) < 0) ! 366: goto bad; ! 367: #endif ! 368: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); ! 369: return; ! 370: } ! 371: ! 372: /* ! 373: * Construct sockaddr format source address. ! 374: * Stuff source address and datagram in user buffer. ! 375: */ ! 376: udp_in.sin_port = uh->uh_sport; ! 377: udp_in.sin_addr = ip->ip_src; ! 378: if (inp->inp_flags & INP_CONTROLOPTS ! 379: || inp->inp_socket->so_options & SO_TIMESTAMP) ! 380: ip_savecontrol(inp, &opts, ip, m); ! 381: iphlen += sizeof(struct udphdr); ! 382: m->m_len -= iphlen; ! 383: m->m_pkthdr.len -= iphlen; ! 384: m->m_data += iphlen; ! 385: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, ! 386: m, opts) == 0) { ! 387: udpstat.udps_fullsock++; ! 388: goto bad; ! 389: } ! 390: sorwakeup(inp->inp_socket); ! 391: return; ! 392: bad: ! 393: m_freem(m); ! 394: if (opts) ! 395: m_freem(opts); ! 396: } ! 397: ! 398: /* ! 399: * Notify a udp user of an asynchronous error; ! 400: * just wake up so that he can collect error status. ! 401: */ ! 402: static void ! 403: udp_notify(inp, errno) ! 404: register struct inpcb *inp; ! 405: int errno; ! 406: { ! 407: inp->inp_socket->so_error = errno; ! 408: sorwakeup(inp->inp_socket); ! 409: sowwakeup(inp->inp_socket); ! 410: } ! 411: ! 412: void ! 413: udp_ctlinput(cmd, sa, vip) ! 414: int cmd; ! 415: struct sockaddr *sa; ! 416: void *vip; ! 417: { ! 418: register struct ip *ip = vip; ! 419: register struct udphdr *uh; ! 420: ! 421: if (!PRC_IS_REDIRECT(cmd) && ! 422: ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) ! 423: return; ! 424: if (ip) { ! 425: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ! 426: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, ! 427: cmd, udp_notify); ! 428: } else ! 429: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); ! 430: } ! 431: ! 432: ! 433: static int ! 434: udp_pcblist SYSCTL_HANDLER_ARGS ! 435: { ! 436: int error, i, n, s; ! 437: struct inpcb *inp, **inp_list; ! 438: inp_gen_t gencnt; ! 439: struct xinpgen xig; ! 440: ! 441: /* ! 442: * The process of preparing the TCB list is too time-consuming and ! 443: * resource-intensive to repeat twice on every request. ! 444: */ ! 445: if (req->oldptr == 0) { ! 446: n = udbinfo.ipi_count; ! 447: req->oldidx = 2 * (sizeof xig) ! 448: + (n + n/8) * sizeof(struct xinpcb); ! 449: return 0; ! 450: } ! 451: ! 452: if (req->newptr != 0) ! 453: return EPERM; ! 454: ! 455: /* ! 456: * OK, now we're committed to doing something. ! 457: */ ! 458: s = splnet(); ! 459: gencnt = udbinfo.ipi_gencnt; ! 460: n = udbinfo.ipi_count; ! 461: splx(s); ! 462: ! 463: xig.xig_len = sizeof xig; ! 464: xig.xig_count = n; ! 465: xig.xig_gen = gencnt; ! 466: xig.xig_sogen = so_gencnt; ! 467: error = SYSCTL_OUT(req, &xig, sizeof xig); ! 468: if (error) ! 469: return error; ! 470: ! 471: inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); ! 472: if (inp_list == 0) { ! 473: return ENOMEM; ! 474: } ! 475: s = splnet(); ! 476: for (inp = udbinfo.listhead->lh_first, i = 0; inp && i < n; ! 477: inp = inp->inp_list.le_next) { ! 478: if (inp->inp_gencnt <= gencnt) ! 479: inp_list[i++] = inp; ! 480: } ! 481: splx(s); ! 482: n = i; ! 483: ! 484: error = 0; ! 485: for (i = 0; i < n; i++) { ! 486: inp = inp_list[i]; ! 487: if (inp->inp_gencnt <= gencnt) { ! 488: struct xinpcb xi; ! 489: xi.xi_len = sizeof xi; ! 490: /* XXX should avoid extra copy */ ! 491: bcopy(inp, &xi.xi_inp, sizeof *inp); ! 492: if (inp->inp_socket) ! 493: sotoxsocket(inp->inp_socket, &xi.xi_socket); ! 494: error = SYSCTL_OUT(req, &xi, sizeof xi); ! 495: } ! 496: } ! 497: if (!error) { ! 498: /* ! 499: * Give the user an updated idea of our state. ! 500: * If the generation differs from what we told ! 501: * her before, she knows that something happened ! 502: * while we were processing this request, and it ! 503: * might be necessary to retry. ! 504: */ ! 505: s = splnet(); ! 506: xig.xig_gen = udbinfo.ipi_gencnt; ! 507: xig.xig_sogen = so_gencnt; ! 508: xig.xig_count = udbinfo.ipi_count; ! 509: splx(s); ! 510: error = SYSCTL_OUT(req, &xig, sizeof xig); ! 511: } ! 512: FREE(inp_list, M_TEMP); ! 513: return error; ! 514: } ! 515: ! 516: SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, ! 517: udp_pcblist, "S,xinpcb", "List of active UDP sockets"); ! 518: ! 519: ! 520: ! 521: static int ! 522: udp_output(inp, m, addr, control, p) ! 523: register struct inpcb *inp; ! 524: register struct mbuf *m; ! 525: struct sockaddr *addr; ! 526: struct mbuf *control; ! 527: struct proc *p; ! 528: { ! 529: register struct udpiphdr *ui; ! 530: register int len = m->m_pkthdr.len; ! 531: struct in_addr laddr; ! 532: int s = 0, error = 0; ! 533: ! 534: if (control) ! 535: m_freem(control); /* XXX */ ! 536: ! 537: if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { ! 538: error = EMSGSIZE; ! 539: goto release; ! 540: } ! 541: ! 542: if (addr) { ! 543: laddr = inp->inp_laddr; ! 544: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 545: error = EISCONN; ! 546: goto release; ! 547: } ! 548: /* ! 549: * Must block input while temporarily connected. ! 550: */ ! 551: s = splnet(); ! 552: error = in_pcbconnect(inp, addr, p); ! 553: if (error) { ! 554: splx(s); ! 555: goto release; ! 556: } ! 557: } else { ! 558: if (inp->inp_faddr.s_addr == INADDR_ANY) { ! 559: error = ENOTCONN; ! 560: goto release; ! 561: } ! 562: } ! 563: /* ! 564: * Calculate data length and get a mbuf ! 565: * for UDP and IP headers. ! 566: */ ! 567: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); ! 568: if (m == 0) { ! 569: error = ENOBUFS; ! 570: if (addr) ! 571: splx(s); ! 572: goto release; ! 573: } ! 574: ! 575: /* ! 576: * Fill in mbuf with extended UDP header ! 577: * and addresses and length put into network format. ! 578: */ ! 579: ui = mtod(m, struct udpiphdr *); ! 580: bzero(ui->ui_x1, sizeof(ui->ui_x1)); ! 581: ui->ui_pr = IPPROTO_UDP; ! 582: ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); ! 583: ui->ui_src = inp->inp_laddr; ! 584: ui->ui_dst = inp->inp_faddr; ! 585: ui->ui_sport = inp->inp_lport; ! 586: ui->ui_dport = inp->inp_fport; ! 587: ui->ui_ulen = ui->ui_len; ! 588: ! 589: /* ! 590: * Stuff checksum and output datagram. ! 591: */ ! 592: ui->ui_sum = 0; ! 593: if (udpcksum) { ! 594: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) ! 595: ui->ui_sum = 0xffff; ! 596: } ! 597: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ! 598: ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ ! 599: ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ ! 600: udpstat.udps_opackets++; ! 601: error = ip_output(m, inp->inp_options, &inp->inp_route, ! 602: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), ! 603: inp->inp_moptions); ! 604: ! 605: if (addr) { ! 606: in_pcbdisconnect(inp); ! 607: inp->inp_laddr = laddr; /* XXX rehash? */ ! 608: splx(s); ! 609: } ! 610: return (error); ! 611: ! 612: release: ! 613: m_freem(m); ! 614: return (error); ! 615: } ! 616: ! 617: static u_long udp_sendspace = 9216; /* really max datagram size */ ! 618: /* 40 1K datagrams */ ! 619: SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, ! 620: &udp_sendspace, 0, ""); ! 621: ! 622: static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); ! 623: SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, ! 624: &udp_recvspace, 0, ""); ! 625: ! 626: static int ! 627: udp_abort(struct socket *so) ! 628: { ! 629: struct inpcb *inp; ! 630: int s; ! 631: ! 632: inp = sotoinpcb(so); ! 633: if (inp == 0) ! 634: return EINVAL; /* ??? possible? panic instead? */ ! 635: soisdisconnected(so); ! 636: s = splnet(); ! 637: in_pcbdetach(inp); ! 638: splx(s); ! 639: return 0; ! 640: } ! 641: ! 642: static int ! 643: udp_attach(struct socket *so, int proto, struct proc *p) ! 644: { ! 645: struct inpcb *inp; ! 646: int s, error; ! 647: ! 648: inp = sotoinpcb(so); ! 649: if (inp != 0) ! 650: return EINVAL; ! 651: ! 652: s = splnet(); ! 653: error = in_pcballoc(so, &udbinfo, p); ! 654: splx(s); ! 655: if (error) ! 656: return error; ! 657: error = soreserve(so, udp_sendspace, udp_recvspace); ! 658: if (error) ! 659: return error; ! 660: ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; ! 661: return 0; ! 662: } ! 663: ! 664: static int ! 665: udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p) ! 666: { ! 667: struct inpcb *inp; ! 668: int s, error; ! 669: ! 670: inp = sotoinpcb(so); ! 671: if (inp == 0) ! 672: return EINVAL; ! 673: s = splnet(); ! 674: error = in_pcbbind(inp, nam, p); ! 675: splx(s); ! 676: return error; ! 677: } ! 678: ! 679: static int ! 680: udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p) ! 681: { ! 682: struct inpcb *inp; ! 683: int s, error; ! 684: ! 685: inp = sotoinpcb(so); ! 686: if (inp == 0) ! 687: return EINVAL; ! 688: if (inp->inp_faddr.s_addr != INADDR_ANY) ! 689: return EISCONN; ! 690: s = splnet(); ! 691: error = in_pcbconnect(inp, nam, p); ! 692: splx(s); ! 693: if (error == 0) ! 694: soisconnected(so); ! 695: return error; ! 696: } ! 697: ! 698: static int ! 699: udp_detach(struct socket *so) ! 700: { ! 701: struct inpcb *inp; ! 702: int s; ! 703: ! 704: inp = sotoinpcb(so); ! 705: if (inp == 0) ! 706: return EINVAL; ! 707: s = splnet(); ! 708: in_pcbdetach(inp); ! 709: splx(s); ! 710: return 0; ! 711: } ! 712: ! 713: static int ! 714: udp_disconnect(struct socket *so) ! 715: { ! 716: struct inpcb *inp; ! 717: int s; ! 718: ! 719: inp = sotoinpcb(so); ! 720: if (inp == 0) ! 721: return EINVAL; ! 722: if (inp->inp_faddr.s_addr == INADDR_ANY) ! 723: return ENOTCONN; ! 724: ! 725: s = splnet(); ! 726: in_pcbdisconnect(inp); ! 727: inp->inp_laddr.s_addr = INADDR_ANY; ! 728: splx(s); ! 729: so->so_state &= ~SS_ISCONNECTED; /* XXX */ ! 730: return 0; ! 731: } ! 732: ! 733: static int ! 734: udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, ! 735: struct mbuf *control, struct proc *p) ! 736: { ! 737: struct inpcb *inp; ! 738: ! 739: inp = sotoinpcb(so); ! 740: if (inp == 0) { ! 741: m_freem(m); ! 742: return EINVAL; ! 743: } ! 744: return udp_output(inp, m, addr, control, p); ! 745: } ! 746: ! 747: static int ! 748: udp_shutdown(struct socket *so) ! 749: { ! 750: struct inpcb *inp; ! 751: ! 752: inp = sotoinpcb(so); ! 753: if (inp == 0) ! 754: return EINVAL; ! 755: socantsendmore(so); ! 756: return 0; ! 757: } ! 758: ! 759: struct pr_usrreqs udp_usrreqs = { ! 760: udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect, ! 761: pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, ! 762: pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, ! 763: pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, ! 764: in_setsockaddr, sosend, soreceive, sopoll ! 765: }; ! 766:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.