1 /* $NetBSD: udp_usrreq.c,v 1.25 1995/11/21 01:07:46 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 36 */ 37 38 #include <sys/param.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/in_var.h> 53 #include <netinet/ip.h> 54 #include <netinet/in_pcb.h> 55 #include <netinet/ip_var.h> 56 #include <netinet/ip_icmp.h> 57 #include <netinet/udp.h> 58 #include <netinet/udp_var.h> 59 60 /* 61 * UDP protocol implementation. 62 * Per RFC 768, August, 1980. 63 */ 64 #ifndef COMPAT_42 65 int udpcksum = 1; 66 #else 67 int udpcksum = 0; /* XXX */ 68 #endif 69 70 struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 71 struct inpcb *udp_last_inpcb = 0; 72 73 static void udp_detach __P((struct inpcb *)); 74 static void udp_notify __P((struct inpcb *, int)); 75 static struct mbuf *udp_saveopt __P((caddr_t, int, int)); 76 77 void 78 udp_init() 79 { 80 81 in_pcbinit(&udbtable); 82 } 83 84 void 85 udp_input(m, iphlen) 86 register struct mbuf *m; 87 int iphlen; 88 { 89 register struct ip *ip; 90 register struct udphdr *uh; 91 register struct inpcb *inp; 92 struct mbuf *opts = 0; 93 int len; 94 struct ip save_ip; 95 96 udpstat.udps_ipackets++; 97 98 /* 99 * Strip IP options, if any; should skip this, 100 * make available to user, and use on returned packets, 101 * but we don't yet have a way to check the checksum 102 * with options still present. 103 */ 104 if (iphlen > sizeof (struct ip)) { 105 ip_stripoptions(m, (struct mbuf *)0); 106 iphlen = sizeof(struct ip); 107 } 108 109 /* 110 * Get IP and UDP header together in first mbuf. 111 */ 112 ip = mtod(m, struct ip *); 113 if (m->m_len < iphlen + sizeof(struct udphdr)) { 114 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 115 udpstat.udps_hdrops++; 116 return; 117 } 118 ip = mtod(m, struct ip *); 119 } 120 uh = (struct udphdr *)((caddr_t)ip + iphlen); 121 122 /* 123 * Make mbuf data length reflect UDP length. 124 * If not enough data to reflect UDP length, drop. 125 */ 126 len = ntohs((u_int16_t)uh->uh_ulen); 127 if (ip->ip_len != len) { 128 if (len > ip->ip_len) { 129 udpstat.udps_badlen++; 130 goto bad; 131 } 132 m_adj(m, len - ip->ip_len); 133 /* ip->ip_len = len; */ 134 } 135 /* 136 * Save a copy of the IP header in case we want restore it 137 * for sending an ICMP error message in response. 138 */ 139 save_ip = *ip; 140 141 /* 142 * Checksum extended UDP header and data. 143 */ 144 if (udpcksum && uh->uh_sum) { 145 bzero(((struct ipovly *)ip)->ih_x1, 146 sizeof ((struct ipovly *)ip)->ih_x1); 147 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 148 if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 149 udpstat.udps_badsum++; 150 m_freem(m); 151 return; 152 } 153 } 154 155 if (IN_MULTICAST(ip->ip_dst.s_addr) || 156 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 157 struct socket *last; 158 /* 159 * Deliver a multicast or broadcast datagram to *all* sockets 160 * for which the local and remote addresses and ports match 161 * those of the incoming datagram. This allows more than 162 * one process to receive multi/broadcasts on the same port. 163 * (This really ought to be done for unicast datagrams as 164 * well, but that would cause problems with existing 165 * applications that open both address-specific sockets and 166 * a wildcard socket listening to the same port -- they would 167 * end up receiving duplicates of every unicast datagram. 168 * Those applications open the multiple sockets to overcome an 169 * inadequacy of the UDP socket interface, but for backwards 170 * compatibility we avoid the problem here rather than 171 * fixing the interface. Maybe 4.5BSD will remedy this?) 172 */ 173 174 /* 175 * Construct sockaddr format source address. 176 */ 177 udp_in.sin_port = uh->uh_sport; 178 udp_in.sin_addr = ip->ip_src; 179 m->m_len -= sizeof (struct udpiphdr); 180 m->m_data += sizeof (struct udpiphdr); 181 /* 182 * Locate pcb(s) for datagram. 183 * (Algorithm copied from raw_intr().) 184 */ 185 last = NULL; 186 for (inp = udbtable.inpt_queue.cqh_first; 187 inp != (struct inpcb *)&udbtable.inpt_queue; 188 inp = inp->inp_queue.cqe_next) { 189 if (inp->inp_lport != uh->uh_dport) 190 continue; 191 if (inp->inp_laddr.s_addr != INADDR_ANY) { 192 if (inp->inp_laddr.s_addr != 193 ip->ip_dst.s_addr) 194 continue; 195 } 196 if (inp->inp_faddr.s_addr != INADDR_ANY) { 197 if (inp->inp_faddr.s_addr != 198 ip->ip_src.s_addr || 199 inp->inp_fport != uh->uh_sport) 200 continue; 201 } 202 203 if (last != NULL) { 204 struct mbuf *n; 205 206 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 207 if (sbappendaddr(&last->so_rcv, 208 sintosa(&udp_in), n, 209 (struct mbuf *)0) == 0) { 210 m_freem(n); 211 udpstat.udps_fullsock++; 212 } else 213 sorwakeup(last); 214 } 215 } 216 last = inp->inp_socket; 217 /* 218 * Don't look for additional matches if this one does 219 * not have either the SO_REUSEPORT or SO_REUSEADDR 220 * socket options set. This heuristic avoids searching 221 * through all pcbs in the common case of a non-shared 222 * port. It * assumes that an application will never 223 * clear these options after setting them. 224 */ 225 if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) 226 break; 227 } 228 229 if (last == NULL) { 230 /* 231 * No matching pcb found; discard datagram. 232 * (No need to send an ICMP Port Unreachable 233 * for a broadcast or multicast datgram.) 234 */ 235 udpstat.udps_noportbcast++; 236 goto bad; 237 } 238 if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m, 239 (struct mbuf *)0) == 0) { 240 udpstat.udps_fullsock++; 241 goto bad; 242 } 243 sorwakeup(last); 244 return; 245 } 246 /* 247 * Locate pcb for datagram. 248 */ 249 inp = udp_last_inpcb; 250 if (inp == 0 || 251 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 udpstat.udpps_pcbcachemiss++; 256 inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport, 257 ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); 258 if (inp == 0) { 259 udpstat.udps_noport++; 260 if (m->m_flags & (M_BCAST | M_MCAST)) { 261 udpstat.udps_noportbcast++; 262 goto bad; 263 } 264 *ip = save_ip; 265 ip->ip_len += iphlen; 266 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 267 return; 268 } 269 udp_last_inpcb = inp; 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, sintosa(&udp_in), m, 309 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 int inetctlerrmap[]; 369 void (*notify) __P((struct inpcb *, int)) = udp_notify; 370 int errno; 371 372 if ((unsigned)cmd >= PRC_NCMDS) 373 return; 374 errno = inetctlerrmap[cmd]; 375 if (PRC_IS_REDIRECT(cmd)) 376 notify = in_rtchange, ip = 0; 377 else if (cmd == PRC_HOSTDEAD) 378 ip = 0; 379 else if (errno == 0) 380 return; 381 if (ip) { 382 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 383 in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src, 384 uh->uh_sport, errno, notify); 385 } else 386 in_pcbnotifyall(&udbtable, sa, errno, notify); 387 } 388 389 int 390 udp_output(inp, m, addr, control) 391 register struct inpcb *inp; 392 register struct mbuf *m; 393 struct mbuf *addr, *control; 394 { 395 register struct udpiphdr *ui; 396 register int len = m->m_pkthdr.len; 397 struct in_addr laddr; 398 int s, error = 0; 399 400 if (control) 401 m_freem(control); /* XXX */ 402 403 if (addr) { 404 laddr = inp->inp_laddr; 405 if (inp->inp_faddr.s_addr != INADDR_ANY) { 406 error = EISCONN; 407 goto release; 408 } 409 /* 410 * Must block input while temporarily connected. 411 */ 412 s = splsoftnet(); 413 error = in_pcbconnect(inp, addr); 414 if (error) { 415 splx(s); 416 goto release; 417 } 418 } else { 419 if (inp->inp_faddr.s_addr == INADDR_ANY) { 420 error = ENOTCONN; 421 goto release; 422 } 423 } 424 /* 425 * Calculate data length and get a mbuf 426 * for UDP and IP headers. 427 */ 428 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 429 if (m == 0) { 430 error = ENOBUFS; 431 goto release; 432 } 433 434 /* 435 * Fill in mbuf with extended UDP header 436 * and addresses and length put into network format. 437 */ 438 ui = mtod(m, struct udpiphdr *); 439 bzero(ui->ui_x1, sizeof ui->ui_x1); 440 ui->ui_pr = IPPROTO_UDP; 441 ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); 442 ui->ui_src = inp->inp_laddr; 443 ui->ui_dst = inp->inp_faddr; 444 ui->ui_sport = inp->inp_lport; 445 ui->ui_dport = inp->inp_fport; 446 ui->ui_ulen = ui->ui_len; 447 448 /* 449 * Stuff checksum and output datagram. 450 */ 451 ui->ui_sum = 0; 452 if (udpcksum) { 453 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 454 ui->ui_sum = 0xffff; 455 } 456 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 457 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 458 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 459 udpstat.udps_opackets++; 460 error = ip_output(m, inp->inp_options, &inp->inp_route, 461 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 462 inp->inp_moptions); 463 464 if (addr) { 465 in_pcbdisconnect(inp); 466 inp->inp_laddr = laddr; 467 splx(s); 468 } 469 return (error); 470 471 release: 472 m_freem(m); 473 return (error); 474 } 475 476 u_long udp_sendspace = 9216; /* really max datagram size */ 477 u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 478 /* 40 1K datagrams */ 479 480 /*ARGSUSED*/ 481 int 482 udp_usrreq(so, req, m, addr, control) 483 struct socket *so; 484 int req; 485 struct mbuf *m, *addr, *control; 486 { 487 struct inpcb *inp = sotoinpcb(so); 488 int error = 0; 489 int s; 490 491 if (req == PRU_CONTROL) 492 return (in_control(so, (long)m, (caddr_t)addr, 493 (struct ifnet *)control)); 494 if (inp == NULL && req != PRU_ATTACH) { 495 error = EINVAL; 496 goto release; 497 } 498 /* 499 * Note: need to block udp_input while changing 500 * the udp pcb queue and/or pcb addresses. 501 */ 502 switch (req) { 503 504 case PRU_ATTACH: 505 if (inp != NULL) { 506 error = EINVAL; 507 break; 508 } 509 s = splsoftnet(); 510 error = in_pcballoc(so, &udbtable); 511 splx(s); 512 if (error) 513 break; 514 error = soreserve(so, udp_sendspace, udp_recvspace); 515 if (error) 516 break; 517 ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; 518 break; 519 520 case PRU_DETACH: 521 udp_detach(inp); 522 break; 523 524 case PRU_BIND: 525 s = splsoftnet(); 526 error = in_pcbbind(inp, addr); 527 splx(s); 528 break; 529 530 case PRU_LISTEN: 531 error = EOPNOTSUPP; 532 break; 533 534 case PRU_CONNECT: 535 if (inp->inp_faddr.s_addr != INADDR_ANY) { 536 error = EISCONN; 537 break; 538 } 539 s = splsoftnet(); 540 error = in_pcbconnect(inp, addr); 541 splx(s); 542 if (error == 0) 543 soisconnected(so); 544 break; 545 546 case PRU_CONNECT2: 547 error = EOPNOTSUPP; 548 break; 549 550 case PRU_ACCEPT: 551 error = EOPNOTSUPP; 552 break; 553 554 case PRU_DISCONNECT: 555 if (inp->inp_faddr.s_addr == INADDR_ANY) { 556 error = ENOTCONN; 557 break; 558 } 559 s = splsoftnet(); 560 in_pcbdisconnect(inp); 561 inp->inp_laddr.s_addr = INADDR_ANY; 562 splx(s); 563 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 564 break; 565 566 case PRU_SHUTDOWN: 567 socantsendmore(so); 568 break; 569 570 case PRU_SEND: 571 return (udp_output(inp, m, addr, control)); 572 573 case PRU_ABORT: 574 soisdisconnected(so); 575 udp_detach(inp); 576 break; 577 578 case PRU_SOCKADDR: 579 in_setsockaddr(inp, addr); 580 break; 581 582 case PRU_PEERADDR: 583 in_setpeeraddr(inp, addr); 584 break; 585 586 case PRU_SENSE: 587 /* 588 * stat: don't bother with a blocksize. 589 */ 590 return (0); 591 592 case PRU_SENDOOB: 593 case PRU_FASTTIMO: 594 case PRU_SLOWTIMO: 595 case PRU_PROTORCV: 596 case PRU_PROTOSEND: 597 error = EOPNOTSUPP; 598 break; 599 600 case PRU_RCVD: 601 case PRU_RCVOOB: 602 return (EOPNOTSUPP); /* do not free mbuf's */ 603 604 default: 605 panic("udp_usrreq"); 606 } 607 608 release: 609 if (control) { 610 printf("udp control data unexpectedly retained\n"); 611 m_freem(control); 612 } 613 if (m) 614 m_freem(m); 615 return (error); 616 } 617 618 static void 619 udp_detach(inp) 620 struct inpcb *inp; 621 { 622 int s = splsoftnet(); 623 624 if (inp == udp_last_inpcb) 625 udp_last_inpcb = 0; 626 in_pcbdetach(inp); 627 splx(s); 628 } 629 630 /* 631 * Sysctl for udp variables. 632 */ 633 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 634 int *name; 635 u_int namelen; 636 void *oldp; 637 size_t *oldlenp; 638 void *newp; 639 size_t newlen; 640 { 641 /* All sysctl names at this level are terminal. */ 642 if (namelen != 1) 643 return (ENOTDIR); 644 645 switch (name[0]) { 646 case UDPCTL_CHECKSUM: 647 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 648 default: 649 return (ENOPROTOOPT); 650 } 651 /* NOTREACHED */ 652 } 653