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