Esempio n. 1
0
/**
 * Reads and retains the host interface handle.
 *
 * @returns The handle, NULL if detached.
 * @param   pThis
 */
DECLINLINE(ifnet_t) vboxNetFltDarwinRetainIfNet(PVBOXNETFLTINS pThis)
{
    ifnet_t pIfNet = NULL;

    /*
     * Be careful here to avoid problems racing the detached callback.
     */
    RTSpinlockAcquire(pThis->hSpinlock);
    if (!ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
    {
        pIfNet = ASMAtomicUoReadPtrT(&pThis->u.s.pIfNet, ifnet_t);
        if (pIfNet)
            ifnet_reference(pIfNet);
    }
    RTSpinlockReleaseNoInts(pThis->hSpinlock);

    return pIfNet;
}
Esempio n. 2
0
File: in6_src.c Progetto: Prajna/xnu
static int
in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
    struct ip6_moptions *mopts, struct route_in6 *ro, unsigned int ifscope,
    unsigned int nocell, struct ifnet **retifp)
{
	int error;
	struct route_in6 sro;
	struct rtentry *rt = NULL;

	if (ro == NULL) {
		bzero(&sro, sizeof(sro));
		ro = &sro;
	}

	if ((error = selectroute(NULL, dstsock, opts, mopts, ro, retifp,
	    &rt, 0, 1, ifscope, nocell)) != 0) {
		if (ro == &sro && rt && rt == sro.ro_rt)
			rtfree(rt);
		return (error);
	}

	/*
	 * do not use a rejected or black hole route.
	 * XXX: this check should be done in the L2 output routine.
	 * However, if we skipped this check here, we'd see the following
	 * scenario:
	 * - install a rejected route for a scoped address prefix
	 *   (like fe80::/10)
	 * - send a packet to a destination that matches the scoped prefix,
	 *   with ambiguity about the scope zone.
	 * - pick the outgoing interface from the route, and disambiguate the
	 *   scope zone with the interface.
	 * - ip6_output() would try to get another route with the "new"
	 *   destination, which may be valid.
	 * - we'd see no error on output.
	 * Although this may not be very harmful, it should still be confusing.
	 * We thus reject the case here.
	 */
	if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE))) {
		int flags = (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);

		if (ro == &sro && rt && rt == sro.ro_rt)
			rtfree(rt);
		return (flags);
	}

	/*
	 * Adjust the "outgoing" interface.  If we're going to loop the packet
	 * back to ourselves, the ifp would be the loopback interface.
	 * However, we'd rather know the interface associated to the
	 * destination address (which should probably be one of our own
	 * addresses.)
	 */
	if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp) {
		if (*retifp != NULL)
			ifnet_release(*retifp);
		*retifp = rt->rt_ifa->ifa_ifp;
		ifnet_reference(*retifp);
	}

	if (ro == &sro && rt && rt == sro.ro_rt)
		rtfree(rt);
	return (0);
}
Esempio n. 3
0
File: in6_src.c Progetto: Prajna/xnu
/*
 * Given a source IPv6 address (and route, if available), determine the best
 * interface to send the packet from.  Checking for (and updating) the
 * ROF_SRCIF_SELECTED flag in the pcb-supplied route placeholder is done
 * without any locks, based on the assumption that in the event this is
 * called from ip6_output(), the output operation is single-threaded per-pcb,
 * i.e. for any given pcb there can only be one thread performing output at
 * the IPv6 layer.
 *
 * This routine is analogous to in_selectsrcif() for IPv4.
 *
 * clone - meaningful only for bsdi and freebsd
 */
static int
selectroute(struct sockaddr_in6 *srcsock, struct sockaddr_in6 *dstsock,
    struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct route_in6 *ro,
    struct ifnet **retifp, struct rtentry **retrt, int clone,
    int norouteok, unsigned int ifscope, unsigned int nocell)
{
	int error = 0;
	struct ifnet *ifp = NULL;
	struct route_in6 *route = NULL;
	struct sockaddr_in6 *sin6_next;
	struct in6_pktinfo *pi = NULL;
	struct in6_addr *dst = &dstsock->sin6_addr;
	struct ifaddr *ifa = NULL;
	char s_src[MAX_IPv6_STR_LEN], s_dst[MAX_IPv6_STR_LEN];
	boolean_t select_srcif;

#if 0
	char ip6buf[INET6_ADDRSTRLEN];

	if (dstsock->sin6_addr.s6_addr32[0] == 0 &&
	    dstsock->sin6_addr.s6_addr32[1] == 0 &&
	    !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) {
		printf("in6_selectroute: strange destination %s\n",
		       ip6_sprintf(ip6buf, &dstsock->sin6_addr));
	} else {
		printf("in6_selectroute: destination = %s%%%d\n",
		       ip6_sprintf(ip6buf, &dstsock->sin6_addr),
		       dstsock->sin6_scope_id); /* for debug */
	}
#endif

	if (retifp != NULL)
		*retifp = NULL;

	if (retrt != NULL)
		*retrt = NULL;

	if (ip6_select_srcif_debug) {
		struct in6_addr src;
		src = (srcsock != NULL) ? srcsock->sin6_addr : in6addr_any;
		(void) inet_ntop(AF_INET6, &src, s_src, sizeof (s_src));
		(void) inet_ntop(AF_INET6, dst, s_dst, sizeof (s_dst));
	}

	/*
	 * If the destination address is UNSPECIFIED addr, bail out.
	 */
	if (IN6_IS_ADDR_UNSPECIFIED(dst)) {
		error = EHOSTUNREACH;
		goto done;
	}

	/*
	 * Perform source interface selection only if Scoped Routing
	 * is enabled and a source address that isn't unspecified.
	 */
	select_srcif = (ip6_doscopedroute && srcsock != NULL &&
	    !IN6_IS_ADDR_UNSPECIFIED(&srcsock->sin6_addr));

	/*
	 * If Scoped Routing is disabled, ignore the given ifscope.
	 * Otherwise even if source selection won't be performed,
	 * we still obey IPV6_BOUND_IF.
	 */
	if (!ip6_doscopedroute && ifscope != IFSCOPE_NONE)
		ifscope = IFSCOPE_NONE;

	/* If the caller specified the outgoing interface explicitly, use it */
	if (opts != NULL && (pi = opts->ip6po_pktinfo) != NULL &&
	    pi->ipi6_ifindex != 0) {
		/*
		 * If IPV6_PKTINFO takes precedence over IPV6_BOUND_IF.
		 */
		ifscope = pi->ipi6_ifindex;
		ifnet_head_lock_shared();
		/* ifp may be NULL if detached or out of range */
		ifp = (ifscope <= if_index) ? ifindex2ifnet[ifscope] : NULL;
		ifnet_head_done();
		if (norouteok || retrt == NULL || IN6_IS_ADDR_MULTICAST(dst)) {
			/*
			 * We do not have to check or get the route for
			 * multicast.  If the caller didn't ask/care for
			 * the route and we have no interface to use,
			 * it's an error.
			 */
			if (ifp == NULL)
				error = EHOSTUNREACH;
			goto done;
		} else {
			goto getsrcif;
		}
	}

	/*
	 * If the destination address is a multicast address and the outgoing
	 * interface for the address is specified by the caller, use it.
	 */
	if (IN6_IS_ADDR_MULTICAST(dst) && mopts != NULL) {
		IM6O_LOCK(mopts);
		if ((ifp = mopts->im6o_multicast_ifp) != NULL) {
			IM6O_UNLOCK(mopts);
			goto done; /* we do not need a route for multicast. */
		}
		IM6O_UNLOCK(mopts);
	}

getsrcif:
	/*
	 * If the outgoing interface was not set via IPV6_BOUND_IF or
	 * IPV6_PKTINFO, use the scope ID in the destination address.
	 */
	if (ip6_doscopedroute && ifscope == IFSCOPE_NONE)
		ifscope = dstsock->sin6_scope_id;

	/*
	 * Perform source interface selection; the source IPv6 address
	 * must belong to one of the addresses of the interface used
	 * by the route.  For performance reasons, do this only if
	 * there is no route, or if the routing table has changed,
	 * or if we haven't done source interface selection on this
	 * route (for this PCB instance) before.
	 */
	if (!select_srcif || (ro != NULL && ro->ro_rt != NULL &&
	    (ro->ro_rt->rt_flags & RTF_UP) &&
	    ro->ro_rt->generation_id == route_generation &&
	    (ro->ro_flags & ROF_SRCIF_SELECTED))) {
		if (ro != NULL && ro->ro_rt != NULL) {
			ifa = ro->ro_rt->rt_ifa;
			IFA_ADDREF(ifa);
		}
		goto getroute;
	}

	/*
	 * Given the source IPv6 address, find a suitable source interface
	 * to use for transmission; if a scope ID has been specified,
	 * optimize the search by looking at the addresses only for that
	 * interface.  This is still suboptimal, however, as we need to
	 * traverse the per-interface list.
	 */
	if (ifscope != IFSCOPE_NONE || (ro != NULL && ro->ro_rt != NULL)) {
		unsigned int scope = ifscope;
		struct ifnet *rt_ifp;

		rt_ifp = (ro->ro_rt != NULL) ? ro->ro_rt->rt_ifp : NULL;

		/*
		 * If no scope is specified and the route is stale (pointing
		 * to a defunct interface) use the current primary interface;
		 * this happens when switching between interfaces configured
		 * with the same IPv6 address.  Otherwise pick up the scope
		 * information from the route; the ULP may have looked up a
		 * correct route and we just need to verify it here and mark
		 * it with the ROF_SRCIF_SELECTED flag below.
		 */
		if (scope == IFSCOPE_NONE) {
			scope = rt_ifp->if_index;
			if (scope != get_primary_ifscope(AF_INET6) &&
			    ro->ro_rt->generation_id != route_generation)
				scope = get_primary_ifscope(AF_INET6);
		}

		ifa = (struct ifaddr *)
		    ifa_foraddr6_scoped(&srcsock->sin6_addr, scope);

		if (ip6_select_srcif_debug && ifa != NULL) {
			if (ro->ro_rt != NULL) {
				printf("%s->%s ifscope %d->%d ifa_if %s "
				    "ro_if %s\n", s_src, s_dst, ifscope,
				    scope, if_name(ifa->ifa_ifp),
				    if_name(rt_ifp));
			} else {
				printf("%s->%s ifscope %d->%d ifa_if %s\n",
				    s_src, s_dst, ifscope, scope,
				    if_name(ifa->ifa_ifp));
			}
		}
	}

	/*
	 * Slow path; search for an interface having the corresponding source
	 * IPv6 address if the scope was not specified by the caller, and:
	 *
	 *   1) There currently isn't any route, or,
	 *   2) The interface used by the route does not own that source
	 *	IPv6 address; in this case, the route will get blown away
	 *	and we'll do a more specific scoped search using the newly
	 *	found interface.
	 */
	if (ifa == NULL && ifscope == IFSCOPE_NONE) {
		ifa = (struct ifaddr *)ifa_foraddr6(&srcsock->sin6_addr);

		if (ip6_select_srcif_debug && ifa != NULL) {
			printf("%s->%s ifscope %d ifa_if %s\n",
			    s_src, s_dst, ifscope, if_name(ifa->ifa_ifp));
		}

	}

getroute:
	if (ifa != NULL)
		ifscope = ifa->ifa_ifp->if_index;

	/*
	 * If the next hop address for the packet is specified by the caller,
	 * use it as the gateway.
	 */
	if (opts != NULL && opts->ip6po_nexthop != NULL) {
		struct route_in6 *ron;

		sin6_next = satosin6(opts->ip6po_nexthop);

		/* at this moment, we only support AF_INET6 next hops */
		if (sin6_next->sin6_family != AF_INET6) {
			error = EAFNOSUPPORT; /* or should we proceed? */
			goto done;
		}

		/*
		 * If the next hop is an IPv6 address, then the node identified
		 * by that address must be a neighbor of the sending host.
		 */
		ron = &opts->ip6po_nextroute;
		if (ron->ro_rt != NULL)
			RT_LOCK(ron->ro_rt);
		if ((ron->ro_rt != NULL &&
		    ((ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=
		    (RTF_UP | RTF_LLINFO) ||
		    ron->ro_rt->generation_id != route_generation ||
		    (select_srcif && (ifa == NULL ||
		    ifa->ifa_ifp != ron->ro_rt->rt_ifp)))) ||
		    !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
		    &sin6_next->sin6_addr)) {
			if (ron->ro_rt != NULL) {
				RT_UNLOCK(ron->ro_rt);
				rtfree(ron->ro_rt);
				ron->ro_rt = NULL;
			}
			*satosin6(&ron->ro_dst) = *sin6_next;
		}
		if (ron->ro_rt == NULL) {
			rtalloc_scoped((struct route *)ron, ifscope);
			if (ron->ro_rt != NULL)
				RT_LOCK(ron->ro_rt);
			if (ron->ro_rt == NULL ||
			    !(ron->ro_rt->rt_flags & RTF_LLINFO) ||
			    !IN6_ARE_ADDR_EQUAL(&satosin6(rt_key(ron->ro_rt))->
			    sin6_addr, &sin6_next->sin6_addr)) {
				if (ron->ro_rt != NULL) {
					RT_UNLOCK(ron->ro_rt);
					rtfree(ron->ro_rt);
					ron->ro_rt = NULL;
				}
				error = EHOSTUNREACH;
				goto done;
			}
		}
		route = ron;
		ifp = ron->ro_rt->rt_ifp;

		/*
		 * When cloning is required, try to allocate a route to the
		 * destination so that the caller can store path MTU
		 * information.
		 */
		if (!clone) {
			if (select_srcif) {
				/* Keep the route locked */
				goto validateroute;
			}
			RT_UNLOCK(ron->ro_rt);
			goto done;
		}
		RT_UNLOCK(ron->ro_rt);
	}

	/*
	 * Use a cached route if it exists and is valid, else try to allocate
	 * a new one.  Note that we should check the address family of the
	 * cached destination, in case of sharing the cache with IPv4.
	 */
	if (ro == NULL)
		goto done;
	if (ro->ro_rt != NULL)
		RT_LOCK(ro->ro_rt);
	if (ro->ro_rt != NULL && (!(ro->ro_rt->rt_flags & RTF_UP) ||
	    satosin6(&ro->ro_dst)->sin6_family != AF_INET6 ||
	    ro->ro_rt->generation_id != route_generation ||
	    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst) ||
	    (select_srcif && (ifa == NULL ||
	    ifa->ifa_ifp != ro->ro_rt->rt_ifp)))) {
		RT_UNLOCK(ro->ro_rt);
		rtfree(ro->ro_rt);
		ro->ro_rt = NULL;
	}
	if (ro->ro_rt == NULL) {
		struct sockaddr_in6 *sa6;

		if (ro->ro_rt != NULL)
			RT_UNLOCK(ro->ro_rt);
		/* No route yet, so try to acquire one */
		bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
		sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
		sa6->sin6_family = AF_INET6;
		sa6->sin6_len = sizeof(struct sockaddr_in6);
		sa6->sin6_addr = *dst;
		if (IN6_IS_ADDR_MULTICAST(dst)) {
			ro->ro_rt = rtalloc1_scoped(
			    &((struct route *)ro)->ro_dst, 0, 0, ifscope);
		} else {
			rtalloc_scoped((struct route *)ro, ifscope);
		}
		if (ro->ro_rt != NULL)
			RT_LOCK(ro->ro_rt);
	}

	/*
	 * Do not care about the result if we have the nexthop
	 * explicitly specified (in case we're asked to clone.)
	 */
	if (opts != NULL && opts->ip6po_nexthop != NULL) {
		if (ro->ro_rt != NULL)
			RT_UNLOCK(ro->ro_rt);
		goto done;
	}

	if (ro->ro_rt != NULL) {
		RT_LOCK_ASSERT_HELD(ro->ro_rt);
		ifp = ro->ro_rt->rt_ifp;
	} else {
		error = EHOSTUNREACH;
	}
	route = ro;

validateroute:
	if (select_srcif) {
		boolean_t has_route = (route != NULL && route->ro_rt != NULL);

		if (has_route)
			RT_LOCK_ASSERT_HELD(route->ro_rt);
		/*
		 * If there is a non-loopback route with the wrong interface,
		 * or if there is no interface configured with such an address,
		 * blow it away.  Except for local/loopback, we look for one
		 * with a matching interface scope/index.
		 */
		if (has_route && (ifa == NULL ||
		    (ifa->ifa_ifp != ifp && ifp != lo_ifp) ||
		    !(route->ro_rt->rt_flags & RTF_UP))) {
			if (ip6_select_srcif_debug) {
				if (ifa != NULL) {
					printf("%s->%s ifscope %d ro_if %s "
					    "!= ifa_if %s (cached route "
					    "cleared)\n", s_src, s_dst,
					    ifscope, if_name(ifp),
					    if_name(ifa->ifa_ifp));
				} else {
					printf("%s->%s ifscope %d ro_if %s "
					    "(no ifa_if found)\n", s_src,
					    s_dst, ifscope, if_name(ifp));
				}
			}
			RT_UNLOCK(route->ro_rt);
			rtfree(route->ro_rt);
			route->ro_rt = NULL;
			route->ro_flags &= ~ROF_SRCIF_SELECTED;
			error = EHOSTUNREACH;
			/* Undo the settings done above */
			route = NULL;
			ifp = NULL;
		} else if (has_route) {
			route->ro_flags |= ROF_SRCIF_SELECTED;
			route->ro_rt->generation_id = route_generation;
			RT_UNLOCK(route->ro_rt);
		}
	} else {
		if (ro->ro_rt != NULL)
			RT_UNLOCK(ro->ro_rt);
		if (ifp != NULL && opts != NULL &&
		    opts->ip6po_pktinfo != NULL &&
		    opts->ip6po_pktinfo->ipi6_ifindex != 0) {
			/*
			 * Check if the outgoing interface conflicts with the
			 * interface specified by ipi6_ifindex (if specified).
			 * Note that loopback interface is always okay.
			 * (this may happen when we are sending a packet to
			 * one of our own addresses.)
			 */
			if (!(ifp->if_flags & IFF_LOOPBACK) && ifp->if_index !=
			    opts->ip6po_pktinfo->ipi6_ifindex) {
				error = EHOSTUNREACH;
				goto done;
			}
		}
	}

done:
	if (nocell && error == 0) {
		if ((ifp != NULL && ifp->if_type == IFT_CELLULAR) ||
		    (route != NULL && route->ro_rt != NULL &&
		    route->ro_rt->rt_ifp->if_type == IFT_CELLULAR)) {
			if (route != NULL && route->ro_rt != NULL) {
				rtfree(route->ro_rt);
				route->ro_rt = NULL;
				route->ro_flags &= ~ROF_SRCIF_SELECTED;
				route = NULL;
			}
			ifp = NULL;
			error = EHOSTUNREACH;
		}
	}

	if (ifp == NULL && (route == NULL || route->ro_rt == NULL)) {
		/*
		 * This can happen if the caller did not pass a cached route
		 * nor any other hints.  We treat this case an error.
		 */
		error = EHOSTUNREACH;
	}
	if (error == EHOSTUNREACH)
		ip6stat.ip6s_noroute++;

	if (error == 0) {
		if (retifp != NULL) {
			if (ifp != NULL)
				ifnet_reference(ifp);	/* for caller */
			*retifp = ifp;
		}
		if (retrt != NULL && route != NULL)
			*retrt = route->ro_rt;	/* ro_rt may be NULL */
	} else if (select_srcif && ip6_select_srcif_debug) {
		printf("%s->%s ifscope %d ifa_if %s ro_if %s (error=%d)\n",
		    s_src, s_dst, ifscope,
		    (ifa != NULL) ? if_name(ifa->ifa_ifp) : "NONE",
		    (ifp != NULL) ? if_name(ifp) : "NONE", error);
	}

	if (ifa != NULL)
		IFA_REMREF(ifa);

	return (error);
}
Esempio n. 4
0
bool REACConnection::initWithInterface(IOWorkLoop *workLoop_, ifnet_t interface_, REACMode mode_,
                                       reac_connection_callback_t connectionCallback_,
                                       reac_samples_callback_t samplesCallback_,
                                       reac_get_samples_callback_t getSamplesCallback_,
                                       void *cookieA_,
                                       void *cookieB_,
                                       UInt8 inChannels_,
                                       UInt8 outChannels_) {
    dataStream = NULL;
    deviceInfo = NULL;
    filterCommandGate = NULL;
    workLoop = NULL;
    timerEventSource = NULL;
    interface = NULL;

    if (NULL == workLoop_) {
        goto Fail;
    }
    workLoop = workLoop_;
    workLoop->retain();

    // Add the command gate to the workloop
    filterCommandGate = IOCommandGate::commandGate(this, (IOCommandGate::Action)filterCommandGateMsg);
    if (NULL == filterCommandGate ||
            (workLoop->addEventSource(filterCommandGate) != kIOReturnSuccess) ) {
        IOLog("REACConnection::initWithInterface() - Error: Can't create or add commandGate\n");
        goto Fail;
    }

    // Add the timer event source to the workloop
    connectionCounter = 0;
    lastSeenConnectionCounter = 0;
    timerEventSource = IOTimerEventSource::timerEventSource(this, (IOTimerEventSource::Action)&REACConnection::timerFired);
    if (NULL == timerEventSource) {
        IOLog("REACConnection::initWithInterface() - Error: Failed to create timer event source.\n");
        goto Fail;
    }

    // Hack: Pretend to be connected immediately
    deviceInfo = (REACDeviceInfo*) IOMalloc(sizeof(REACDeviceInfo));
    if (NULL == deviceInfo) {
        IOLog("REACConnection::initWithInterface() - Error: Failed to allocate device info object.\n");
        goto Fail;
    }
    deviceInfo->addr[0] = 0x00;
    deviceInfo->addr[1] = 0x40;
    deviceInfo->addr[2] = 0xab;
    deviceInfo->addr[3] = 0xc4;
    deviceInfo->addr[4] = 0x80;
    deviceInfo->addr[5] = 0xf6;
    deviceInfo->in_channels = 16;
    deviceInfo->out_channels = 8;
    started = false;
    connected = false;

    lastCounter = 0;
    lastSeenConnectionCounter = 0;
    lastSentAnnouncementCounter = 0;
    splitAnnouncementCounter = 0;
    connectionCallback = connectionCallback_;
    samplesCallback = samplesCallback_;
    getSamplesCallback = getSamplesCallback_;
    cookieA = cookieA_;
    cookieB = cookieB_;
    mode = mode_;
    inChannels = inChannels_;
    outChannels = outChannels_;

    dataStream = REACDataStream::withConnection(this); // mode has to be set before this is called.
    if (NULL == dataStream) {
        goto Fail;
    }

    ifnet_reference(interface_);
    interface = interface_;

    if (kIOReturnSuccess != REACConnection::getInterfaceMacAddress(interface, interfaceAddr, sizeof(interfaceAddr))) {
        IOLog("REACConnection::initWithInterface() - Error: Failed to get interface address.\n");
        goto Fail;
    }

    // TODO This is a hack. It seems to be needless though.
    //static const UInt8 counterfeitMac[] = {
    //    0x00, 0x40, 0xab, 0xc4, 0xb7, 0x58
    //};
    //memcpy(interfaceAddr, counterfeitMac, sizeof(interfaceAddr));

    // Calculate our timeout in nanosecs, taking care to keep 64bits
    if (REAC_MASTER == mode_) {
        timeoutNS = 1000000000;
        timeoutNS /= REAC_PACKETS_PER_SECOND;
    }
    else {
        timeoutNS = REAC_CONNECTION_CHECK_TIMEOUT_MS;
        timeoutNS *= 1000000;
    }

    // Hack: Announce connect
    if (REAC_MASTER == mode) {
        if (NULL != connectionCallback) {
            connectionCallback(this, &cookieA, &cookieB, deviceInfo);
        }
    }

    return true;

Fail:
    deinit();
    return false;
}
Esempio n. 5
0
File: bpf.c Progetto: SbIm/xnu-env
errno_t
bpf_attach(
	ifnet_t			ifp,
	u_int32_t		dlt,
	u_int32_t		hdrlen,
	bpf_send_func	send,
	bpf_tap_func	tap)
{
	struct bpf_if *bp_new;
	struct bpf_if *bp_temp;
	struct bpf_if *bp_first = NULL;
	
	bp_new = (struct bpf_if *) _MALLOC(sizeof(*bp_new), M_DEVBUF, M_WAIT);
	if (bp_new == 0)
		panic("bpfattach");

	lck_mtx_lock(bpf_mlock);

	/*
	 * Check if this interface/dlt is already attached, record first
	 * attachment for this interface.
	 */
	for (bp_temp = bpf_iflist; bp_temp && (bp_temp->bif_ifp != ifp ||
		 bp_temp->bif_dlt != dlt); bp_temp = bp_temp->bif_next) {
		 if (bp_temp->bif_ifp == ifp && bp_first == NULL)
		 	bp_first = bp_temp;
	}
	
	if (bp_temp != NULL) {
		printf("bpfattach - %s%d with dlt %d is already attached\n",
			ifp->if_name, ifp->if_unit, dlt);
		FREE(bp_new, M_DEVBUF);
		lck_mtx_unlock(bpf_mlock);
		return EEXIST;
	}
	
	bzero(bp_new, sizeof(*bp_new));
	bp_new->bif_ifp = ifp;
	bp_new->bif_dlt = dlt;
	bp_new->bif_send = send;
	bp_new->bif_tap = tap;
	
	if (bp_first == NULL) {
		/* No other entries for this ifp */
		bp_new->bif_next = bpf_iflist;
		bpf_iflist = bp_new;
	}
	else {
		/* Add this after the first entry for this interface */
		bp_new->bif_next = bp_first->bif_next;
		bp_first->bif_next = bp_new;
	}
	
	/*
	 * Compute the length of the bpf header.  This is not necessarily
	 * equal to SIZEOF_BPF_HDR because we want to insert spacing such
	 * that the network layer header begins on a longword boundary (for
	 * performance reasons and to alleviate alignment restrictions).
	 */
	bp_new->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
	
	/* Take a reference on the interface */
	ifnet_reference(ifp);

	lck_mtx_unlock(bpf_mlock);

#ifndef __APPLE__
	if (bootverbose)
		printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit);
#endif

	return 0;
}