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.41 1997/10/28 15:58:54 bde Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.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/sysctl.h> 46 #include <sys/syslog.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 51 #include <netinet/in.h> 52 #include <netinet/in_systm.h> 53 #include <netinet/ip.h> 54 #include <netinet/in_pcb.h> 55 #include <netinet/in_var.h> 56 #include <netinet/ip_var.h> 57 #include <netinet/ip_icmp.h> 58 #include <netinet/udp.h> 59 #include <netinet/udp_var.h> 60 61 /* 62 * UDP protocol implementation. 63 * Per RFC 768, August, 1980. 64 */ 65 #ifndef COMPAT_42 66 static int udpcksum = 1; 67 #else 68 static int udpcksum = 0; /* XXX */ 69 #endif 70 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, 71 &udpcksum, 0, ""); 72 73 static int log_in_vain = 0; 74 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, 75 &log_in_vain, 0, ""); 76 77 static struct inpcbhead udb; /* from udp_var.h */ 78 static struct inpcbinfo udbinfo; 79 80 #ifndef UDBHASHSIZE 81 #define UDBHASHSIZE 64 82 #endif 83 84 static struct udpstat udpstat; /* from udp_var.h */ 85 SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, 86 &udpstat, udpstat, ""); 87 88 static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 89 90 static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, 91 struct mbuf *, struct proc *)); 92 static void udp_notify __P((struct inpcb *, int)); 93 94 void 95 udp_init() 96 { 97 LIST_INIT(&udb); 98 udbinfo.listhead = &udb; 99 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); 100 } 101 102 void 103 udp_input(m, iphlen) 104 register struct mbuf *m; 105 int iphlen; 106 { 107 register struct ip *ip; 108 register struct udphdr *uh; 109 register struct inpcb *inp; 110 struct mbuf *opts = 0; 111 int len; 112 struct ip save_ip; 113 114 udpstat.udps_ipackets++; 115 116 /* 117 * Strip IP options, if any; should skip this, 118 * make available to user, and use on returned packets, 119 * but we don't yet have a way to check the checksum 120 * with options still present. 121 */ 122 if (iphlen > sizeof (struct ip)) { 123 ip_stripoptions(m, (struct mbuf *)0); 124 iphlen = sizeof(struct ip); 125 } 126 127 /* 128 * Get IP and UDP header together in first mbuf. 129 */ 130 ip = mtod(m, struct ip *); 131 if (m->m_len < iphlen + sizeof(struct udphdr)) { 132 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 133 udpstat.udps_hdrops++; 134 return; 135 } 136 ip = mtod(m, struct ip *); 137 } 138 uh = (struct udphdr *)((caddr_t)ip + iphlen); 139 140 /* 141 * Make mbuf data length reflect UDP length. 142 * If not enough data to reflect UDP length, drop. 143 */ 144 len = ntohs((u_short)uh->uh_ulen); 145 if (ip->ip_len != len) { 146 if (len > ip->ip_len || len < sizeof(struct udphdr)) { 147 udpstat.udps_badlen++; 148 goto bad; 149 } 150 m_adj(m, len - ip->ip_len); 151 /* ip->ip_len = len; */ 152 } 153 /* 154 * Save a copy of the IP header in case we want restore it 155 * for sending an ICMP error message in response. 156 */ 157 save_ip = *ip; 158 159 /* 160 * Checksum extended UDP header and data. 161 */ 162 if (uh->uh_sum) { 163 ((struct ipovly *)ip)->ih_next = 0; 164 ((struct ipovly *)ip)->ih_prev = 0; 165 ((struct ipovly *)ip)->ih_x1 = 0; 166 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 167 uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); 168 if (uh->uh_sum) { 169 udpstat.udps_badsum++; 170 m_freem(m); 171 return; 172 } 173 } 174 175 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 176 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 177 struct inpcb *last; 178 /* 179 * Deliver a multicast or broadcast datagram to *all* sockets 180 * for which the local and remote addresses and ports match 181 * those of the incoming datagram. This allows more than 182 * one process to receive multi/broadcasts on the same port. 183 * (This really ought to be done for unicast datagrams as 184 * well, but that would cause problems with existing 185 * applications that open both address-specific sockets and 186 * a wildcard socket listening to the same port -- they would 187 * end up receiving duplicates of every unicast datagram. 188 * Those applications open the multiple sockets to overcome an 189 * inadequacy of the UDP socket interface, but for backwards 190 * compatibility we avoid the problem here rather than 191 * fixing the interface. Maybe 4.5BSD will remedy this?) 192 */ 193 194 /* 195 * Construct sockaddr format source address. 196 */ 197 udp_in.sin_port = uh->uh_sport; 198 udp_in.sin_addr = ip->ip_src; 199 m->m_len -= sizeof (struct udpiphdr); 200 m->m_data += sizeof (struct udpiphdr); 201 /* 202 * Locate pcb(s) for datagram. 203 * (Algorithm copied from raw_intr().) 204 */ 205 last = NULL; 206 for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 207 if (inp->inp_lport != uh->uh_dport) 208 continue; 209 if (inp->inp_laddr.s_addr != INADDR_ANY) { 210 if (inp->inp_laddr.s_addr != 211 ip->ip_dst.s_addr) 212 continue; 213 } 214 if (inp->inp_faddr.s_addr != INADDR_ANY) { 215 if (inp->inp_faddr.s_addr != 216 ip->ip_src.s_addr || 217 inp->inp_fport != uh->uh_sport) 218 continue; 219 } 220 221 if (last != NULL) { 222 struct mbuf *n; 223 224 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 225 if (last->inp_flags & INP_CONTROLOPTS 226 || last->inp_socket->so_options & SO_TIMESTAMP) 227 ip_savecontrol(last, &opts, ip, n); 228 if (sbappendaddr(&last->inp_socket->so_rcv, 229 (struct sockaddr *)&udp_in, 230 n, opts) == 0) { 231 m_freem(n); 232 if (opts) 233 m_freem(opts); 234 udpstat.udps_fullsock++; 235 } else 236 sorwakeup(last->inp_socket); 237 opts = 0; 238 } 239 } 240 last = inp; 241 /* 242 * Don't look for additional matches if this one does 243 * not have either the SO_REUSEPORT or SO_REUSEADDR 244 * socket options set. This heuristic avoids searching 245 * through all pcbs in the common case of a non-shared 246 * port. It * assumes that an application will never 247 * clear these options after setting them. 248 */ 249 if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) 250 break; 251 } 252 253 if (last == NULL) { 254 /* 255 * No matching pcb found; discard datagram. 256 * (No need to send an ICMP Port Unreachable 257 * for a broadcast or multicast datgram.) 258 */ 259 udpstat.udps_noportbcast++; 260 goto bad; 261 } 262 if (last->inp_flags & INP_CONTROLOPTS 263 || last->inp_socket->so_options & SO_TIMESTAMP) 264 ip_savecontrol(last, &opts, ip, m); 265 if (sbappendaddr(&last->inp_socket->so_rcv, 266 (struct sockaddr *)&udp_in, 267 m, opts) == 0) { 268 udpstat.udps_fullsock++; 269 goto bad; 270 } 271 sorwakeup(last->inp_socket); 272 return; 273 } 274 /* 275 * Locate pcb for datagram. 276 */ 277 inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport, 278 ip->ip_dst, uh->uh_dport, 1); 279 if (inp == NULL) { 280 if (log_in_vain) { 281 char buf[4*sizeof "123"]; 282 283 strcpy(buf, inet_ntoa(ip->ip_dst)); 284 log(LOG_INFO, 285 "Connection attempt to UDP %s:%d from %s:%d\n", 286 buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), 287 ntohs(uh->uh_sport)); 288 } 289 udpstat.udps_noport++; 290 if (m->m_flags & (M_BCAST | M_MCAST)) { 291 udpstat.udps_noportbcast++; 292 goto bad; 293 } 294 *ip = save_ip; 295 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 296 return; 297 } 298 299 /* 300 * Construct sockaddr format source address. 301 * Stuff source address and datagram in user buffer. 302 */ 303 udp_in.sin_port = uh->uh_sport; 304 udp_in.sin_addr = ip->ip_src; 305 if (inp->inp_flags & INP_CONTROLOPTS 306 || inp->inp_socket->so_options & SO_TIMESTAMP) 307 ip_savecontrol(inp, &opts, ip, m); 308 iphlen += sizeof(struct udphdr); 309 m->m_len -= iphlen; 310 m->m_pkthdr.len -= iphlen; 311 m->m_data += iphlen; 312 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 313 m, opts) == 0) { 314 udpstat.udps_fullsock++; 315 goto bad; 316 } 317 sorwakeup(inp->inp_socket); 318 return; 319 bad: 320 m_freem(m); 321 if (opts) 322 m_freem(opts); 323 } 324 325 /* 326 * Notify a udp user of an asynchronous error; 327 * just wake up so that he can collect error status. 328 */ 329 static void 330 udp_notify(inp, errno) 331 register struct inpcb *inp; 332 int errno; 333 { 334 inp->inp_socket->so_error = errno; 335 sorwakeup(inp->inp_socket); 336 sowwakeup(inp->inp_socket); 337 } 338 339 void 340 udp_ctlinput(cmd, sa, vip) 341 int cmd; 342 struct sockaddr *sa; 343 void *vip; 344 { 345 register struct ip *ip = vip; 346 register struct udphdr *uh; 347 348 if (!PRC_IS_REDIRECT(cmd) && 349 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 350 return; 351 if (ip) { 352 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 353 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 354 cmd, udp_notify); 355 } else 356 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 357 } 358 359 static int 360 udp_output(inp, m, addr, control, p) 361 register struct inpcb *inp; 362 register struct mbuf *m; 363 struct sockaddr *addr; 364 struct mbuf *control; 365 struct proc *p; 366 { 367 register struct udpiphdr *ui; 368 register int len = m->m_pkthdr.len; 369 struct in_addr laddr; 370 int s = 0, error = 0; 371 372 if (control) 373 m_freem(control); /* XXX */ 374 375 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { 376 error = EMSGSIZE; 377 goto release; 378 } 379 380 if (addr) { 381 laddr = inp->inp_laddr; 382 if (inp->inp_faddr.s_addr != INADDR_ANY) { 383 error = EISCONN; 384 goto release; 385 } 386 /* 387 * Must block input while temporarily connected. 388 */ 389 s = splnet(); 390 error = in_pcbconnect(inp, addr, p); 391 if (error) { 392 splx(s); 393 goto release; 394 } 395 } else { 396 if (inp->inp_faddr.s_addr == INADDR_ANY) { 397 error = ENOTCONN; 398 goto release; 399 } 400 } 401 /* 402 * Calculate data length and get a mbuf 403 * for UDP and IP headers. 404 */ 405 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 406 if (m == 0) { 407 error = ENOBUFS; 408 if (addr) 409 splx(s); 410 goto release; 411 } 412 413 /* 414 * Fill in mbuf with extended UDP header 415 * and addresses and length put into network format. 416 */ 417 ui = mtod(m, struct udpiphdr *); 418 ui->ui_next = ui->ui_prev = 0; 419 ui->ui_x1 = 0; 420 ui->ui_pr = IPPROTO_UDP; 421 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 422 ui->ui_src = inp->inp_laddr; 423 ui->ui_dst = inp->inp_faddr; 424 ui->ui_sport = inp->inp_lport; 425 ui->ui_dport = inp->inp_fport; 426 ui->ui_ulen = ui->ui_len; 427 428 /* 429 * Stuff checksum and output datagram. 430 */ 431 ui->ui_sum = 0; 432 if (udpcksum) { 433 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 434 ui->ui_sum = 0xffff; 435 } 436 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 437 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ 438 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ 439 udpstat.udps_opackets++; 440 error = ip_output(m, inp->inp_options, &inp->inp_route, 441 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 442 inp->inp_moptions); 443 444 if (addr) { 445 in_pcbdisconnect(inp); 446 inp->inp_laddr = laddr; /* XXX rehash? */ 447 splx(s); 448 } 449 return (error); 450 451 release: 452 m_freem(m); 453 return (error); 454 } 455 456 static u_long udp_sendspace = 9216; /* really max datagram size */ 457 /* 40 1K datagrams */ 458 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, 459 &udp_sendspace, 0, ""); 460 461 static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 462 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, 463 &udp_recvspace, 0, ""); 464 465 static int 466 udp_abort(struct socket *so) 467 { 468 struct inpcb *inp; 469 int s; 470 471 inp = sotoinpcb(so); 472 if (inp == 0) 473 return EINVAL; /* ??? possible? panic instead? */ 474 soisdisconnected(so); 475 s = splnet(); 476 in_pcbdetach(inp); 477 splx(s); 478 return 0; 479 } 480 481 static int 482 udp_attach(struct socket *so, int proto, struct proc *p) 483 { 484 struct inpcb *inp; 485 int s, error; 486 487 inp = sotoinpcb(so); 488 if (inp != 0) 489 return EINVAL; 490 491 s = splnet(); 492 error = in_pcballoc(so, &udbinfo, p); 493 splx(s); 494 if (error) 495 return error; 496 error = soreserve(so, udp_sendspace, udp_recvspace); 497 if (error) 498 return error; 499 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; 500 return 0; 501 } 502 503 static int 504 udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 505 { 506 struct inpcb *inp; 507 int s, error; 508 509 inp = sotoinpcb(so); 510 if (inp == 0) 511 return EINVAL; 512 s = splnet(); 513 error = in_pcbbind(inp, nam, p); 514 splx(s); 515 return error; 516 } 517 518 static int 519 udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 520 { 521 struct inpcb *inp; 522 int s, error; 523 524 inp = sotoinpcb(so); 525 if (inp == 0) 526 return EINVAL; 527 if (inp->inp_faddr.s_addr != INADDR_ANY) 528 return EISCONN; 529 s = splnet(); 530 error = in_pcbconnect(inp, nam, p); 531 splx(s); 532 if (error == 0) 533 soisconnected(so); 534 return error; 535 } 536 537 static int 538 udp_detach(struct socket *so) 539 { 540 struct inpcb *inp; 541 int s; 542 543 inp = sotoinpcb(so); 544 if (inp == 0) 545 return EINVAL; 546 s = splnet(); 547 in_pcbdetach(inp); 548 splx(s); 549 return 0; 550 } 551 552 static int 553 udp_disconnect(struct socket *so) 554 { 555 struct inpcb *inp; 556 int s; 557 558 inp = sotoinpcb(so); 559 if (inp == 0) 560 return EINVAL; 561 if (inp->inp_faddr.s_addr == INADDR_ANY) 562 return ENOTCONN; 563 564 s = splnet(); 565 in_pcbdisconnect(inp); 566 inp->inp_laddr.s_addr = INADDR_ANY; 567 splx(s); 568 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 569 return 0; 570 } 571 572 static int 573 udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 574 struct mbuf *control, struct proc *p) 575 { 576 struct inpcb *inp; 577 578 inp = sotoinpcb(so); 579 if (inp == 0) { 580 m_freem(m); 581 return EINVAL; 582 } 583 return udp_output(inp, m, addr, control, p); 584 } 585 586 static int 587 udp_shutdown(struct socket *so) 588 { 589 struct inpcb *inp; 590 591 inp = sotoinpcb(so); 592 if (inp == 0) 593 return EINVAL; 594 socantsendmore(so); 595 return 0; 596 } 597 598 struct pr_usrreqs udp_usrreqs = { 599 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect, 600 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, 601 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 602 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, 603 in_setsockaddr, sosend, soreceive, sopoll 604 }; 605