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