1/* 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1982, 1986, 1988, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.98 2004/08/17 22:05:54 andre Exp $ 61 */ 62 63#if !INET 64#error "IPDIVERT requires INET." 65#endif 66 67#include <sys/param.h> 68#include <sys/kernel.h> 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/socket.h> 72#include <sys/domain.h> 73#include <sys/protosw.h> 74#include <sys/socketvar.h> 75#include <sys/sysctl.h> 76#include <sys/systm.h> 77#include <sys/proc.h> 78 79#include <machine/endian.h> 80 81#include <net/if.h> 82#include <net/route.h> 83#include <net/kpi_protocol.h> 84 85#include <netinet/in.h> 86#include <netinet/in_systm.h> 87#include <netinet/ip.h> 88#include <netinet/in_pcb.h> 89#include <netinet/in_var.h> 90#include <netinet/ip_var.h> 91#include <netinet/ip_fw.h> 92#include <netinet/ip_divert.h> 93 94#include <kern/zalloc.h> 95#include <libkern/OSAtomic.h> 96 97/* 98 * Divert sockets 99 */ 100 101/* 102 * Allocate enough space to hold a full IP packet 103 */ 104#define DIVSNDQ (65536 + 100) 105#define DIVRCVQ (65536 + 100) 106 107/* 108 * Divert sockets work in conjunction with ipfw, see the divert(4) 109 * manpage for features. 110 * Internally, packets selected by ipfw in ip_input() or ip_output(), 111 * and never diverted before, are passed to the input queue of the 112 * divert socket with a given 'divert_port' number (as specified in 113 * the matching ipfw rule), and they are tagged with a 16 bit cookie 114 * (representing the rule number of the matching ipfw rule), which 115 * is passed to process reading from the socket. 116 * 117 * Packets written to the divert socket are again tagged with a cookie 118 * (usually the same as above) and a destination address. 119 * If the destination address is INADDR_ANY then the packet is 120 * treated as outgoing and sent to ip_output(), otherwise it is 121 * treated as incoming and sent to ip_input(). 122 * In both cases, the packet is tagged with the cookie. 123 * 124 * On reinjection, processing in ip_input() and ip_output() 125 * will be exactly the same as for the original packet, except that 126 * ipfw processing will start at the rule number after the one 127 * written in the cookie (so, tagging a packet with a cookie of 0 128 * will cause it to be effectively considered as a standard packet). 129 */ 130 131/* Internal variables */ 132static struct inpcbhead divcb; 133static struct inpcbinfo divcbinfo; 134 135static u_int32_t div_sendspace = DIVSNDQ; /* XXX sysctl ? */ 136static u_int32_t div_recvspace = DIVRCVQ; /* XXX sysctl ? */ 137 138/* Optimization: have this preinitialized */ 139static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET, 0, { 0 }, { 0,0,0,0,0,0,0,0 } }; 140 141/* Internal functions */ 142static int div_output(struct socket *so, 143 struct mbuf *m, struct sockaddr *addr, struct mbuf *control); 144 145extern int load_ipfw(void); 146/* 147 * Initialize divert connection block queue. 148 */ 149void 150div_init(void) 151{ 152 struct inpcbinfo *pcbinfo; 153 LIST_INIT(&divcb); 154 divcbinfo.listhead = &divcb; 155 /* 156 * XXX We don't use the hash list for divert IP, but it's easier 157 * to allocate a one entry hash list than it is to check all 158 * over the place for hashbase == NULL. 159 */ 160 divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask); 161 divcbinfo.porthashbase = hashinit(1, M_PCB, &divcbinfo.porthashmask); 162 divcbinfo.ipi_zone = (void *) zinit(sizeof(struct inpcb),(maxsockets * sizeof(struct inpcb)), 163 4096, "divzone"); 164 pcbinfo = &divcbinfo; 165 /* 166 * allocate lock group attribute and group for udp pcb mutexes 167 */ 168 pcbinfo->mtx_grp_attr = lck_grp_attr_alloc_init(); 169 170 pcbinfo->mtx_grp = lck_grp_alloc_init("divcb", pcbinfo->mtx_grp_attr); 171 172 /* 173 * allocate the lock attribute for divert pcb mutexes 174 */ 175 pcbinfo->mtx_attr = lck_attr_alloc_init(); 176 177 if ((pcbinfo->mtx = lck_rw_alloc_init(pcbinfo->mtx_grp, pcbinfo->mtx_attr)) == NULL) 178 return; /* pretty much dead if this fails... */ 179 180#if IPFIREWALL 181 if (!IPFW_LOADED) { 182 load_ipfw(); 183 } 184#endif 185} 186 187/* 188 * IPPROTO_DIVERT is not a real IP protocol; don't allow any packets 189 * with that protocol number to enter the system from the outside. 190 */ 191void 192div_input(struct mbuf *m, __unused int off) 193{ 194 OSAddAtomic(1, &ipstat.ips_noproto); 195 m_freem(m); 196} 197 198/* 199 * Divert a packet by passing it up to the divert socket at port 'port'. 200 * 201 * Setup generic address and protocol structures for div_input routine, 202 * then pass them along with mbuf chain. 203 * ###LOCK called in ip_mutex from ip_output/ip_input 204 */ 205void 206divert_packet(struct mbuf *m, int incoming, int port, int rule) 207{ 208 struct ip *ip; 209 struct inpcb *inp; 210 struct socket *sa; 211 u_int16_t nport; 212 213 /* Sanity check */ 214 KASSERT(port != 0, ("%s: port=0", __FUNCTION__)); 215 216 divsrc.sin_port = rule; /* record matching rule */ 217 218 /* Assure header */ 219 if (m->m_len < sizeof(struct ip) && 220 (m = m_pullup(m, sizeof(struct ip))) == 0) { 221 return; 222 } 223 ip = mtod(m, struct ip *); 224 225 /* 226 * Record receive interface address, if any. 227 * But only for incoming packets. 228 */ 229 divsrc.sin_addr.s_addr = 0; 230 if (incoming) { 231 struct ifaddr *ifa; 232 233 /* Sanity check */ 234 KASSERT((m->m_flags & M_PKTHDR), ("%s: !PKTHDR", __FUNCTION__)); 235 236 /* Find IP address for receive interface */ 237 ifnet_lock_shared(m->m_pkthdr.rcvif); 238 TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 239 IFA_LOCK(ifa); 240 if (ifa->ifa_addr->sa_family != AF_INET) { 241 IFA_UNLOCK(ifa); 242 continue; 243 } 244 divsrc.sin_addr = 245 ((struct sockaddr_in *)(void *) ifa->ifa_addr)->sin_addr; 246 IFA_UNLOCK(ifa); 247 break; 248 } 249 ifnet_lock_done(m->m_pkthdr.rcvif); 250 } 251 /* 252 * Record the incoming interface name whenever we have one. 253 */ 254 bzero(&divsrc.sin_zero, sizeof(divsrc.sin_zero)); 255 if (m->m_pkthdr.rcvif) { 256 /* 257 * Hide the actual interface name in there in the 258 * sin_zero array. XXX This needs to be moved to a 259 * different sockaddr type for divert, e.g. 260 * sockaddr_div with multiple fields like 261 * sockaddr_dl. Presently we have only 7 bytes 262 * but that will do for now as most interfaces 263 * are 4 or less + 2 or less bytes for unit. 264 * There is probably a faster way of doing this, 265 * possibly taking it from the sockaddr_dl on the iface. 266 * This solves the problem of a P2P link and a LAN interface 267 * having the same address, which can result in the wrong 268 * interface being assigned to the packet when fed back 269 * into the divert socket. Theoretically if the daemon saves 270 * and re-uses the sockaddr_in as suggested in the man pages, 271 * this iface name will come along for the ride. 272 * (see div_output for the other half of this.) 273 */ 274 snprintf(divsrc.sin_zero, sizeof(divsrc.sin_zero), 275 "%s%d", m->m_pkthdr.rcvif->if_name, 276 m->m_pkthdr.rcvif->if_unit); 277 } 278 279 /* Put packet on socket queue, if any */ 280 sa = NULL; 281 nport = htons((u_int16_t)port); 282 lck_rw_lock_shared(divcbinfo.mtx); 283 LIST_FOREACH(inp, &divcb, inp_list) { 284 if (inp->inp_lport == nport) 285 sa = inp->inp_socket; 286 } 287 if (sa) { 288 int error = 0; 289 290 socket_lock(sa, 1); 291 if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, 292 m, (struct mbuf *)0, &error) != 0) 293 sorwakeup(sa); 294 socket_unlock(sa, 1); 295 } else { 296 m_freem(m); 297 OSAddAtomic(1, &ipstat.ips_noproto); 298 OSAddAtomic(-1, &ipstat.ips_delivered); 299 } 300 lck_rw_done(divcbinfo.mtx); 301} 302 303/* 304 * Deliver packet back into the IP processing machinery. 305 * 306 * If no address specified, or address is 0.0.0.0, send to ip_output(); 307 * otherwise, send to ip_input() and mark as having been received on 308 * the interface with that address. 309 * ###LOCK called in inet_proto mutex when from div_send. 310 */ 311static int 312div_output(struct socket *so, struct mbuf *m, struct sockaddr *addr, 313 struct mbuf *control) 314{ 315 struct inpcb *const inp = sotoinpcb(so); 316 struct ip *const ip = mtod(m, struct ip *); 317 struct sockaddr_in *sin = (struct sockaddr_in *)(void *)addr; 318 int error = 0; 319 mbuf_svc_class_t msc = MBUF_SC_UNSPEC; 320 321 if (control != NULL) { 322 msc = mbuf_service_class_from_control(control); 323 324 m_freem(control); /* XXX */ 325 } 326 /* Loopback avoidance and state recovery */ 327 if (sin) { 328 struct m_tag *mtag; 329 struct divert_tag *dt; 330 int len = 0; 331 char *c = sin->sin_zero; 332 333 mtag = m_tag_create(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_DIVERT, 334 sizeof(struct divert_tag), M_NOWAIT, m); 335 if (mtag == NULL) { 336 error = ENOBUFS; 337 goto cantsend; 338 } 339 dt = (struct divert_tag *)(mtag+1); 340 dt->info = 0; 341 dt->cookie = sin->sin_port; 342 m_tag_prepend(m, mtag); 343 344 /* 345 * Find receive interface with the given name or IP address. 346 * The name is user supplied data so don't trust it's size or 347 * that it is zero terminated. The name has priority. 348 * We are presently assuming that the sockaddr_in 349 * has not been replaced by a sockaddr_div, so we limit it 350 * to 16 bytes in total. the name is stuffed (if it exists) 351 * in the sin_zero[] field. 352 */ 353 while (*c++ && (len++ < sizeof(sin->sin_zero))); 354 if ((len > 0) && (len < sizeof(sin->sin_zero))) 355 m->m_pkthdr.rcvif = ifunit(sin->sin_zero); 356 } 357 358 /* Reinject packet into the system as incoming or outgoing */ 359 if (!sin || sin->sin_addr.s_addr == 0) { 360 struct ip_out_args ipoa = 361 { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF }; 362 struct route ro; 363 struct ip_moptions *imo; 364 365 /* 366 * Don't allow both user specified and setsockopt options, 367 * and don't allow packet length sizes that will crash 368 */ 369 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || 370 ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { 371 error = EINVAL; 372 goto cantsend; 373 } 374 375 /* Convert fields to host order for ip_output() */ 376#if BYTE_ORDER != BIG_ENDIAN 377 NTOHS(ip->ip_len); 378 NTOHS(ip->ip_off); 379#endif 380 381 OSAddAtomic(1, &ipstat.ips_rawout); 382 /* Copy the cached route and take an extra reference */ 383 inp_route_copyout(inp, &ro); 384 385 set_packet_service_class(m, so, msc, 0); 386 387 imo = inp->inp_moptions; 388 if (imo != NULL) 389 IMO_ADDREF(imo); 390 socket_unlock(so, 0); 391#if CONFIG_MACF_NET 392 mac_mbuf_label_associate_inpcb(inp, m); 393#endif 394 /* Send packet to output processing */ 395 error = ip_output(m, inp->inp_options, &ro, 396 (so->so_options & SO_DONTROUTE) | 397 IP_ALLOWBROADCAST | IP_RAWOUTPUT | IP_OUTARGS, 398 imo, &ipoa); 399 400 socket_lock(so, 0); 401 if (imo != NULL) 402 IMO_REMREF(imo); 403 /* Synchronize cached PCB route */ 404 inp_route_copyin(inp, &ro); 405 } else { 406 struct ifaddr *ifa; 407 408 /* If no luck with the name above. check by IP address. */ 409 if (m->m_pkthdr.rcvif == NULL) { 410 /* 411 * Make sure there are no distractions 412 * for ifa_ifwithaddr. Clear the port and the ifname. 413 * Maybe zap all 8 bytes at once using a 64bit write? 414 */ 415 bzero(sin->sin_zero, sizeof(sin->sin_zero)); 416 /* *((u_int64_t *)sin->sin_zero) = 0; */ /* XXX ?? */ 417 sin->sin_port = 0; 418 if (!(ifa = ifa_ifwithaddr((struct sockaddr *) sin))) { 419 error = EADDRNOTAVAIL; 420 goto cantsend; 421 } 422 m->m_pkthdr.rcvif = ifa->ifa_ifp; 423 IFA_REMREF(ifa); 424 } 425#if CONFIG_MACF_NET 426 mac_mbuf_label_associate_socket(so, m); 427#endif 428 /* Send packet to input processing */ 429 proto_inject(PF_INET, m); 430 } 431 432 return error; 433 434cantsend: 435 m_freem(m); 436 return error; 437} 438 439static int 440div_attach(struct socket *so, int proto, struct proc *p) 441{ 442 struct inpcb *inp; 443 int error; 444 445 446 inp = sotoinpcb(so); 447 if (inp) 448 panic("div_attach"); 449 if ((error = proc_suser(p)) != 0) 450 return error; 451 452 error = soreserve(so, div_sendspace, div_recvspace); 453 if (error) 454 return error; 455 error = in_pcballoc(so, &divcbinfo, p); 456 if (error) 457 return error; 458 inp = (struct inpcb *)so->so_pcb; 459 inp->inp_ip_p = proto; 460 inp->inp_vflag |= INP_IPV4; 461 inp->inp_flags |= INP_HDRINCL; 462 /* The socket is always "connected" because 463 we always know "where" to send the packet */ 464 so->so_state |= SS_ISCONNECTED; 465 466#ifdef MORE_DICVLOCK_DEBUG 467 printf("div_attach: so=%p sopcb=%p lock=%x ref=%x\n", 468 so, so->so_pcb, &(((struct inpcb *)so->so_pcb)->inpcb_mtx), so->so_usecount); 469#endif 470 return 0; 471} 472 473static int 474div_detach(struct socket *so) 475{ 476 struct inpcb *inp; 477 478#ifdef MORE_DICVLOCK_DEBUG 479 printf("div_detach: so=%p sopcb=%p lock=%x ref=%x\n", 480 so, so->so_pcb, &(((struct inpcb *)so->so_pcb)->inpcb_mtx), so->so_usecount); 481#endif 482 inp = sotoinpcb(so); 483 if (inp == 0) 484 panic("div_detach: so=%p null inp\n", so); 485 in_pcbdetach(inp); 486 inp->inp_state = INPCB_STATE_DEAD; 487 return 0; 488} 489 490static int 491div_abort(struct socket *so) 492{ 493 soisdisconnected(so); 494 return div_detach(so); 495} 496 497static int 498div_disconnect(struct socket *so) 499{ 500 if ((so->so_state & SS_ISCONNECTED) == 0) 501 return ENOTCONN; 502 return div_abort(so); 503} 504 505static int 506div_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 507{ 508 struct inpcb *inp; 509 int error; 510 511 inp = sotoinpcb(so); 512 /* in_pcbbind assumes that the socket is a sockaddr_in 513 * and in_pcbbind requires a valid address. Since divert 514 * sockets don't we need to make sure the address is 515 * filled in properly. 516 * XXX -- divert should not be abusing in_pcbind 517 * and should probably have its own family. 518 */ 519 if (nam->sa_family != AF_INET) { 520 error = EAFNOSUPPORT; 521 } else { 522 ((struct sockaddr_in *)(void *)nam)->sin_addr.s_addr = INADDR_ANY; 523 error = in_pcbbind(inp, nam, p); 524 } 525 return error; 526} 527 528static int 529div_shutdown(struct socket *so) 530{ 531 socantsendmore(so); 532 return 0; 533} 534 535static int 536div_send(struct socket *so, __unused int flags, struct mbuf *m, struct sockaddr *nam, 537 struct mbuf *control, __unused struct proc *p) 538{ 539 /* Packet must have a header (but that's about it) */ 540 if (m->m_len < sizeof (struct ip) && 541 (m = m_pullup(m, sizeof (struct ip))) == 0) { 542 OSAddAtomic(1, &ipstat.ips_toosmall); 543 m_freem(m); 544 return EINVAL; 545 } 546 547 /* Send packet */ 548 return div_output(so, m, nam, control); 549} 550 551#if 0 552static int 553div_pcblist SYSCTL_HANDLER_ARGS 554{ 555#pragma unused(oidp, arg1, arg2) 556 int error, i, n; 557 struct inpcb *inp, **inp_list; 558 inp_gen_t gencnt; 559 struct xinpgen xig; 560 561 /* 562 * The process of preparing the TCB list is too time-consuming and 563 * resource-intensive to repeat twice on every request. 564 */ 565 lck_rw_lock_exclusive(divcbinfo.mtx); 566 if (req->oldptr == USER_ADDR_NULL) { 567 n = divcbinfo.ipi_count; 568 req->oldidx = 2 * (sizeof xig) 569 + (n + n/8) * sizeof(struct xinpcb); 570 lck_rw_done(divcbinfo.mtx); 571 return 0; 572 } 573 574 if (req->newptr != USER_ADDR_NULL) { 575 lck_rw_done(divcbinfo.mtx); 576 return EPERM; 577 } 578 579 /* 580 * OK, now we're committed to doing something. 581 */ 582 gencnt = divcbinfo.ipi_gencnt; 583 n = divcbinfo.ipi_count; 584 585 bzero(&xig, sizeof(xig)); 586 xig.xig_len = sizeof xig; 587 xig.xig_count = n; 588 xig.xig_gen = gencnt; 589 xig.xig_sogen = so_gencnt; 590 error = SYSCTL_OUT(req, &xig, sizeof xig); 591 if (error) { 592 lck_rw_done(divcbinfo.mtx); 593 return error; 594 } 595 596 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); 597 if (inp_list == 0) { 598 lck_rw_done(divcbinfo.mtx); 599 return ENOMEM; 600 } 601 602 for (inp = LIST_FIRST(divcbinfo.listhead), i = 0; inp && i < n; 603 inp = LIST_NEXT(inp, inp_list)) { 604#ifdef __APPLE__ 605 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) 606#else 607 if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp)) 608#endif 609 inp_list[i++] = inp; 610 } 611 n = i; 612 613 error = 0; 614 for (i = 0; i < n; i++) { 615 inp = inp_list[i]; 616 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) { 617 struct xinpcb xi; 618 619 bzero(&xi, sizeof(xi)); 620 xi.xi_len = sizeof xi; 621 /* XXX should avoid extra copy */ 622 inpcb_to_compat(inp, &xi.xi_inp); 623 if (inp->inp_socket) 624 sotoxsocket(inp->inp_socket, &xi.xi_socket); 625 error = SYSCTL_OUT(req, &xi, sizeof xi); 626 } 627 } 628 if (!error) { 629 /* 630 * Give the user an updated idea of our state. 631 * If the generation differs from what we told 632 * them before, they know that something happened 633 * while we were processing this request, and it 634 * might be necessary to retry. 635 */ 636 bzero(&xig, sizeof(xig)); 637 xig.xig_len = sizeof xig; 638 xig.xig_gen = divcbinfo.ipi_gencnt; 639 xig.xig_sogen = so_gencnt; 640 xig.xig_count = divcbinfo.ipi_count; 641 error = SYSCTL_OUT(req, &xig, sizeof xig); 642 } 643 FREE(inp_list, M_TEMP); 644 lck_rw_done(divcbinfo.mtx); 645 return error; 646} 647#endif 648 649__private_extern__ int 650div_lock(struct socket *so, int refcount, void *lr) 651{ 652 void *lr_saved; 653 654 if (lr == NULL) 655 lr_saved = __builtin_return_address(0); 656 else 657 lr_saved = lr; 658 659#ifdef MORE_DICVLOCK_DEBUG 660 printf("div_lock: so=%p sopcb=%p lock=%p ref=%x lr=%p\n", 661 so, so->so_pcb, so->so_pcb ? 662 &(((struct inpcb *)so->so_pcb)->inpcb_mtx) : NULL, 663 so->so_usecount, lr_saved); 664#endif 665 if (so->so_pcb) { 666 lck_mtx_lock(&((struct inpcb *)so->so_pcb)->inpcb_mtx); 667 } else { 668 panic("div_lock: so=%p NO PCB! lr=%p lrh= lrh= %s\n", 669 so, lr_saved, solockhistory_nr(so)); 670 /* NOTREACHED */ 671 } 672 673 if (so->so_usecount < 0) { 674 panic("div_lock: so=%p so_pcb=%p lr=%p ref=%x lrh= %s\n", 675 so, so->so_pcb, lr_saved, so->so_usecount, 676 solockhistory_nr(so)); 677 /* NOTREACHED */ 678 } 679 680 if (refcount) 681 so->so_usecount++; 682 so->lock_lr[so->next_lock_lr] = lr_saved; 683 so->next_lock_lr = (so->next_lock_lr+1) % SO_LCKDBG_MAX; 684 685 return (0); 686} 687 688__private_extern__ int 689div_unlock(struct socket *so, int refcount, void *lr) 690{ 691 void *lr_saved; 692 lck_mtx_t * mutex_held; 693 struct inpcb *inp = sotoinpcb(so); 694 695 if (lr == NULL) 696 lr_saved = __builtin_return_address(0); 697 else 698 lr_saved = lr; 699 700#ifdef MORE_DICVLOCK_DEBUG 701 printf("div_unlock: so=%p sopcb=%p lock=%p ref=%x lr=%p\n", 702 so, so->so_pcb, so->so_pcb ? 703 &(((struct inpcb *)so->so_pcb)->inpcb_mtx) : NULL, 704 so->so_usecount, lr_saved); 705#endif 706 if (refcount) 707 so->so_usecount--; 708 709 if (so->so_usecount < 0) { 710 panic("div_unlock: so=%p usecount=%x lrh= %s\n", 711 so, so->so_usecount, solockhistory_nr(so)); 712 /* NOTREACHED */ 713 } 714 if (so->so_pcb == NULL) { 715 panic("div_unlock: so=%p NO PCB usecount=%x lr=%p lrh= %s\n", 716 so, so->so_usecount, lr_saved, solockhistory_nr(so)); 717 /* NOTREACHED */ 718 } 719 mutex_held = &((struct inpcb *)so->so_pcb)->inpcb_mtx; 720 721 if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) { 722 lck_rw_lock_exclusive(divcbinfo.mtx); 723 if (inp->inp_state != INPCB_STATE_DEAD) 724 in_pcbdetach(inp); 725 in_pcbdispose(inp); 726 lck_rw_done(divcbinfo.mtx); 727 return (0); 728 } 729 lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED); 730 so->unlock_lr[so->next_unlock_lr] = lr_saved; 731 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX; 732 lck_mtx_unlock(mutex_held); 733 return (0); 734} 735 736__private_extern__ lck_mtx_t * 737div_getlock(struct socket *so, __unused int locktype) 738{ 739 struct inpcb *inpcb = (struct inpcb *)so->so_pcb; 740 741 if (so->so_pcb) { 742 if (so->so_usecount < 0) 743 panic("div_getlock: so=%p usecount=%x lrh= %s\n", 744 so, so->so_usecount, solockhistory_nr(so)); 745 return(&inpcb->inpcb_mtx); 746 } else { 747 panic("div_getlock: so=%p NULL NO PCB lrh= %s\n", 748 so, solockhistory_nr(so)); 749 return (so->so_proto->pr_domain->dom_mtx); 750 } 751} 752 753 754struct pr_usrreqs div_usrreqs = { 755 div_abort, pru_accept_notsupp, div_attach, div_bind, 756 pru_connect_notsupp, pru_connect2_notsupp, in_control, div_detach, 757 div_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 758 pru_rcvoob_notsupp, div_send, pru_sense_null, div_shutdown, 759 in_setsockaddr, sosend, soreceive, pru_sopoll_notsupp 760}; 761 762