Annotation of sys/netinet/udp_usrreq.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: udp_usrreq.c,v 1.114 2007/06/11 11:29:35 henning Exp $ */
! 2: /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1988, 1990, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
! 33: *
! 34: * NRL grants permission for redistribution and use in source and binary
! 35: * forms, with or without modification, of the software and documentation
! 36: * created at NRL provided that the following conditions are met:
! 37: *
! 38: * 1. Redistributions of source code must retain the above copyright
! 39: * notice, this list of conditions and the following disclaimer.
! 40: * 2. Redistributions in binary form must reproduce the above copyright
! 41: * notice, this list of conditions and the following disclaimer in the
! 42: * documentation and/or other materials provided with the distribution.
! 43: * 3. All advertising materials mentioning features or use of this software
! 44: * must display the following acknowledgements:
! 45: * This product includes software developed by the University of
! 46: * California, Berkeley and its contributors.
! 47: * This product includes software developed at the Information
! 48: * Technology Division, US Naval Research Laboratory.
! 49: * 4. Neither the name of the NRL nor the names of its contributors
! 50: * may be used to endorse or promote products derived from this software
! 51: * without specific prior written permission.
! 52: *
! 53: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
! 54: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
! 56: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
! 57: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 58: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 59: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 60: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 61: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 62: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 63: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 64: *
! 65: * The views and conclusions contained in the software and documentation
! 66: * are those of the authors and should not be interpreted as representing
! 67: * official policies, either expressed or implied, of the US Naval
! 68: * Research Laboratory (NRL).
! 69: */
! 70:
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/mbuf.h>
! 74: #include <sys/protosw.h>
! 75: #include <sys/socket.h>
! 76: #include <sys/socketvar.h>
! 77: #include <sys/sysctl.h>
! 78:
! 79: #include <net/if.h>
! 80: #include <net/route.h>
! 81:
! 82: #include <netinet/in.h>
! 83: #include <netinet/in_systm.h>
! 84: #include <netinet/in_var.h>
! 85: #include <netinet/ip.h>
! 86: #include <netinet/in_pcb.h>
! 87: #include <netinet/ip_var.h>
! 88: #include <netinet/ip_icmp.h>
! 89: #include <netinet/udp.h>
! 90: #include <netinet/udp_var.h>
! 91:
! 92: #ifdef IPSEC
! 93: #include <netinet/ip_ipsp.h>
! 94: #include <netinet/ip_esp.h>
! 95: #endif
! 96:
! 97: #ifdef INET6
! 98: #ifndef INET
! 99: #include <netinet/in.h>
! 100: #endif
! 101: #include <netinet6/ip6protosw.h>
! 102:
! 103: extern int ip6_defhlim;
! 104: #endif /* INET6 */
! 105:
! 106: /*
! 107: * UDP protocol implementation.
! 108: * Per RFC 768, August, 1980.
! 109: */
! 110: int udpcksum = 1;
! 111:
! 112: u_int udp_sendspace = 9216; /* really max datagram size */
! 113: u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
! 114: /* 40 1K datagrams */
! 115:
! 116: int *udpctl_vars[UDPCTL_MAXID] = UDPCTL_VARS;
! 117:
! 118: struct inpcbtable udbtable;
! 119: struct udpstat udpstat;
! 120:
! 121: void udp_detach(struct inpcb *);
! 122: void udp_notify(struct inpcb *, int);
! 123:
! 124: #ifndef UDBHASHSIZE
! 125: #define UDBHASHSIZE 128
! 126: #endif
! 127: int udbhashsize = UDBHASHSIZE;
! 128:
! 129: /* from in_pcb.c */
! 130: extern struct baddynamicports baddynamicports;
! 131:
! 132: void
! 133: udp_init()
! 134: {
! 135: in_pcbinit(&udbtable, udbhashsize);
! 136: }
! 137:
! 138: #ifdef INET6
! 139: int
! 140: udp6_input(mp, offp, proto)
! 141: struct mbuf **mp;
! 142: int *offp, proto;
! 143: {
! 144: struct mbuf *m = *mp;
! 145:
! 146: #if defined(NFAITH) && 0 < NFAITH
! 147: if (m->m_pkthdr.rcvif) {
! 148: if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
! 149: /* XXX send icmp6 host/port unreach? */
! 150: m_freem(m);
! 151: return IPPROTO_DONE;
! 152: }
! 153: }
! 154: #endif
! 155:
! 156: udp_input(m, *offp, proto);
! 157: return IPPROTO_DONE;
! 158: }
! 159: #endif
! 160:
! 161: void
! 162: udp_input(struct mbuf *m, ...)
! 163: {
! 164: struct ip *ip;
! 165: struct udphdr *uh;
! 166: struct inpcb *inp;
! 167: struct mbuf *opts = NULL;
! 168: struct ip save_ip;
! 169: int iphlen, len;
! 170: va_list ap;
! 171: u_int16_t savesum;
! 172: union {
! 173: struct sockaddr sa;
! 174: struct sockaddr_in sin;
! 175: #ifdef INET6
! 176: struct sockaddr_in6 sin6;
! 177: #endif /* INET6 */
! 178: } srcsa, dstsa;
! 179: #ifdef INET6
! 180: struct ip6_hdr *ip6;
! 181: #endif /* INET6 */
! 182: #ifdef IPSEC
! 183: struct m_tag *mtag;
! 184: struct tdb_ident *tdbi;
! 185: struct tdb *tdb;
! 186: int error, s;
! 187: #endif /* IPSEC */
! 188:
! 189: va_start(ap, m);
! 190: iphlen = va_arg(ap, int);
! 191: va_end(ap);
! 192:
! 193: udpstat.udps_ipackets++;
! 194:
! 195: switch (mtod(m, struct ip *)->ip_v) {
! 196: case 4:
! 197: ip = mtod(m, struct ip *);
! 198: #ifdef INET6
! 199: ip6 = NULL;
! 200: #endif /* INET6 */
! 201: srcsa.sa.sa_family = AF_INET;
! 202: break;
! 203: #ifdef INET6
! 204: case 6:
! 205: ip = NULL;
! 206: ip6 = mtod(m, struct ip6_hdr *);
! 207: srcsa.sa.sa_family = AF_INET6;
! 208: break;
! 209: #endif /* INET6 */
! 210: default:
! 211: goto bad;
! 212: }
! 213:
! 214: IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
! 215: if (!uh) {
! 216: udpstat.udps_hdrops++;
! 217: return;
! 218: }
! 219:
! 220: /* Check for illegal destination port 0 */
! 221: if (uh->uh_dport == 0) {
! 222: udpstat.udps_noport++;
! 223: goto bad;
! 224: }
! 225:
! 226: /*
! 227: * Make mbuf data length reflect UDP length.
! 228: * If not enough data to reflect UDP length, drop.
! 229: */
! 230: len = ntohs((u_int16_t)uh->uh_ulen);
! 231: if (ip) {
! 232: if (m->m_pkthdr.len - iphlen != len) {
! 233: if (len > (m->m_pkthdr.len - iphlen) ||
! 234: len < sizeof(struct udphdr)) {
! 235: udpstat.udps_badlen++;
! 236: goto bad;
! 237: }
! 238: m_adj(m, len - (m->m_pkthdr.len - iphlen));
! 239: }
! 240: }
! 241: #ifdef INET6
! 242: else if (ip6) {
! 243: /* jumbograms */
! 244: if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff)
! 245: len = m->m_pkthdr.len - iphlen;
! 246: if (len != m->m_pkthdr.len - iphlen) {
! 247: udpstat.udps_badlen++;
! 248: goto bad;
! 249: }
! 250: }
! 251: #endif
! 252: else /* shouldn't happen */
! 253: goto bad;
! 254:
! 255: /*
! 256: * Save a copy of the IP header in case we want restore it
! 257: * for sending an ICMP error message in response.
! 258: */
! 259: if (ip)
! 260: save_ip = *ip;
! 261:
! 262: /*
! 263: * Checksum extended UDP header and data.
! 264: * from W.R.Stevens: check incoming udp cksums even if
! 265: * udpcksum is not set.
! 266: */
! 267: savesum = uh->uh_sum;
! 268: #ifdef INET6
! 269: if (ip6) {
! 270: /* Be proactive about malicious use of IPv4 mapped address */
! 271: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
! 272: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
! 273: /* XXX stat */
! 274: goto bad;
! 275: }
! 276:
! 277: /*
! 278: * In IPv6, the UDP checksum is ALWAYS used.
! 279: */
! 280: if (uh->uh_sum == 0) {
! 281: udpstat.udps_nosum++;
! 282: goto bad;
! 283: }
! 284: if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, iphlen, len))) {
! 285: udpstat.udps_badsum++;
! 286: goto bad;
! 287: }
! 288: } else
! 289: #endif /* INET6 */
! 290: if (uh->uh_sum) {
! 291: if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
! 292: if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
! 293: udpstat.udps_badsum++;
! 294: udpstat.udps_inhwcsum++;
! 295: m_freem(m);
! 296: return;
! 297: }
! 298:
! 299: if ((uh->uh_sum = in4_cksum(m, IPPROTO_UDP,
! 300: iphlen, len))) {
! 301: udpstat.udps_badsum++;
! 302: m_freem(m);
! 303: return;
! 304: }
! 305: } else {
! 306: m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK;
! 307: udpstat.udps_inhwcsum++;
! 308: }
! 309: } else
! 310: udpstat.udps_nosum++;
! 311:
! 312: #ifdef IPSEC
! 313: if (udpencap_enable && udpencap_port &&
! 314: uh->uh_dport == htons(udpencap_port)) {
! 315: u_int32_t spi;
! 316: int skip = iphlen + sizeof(struct udphdr);
! 317:
! 318: if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) {
! 319: /* packet too short */
! 320: m_freem(m);
! 321: return;
! 322: }
! 323: m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
! 324: /*
! 325: * decapsulate if the SPI is not zero, otherwise pass
! 326: * to userland
! 327: */
! 328: if (spi != 0) {
! 329: if ((m = m_pullup2(m, skip)) == NULL) {
! 330: udpstat.udps_hdrops++;
! 331: return;
! 332: }
! 333:
! 334: /* remove the UDP header */
! 335: bcopy(mtod(m, u_char *),
! 336: mtod(m, u_char *) + sizeof(struct udphdr), iphlen);
! 337: m_adj(m, sizeof(struct udphdr));
! 338: skip -= sizeof(struct udphdr);
! 339:
! 340: espstat.esps_udpencin++;
! 341: ipsec_common_input(m, skip, offsetof(struct ip, ip_p),
! 342: srcsa.sa.sa_family, IPPROTO_ESP, 1);
! 343: return;
! 344: }
! 345: }
! 346: #endif
! 347:
! 348: switch (srcsa.sa.sa_family) {
! 349: case AF_INET:
! 350: bzero(&srcsa, sizeof(struct sockaddr_in));
! 351: srcsa.sin.sin_len = sizeof(struct sockaddr_in);
! 352: srcsa.sin.sin_family = AF_INET;
! 353: srcsa.sin.sin_port = uh->uh_sport;
! 354: srcsa.sin.sin_addr = ip->ip_src;
! 355:
! 356: bzero(&dstsa, sizeof(struct sockaddr_in));
! 357: dstsa.sin.sin_len = sizeof(struct sockaddr_in);
! 358: dstsa.sin.sin_family = AF_INET;
! 359: dstsa.sin.sin_port = uh->uh_dport;
! 360: dstsa.sin.sin_addr = ip->ip_dst;
! 361: break;
! 362: #ifdef INET6
! 363: case AF_INET6:
! 364: bzero(&srcsa, sizeof(struct sockaddr_in6));
! 365: srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
! 366: srcsa.sin6.sin6_family = AF_INET6;
! 367: srcsa.sin6.sin6_port = uh->uh_sport;
! 368: #if 0 /*XXX inbound flowinfo */
! 369: srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow;
! 370: #endif
! 371: /* KAME hack: recover scopeid */
! 372: (void)in6_recoverscope(&srcsa.sin6, &ip6->ip6_src,
! 373: m->m_pkthdr.rcvif);
! 374:
! 375: bzero(&dstsa, sizeof(struct sockaddr_in6));
! 376: dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
! 377: dstsa.sin6.sin6_family = AF_INET6;
! 378: dstsa.sin6.sin6_port = uh->uh_dport;
! 379: /* KAME hack: recover scopeid */
! 380: (void)in6_recoverscope(&dstsa.sin6, &ip6->ip6_dst,
! 381: m->m_pkthdr.rcvif);
! 382: break;
! 383: #endif /* INET6 */
! 384: }
! 385:
! 386: #ifdef INET6
! 387: if ((ip6 && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) ||
! 388: (ip && IN_MULTICAST(ip->ip_dst.s_addr)) ||
! 389: (ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
! 390: #else /* INET6 */
! 391: if (IN_MULTICAST(ip->ip_dst.s_addr) ||
! 392: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
! 393: #endif /* INET6 */
! 394: struct inpcb *last;
! 395: /*
! 396: * Deliver a multicast or broadcast datagram to *all* sockets
! 397: * for which the local and remote addresses and ports match
! 398: * those of the incoming datagram. This allows more than
! 399: * one process to receive multi/broadcasts on the same port.
! 400: * (This really ought to be done for unicast datagrams as
! 401: * well, but that would cause problems with existing
! 402: * applications that open both address-specific sockets and
! 403: * a wildcard socket listening to the same port -- they would
! 404: * end up receiving duplicates of every unicast datagram.
! 405: * Those applications open the multiple sockets to overcome an
! 406: * inadequacy of the UDP socket interface, but for backwards
! 407: * compatibility we avoid the problem here rather than
! 408: * fixing the interface. Maybe 4.5BSD will remedy this?)
! 409: */
! 410:
! 411: iphlen += sizeof(struct udphdr);
! 412:
! 413: /*
! 414: * Locate pcb(s) for datagram.
! 415: * (Algorithm copied from raw_intr().)
! 416: */
! 417: last = NULL;
! 418: CIRCLEQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) {
! 419: #ifdef INET6
! 420: /* don't accept it if AF does not match */
! 421: if (ip6 && !(inp->inp_flags & INP_IPV6))
! 422: continue;
! 423: if (!ip6 && (inp->inp_flags & INP_IPV6))
! 424: continue;
! 425: #endif
! 426: if (inp->inp_lport != uh->uh_dport)
! 427: continue;
! 428: #ifdef INET6
! 429: if (ip6) {
! 430: if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
! 431: if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
! 432: &ip6->ip6_dst))
! 433: continue;
! 434: } else
! 435: #endif /* INET6 */
! 436: if (inp->inp_laddr.s_addr != INADDR_ANY) {
! 437: if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
! 438: continue;
! 439: }
! 440: #ifdef INET6
! 441: if (ip6) {
! 442: if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
! 443: if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
! 444: &ip6->ip6_src) ||
! 445: inp->inp_fport != uh->uh_sport)
! 446: continue;
! 447: } else
! 448: #endif /* INET6 */
! 449: if (inp->inp_faddr.s_addr != INADDR_ANY) {
! 450: if (inp->inp_faddr.s_addr !=
! 451: ip->ip_src.s_addr ||
! 452: inp->inp_fport != uh->uh_sport)
! 453: continue;
! 454: }
! 455:
! 456: if (last != NULL) {
! 457: struct mbuf *n;
! 458:
! 459: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
! 460: #ifdef INET6
! 461: if (ip6 && (last->inp_flags &
! 462: IN6P_CONTROLOPTS))
! 463: ip6_savecontrol(last, n, &opts);
! 464: #endif /* INET6 */
! 465: if (ip && (last->inp_flags &
! 466: INP_CONTROLOPTS))
! 467: ip_savecontrol(last, &opts,
! 468: ip, n);
! 469:
! 470: m_adj(n, iphlen);
! 471: if (sbappendaddr(
! 472: &last->inp_socket->so_rcv,
! 473: &srcsa.sa, n, opts) == 0) {
! 474: m_freem(n);
! 475: if (opts)
! 476: m_freem(opts);
! 477: udpstat.udps_fullsock++;
! 478: } else
! 479: sorwakeup(last->inp_socket);
! 480: opts = NULL;
! 481: }
! 482: }
! 483: last = inp;
! 484: /*
! 485: * Don't look for additional matches if this one does
! 486: * not have either the SO_REUSEPORT or SO_REUSEADDR
! 487: * socket options set. This heuristic avoids searching
! 488: * through all pcbs in the common case of a non-shared
! 489: * port. It * assumes that an application will never
! 490: * clear these options after setting them.
! 491: */
! 492: if ((last->inp_socket->so_options & (SO_REUSEPORT |
! 493: SO_REUSEADDR)) == 0)
! 494: break;
! 495: }
! 496:
! 497: if (last == NULL) {
! 498: /*
! 499: * No matching pcb found; discard datagram.
! 500: * (No need to send an ICMP Port Unreachable
! 501: * for a broadcast or multicast datgram.)
! 502: */
! 503: udpstat.udps_noportbcast++;
! 504: goto bad;
! 505: }
! 506:
! 507: #ifdef INET6
! 508: if (ip6 && (last->inp_flags & IN6P_CONTROLOPTS))
! 509: ip6_savecontrol(last, m, &opts);
! 510: #endif /* INET6 */
! 511: if (ip && (last->inp_flags & INP_CONTROLOPTS))
! 512: ip_savecontrol(last, &opts, ip, m);
! 513:
! 514: m_adj(m, iphlen);
! 515: if (sbappendaddr(&last->inp_socket->so_rcv,
! 516: &srcsa.sa, m, opts) == 0) {
! 517: udpstat.udps_fullsock++;
! 518: goto bad;
! 519: }
! 520: sorwakeup(last->inp_socket);
! 521: return;
! 522: }
! 523: /*
! 524: * Locate pcb for datagram.
! 525: */
! 526: #ifdef INET6
! 527: if (ip6)
! 528: inp = in6_pcbhashlookup(&udbtable, &ip6->ip6_src, uh->uh_sport,
! 529: &ip6->ip6_dst, uh->uh_dport);
! 530: else
! 531: #endif /* INET6 */
! 532: inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
! 533: ip->ip_dst, uh->uh_dport);
! 534: if (inp == 0) {
! 535: int inpl_reverse = 0;
! 536: if (m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST)
! 537: inpl_reverse = 1;
! 538: ++udpstat.udps_pcbhashmiss;
! 539: #ifdef INET6
! 540: if (ip6) {
! 541: inp = in6_pcblookup_listen(&udbtable,
! 542: &ip6->ip6_dst, uh->uh_dport, inpl_reverse);
! 543: } else
! 544: #endif /* INET6 */
! 545: inp = in_pcblookup_listen(&udbtable,
! 546: ip->ip_dst, uh->uh_dport, inpl_reverse);
! 547: if (inp == 0) {
! 548: udpstat.udps_noport++;
! 549: if (m->m_flags & (M_BCAST | M_MCAST)) {
! 550: udpstat.udps_noportbcast++;
! 551: goto bad;
! 552: }
! 553: #ifdef INET6
! 554: if (ip6) {
! 555: uh->uh_sum = savesum;
! 556: icmp6_error(m, ICMP6_DST_UNREACH,
! 557: ICMP6_DST_UNREACH_NOPORT,0);
! 558: } else
! 559: #endif /* INET6 */
! 560: {
! 561: *ip = save_ip;
! 562: uh->uh_sum = savesum;
! 563: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
! 564: 0, 0);
! 565: }
! 566: return;
! 567: }
! 568: }
! 569:
! 570: #ifdef IPSEC
! 571: mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
! 572: s = splnet();
! 573: if (mtag != NULL) {
! 574: tdbi = (struct tdb_ident *)(mtag + 1);
! 575: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
! 576: } else
! 577: tdb = NULL;
! 578: ipsp_spd_lookup(m, srcsa.sa.sa_family, iphlen, &error,
! 579: IPSP_DIRECTION_IN, tdb, inp);
! 580: if (error) {
! 581: splx(s);
! 582: goto bad;
! 583: }
! 584:
! 585: /* Latch SA only if the socket is connected */
! 586: if (inp->inp_tdb_in != tdb &&
! 587: (inp->inp_socket->so_state & SS_ISCONNECTED)) {
! 588: if (tdb) {
! 589: tdb_add_inp(tdb, inp, 1);
! 590: if (inp->inp_ipo == NULL) {
! 591: inp->inp_ipo = ipsec_add_policy(inp,
! 592: srcsa.sa.sa_family, IPSP_DIRECTION_OUT);
! 593: if (inp->inp_ipo == NULL) {
! 594: splx(s);
! 595: goto bad;
! 596: }
! 597: }
! 598: if (inp->inp_ipo->ipo_dstid == NULL &&
! 599: tdb->tdb_srcid != NULL) {
! 600: inp->inp_ipo->ipo_dstid = tdb->tdb_srcid;
! 601: tdb->tdb_srcid->ref_count++;
! 602: }
! 603: if (inp->inp_ipsec_remotecred == NULL &&
! 604: tdb->tdb_remote_cred != NULL) {
! 605: inp->inp_ipsec_remotecred =
! 606: tdb->tdb_remote_cred;
! 607: tdb->tdb_remote_cred->ref_count++;
! 608: }
! 609: if (inp->inp_ipsec_remoteauth == NULL &&
! 610: tdb->tdb_remote_auth != NULL) {
! 611: inp->inp_ipsec_remoteauth =
! 612: tdb->tdb_remote_auth;
! 613: tdb->tdb_remote_auth->ref_count++;
! 614: }
! 615: } else { /* Just reset */
! 616: TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp,
! 617: inp_tdb_in_next);
! 618: inp->inp_tdb_in = NULL;
! 619: }
! 620: }
! 621: splx(s);
! 622: #endif /*IPSEC */
! 623:
! 624: opts = NULL;
! 625: #ifdef INET6
! 626: if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS))
! 627: ip6_savecontrol(inp, m, &opts);
! 628: #endif /* INET6 */
! 629: if (ip && (inp->inp_flags & INP_CONTROLOPTS))
! 630: ip_savecontrol(inp, &opts, ip, m);
! 631:
! 632: iphlen += sizeof(struct udphdr);
! 633: m_adj(m, iphlen);
! 634: if (sbappendaddr(&inp->inp_socket->so_rcv, &srcsa.sa, m, opts) == 0) {
! 635: udpstat.udps_fullsock++;
! 636: goto bad;
! 637: }
! 638: sorwakeup(inp->inp_socket);
! 639: return;
! 640: bad:
! 641: m_freem(m);
! 642: if (opts)
! 643: m_freem(opts);
! 644: }
! 645:
! 646: /*
! 647: * Notify a udp user of an asynchronous error;
! 648: * just wake up so that he can collect error status.
! 649: */
! 650: void
! 651: udp_notify(inp, errno)
! 652: struct inpcb *inp;
! 653: int errno;
! 654: {
! 655: inp->inp_socket->so_error = errno;
! 656: sorwakeup(inp->inp_socket);
! 657: sowwakeup(inp->inp_socket);
! 658: }
! 659:
! 660: #ifdef INET6
! 661: void
! 662: udp6_ctlinput(cmd, sa, d)
! 663: int cmd;
! 664: struct sockaddr *sa;
! 665: void *d;
! 666: {
! 667: struct udphdr uh;
! 668: struct sockaddr_in6 sa6;
! 669: struct ip6_hdr *ip6;
! 670: struct mbuf *m;
! 671: int off;
! 672: void *cmdarg;
! 673: struct ip6ctlparam *ip6cp = NULL;
! 674: struct udp_portonly {
! 675: u_int16_t uh_sport;
! 676: u_int16_t uh_dport;
! 677: } *uhp;
! 678: void (*notify)(struct inpcb *, int) = udp_notify;
! 679:
! 680: if (sa == NULL)
! 681: return;
! 682: if (sa->sa_family != AF_INET6 ||
! 683: sa->sa_len != sizeof(struct sockaddr_in6))
! 684: return;
! 685:
! 686: if ((unsigned)cmd >= PRC_NCMDS)
! 687: return;
! 688: if (PRC_IS_REDIRECT(cmd))
! 689: notify = in_rtchange, d = NULL;
! 690: else if (cmd == PRC_HOSTDEAD)
! 691: d = NULL;
! 692: else if (cmd == PRC_MSGSIZE)
! 693: ; /* special code is present, see below */
! 694: else if (inet6ctlerrmap[cmd] == 0)
! 695: return;
! 696:
! 697: /* if the parameter is from icmp6, decode it. */
! 698: if (d != NULL) {
! 699: ip6cp = (struct ip6ctlparam *)d;
! 700: m = ip6cp->ip6c_m;
! 701: ip6 = ip6cp->ip6c_ip6;
! 702: off = ip6cp->ip6c_off;
! 703: cmdarg = ip6cp->ip6c_cmdarg;
! 704: } else {
! 705: m = NULL;
! 706: ip6 = NULL;
! 707: cmdarg = NULL;
! 708: /* XXX: translate addresses into internal form */
! 709: sa6 = *(struct sockaddr_in6 *)sa;
! 710: #ifndef SCOPEDROUTING
! 711: if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL, NULL)) {
! 712: /* should be impossible */
! 713: return;
! 714: }
! 715: #endif
! 716: }
! 717:
! 718: if (ip6cp && ip6cp->ip6c_finaldst) {
! 719: bzero(&sa6, sizeof(sa6));
! 720: sa6.sin6_family = AF_INET6;
! 721: sa6.sin6_len = sizeof(sa6);
! 722: sa6.sin6_addr = *ip6cp->ip6c_finaldst;
! 723: /* XXX: assuming M is valid in this case */
! 724: sa6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
! 725: ip6cp->ip6c_finaldst);
! 726: #ifndef SCOPEDROUTING
! 727: if (in6_embedscope(ip6cp->ip6c_finaldst, &sa6, NULL, NULL)) {
! 728: /* should be impossible */
! 729: return;
! 730: }
! 731: #endif
! 732: } else {
! 733: /* XXX: translate addresses into internal form */
! 734: sa6 = *(struct sockaddr_in6 *)sa;
! 735: #ifndef SCOPEDROUTING
! 736: if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL, NULL)) {
! 737: /* should be impossible */
! 738: return;
! 739: }
! 740: #endif
! 741: }
! 742:
! 743: if (ip6) {
! 744: /*
! 745: * XXX: We assume that when IPV6 is non NULL,
! 746: * M and OFF are valid.
! 747: */
! 748: struct sockaddr_in6 sa6_src;
! 749:
! 750: /* check if we can safely examine src and dst ports */
! 751: if (m->m_pkthdr.len < off + sizeof(*uhp))
! 752: return;
! 753:
! 754: bzero(&uh, sizeof(uh));
! 755: m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
! 756:
! 757: bzero(&sa6_src, sizeof(sa6_src));
! 758: sa6_src.sin6_family = AF_INET6;
! 759: sa6_src.sin6_len = sizeof(sa6_src);
! 760: sa6_src.sin6_addr = ip6->ip6_src;
! 761: sa6_src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
! 762: &ip6->ip6_src);
! 763: #ifndef SCOPEDROUTING
! 764: if (in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL, NULL)) {
! 765: /* should be impossible */
! 766: return;
! 767: }
! 768: #endif
! 769:
! 770: if (cmd == PRC_MSGSIZE) {
! 771: int valid = 0;
! 772:
! 773: /*
! 774: * Check to see if we have a valid UDP socket
! 775: * corresponding to the address in the ICMPv6 message
! 776: * payload.
! 777: */
! 778: if (in6_pcbhashlookup(&udbtable, &sa6.sin6_addr,
! 779: uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport))
! 780: valid = 1;
! 781: #if 0
! 782: /*
! 783: * As the use of sendto(2) is fairly popular,
! 784: * we may want to allow non-connected pcb too.
! 785: * But it could be too weak against attacks...
! 786: * We should at least check if the local address (= s)
! 787: * is really ours.
! 788: */
! 789: else if (in6_pcblookup_listen(&udbtable,
! 790: &sa6_src.sin6_addr, uh.uh_sport, 0);
! 791: valid = 1;
! 792: #endif
! 793:
! 794: /*
! 795: * Depending on the value of "valid" and routing table
! 796: * size (mtudisc_{hi,lo}wat), we will:
! 797: * - recalculate the new MTU and create the
! 798: * corresponding routing entry, or
! 799: * - ignore the MTU change notification.
! 800: */
! 801: icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
! 802:
! 803: /*
! 804: * regardless of if we called icmp6_mtudisc_update(),
! 805: * we need to call in6_pcbnotify(), to notify path
! 806: * MTU change to the userland (2292bis-02), because
! 807: * some unconnected sockets may share the same
! 808: * destination and want to know the path MTU.
! 809: */
! 810: }
! 811:
! 812: (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6,
! 813: uh.uh_dport, (struct sockaddr *)&sa6_src,
! 814: uh.uh_sport, cmd, cmdarg, notify);
! 815: } else {
! 816: (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6, 0,
! 817: (struct sockaddr *)&sa6_any, 0, cmd, cmdarg, notify);
! 818: }
! 819: }
! 820: #endif
! 821:
! 822: void *
! 823: udp_ctlinput(cmd, sa, v)
! 824: int cmd;
! 825: struct sockaddr *sa;
! 826: void *v;
! 827: {
! 828: struct ip *ip = v;
! 829: struct udphdr *uhp;
! 830: struct in_addr faddr;
! 831: struct inpcb *inp;
! 832: extern int inetctlerrmap[];
! 833: void (*notify)(struct inpcb *, int) = udp_notify;
! 834: int errno;
! 835:
! 836: if (sa == NULL)
! 837: return NULL;
! 838: if (sa->sa_family != AF_INET ||
! 839: sa->sa_len != sizeof(struct sockaddr_in))
! 840: return NULL;
! 841: faddr = satosin(sa)->sin_addr;
! 842: if (faddr.s_addr == INADDR_ANY)
! 843: return NULL;
! 844:
! 845: if ((unsigned)cmd >= PRC_NCMDS)
! 846: return NULL;
! 847: errno = inetctlerrmap[cmd];
! 848: if (PRC_IS_REDIRECT(cmd))
! 849: notify = in_rtchange, ip = 0;
! 850: else if (cmd == PRC_HOSTDEAD)
! 851: ip = 0;
! 852: else if (errno == 0)
! 853: return NULL;
! 854: if (ip) {
! 855: uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
! 856:
! 857: #ifdef IPSEC
! 858: /* PMTU discovery for udpencap */
! 859: if (cmd == PRC_MSGSIZE && ip_mtudisc && udpencap_enable &&
! 860: udpencap_port && uhp->uh_sport == htons(udpencap_port)) {
! 861: udpencap_ctlinput(cmd, sa, v);
! 862: return (NULL);
! 863: }
! 864: #endif
! 865: inp = in_pcbhashlookup(&udbtable,
! 866: ip->ip_dst, uhp->uh_dport, ip->ip_src, uhp->uh_sport);
! 867: if (inp && inp->inp_socket != NULL)
! 868: notify(inp, errno);
! 869: } else
! 870: in_pcbnotifyall(&udbtable, sa, errno, notify);
! 871: return (NULL);
! 872: }
! 873:
! 874: int
! 875: udp_output(struct mbuf *m, ...)
! 876: {
! 877: struct inpcb *inp;
! 878: struct mbuf *addr, *control;
! 879: struct udpiphdr *ui;
! 880: int len = m->m_pkthdr.len;
! 881: struct in_addr laddr;
! 882: int s = 0, error = 0;
! 883: va_list ap;
! 884:
! 885: va_start(ap, m);
! 886: inp = va_arg(ap, struct inpcb *);
! 887: addr = va_arg(ap, struct mbuf *);
! 888: control = va_arg(ap, struct mbuf *);
! 889: va_end(ap);
! 890:
! 891: #ifdef DIAGNOSTIC
! 892: if ((inp->inp_flags & INP_IPV6) != 0)
! 893: panic("IPv6 inpcb to udp_output");
! 894: #endif
! 895:
! 896: /*
! 897: * Compute the packet length of the IP header, and
! 898: * punt if the length looks bogus.
! 899: */
! 900: if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
! 901: error = EMSGSIZE;
! 902: goto release;
! 903: }
! 904:
! 905: if (addr) {
! 906: laddr = inp->inp_laddr;
! 907: if (inp->inp_faddr.s_addr != INADDR_ANY) {
! 908: error = EISCONN;
! 909: goto release;
! 910: }
! 911: /*
! 912: * Must block input while temporarily connected.
! 913: */
! 914: s = splsoftnet();
! 915: error = in_pcbconnect(inp, addr);
! 916: if (error) {
! 917: splx(s);
! 918: goto release;
! 919: }
! 920: } else {
! 921: if (inp->inp_faddr.s_addr == INADDR_ANY) {
! 922: error = ENOTCONN;
! 923: goto release;
! 924: }
! 925: }
! 926: /*
! 927: * Calculate data length and get a mbuf
! 928: * for UDP and IP headers.
! 929: */
! 930: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
! 931: if (m == 0) {
! 932: error = ENOBUFS;
! 933: goto bail;
! 934: }
! 935:
! 936: /*
! 937: * Fill in mbuf with extended UDP header
! 938: * and addresses and length put into network format.
! 939: */
! 940: ui = mtod(m, struct udpiphdr *);
! 941: bzero(ui->ui_x1, sizeof ui->ui_x1);
! 942: ui->ui_pr = IPPROTO_UDP;
! 943: ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
! 944: ui->ui_src = inp->inp_laddr;
! 945: ui->ui_dst = inp->inp_faddr;
! 946: ui->ui_sport = inp->inp_lport;
! 947: ui->ui_dport = inp->inp_fport;
! 948: ui->ui_ulen = ui->ui_len;
! 949:
! 950: /*
! 951: * Compute the pseudo-header checksum; defer further checksumming
! 952: * until ip_output() or hardware (if it exists).
! 953: */
! 954: if (udpcksum) {
! 955: m->m_pkthdr.csum_flags |= M_UDPV4_CSUM_OUT;
! 956: ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr,
! 957: ui->ui_dst.s_addr, htons((u_int16_t)len +
! 958: sizeof (struct udphdr) + IPPROTO_UDP));
! 959: } else
! 960: ui->ui_sum = 0;
! 961: ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len);
! 962: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;
! 963: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;
! 964:
! 965: udpstat.udps_opackets++;
! 966: error = ip_output(m, inp->inp_options, &inp->inp_route,
! 967: inp->inp_socket->so_options &
! 968: (SO_DONTROUTE | SO_BROADCAST | SO_JUMBO),
! 969: inp->inp_moptions, inp);
! 970:
! 971: bail:
! 972: if (addr) {
! 973: inp->inp_laddr = laddr;
! 974: in_pcbdisconnect(inp);
! 975: splx(s);
! 976: }
! 977: if (control)
! 978: m_freem(control);
! 979: return (error);
! 980:
! 981: release:
! 982: m_freem(m);
! 983: if (control)
! 984: m_freem(control);
! 985: return (error);
! 986: }
! 987:
! 988: #ifdef INET6
! 989: /*ARGSUSED*/
! 990: int
! 991: udp6_usrreq(so, req, m, addr, control, p)
! 992: struct socket *so;
! 993: int req;
! 994: struct mbuf *m, *addr, *control;
! 995: struct proc *p;
! 996: {
! 997:
! 998: return udp_usrreq(so, req, m, addr, control);
! 999: }
! 1000: #endif
! 1001:
! 1002: /*ARGSUSED*/
! 1003: int
! 1004: udp_usrreq(so, req, m, addr, control)
! 1005: struct socket *so;
! 1006: int req;
! 1007: struct mbuf *m, *addr, *control;
! 1008: {
! 1009: struct inpcb *inp = sotoinpcb(so);
! 1010: int error = 0;
! 1011: int s;
! 1012:
! 1013: if (req == PRU_CONTROL) {
! 1014: #ifdef INET6
! 1015: if (inp->inp_flags & INP_IPV6)
! 1016: return (in6_control(so, (u_long)m, (caddr_t)addr,
! 1017: (struct ifnet *)control, 0));
! 1018: else
! 1019: #endif /* INET6 */
! 1020: return (in_control(so, (u_long)m, (caddr_t)addr,
! 1021: (struct ifnet *)control));
! 1022: }
! 1023: if (inp == NULL && req != PRU_ATTACH) {
! 1024: error = EINVAL;
! 1025: goto release;
! 1026: }
! 1027: /*
! 1028: * Note: need to block udp_input while changing
! 1029: * the udp pcb queue and/or pcb addresses.
! 1030: */
! 1031: switch (req) {
! 1032:
! 1033: case PRU_ATTACH:
! 1034: if (inp != NULL) {
! 1035: error = EINVAL;
! 1036: break;
! 1037: }
! 1038: s = splsoftnet();
! 1039: error = in_pcballoc(so, &udbtable);
! 1040: splx(s);
! 1041: if (error)
! 1042: break;
! 1043: error = soreserve(so, udp_sendspace, udp_recvspace);
! 1044: if (error)
! 1045: break;
! 1046: #ifdef INET6
! 1047: if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
! 1048: ((struct inpcb *) so->so_pcb)->inp_ipv6.ip6_hlim =
! 1049: ip6_defhlim;
! 1050: else
! 1051: #endif /* INET6 */
! 1052: ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
! 1053: break;
! 1054:
! 1055: case PRU_DETACH:
! 1056: udp_detach(inp);
! 1057: break;
! 1058:
! 1059: case PRU_BIND:
! 1060: s = splsoftnet();
! 1061: #ifdef INET6
! 1062: if (inp->inp_flags & INP_IPV6)
! 1063: error = in6_pcbbind(inp, addr);
! 1064: else
! 1065: #endif
! 1066: error = in_pcbbind(inp, addr);
! 1067: splx(s);
! 1068: break;
! 1069:
! 1070: case PRU_LISTEN:
! 1071: error = EOPNOTSUPP;
! 1072: break;
! 1073:
! 1074: case PRU_CONNECT:
! 1075: #ifdef INET6
! 1076: if (inp->inp_flags & INP_IPV6) {
! 1077: if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
! 1078: error = EISCONN;
! 1079: break;
! 1080: }
! 1081: s = splsoftnet();
! 1082: error = in6_pcbconnect(inp, addr);
! 1083: splx(s);
! 1084: } else
! 1085: #endif /* INET6 */
! 1086: {
! 1087: if (inp->inp_faddr.s_addr != INADDR_ANY) {
! 1088: error = EISCONN;
! 1089: break;
! 1090: }
! 1091: s = splsoftnet();
! 1092: error = in_pcbconnect(inp, addr);
! 1093: splx(s);
! 1094: }
! 1095:
! 1096: if (error == 0)
! 1097: soisconnected(so);
! 1098: break;
! 1099:
! 1100: case PRU_CONNECT2:
! 1101: error = EOPNOTSUPP;
! 1102: break;
! 1103:
! 1104: case PRU_ACCEPT:
! 1105: error = EOPNOTSUPP;
! 1106: break;
! 1107:
! 1108: case PRU_DISCONNECT:
! 1109: #ifdef INET6
! 1110: if (inp->inp_flags & INP_IPV6) {
! 1111: if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
! 1112: error = ENOTCONN;
! 1113: break;
! 1114: }
! 1115: } else
! 1116: #endif /* INET6 */
! 1117: {
! 1118: if (inp->inp_faddr.s_addr == INADDR_ANY) {
! 1119: error = ENOTCONN;
! 1120: break;
! 1121: }
! 1122: }
! 1123:
! 1124: s = splsoftnet();
! 1125: #ifdef INET6
! 1126: if (inp->inp_flags & INP_IPV6)
! 1127: inp->inp_laddr6 = in6addr_any;
! 1128: else
! 1129: #endif /* INET6 */
! 1130: inp->inp_laddr.s_addr = INADDR_ANY;
! 1131: in_pcbdisconnect(inp);
! 1132:
! 1133: splx(s);
! 1134: so->so_state &= ~SS_ISCONNECTED; /* XXX */
! 1135: break;
! 1136:
! 1137: case PRU_SHUTDOWN:
! 1138: socantsendmore(so);
! 1139: break;
! 1140:
! 1141: case PRU_SEND:
! 1142: #ifdef INET6
! 1143: if (inp->inp_flags & INP_IPV6)
! 1144: return (udp6_output(inp, m, addr, control));
! 1145: else
! 1146: return (udp_output(m, inp, addr, control));
! 1147: #else
! 1148: return (udp_output(m, inp, addr, control));
! 1149: #endif
! 1150:
! 1151: case PRU_ABORT:
! 1152: soisdisconnected(so);
! 1153: udp_detach(inp);
! 1154: break;
! 1155:
! 1156: case PRU_SOCKADDR:
! 1157: #ifdef INET6
! 1158: if (inp->inp_flags & INP_IPV6)
! 1159: in6_setsockaddr(inp, addr);
! 1160: else
! 1161: #endif /* INET6 */
! 1162: in_setsockaddr(inp, addr);
! 1163: break;
! 1164:
! 1165: case PRU_PEERADDR:
! 1166: #ifdef INET6
! 1167: if (inp->inp_flags & INP_IPV6)
! 1168: in6_setpeeraddr(inp, addr);
! 1169: else
! 1170: #endif /* INET6 */
! 1171: in_setpeeraddr(inp, addr);
! 1172: break;
! 1173:
! 1174: case PRU_SENSE:
! 1175: /*
! 1176: * stat: don't bother with a blocksize.
! 1177: */
! 1178: /*
! 1179: * Perhaps Path MTU might be returned for a connected
! 1180: * UDP socket in this case.
! 1181: */
! 1182: return (0);
! 1183:
! 1184: case PRU_SENDOOB:
! 1185: case PRU_FASTTIMO:
! 1186: case PRU_SLOWTIMO:
! 1187: case PRU_PROTORCV:
! 1188: case PRU_PROTOSEND:
! 1189: error = EOPNOTSUPP;
! 1190: break;
! 1191:
! 1192: case PRU_RCVD:
! 1193: case PRU_RCVOOB:
! 1194: return (EOPNOTSUPP); /* do not free mbuf's */
! 1195:
! 1196: default:
! 1197: panic("udp_usrreq");
! 1198: }
! 1199:
! 1200: release:
! 1201: if (control) {
! 1202: m_freem(control);
! 1203: }
! 1204: if (m)
! 1205: m_freem(m);
! 1206: return (error);
! 1207: }
! 1208:
! 1209: void
! 1210: udp_detach(inp)
! 1211: struct inpcb *inp;
! 1212: {
! 1213: int s = splsoftnet();
! 1214:
! 1215: in_pcbdetach(inp);
! 1216: splx(s);
! 1217: }
! 1218:
! 1219: /*
! 1220: * Sysctl for udp variables.
! 1221: */
! 1222: int
! 1223: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
! 1224: int *name;
! 1225: u_int namelen;
! 1226: void *oldp;
! 1227: size_t *oldlenp;
! 1228: void *newp;
! 1229: size_t newlen;
! 1230: {
! 1231: /* All sysctl names at this level are terminal. */
! 1232: if (namelen != 1)
! 1233: return (ENOTDIR);
! 1234:
! 1235: switch (name[0]) {
! 1236: case UDPCTL_BADDYNAMIC:
! 1237: return (sysctl_struct(oldp, oldlenp, newp, newlen,
! 1238: baddynamicports.udp, sizeof(baddynamicports.udp)));
! 1239: default:
! 1240: if (name[0] < UDPCTL_MAXID)
! 1241: return (sysctl_int_arr(udpctl_vars, name, namelen,
! 1242: oldp, oldlenp, newp, newlen));
! 1243: return (ENOPROTOOPT);
! 1244: }
! 1245: /* NOTREACHED */
! 1246: }
CVSweb