Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.1
1.1 ! cgd 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: }
CVSweb <webmaster@jp.NetBSD.org>