X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..d1ecb069dfe24481e4a83f44cb5217a2b06746d7:/bsd/netinet/ip_divert.c?ds=sidebyside diff --git a/bsd/netinet/ip_divert.c b/bsd/netinet/ip_divert.c index 8a02c85b5..f5db5922a 100644 --- a/bsd/netinet/ip_divert.c +++ b/bsd/netinet/ip_divert.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1986, 1988, 1993 @@ -62,7 +60,7 @@ * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.98 2004/08/17 22:05:54 andre Exp $ */ -#ifndef INET +#if !INET #error "IPDIVERT requires INET." #endif @@ -78,9 +76,11 @@ #include #include +#include #include #include +#include #include #include @@ -92,6 +92,7 @@ #include #include +#include /* * Divert sockets @@ -131,11 +132,11 @@ static struct inpcbhead divcb; static struct inpcbinfo divcbinfo; -static u_long div_sendspace = DIVSNDQ; /* XXX sysctl ? */ -static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */ +static u_int32_t div_sendspace = DIVSNDQ; /* XXX sysctl ? */ +static u_int32_t div_recvspace = DIVRCVQ; /* XXX sysctl ? */ /* Optimization: have this preinitialized */ -static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET, }; +static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET, 0, { 0 }, { 0,0,0,0,0,0,0,0 } }; /* Internal functions */ static int div_output(struct socket *so, @@ -172,14 +173,15 @@ div_init(void) * allocate the lock attribute for divert pcb mutexes */ pcbinfo->mtx_attr = lck_attr_alloc_init(); - lck_attr_setdefault(pcbinfo->mtx_attr); if ((pcbinfo->mtx = lck_rw_alloc_init(pcbinfo->mtx_grp, pcbinfo->mtx_attr)) == NULL) return; /* pretty much dead if this fails... */ +#if IPFIREWALL if (!IPFW_LOADED) { load_ipfw(); } +#endif } /* @@ -189,7 +191,7 @@ div_init(void) void div_input(struct mbuf *m, __unused int off) { - ipstat.ips_noproto++; + OSAddAtomic(1, &ipstat.ips_noproto); m_freem(m); } @@ -290,8 +292,8 @@ divert_packet(struct mbuf *m, int incoming, int port, int rule) socket_unlock(sa, 1); } else { m_freem(m); - ipstat.ips_noproto++; - ipstat.ips_delivered--; + OSAddAtomic(1, &ipstat.ips_noproto); + OSAddAtomic(-1, &ipstat.ips_delivered); } lck_rw_done(divcbinfo.mtx); } @@ -305,14 +307,11 @@ divert_packet(struct mbuf *m, int incoming, int port, int rule) * ###LOCK called in inet_proto mutex when from div_send. */ static int -div_output(so, m, addr, control) - struct socket *so; - register struct mbuf *m; - struct sockaddr *addr; - struct mbuf *control; +div_output(struct socket *so, struct mbuf *m, struct sockaddr *addr, + struct mbuf *control) { - register struct inpcb *const inp = sotoinpcb(so); - register struct ip *const ip = mtod(m, struct ip *); + struct inpcb *const inp = sotoinpcb(so); + struct ip *const ip = mtod(m, struct ip *); struct sockaddr_in *sin = (struct sockaddr_in *)addr; int error = 0; @@ -353,6 +352,9 @@ div_output(so, m, addr, control) /* Reinject packet into the system as incoming or outgoing */ if (!sin || sin->sin_addr.s_addr == 0) { + struct ip_out_args ipoa = { IFSCOPE_NONE }; + struct route ro; + /* * Don't allow both user specified and setsockopt options, * and don't allow packet length sizes that will crash @@ -364,18 +366,33 @@ div_output(so, m, addr, control) } /* Convert fields to host order for ip_output() */ +#if BYTE_ORDER != BIG_ENDIAN NTOHS(ip->ip_len); NTOHS(ip->ip_off); +#endif + + OSAddAtomic(1, &ipstat.ips_rawout); + /* Copy the cached route and take an extra reference */ + inp_route_copyout(inp, &ro); + +#if PKT_PRIORITY + if (soisbackground(so)) + m_prio_background(m); +#endif /* PKT_PRIORITY */ - /* Send packet to output processing */ - ipstat.ips_rawout++; /* XXX */ socket_unlock(so, 0); - error = ip_output(m, - inp->inp_options, &inp->inp_route, +#if CONFIG_MACF_NET + mac_mbuf_label_associate_inpcb(inp, m); +#endif + /* Send packet to output processing */ + error = ip_output(m, inp->inp_options, &ro, (so->so_options & SO_DONTROUTE) | - IP_ALLOWBROADCAST | IP_RAWOUTPUT, - inp->inp_moptions); + IP_ALLOWBROADCAST | IP_RAWOUTPUT | IP_OUTARGS, + inp->inp_moptions, &ipoa); + socket_lock(so, 0); + /* Synchronize cached PCB route */ + inp_route_copyin(inp, &ro); } else { struct ifaddr *ifa; @@ -396,30 +413,9 @@ div_output(so, m, addr, control) m->m_pkthdr.rcvif = ifa->ifa_ifp; ifafree(ifa); } - - if ((~IF_HWASSIST_CSUM_FLAGS(m->m_pkthdr.rcvif->if_hwassist) & - m->m_pkthdr.csum_flags) == 0) { - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } - m->m_pkthdr.csum_flags |= - CSUM_DATA_VALID | CSUM_PSEUDO_HDR | - CSUM_IP_CHECKED | CSUM_IP_VALID; - m->m_pkthdr.csum_data = 0xffff; - } - else if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - int hlen; - -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; +#if CONFIG_MACF_NET + mac_mbuf_label_associate_socket(so, m); #endif - in_delayed_cksum(m); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - ip->ip_sum = in_cksum(m, hlen); - } - /* Send packet to input processing */ proto_inject(PF_INET, m); } @@ -441,7 +437,7 @@ div_attach(struct socket *so, int proto, struct proc *p) inp = sotoinpcb(so); if (inp) panic("div_attach"); - if (p && (error = proc_suser(p)) != 0) + if ((error = proc_suser(p)) != 0) return error; error = soreserve(so, div_sendspace, div_recvspace); @@ -459,7 +455,7 @@ div_attach(struct socket *so, int proto, struct proc *p) so->so_state |= SS_ISCONNECTED; #ifdef MORE_DICVLOCK_DEBUG - printf("div_attach: so=%x sopcb=%x lock=%x ref=%x\n", + printf("div_attach: so=%p sopcb=%p lock=%x ref=%x\n", so, so->so_pcb, ((struct inpcb *)so->so_pcb)->inpcb_mtx, so->so_usecount); #endif return 0; @@ -471,12 +467,12 @@ div_detach(struct socket *so) struct inpcb *inp; #ifdef MORE_DICVLOCK_DEBUG - printf("div_detach: so=%x sopcb=%x lock=%x ref=%x\n", + printf("div_detach: so=%p sopcb=%p lock=%x ref=%x\n", so, so->so_pcb, ((struct inpcb *)so->so_pcb)->inpcb_mtx, so->so_usecount); #endif inp = sotoinpcb(so); if (inp == 0) - panic("div_detach: so=%x null inp\n", so); + panic("div_detach: so=%p null inp\n", so); in_pcbdetach(inp); inp->inp_state = INPCB_STATE_DEAD; return 0; @@ -534,7 +530,7 @@ div_send(struct socket *so, __unused int flags, struct mbuf *m, struct sockaddr /* Packet must have a header (but that's about it) */ if (m->m_len < sizeof (struct ip) && (m = m_pullup(m, sizeof (struct ip))) == 0) { - ipstat.ips_toosmall++; + OSAddAtomic(1, &ipstat.ips_toosmall); m_freem(m); return EINVAL; } @@ -543,9 +539,11 @@ div_send(struct socket *so, __unused int flags, struct mbuf *m, struct sockaddr return div_output(so, m, nam, control); } +#if 0 static int div_pcblist SYSCTL_HANDLER_ARGS { +#pragma unused(oidp, arg1, arg2) int error, i, n; struct inpcb *inp, **inp_list; inp_gen_t gencnt; @@ -637,86 +635,92 @@ div_pcblist SYSCTL_HANDLER_ARGS lck_rw_done(divcbinfo.mtx); return error; } +#endif __private_extern__ int -div_lock(struct socket *so, int refcount, int lr) - { - int lr_saved; -#ifdef __ppc__ - if (lr == 0) { - __asm__ volatile("mflr %0" : "=r" (lr_saved)); - } - else lr_saved = lr; -#endif - +div_lock(struct socket *so, int refcount, void *lr) +{ + void *lr_saved; + + if (lr == NULL) + lr_saved = __builtin_return_address(0); + else + lr_saved = lr; + #ifdef MORE_DICVLOCK_DEBUG - printf("div_lock: so=%x sopcb=%x lock=%x ref=%x lr=%x\n", - so, - so->so_pcb, - so->so_pcb ? ((struct inpcb *)so->so_pcb)->inpcb_mtx : 0, - so->so_usecount, - lr_saved); + printf("div_lock: so=%p sopcb=%p lock=%p ref=%x lr=%p\n", + so, so->so_pcb, so->so_pcb ? + ((struct inpcb *)so->so_pcb)->inpcb_mtx : NULL, + so->so_usecount, lr_saved); #endif if (so->so_pcb) { lck_mtx_lock(((struct inpcb *)so->so_pcb)->inpcb_mtx); } else { - panic("div_lock: so=%x NO PCB! lr=%x\n", so, lr_saved); - lck_mtx_lock(so->so_proto->pr_domain->dom_mtx); + panic("div_lock: so=%p NO PCB! lr=%p lrh= lrh= %s\n", + so, lr_saved, solockhistory_nr(so)); + /* NOTREACHED */ } - - if (so->so_usecount < 0) - panic("div_lock: so=%x so_pcb=%x lr=%x ref=%x\n", - so, so->so_pcb, lr_saved, so->so_usecount); - + + if (so->so_usecount < 0) { + panic("div_lock: so=%p so_pcb=%p lr=%p ref=%x lrh= %s\n", + so, so->so_pcb, lr_saved, so->so_usecount, + solockhistory_nr(so)); + /* NOTREACHED */ + } + if (refcount) so->so_usecount++; - so->reserved3 = (void *)lr_saved; + so->lock_lr[so->next_lock_lr] = lr_saved; + so->next_lock_lr = (so->next_lock_lr+1) % SO_LCKDBG_MAX; return (0); } __private_extern__ int -div_unlock(struct socket *so, int refcount, int lr) +div_unlock(struct socket *so, int refcount, void *lr) { - int lr_saved; + void *lr_saved; lck_mtx_t * mutex_held; - struct inpcb *inp = sotoinpcb(so); -#ifdef __ppc__ - if (lr == 0) { - __asm__ volatile("mflr %0" : "=r" (lr_saved)); - } - else lr_saved = lr; -#endif - + struct inpcb *inp = sotoinpcb(so); + + if (lr == NULL) + lr_saved = __builtin_return_address(0); + else + lr_saved = lr; + #ifdef MORE_DICVLOCK_DEBUG - printf("div_unlock: so=%x sopcb=%x lock=%x ref=%x lr=%x\n", - so, - so->so_pcb, - so->so_pcb ? ((struct inpcb *)so->so_pcb)->inpcb_mtx : 0, - so->so_usecount, - lr_saved); + printf("div_unlock: so=%p sopcb=%p lock=%p ref=%x lr=%p\n", + so, so->so_pcb, so->so_pcb ? + ((struct inpcb *)so->so_pcb)->inpcb_mtx : NULL, + so->so_usecount, lr_saved); #endif if (refcount) so->so_usecount--; - - if (so->so_usecount < 0) - panic("div_unlock: so=%x usecount=%x\n", so, so->so_usecount); + + if (so->so_usecount < 0) { + panic("div_unlock: so=%p usecount=%x lrh= %s\n", + so, so->so_usecount, solockhistory_nr(so)); + /* NOTREACHED */ + } if (so->so_pcb == NULL) { - panic("div_unlock: so=%x NO PCB usecount=%x lr=%x\n", so, so->so_usecount, lr_saved); - mutex_held = so->so_proto->pr_domain->dom_mtx; - } else { - mutex_held = ((struct inpcb *)so->so_pcb)->inpcb_mtx; + panic("div_unlock: so=%p NO PCB usecount=%x lr=%p lrh= %s\n", + so, so->so_usecount, lr_saved, solockhistory_nr(so)); + /* NOTREACHED */ } + mutex_held = ((struct inpcb *)so->so_pcb)->inpcb_mtx; if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) { lck_rw_lock_exclusive(divcbinfo.mtx); + if (inp->inp_state != INPCB_STATE_DEAD) + in_pcbdetach(inp); in_pcbdispose(inp); lck_rw_done(divcbinfo.mtx); return (0); } lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED); + so->unlock_lr[so->next_unlock_lr] = lr_saved; + so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX; lck_mtx_unlock(mutex_held); - so->reserved4 = (void *)lr_saved; return (0); } @@ -727,10 +731,12 @@ div_getlock(struct socket *so, __unused int locktype) if (so->so_pcb) { if (so->so_usecount < 0) - panic("div_getlock: so=%x usecount=%x\n", so, so->so_usecount); + panic("div_getlock: so=%p usecount=%x lrh= %s\n", + so, so->so_usecount, solockhistory_nr(so)); return(inpcb->inpcb_mtx); } else { - panic("div_getlock: so=%x NULL so_pcb\n", so); + panic("div_getlock: so=%p NULL NO PCB lrh= %s\n", + so, solockhistory_nr(so)); return (so->so_proto->pr_domain->dom_mtx); } }