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