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