1 /* 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 3 * The Regents of the University of California. 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 8.6 (Berkeley) 5/23/95 34 * $Id: udp_usrreq.c,v 1.13 1995/08/17 22:09:14 olah Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/protosw.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/errno.h> 45 #include <sys/stat.h> 46 #include <sys/queue.h> 47 #include <vm/vm.h> 48 #include <sys/sysctl.h> 49 50 #include <net/if.h> 51 #include <net/route.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 #include <netinet/in_pcb.h> 57 #include <netinet/in_var.h> 58 #include <netinet/ip_var.h> 59 #include <netinet/ip_icmp.h> 60 #include <netinet/udp.h> 61 #include <netinet/udp_var.h> 62 63 /* 64 * UDP protocol implementation. 65 * Per RFC 768, August, 1980. 66 */ 67 #ifndef COMPAT_42 68 int udpcksum = 1; 69 #else 70 int udpcksum = 0; /* XXX */ 71 #endif 72 73 struct inpcbhead udb; /* from udp_var.h */ 74 struct inpcbinfo udbinfo; 75 76 #ifndef UDBHASHSIZE 77 #define UDBHASHSIZE 64 78 #endif 79 80 struct udpstat udpstat; /* from udp_var.h */ 81 82 struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 83 84 static void udp_detach __P((struct inpcb *)); 85 static void udp_notify __P((struct inpcb *, int)); 86 static struct mbuf *udp_saveopt __P((caddr_t, int, int)); 87 88 void 89 udp_init() 90 { 91 LIST_INIT(&udb); 92 udbinfo.listhead = &udb; 93 udbinfo.hashbase = phashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashsize); 94 } 95 96 void 97 udp_input(m, iphlen) 98 register struct mbuf *m; 99 int iphlen; 100 { 101 register struct ip *ip; 102 register struct udphdr *uh; 103 register struct inpcb *inp; 104 struct mbuf *opts = 0; 105 int len; 106 struct ip save_ip; 107 108 udpstat.udps_ipackets++; 109 110 /* 111 * Strip IP options, if any; should skip this, 112 * make available to user, and use on returned packets, 113 * but we don't yet have a way to check the checksum 114 * with options still present. 115 */ 116 if (iphlen > sizeof (struct ip)) { 117 ip_stripoptions(m, (struct mbuf *)0); 118 iphlen = sizeof(struct ip); 119 } 120 121 /* 122 * Get IP and UDP header together in first mbuf. 123 */ 124 ip = mtod(m, struct ip *); 125 if (m->m_len < iphlen + sizeof(struct udphdr)) { 126 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 127 udpstat.udps_hdrops++; 128 return; 129 } 130 ip = mtod(m, struct ip *); 131 } 132 uh = (struct udphdr *)((caddr_t)ip + iphlen); 133 134 /* 135 * Make mbuf data length reflect UDP length. 136 * If not enough data to reflect UDP length, drop. 137 */ 138 len = ntohs((u_short)uh->uh_ulen); 139 if (ip->ip_len != len) { 140 if (len > ip->ip_len || len < sizeof(struct udphdr)) { 141 udpstat.udps_badlen++; 142 goto bad; 143 } 144 m_adj(m, len - ip->ip_len); 145 /* ip->ip_len = len; */ 146 } 147 /* 148 * Save a copy of the IP header in case we want restore it 149 * for sending an ICMP error message in response. 150 */ 151 save_ip = *ip; 152 153 /* 154 * Checksum extended UDP header and data. 155 */ 156 if (uh->uh_sum) { 157 ((struct ipovly *)ip)->ih_next = 0; 158 ((struct ipovly *)ip)->ih_prev = 0; 159 ((struct ipovly *)ip)->ih_x1 = 0; 160 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 161 uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); 162 if (uh->uh_sum) { 163 udpstat.udps_badsum++; 164 m_freem(m); 165 return; 166 } 167 } 168 169 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 170 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 171 struct socket *last; 172 /* 173 * Deliver a multicast or broadcast datagram to *all* sockets 174 * for which the local and remote addresses and ports match 175 * those of the incoming datagram. This allows more than 176 * one process to receive multi/broadcasts on the same port. 177 * (This really ought to be done for unicast datagrams as 178 * well, but that would cause problems with existing 179 * applications that open both address-specific sockets and 180 * a wildcard socket listening to the same port -- they would 181 * end up receiving duplicates of every unicast datagram. 182 * Those applications open the multiple sockets to overcome an 183 * inadequacy of the UDP socket interface, but for backwards 184 * compatibility we avoid the problem here rather than 185 * fixing the interface. Maybe 4.5BSD will remedy this?) 186 */ 187 188 /* 189 * Construct sockaddr format source address. 190 */ 191 udp_in.sin_port = uh->uh_sport; 192 udp_in.sin_addr = ip->ip_src; 193 m->m_len -= sizeof (struct udpiphdr); 194 m->m_data += sizeof (struct udpiphdr); 195 /* 196 * Locate pcb(s) for datagram. 197 * (Algorithm copied from raw_intr().) 198 */ 199 last = NULL; 200 for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 201 if (inp->inp_lport != uh->uh_dport) 202 continue; 203 if (inp->inp_laddr.s_addr != INADDR_ANY) { 204 if (inp->inp_laddr.s_addr != 205 ip->ip_dst.s_addr) 206 continue; 207 } 208 if (inp->inp_faddr.s_addr != INADDR_ANY) { 209 if (inp->inp_faddr.s_addr != 210 ip->ip_src.s_addr || 211 inp->inp_fport != uh->uh_sport) 212 continue; 213 } 214 215 if (last != NULL) { 216 struct mbuf *n; 217 218 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 219 if (sbappendaddr(&last->so_rcv, 220 (struct sockaddr *)&udp_in, 221 n, (struct mbuf *)0) == 0) { 222 m_freem(n); 223 udpstat.udps_fullsock++; 224 } else 225 sorwakeup(last); 226 } 227 } 228 last = inp->inp_socket; 229 /* 230 * Don't look for additional matches if this one does 231 * not have either the SO_REUSEPORT or SO_REUSEADDR 232 * socket options set. This heuristic avoids searching 233 * through all pcbs in the common case of a non-shared 234 * port. It * assumes that an application will never 235 * clear these options after setting them. 236 */ 237 if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) 238 break; 239 } 240 241 if (last == NULL) { 242 /* 243 * No matching pcb found; discard datagram. 244 * (No need to send an ICMP Port Unreachable 245 * for a broadcast or multicast datgram.) 246 */ 247 udpstat.udps_noportbcast++; 248 goto bad; 249 } 250 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, 251 m, (struct mbuf *)0) == 0) { 252 udpstat.udps_fullsock++; 253 goto bad; 254 } 255 sorwakeup(last); 256 return; 257 } 258 /* 259 * Locate pcb for datagram. First look for an exact match. 260 */ 261 inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport, 262 ip->ip_dst, uh->uh_dport); 263 /* 264 * ...and if that fails, do a wildcard search. 265 */ 266 if (inp == NULL) { 267 inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, ip->ip_dst, 268 uh->uh_dport, INPLOOKUP_WILDCARD); 269 } 270 if (inp == NULL) { 271 udpstat.udps_noport++; 272 if (m->m_flags & (M_BCAST | M_MCAST)) { 273 udpstat.udps_noportbcast++; 274 goto bad; 275 } 276 *ip = save_ip; 277 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 278 return; 279 } 280 281 /* 282 * Construct sockaddr format source address. 283 * Stuff source address and datagram in user buffer. 284 */ 285 udp_in.sin_port = uh->uh_sport; 286 udp_in.sin_addr = ip->ip_src; 287 if (inp->inp_flags & INP_CONTROLOPTS) { 288 struct mbuf **mp = &opts; 289 290 if (inp->inp_flags & INP_RECVDSTADDR) { 291 *mp = udp_saveopt((caddr_t) &ip->ip_dst, 292 sizeof(struct in_addr), IP_RECVDSTADDR); 293 if (*mp) 294 mp = &(*mp)->m_next; 295 } 296 #ifdef notyet 297 /* options were tossed above */ 298 if (inp->inp_flags & INP_RECVOPTS) { 299 *mp = udp_saveopt((caddr_t) opts_deleted_above, 300 sizeof(struct in_addr), IP_RECVOPTS); 301 if (*mp) 302 mp = &(*mp)->m_next; 303 } 304 /* ip_srcroute doesn't do what we want here, need to fix */ 305 if (inp->inp_flags & INP_RECVRETOPTS) { 306 *mp = udp_saveopt((caddr_t) ip_srcroute(), 307 sizeof(struct in_addr), IP_RECVRETOPTS); 308 if (*mp) 309 mp = &(*mp)->m_next; 310 } 311 #endif 312 } 313 iphlen += sizeof(struct udphdr); 314 m->m_len -= iphlen; 315 m->m_pkthdr.len -= iphlen; 316 m->m_data += iphlen; 317 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 318 m, opts) == 0) { 319 udpstat.udps_fullsock++; 320 goto bad; 321 } 322 sorwakeup(inp->inp_socket); 323 return; 324 bad: 325 m_freem(m); 326 if (opts) 327 m_freem(opts); 328 } 329 330 /* 331 * Create a "control" mbuf containing the specified data 332 * with the specified type for presentation with a datagram. 333 */ 334 struct mbuf * 335 udp_saveopt(p, size, type) 336 caddr_t p; 337 register int size; 338 int type; 339 { 340 register struct cmsghdr *cp; 341 struct mbuf *m; 342 343 if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) 344 return ((struct mbuf *) NULL); 345 cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); 346 (void)memcpy(CMSG_DATA(cp), p, size); 347 size += sizeof(*cp); 348 m->m_len = size; 349 cp->cmsg_len = size; 350 cp->cmsg_level = IPPROTO_IP; 351 cp->cmsg_type = type; 352 return (m); 353 } 354 355 /* 356 * Notify a udp user of an asynchronous error; 357 * just wake up so that he can collect error status. 358 */ 359 static void 360 udp_notify(inp, errno) 361 register struct inpcb *inp; 362 int errno; 363 { 364 inp->inp_socket->so_error = errno; 365 sorwakeup(inp->inp_socket); 366 sowwakeup(inp->inp_socket); 367 } 368 369 void 370 udp_ctlinput(cmd, sa, ip) 371 int cmd; 372 struct sockaddr *sa; 373 register struct ip *ip; 374 { 375 register struct udphdr *uh; 376 377 if (!PRC_IS_REDIRECT(cmd) && 378 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 379 return; 380 if (ip) { 381 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 382 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 383 cmd, udp_notify); 384 } else 385 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 386 } 387 388 int 389 udp_output(inp, m, addr, control) 390 register struct inpcb *inp; 391 register struct mbuf *m; 392 struct mbuf *addr, *control; 393 { 394 register struct udpiphdr *ui; 395 register int len = m->m_pkthdr.len; 396 struct in_addr laddr; 397 int s = 0, error = 0; 398 399 if (control) 400 m_freem(control); /* XXX */ 401 402 if (addr) { 403 laddr = inp->inp_laddr; 404 if (inp->inp_faddr.s_addr != INADDR_ANY) { 405 error = EISCONN; 406 goto release; 407 } 408 /* 409 * Must block input while temporarily connected. 410 */ 411 s = splnet(); 412 error = in_pcbconnect(inp, addr); 413 if (error) { 414 splx(s); 415 goto release; 416 } 417 } else { 418 if (inp->inp_faddr.s_addr == INADDR_ANY) { 419 error = ENOTCONN; 420 goto release; 421 } 422 } 423 /* 424 * Calculate data length and get a mbuf 425 * for UDP and IP headers. 426 */ 427 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 428 if (m == 0) { 429 error = ENOBUFS; 430 if (addr) 431 splx(s); 432 goto release; 433 } 434 435 /* 436 * Fill in mbuf with extended UDP header 437 * and addresses and length put into network format. 438 */ 439 ui = mtod(m, struct udpiphdr *); 440 ui->ui_next = ui->ui_prev = 0; 441 ui->ui_x1 = 0; 442 ui->ui_pr = IPPROTO_UDP; 443 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 444 ui->ui_src = inp->inp_laddr; 445 ui->ui_dst = inp->inp_faddr; 446 ui->ui_sport = inp->inp_lport; 447 ui->ui_dport = inp->inp_fport; 448 ui->ui_ulen = ui->ui_len; 449 450 /* 451 * Stuff checksum and output datagram. 452 */ 453 ui->ui_sum = 0; 454 if (udpcksum) { 455 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 456 ui->ui_sum = 0xffff; 457 } 458 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 459 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 460 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 461 udpstat.udps_opackets++; 462 error = ip_output(m, inp->inp_options, &inp->inp_route, 463 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 464 inp->inp_moptions); 465 466 if (addr) { 467 in_pcbdisconnect(inp); 468 inp->inp_laddr = laddr; 469 splx(s); 470 } 471 return (error); 472 473 release: 474 m_freem(m); 475 return (error); 476 } 477 478 u_long udp_sendspace = 9216; /* really max datagram size */ 479 u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 480 /* 40 1K datagrams */ 481 482 /*ARGSUSED*/ 483 int 484 udp_usrreq(so, req, m, addr, control) 485 struct socket *so; 486 int req; 487 struct mbuf *m, *addr, *control; 488 { 489 struct inpcb *inp = sotoinpcb(so); 490 int error = 0; 491 int s; 492 493 if (req == PRU_CONTROL) 494 return (in_control(so, (u_long)m, (caddr_t)addr, 495 (struct ifnet *)control)); 496 if (inp == NULL && req != PRU_ATTACH) { 497 error = EINVAL; 498 goto release; 499 } 500 /* 501 * Note: need to block udp_input while changing 502 * the udp pcb queue and/or pcb addresses. 503 */ 504 switch (req) { 505 506 case PRU_ATTACH: 507 if (inp != NULL) { 508 error = EINVAL; 509 break; 510 } 511 s = splnet(); 512 error = in_pcballoc(so, &udbinfo); 513 splx(s); 514 if (error) 515 break; 516 error = soreserve(so, udp_sendspace, udp_recvspace); 517 if (error) 518 break; 519 ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; 520 break; 521 522 case PRU_DETACH: 523 udp_detach(inp); 524 break; 525 526 case PRU_BIND: 527 s = splnet(); 528 error = in_pcbbind(inp, addr); 529 splx(s); 530 break; 531 532 case PRU_LISTEN: 533 error = EOPNOTSUPP; 534 break; 535 536 case PRU_CONNECT: 537 if (inp->inp_faddr.s_addr != INADDR_ANY) { 538 error = EISCONN; 539 break; 540 } 541 s = splnet(); 542 error = in_pcbconnect(inp, addr); 543 splx(s); 544 if (error == 0) 545 soisconnected(so); 546 break; 547 548 case PRU_CONNECT2: 549 error = EOPNOTSUPP; 550 break; 551 552 case PRU_ACCEPT: 553 error = EOPNOTSUPP; 554 break; 555 556 case PRU_DISCONNECT: 557 if (inp->inp_faddr.s_addr == INADDR_ANY) { 558 error = ENOTCONN; 559 break; 560 } 561 s = splnet(); 562 in_pcbdisconnect(inp); 563 inp->inp_laddr.s_addr = INADDR_ANY; 564 splx(s); 565 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 566 break; 567 568 case PRU_SHUTDOWN: 569 socantsendmore(so); 570 break; 571 572 case PRU_SEND: 573 return (udp_output(inp, m, addr, control)); 574 575 case PRU_ABORT: 576 soisdisconnected(so); 577 udp_detach(inp); 578 break; 579 580 case PRU_SOCKADDR: 581 in_setsockaddr(inp, addr); 582 break; 583 584 case PRU_PEERADDR: 585 in_setpeeraddr(inp, addr); 586 break; 587 588 case PRU_SENSE: 589 /* 590 * stat: don't bother with a blocksize. 591 */ 592 return (0); 593 594 case PRU_SENDOOB: 595 case PRU_FASTTIMO: 596 case PRU_SLOWTIMO: 597 case PRU_PROTORCV: 598 case PRU_PROTOSEND: 599 error = EOPNOTSUPP; 600 break; 601 602 case PRU_RCVD: 603 case PRU_RCVOOB: 604 return (EOPNOTSUPP); /* do not free mbuf's */ 605 606 default: 607 panic("udp_usrreq"); 608 } 609 610 release: 611 if (control) { 612 printf("udp control data unexpectedly retained\n"); 613 m_freem(control); 614 } 615 if (m) 616 m_freem(m); 617 return (error); 618 } 619 620 static void 621 udp_detach(inp) 622 struct inpcb *inp; 623 { 624 int s = splnet(); 625 626 in_pcbdetach(inp); 627 splx(s); 628 } 629 630 /* 631 * Sysctl for udp variables. 632 */ 633 int 634 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 635 int *name; 636 u_int namelen; 637 void *oldp; 638 size_t *oldlenp; 639 void *newp; 640 size_t newlen; 641 { 642 /* All sysctl names at this level are terminal. */ 643 if (namelen != 1) 644 return (ENOTDIR); 645 646 switch (name[0]) { 647 case UDPCTL_CHECKSUM: 648 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 649 case UDPCTL_STATS: 650 return (sysctl_rdstruct(oldp, oldlenp, newp, &udpstat, 651 sizeof udpstat)); 652 case UDPCTL_MAXDGRAM: 653 return (sysctl_int(oldp, oldlenp, newp, newlen, 654 (int *)&udp_sendspace)); /* XXX */ 655 case UDPCTL_RECVSPACE: 656 return (sysctl_int(oldp, oldlenp, newp, newlen, 657 (int *)&udp_recvspace)); /* XXX */ 658 default: 659 return (ENOPROTOOPT); 660 } 661 /* NOTREACHED */ 662 } 663