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