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