Пример #1
0
bool 
SocketCookie::SendDeferredData()
{
	while (deferredDataHead) 
	{
		if(deferredDataHead->direction)
		{
			if(sock_inject_data_in(socket, deferredDataHead->GetSockAddress(), deferredDataHead->data, deferredDataHead->control, deferredDataHead->flags))
			{
				mbuf_freem(deferredDataHead->data);
				mbuf_freem(deferredDataHead->control);
			}
		}
		else
		{
			sock_inject_data_out(socket, deferredDataHead->GetSockAddress(), deferredDataHead->data, deferredDataHead->control, deferredDataHead->flags);
		}
		
		DeferredData *old = deferredDataHead;
		deferredDataHead = deferredDataHead->next;
		delete old;
	}
	
	deferredDataLast = NULL;
	return true;
}
Пример #2
0
/* Network Interface functions */
static errno_t
utun_output(
			   ifnet_t	interface,
			   mbuf_t	data)
{
	struct utun_pcb	*pcb = ifnet_softc(interface);
	errno_t			result;
	
	if (m_pktlen(data) >= 4) {
		bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0);
	}
	
	if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) {
		/* flush data */
		mbuf_freem(data);
		return 0;
	}

	// otherwise, fall thru to ctl_enqueumbuf
	if (pcb->utun_ctlref) {
		int	length;

		// only pass packets to utun-crypto if crypto is enabled and 'suspend data traffic' is not.
		if ((pcb->utun_flags & (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC)) == UTUN_FLAGS_CRYPTO) {
			if (utun_pkt_crypto_output(pcb, &data) == 0) {
				return 0;
			}
		}

		/*
		 * The ABI requires the protocol in network byte order
		 */
		if (m_pktlen(data) >= 4)
			*(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data));

		length = mbuf_pkthdr_len(data);
		result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR);
		if (result != 0) {
			mbuf_freem(data);
			printf("utun_output - ctl_enqueuembuf failed: %d\n", result);

			ifnet_stat_increment_out(interface, 0, 0, 1);
		}
		else {
			if (!pcb->utun_ext_ifdata_stats)
				ifnet_stat_increment_out(interface, 1, length, 0);
		}
	}
	else 
		mbuf_freem(data);
	
	return 0;
}
Пример #3
0
/* -----------------------------------------------------------------------------
Called by socket layer to send a packet
----------------------------------------------------------------------------- */
int l2tp_send(struct socket *so, int flags, mbuf_t m, struct sockaddr *to,
	    mbuf_t control, struct proc *p)
{

    if (control)
        mbuf_freem(control);
    if (mbuf_len(m) == 0) {
        mbuf_freem(m);
        return 0;
    }

    return l2tp_rfc_output(so->so_pcb, m, to);
}
Пример #4
0
static errno_t
utun_output(ifnet_t	interface,
			mbuf_t data)
{
	struct utun_pcb	*pcb = ifnet_softc(interface);
	errno_t			result;

	VERIFY(interface == pcb->utun_ifp);
	
	if (m_pktlen(data) >= (int32_t)UTUN_HEADER_SIZE(pcb)) {
		bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0);
	}
	
	if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) {
		/* flush data */
		mbuf_freem(data);
		return 0;
	}

	// otherwise, fall thru to ctl_enqueumbuf
	if (pcb->utun_ctlref) {
		int	length;

		/*
		 * The ABI requires the protocol in network byte order
		 */
		if (m_pktlen(data) >= (int32_t)UTUN_HEADER_SIZE(pcb)) {
			*(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data));
		}

		length = mbuf_pkthdr_len(data);
		result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR);
		if (result != 0) {
			mbuf_freem(data);
			printf("utun_output - ctl_enqueuembuf failed: %d\n", result);

			ifnet_stat_increment_out(interface, 0, 0, 1);
		}
		else {
			if (!pcb->utun_ext_ifdata_stats)
				ifnet_stat_increment_out(interface, 1, length, 0);
		}
	}
	else 
		mbuf_freem(data);
	
	return 0;
}
Пример #5
0
/* -----------------------------------------------------------------------------
called from l2tp_rfc when data are present
----------------------------------------------------------------------------- */
int l2tp_input(void *data, mbuf_t m, struct sockaddr *from, int more)
{
    struct socket 	*so = (struct socket *)data;
	int		err;
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);

    if (so->so_tpcb) {
        // we are hooked to ppp
	return l2tp_wan_input(ALIGNED_CAST(struct ppp_link *)so->so_tpcb, m);   // Wcast-align fix - we malloc so->so_tpcb
    }
    
    if (m) {
	if (from == 0) {            
            // no from address, just free the buffer
            mbuf_freem(m);
            return 1;
        }

	if (sbappendaddr(&so->so_rcv, from, (struct mbuf *)m, 0, &err) == 0) {
            //IOLog("l2tp_input no space, so = %p\n", so);
            return 1;
	}
    }
    
    if (!more)
        sorwakeup(so);

    return 0;
}
Пример #6
0
bool 
SocketCookie::ClearDeferredData()
{
	while (deferredDataHead) 
	{
		mbuf_freem(deferredDataHead->data);
		mbuf_freem(deferredDataHead->control);
		
		DeferredData *old = deferredDataHead;
		deferredDataHead = deferredDataHead->next;
		delete old;
	}
	
	deferredDataLast = NULL;
	return true;
}
Пример #7
0
errno_t
utun_pkt_input (struct utun_pcb *pcb, mbuf_t m)
{
	errno_t	result;
	protocol_family_t protocol = 0;

	mbuf_pkthdr_setrcvif(m, pcb->utun_ifp);

	if (m_pktlen(m) >= 4)  {
		protocol = *(u_int32_t *)mbuf_data(m);
	
		bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0);
	}
	if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) {
		/* flush data */
		mbuf_freem(m);
		return 0;
	}

	// quick exit for keepalive packets
	if (protocol == AF_UTUN && pcb->utun_flags & UTUN_FLAGS_CRYPTO) {
		if (utun_pkt_crypto_output(pcb, &m) == 0) {
			return 0;
		}
		printf("%s: utun_pkt_crypto_output failed, flags %x\n", __FUNCTION__, pcb->utun_flags);
		return EINVAL;
	}

	if (!pcb->utun_ext_ifdata_stats) {
		struct ifnet_stat_increment_param	incs;
		
		bzero(&incs, sizeof(incs));
		incs.packets_in = 1;
		incs.bytes_in = mbuf_pkthdr_len(m);
		result = ifnet_input(pcb->utun_ifp, m, &incs);
	} else {
		result = ifnet_input(pcb->utun_ifp, m, NULL);
	}
	if (result != 0) {
		ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1);
		
		printf("%s - ifnet_input failed: %d\n", __FUNCTION__, result);
		mbuf_freem(m);
	}

	return 0;
}
Пример #8
0
/* -----------------------------------------------------------------------------
called from dlil when a packet from the interface is to be dispatched to
the specific network protocol attached by dl_tag.
the network protocol has been determined earlier by the demux function.
the packet is in the mbuf chain m without
the frame header, which is provided separately. (not used)
----------------------------------------------------------------------------- */
errno_t ppp_ipv6_input(ifnet_t ifp, protocol_family_t protocol,
									 mbuf_t packet, char* header)
{
    LOGMBUF("ppp_ipv6_input", packet);

	if (proto_input(PF_INET6, packet))
		mbuf_freem(packet);

	return 0;
}
Пример #9
0
/*
 * Call portmap to lookup a port number for a particular rpc program
 * Returns non-zero error on failure.
 */
int
krpc_portmap(
	struct sockaddr_in *sin,	/* server address */
	u_int prog, u_int vers, u_int proto,	/* host order */
	u_int16_t *portp)		/* network order */
{
	struct sdata {
		u_int32_t prog;		/* call program */
		u_int32_t vers;		/* call version */
		u_int32_t proto;	/* call protocol */
		u_int32_t port;		/* call port (unused) */
	} *sdata;
	struct rdata {
		u_int16_t pad;
		u_int16_t port;
	} *rdata;
	mbuf_t m;
	int error;

	/* The portmapper port is fixed. */
	if (prog == PMAPPROG) {
		*portp = htons(PMAPPORT);
		return 0;
	}

	error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &m);
	if (error)
		return error;
	mbuf_setlen(m, sizeof(*sdata));
	mbuf_pkthdr_setlen(m, sizeof(*sdata));
	sdata = mbuf_data(m);

	/* Do the RPC to get it. */
	sdata->prog = htonl(prog);
	sdata->vers = htonl(vers);
	sdata->proto = htonl(proto);
	sdata->port = 0;

	sin->sin_port = htons(PMAPPORT);
	error = krpc_call(sin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, &m, NULL);
	if (error) 
		return error;

	rdata = mbuf_data(m);

	if (mbuf_len(m) >= sizeof(*rdata)) {
		*portp = rdata->port;
	}

	if (mbuf_len(m) < sizeof(*rdata) || !rdata->port)
		error = EPROGUNAVAIL;

	mbuf_freem(m);
	return (error);
}
Пример #10
0
static errno_t
ipsec_ctl_send(__unused kern_ctl_ref	kctlref,
			   __unused u_int32_t		unit,
			   __unused void			*unitinfo,
			   mbuf_t                  m,
			   __unused int			flags)
{
    /* Receive messages from the control socket. Currently unused. */
    mbuf_freem(m);
	return 0;
}
Пример #11
0
static errno_t
utun_pkt_input (struct utun_pcb *pcb, mbuf_t m)
{
	errno_t	result;
	protocol_family_t protocol = 0;

	mbuf_pkthdr_setrcvif(m, pcb->utun_ifp);

	if (m_pktlen(m) >= (int32_t)UTUN_HEADER_SIZE(pcb))  {
		protocol = *(u_int32_t *)mbuf_data(m);
	
		bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0);
	}
	if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) {
		/* flush data */
		mbuf_freem(m);
		return 0;
	}

	if (!pcb->utun_ext_ifdata_stats) {
		struct ifnet_stat_increment_param	incs;
		
		bzero(&incs, sizeof(incs));
		incs.packets_in = 1;
		incs.bytes_in = mbuf_pkthdr_len(m);
		result = ifnet_input(pcb->utun_ifp, m, &incs);
	} else {
		result = ifnet_input(pcb->utun_ifp, m, NULL);
	}
	if (result != 0) {
		ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1);
		
		printf("%s - ifnet_input failed: %d\n", __FUNCTION__, result);
		mbuf_freem(m);
	}

	return 0;
}
Пример #12
0
void net_habitue_device_SC101::handleResolvePacket(sockaddr_in *addr, mbuf_t m, size_t len, outstanding *out, void *ctx)
{
  clock_get_uptime(&_lastReply);
  
  if (mbuf_len(m) < out->len &&
      mbuf_pullup(&m, out->len) != 0)
  {
    KINFO("pullup failed");
    return;
  }
  
  KDEBUG("resolve succeeded!");
  
  psan_resolve_response_t *res = (psan_resolve_response_t *)mbuf_data(m);
  
  sockaddr_in part;
  bzero(&part, sizeof(part));
  part.sin_len = sizeof(part);
  part.sin_family = AF_INET;
  part.sin_port = htons(PSAN_PORT);
  part.sin_addr = res->ip4;
  
  OSData *partData = OSData::withBytes(&part, sizeof(part));
  if (partData)
  {
    setProperty(gSC101DevicePartitionAddressKey, partData);
    partData->release();
  }
  
  OSData *rootData = OSData::withBytes(addr, sizeof(*addr));
  if (rootData)
  {
    setProperty(gSC101DeviceRootAddressKey, rootData);
    rootData->release();
  }
  
  IODelete(out, outstanding, 1);
  
  mbuf_freem(m);

  if (!getProperty(gSC101DeviceSizeKey))
    disk();
}
////////////////////////////////////////////////////////////////////////////////
//
// inet_firewire_input
//
// IN: struct mbuf  *m, char *frame_header, ifnet_t ifp, 
// IN: u_long dl_tag, int sync_ok
// 
// Invoked by : 
//  It will be called from the context of dlil_input_thread queue from
//  dlil_input_packet
// 
// Process a received firewire ARP/IP packet, the packet is in the mbuf 
// chain m
//
////////////////////////////////////////////////////////////////////////////////
static errno_t
inet_firewire_input(
	__unused ifnet_t			ifp,
	__unused protocol_family_t	protocol_family,
	mbuf_t						m,
	char     					*frame_header)
{
    struct firewire_header *eh = (struct firewire_header *)frame_header;
    u_short fw_type;
	
	ifnet_touch_lastchange(ifp);

    fw_type = ntohs(eh->fw_type);

    switch (fw_type) 
	{
        case FWTYPE_IP:
			{
				mbuf_pullup(&m, sizeof(struct ip));
				if (m == NULL)
					return EJUSTRETURN;
				
				errno_t ret = proto_input(PF_INET, m);
				
				if( ret )
					mbuf_freem(m);

				return ret;
			}
			
        case FWTYPE_ARP:
            firewire_arpintr(m);
			break;

        default:
            return ENOENT;
    }

    return 0;
}
Пример #14
0
void net_habitue_device_SC101::handleAsyncIOPacket(sockaddr_in *addr, mbuf_t m, size_t len, outstanding *out, void *ctx)
{  
  clock_get_uptime(&_lastReply);
  
  outstanding_io *io = (outstanding_io *)ctx;
  bool isWrite = (io->buffer->getDirection() == kIODirectionOut);
  UInt32 ioLen = (io->nblks * SECTOR_SIZE);
  
  IOStorageCompletion completion = io->completion;
  IOReturn status = kIOReturnError;
  IOByteCount wrote = ioLen;
  
  if (isWrite)
  {
    //KDEBUG("%p write %d %d", io, io->block, io->nblks);

    status = kIOReturnSuccess;
  }
  else
  {
    //KDEBUG("%p read %d %d", io, io->block, io->nblks);

    if (mbuf_buffer(io->buffer, 0, m, sizeof(psan_get_response_t), ioLen))
      status = kIOReturnSuccess;
    else
      KINFO("mbuf_buffer failed");
  }
  
  if (status != kIOReturnSuccess)
    KINFO("%p FAILED", io);

  completeIO(io);
  io->addr->release();
  IODelete(io, outstanding_io, 1);
  
  mbuf_freem(m);
  
  IOStorage::complete(completion, status, wrote);
}
Пример #15
0
/*
 * input routine for IPPRPOTO_MOBILE
 * This is a little bit diffrent from the other modes, as the
 * encapsulating header was not prepended, but instead inserted
 * between IP header and payload
 */
mbuf_t in_mobile_input(mbuf_t m, int hlen)
{
#ifdef DEBUG
    printf("%s: got packet\n", __FUNCTION__);
#endif
    struct ip *ip;
    struct mobip_h *mip;
    struct gre_softc *sc;
    int msiz;
    
    if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
        /* No matching tunnel or tunnel is down. */
        return m;
    }
    
    /* from here on, we increased the sc->sc_refcnt, so do remember to decrease it before return */
    
    if (mbuf_len(m) < sizeof(*mip)) {
        mbuf_pullup(&m, sizeof(*mip));
        if (m == NULL)
            goto done;
    }
    ip = mbuf_data(m);
    mip = mbuf_data(m);
    
    if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
        msiz = MOB_H_SIZ_L;
        mip->mi.ip_src.s_addr = mip->mh.osrc;
    } else
        msiz = MOB_H_SIZ_S;
    
    if (mbuf_len(m) < (ip->ip_hl << 2) + msiz) {
        mbuf_pullup(&m, (ip->ip_hl << 2) + msiz);
        if (m == NULL)
            goto done;
        ip = mbuf_data(m);
        mip = mbuf_data(m);
    }
    
    mip->mi.ip_dst.s_addr = mip->mh.odst;
    mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
    
    if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) {
        mbuf_freem(m);
        m = NULL;
        goto done;
    }
    
    bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) +
          (ip->ip_hl << 2), mbuf_len(m) - msiz - (ip->ip_hl << 2));
    mbuf_setdata(m, mbuf_data(m), mbuf_len(m) - msiz);
    mbuf_pkthdr_adjustlen(m, - msiz);
    
    /*
     * On FreeBSD, rip_input() supplies us with ip->ip_len
     * already converted into host byteorder and also decreases
     * it by the lengh of IP header, however, ip_input() expects
     * that this field is in the original format (network byteorder
     * and full size of IP packet), so that adjust accordingly.
     */
    ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz);
    
    ip->ip_sum = 0;
    ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
    
    mbuf_pkthdr_setrcvif(m, sc->sc_ifp);
    mbuf_pkthdr_setheader(m, NULL);
    
    struct ifnet_stat_increment_param incs;
    bzero(&incs, sizeof(incs));
    incs.packets_in = 1;
    incs.bytes_in = mbuf_pkthdr_len(m);

    ifnet_input(sc->sc_ifp, m, &incs);

    m = NULL; /* ifnet_input() has freed the mbuf */

done:
    /* since we got sc->sc_refcnt add by one, we decrease it when done */
    gre_sc_release(sc);
    return m;
}
Пример #16
0
/**
 * Internal worker that create a darwin mbuf for a (scatter/)gather list.
 *
 * @returns Pointer to the mbuf.
 * @param   pThis           The instance.
 * @param   pSG             The (scatter/)gather list.
 */
static mbuf_t vboxNetFltDarwinMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
{
    /// @todo future? mbuf_how_t How = preemption enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
    mbuf_how_t How = MBUF_WAITOK;

    /*
     * We need some way of getting back to our instance data when
     * the mbuf is freed, so use pvUserData for this.
     *  -- this is not relevant anylonger! --
     */
    Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
    Assert(!pSG->pvUserData2);
    pSG->pvUserData = pThis;

    /*
     * Allocate a packet and copy over the data.
     *
     * Using mbuf_attachcluster() here would've been nice but there are two
     * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
     * that it's not supposed to be used for really external buffers. The 2nd
     * point might be argued against considering that the only m_clattach user
     * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
     * However, it's hard to tell if these m_clattach buffers actually makes it
     * to the NICs or not, and even if they did, the NIC would need the physical
     * addresses for the pages they contain and might end up copying the data
     * to a new mbuf anyway.
     *
     * So, in the end it's better to just do it the simple way that will work
     * 100%, even if it involves some extra work (alloc + copy) we really wished
     * to avoid.
     *
     * Note. We can't make use of the physical addresses on darwin because the
     *       way the mbuf / cluster stuff works (see mbuf_data_to_physical and
     *       mcl_to_paddr).
     */
    mbuf_t pPkt = NULL;
    errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
    if (!err)
    {
        /* Skip zero sized memory buffers (paranoia). */
        mbuf_t pCur = pPkt;
        while (pCur && !mbuf_maxlen(pCur))
            pCur = mbuf_next(pCur);
        Assert(pCur);

        /* Set the required packet header attributes. */
        mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
        mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));

        /* Special case the single buffer copy. */
        if (    mbuf_next(pCur)
            &&  mbuf_maxlen(pCur) >= pSG->cbTotal)
        {
            mbuf_setlen(pCur, pSG->cbTotal);
            IntNetSgRead(pSG, mbuf_data(pCur));
        }
        else
        {
            /* Multi buffer copying. */
            size_t  cbLeft = pSG->cbTotal;
            size_t  offSrc = 0;
            while (cbLeft > 0 && pCur)
            {
                size_t cb = mbuf_maxlen(pCur);
                if (cb > cbLeft)
                    cb = cbLeft;
                mbuf_setlen(pCur, cb);
                IntNetSgReadEx(pSG, offSrc, cb, mbuf_data(pCur));

                /* advance */
                offSrc += cb;
                cbLeft -= cb;
                pCur = mbuf_next(pCur);
            }
            Assert(cbLeft == 0);
        }
        if (!err)
        {
            /*
             * Tag the packet and return successfully.
             */
            PVBOXNETFLTTAG pTagData;
            err = mbuf_tag_allocate(pPkt, g_idTag, 0 /* type */, sizeof(VBOXNETFLTTAG) /* tag len */, How, (void **)&pTagData);
            if (!err)
            {
                Assert(pSG->aSegs[0].cb >= sizeof(pTagData->EthHdr));
                memcpy(&pTagData->EthHdr, pSG->aSegs[0].pv, sizeof(pTagData->EthHdr));
                return pPkt;
            }

            /* bailout: */
            AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
        }

        mbuf_freem(pPkt);
    }
    else
        AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
    pSG->pvUserData = NULL;

    return NULL;
}
Пример #17
0
/*
 * Decapsulate. Does the real work and is called from in_gre_input()
 * (above) or ipv4_infilter(), Returns an mbuf back if packet is not
 * yet processed, and NULL if it needs no further processing.
 * proto is the protocol number of the "calling" foo_input() routine.
 */
mbuf_t in_gre_input(mbuf_t m, int hlen)
{
    struct greip *gip;
    struct gre_softc *sc;
    u_int16_t   flags;
    //static u_int32_t   af;
    //u_int8_t    proto;
    
    //proto = ((struct ip *)mbuf_data(m))->ip_p;
    
    if ((sc = gre_lookup(m, IPPROTO_GRE)) == NULL) {
        /* No matching tunnel or tunnel is down. */
        return m;
    }
    
    /* from here on, we increased the sc->sc_refcnt, so do remember to decrease it before return */
    
    if (mbuf_len(m) < sizeof(struct greip)) {
        mbuf_pullup(&m, sizeof(struct greip));
        if (m == NULL)
            goto done;
    }
    gip = mbuf_data(m);
    
    //switch (proto) {
    //    case IPPROTO_GRE:
            hlen += sizeof(struct gre_h);
            
            /* process GRE flags as packet can be of variable len */
            flags = ntohs(gip->gi_flags);
            
            /* Checksum & Offset are present */
            if ((flags & GRE_CP) | (flags & GRE_RP))
                hlen += 4;
            /* We don't support routing fields (variable length) */
            if (flags & GRE_RP)
                goto done;
            if (flags & GRE_KP)
                hlen += 4;
            if (flags & GRE_SP)
                hlen += 4;
            
            switch (ntohs(gip->gi_ptype)) { /* ethertypes */
                case WCCP_PROTOCOL_TYPE:
                    if (sc->wccp_ver == WCCP_V2)
                        hlen += 4;
                    /* FALLTHROUGH */
                case ETHERTYPE_IP:
                    //af = AF_INET;
                    break;
                case ETHERTYPE_IPV6:
                    //af = AF_INET6;
                    break;
                //case ETHERTYPE_AT:
                //    af = AF_APPLETALK;
                //    break;
                default:
                    /* Others not yet supported. */
                    goto done;
            }
    //        break;
    //    default:
            /* Others not yet supported. */
    //        goto done;
    //}
    
    if (hlen > mbuf_pkthdr_len(m)) { /* not a valid GRE packet */
        mbuf_freem(m);
        m = NULL;
        goto done;
    }
    /* Unlike NetBSD, in FreeBSD(as well as Darwin) m_adj() adjusts mbuf_pkthdr_len(m) as well */
    mbuf_adj(m, hlen);
    
    mbuf_pkthdr_setrcvif(m, sc->sc_ifp);
    mbuf_pkthdr_setheader(m, NULL);
    //mbuf_pkthdr_setheader(m, &af); /* it's ugly... */
    
    struct ifnet_stat_increment_param incs;
    bzero(&incs, sizeof(incs));
    incs.packets_in = 1;
    incs.bytes_in = mbuf_pkthdr_len(m);
    
    ifnet_input(sc->sc_ifp, m, &incs);
    
    m = NULL; /* ifnet_input() has freed the mbuf */

done:
    /* since we got sc->sc_refcnt add by one, we decrease it when done */
    gre_sc_release(sc);
    return m;
}
Пример #18
0
/* Network Interface functions */
static errno_t
ipsec_output(ifnet_t	interface,
             mbuf_t     data)
{
	struct ipsec_pcb	*pcb = ifnet_softc(interface);
    struct ipsec_output_state ipsec_state;
    struct route ro;
    struct route_in6 ro6;
    int	length;
    struct ip *ip;
    struct ip6_hdr *ip6;
    struct ip_out_args ipoa;
    struct ip6_out_args ip6oa;
    int error = 0;
    u_int ip_version = 0;
    uint32_t af;
    int flags = 0;
    struct flowadv *adv = NULL;
    
	// Make sure this packet isn't looping through the interface
	if (necp_get_last_interface_index_from_packet(data) == interface->if_index) {
		error = -1;
		goto ipsec_output_err;
	}
	
	// Mark the interface so NECP can evaluate tunnel policy
	necp_mark_packet_from_interface(data, interface);
	
    ip = mtod(data, struct ip *);
    ip_version = ip->ip_v;
	
    switch (ip_version) {
        case 4:
            /* Tap */
            af = AF_INET;
            bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af));
			
            /* Apply encryption */
            bzero(&ipsec_state, sizeof(ipsec_state));
            ipsec_state.m = data;
            ipsec_state.dst = (struct sockaddr *)&ip->ip_dst;
            bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
			
			error = ipsec4_interface_output(&ipsec_state, interface);
            data = ipsec_state.m;
            if (error || data == NULL) {
                printf("ipsec_output: ipsec4_output error %d.\n", error);
                goto ipsec_output_err;
            }
            
            /* Set traffic class, set flow */
            m_set_service_class(data, pcb->ipsec_output_service_class);
            data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
            data->m_pkthdr.pkt_flowid = interface->if_flowhash;
            data->m_pkthdr.pkt_proto = ip->ip_p;
            data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
            
            /* Flip endian-ness for ip_output */
            ip = mtod(data, struct ip *);
            NTOHS(ip->ip_len);
            NTOHS(ip->ip_off);
            
            /* Increment statistics */
            length = mbuf_pkthdr_len(data);
            ifnet_stat_increment_out(interface, 1, length, 0);
			
            /* Send to ip_output */
            bzero(&ro, sizeof(ro));
			
            flags = IP_OUTARGS |	/* Passing out args to specify interface */
			IP_NOIPSEC;				/* To ensure the packet doesn't go through ipsec twice */
			
            bzero(&ipoa, sizeof(ipoa));
            ipoa.ipoa_flowadv.code = 0;
            ipoa.ipoa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
            if (ipsec_state.outgoing_if) {
                ipoa.ipoa_boundif = ipsec_state.outgoing_if;
                ipoa.ipoa_flags |= IPOAF_BOUND_IF;
            }
            
            adv = &ipoa.ipoa_flowadv;
            
            (void) ip_output(data, NULL, &ro, flags, NULL, &ipoa);
            data = NULL;
            
            if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
                error = ENOBUFS;
                ifnet_disable_output(interface);
            }
            
            goto done;
        case 6:
            af = AF_INET6;
            bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af));
            
            data = ipsec6_splithdr(data);
            ip6 = mtod(data, struct ip6_hdr *);
			
            bzero(&ipsec_state, sizeof(ipsec_state));
            ipsec_state.m = data;
            ipsec_state.dst = (struct sockaddr *)&ip6->ip6_dst;
            bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
            
            error = ipsec6_interface_output(&ipsec_state, interface, &ip6->ip6_nxt, ipsec_state.m);
            if (error == 0 && ipsec_state.tunneled == 4)	/* tunneled in IPv4 - packet is gone */
				goto done;
            data = ipsec_state.m;
            if (error || data == NULL) {
                printf("ipsec_output: ipsec6_output error %d.\n", error);
                goto ipsec_output_err;
            }
            
            /* Set traffic class, set flow */
            m_set_service_class(data, pcb->ipsec_output_service_class);
            data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
            data->m_pkthdr.pkt_flowid = interface->if_flowhash;
            data->m_pkthdr.pkt_proto = ip6->ip6_nxt;
            data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
            
            /* Increment statistics */
            length = mbuf_pkthdr_len(data);
            ifnet_stat_increment_out(interface, 1, length, 0);
            
            /* Send to ip6_output */
            bzero(&ro6, sizeof(ro6));
            
            flags = IPV6_OUTARGS;
            
            bzero(&ip6oa, sizeof(ip6oa));
            ip6oa.ip6oa_flowadv.code = 0;
            ip6oa.ip6oa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
            if (ipsec_state.outgoing_if) {
                ip6oa.ip6oa_boundif = ipsec_state.outgoing_if;
                ip6oa.ip6oa_flags |= IPOAF_BOUND_IF;
            }
            
            adv = &ip6oa.ip6oa_flowadv;
            
            (void) ip6_output(data, NULL, &ro6, flags, NULL, NULL, &ip6oa);
            data = NULL;
            
            if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
                error = ENOBUFS;
                ifnet_disable_output(interface);
            }
            
            goto done;
        default:
            printf("ipsec_output: Received unknown packet version %d.\n", ip_version);
            error = -1;
            goto ipsec_output_err;
    }
	
done:
    return error;
    
ipsec_output_err:
    if (data)
        mbuf_freem(data);
	goto done;
}
// Temporarily stuff a vlan tag back into a packet so that tag shows up to bpf.
// We do it by creating a temp header mbuf with the enet/vlan header in it and
// then point its next field to the proper place (after the dest+src addresses) in the original
// mbuf.  
void IOEthernetInterface::_fixupVlanPacket(mbuf_t mt, u_int16_t vlan_tag, int inputPacket)
{
	mbuf_t newmb;
	mbuf_t chain;
	size_t remainingBytes;
	size_t copyBytes = 0;  //initialize to prevent annoying, incorrect warning that it's used uninitialized
	char * destptr;
	
	if( mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &newmb) )
		return;
		
	//init enough of the mbuf to keep bpf happy
	mbuf_setlen(newmb, ETHER_ADDR_LEN*2 + VLAN_HEADER_LEN);
	mbuf_pkthdr_setlen(newmb, mbuf_pkthdr_len( mt ) + VLAN_HEADER_LEN);	
	mbuf_pkthdr_setrcvif(newmb, mbuf_pkthdr_rcvif( mt ) );
	
	//now walk the incoming mbuf to copy out its dst & src address and
	//locate the type/len field in the packet.
	chain = mt;
	remainingBytes = ETHER_ADDR_LEN*2;
	destptr = (char *)mbuf_data( newmb );
	
	while(chain && remainingBytes)
	{
		copyBytes = remainingBytes > mbuf_len( chain ) ? mbuf_len( chain ): remainingBytes;
		
		remainingBytes -= copyBytes;
		bcopy( mbuf_data( chain ), destptr, copyBytes);
		destptr += copyBytes;
		if (mbuf_len( chain ) == copyBytes) //we've completely drained this mbuf
		{
			chain = mbuf_next( chain );  //advance to next
			copyBytes = 0; //if we break out of loop now, make sure the offset is correct
		}
	}
	
	// chain points to the mbuf that contains the packet data with type/len field
	// and copyBytes indicates the offset it's at.
	if(chain==0 || remainingBytes)
	{
		mbuf_freem( newmb );
		return; //if we can't munge the packet, just return
	}
	
	//patch mbuf so its data points after the dst+src address
	mbuf_setdata(chain, (char *)mbuf_data( chain ) + copyBytes, mbuf_len( chain ) - copyBytes );
	
	//finish setting up our head mbuf
	*(short *)(destptr) = htons(ETHERTYPE_VLAN); //vlan magic number
	*(short *)(destptr + 2) = htons( vlan_tag ); // and the tag's value
	mbuf_setnext( newmb, chain ); //stick it infront of the rest of the packet
	
	// feed the tap
	if(inputPacket)
		super::feedPacketInputTap( newmb );
	else
		super::feedPacketOutputTap( newmb );
	
	//release the fake header
	mbuf_setnext( newmb, NULL );
	mbuf_freem( newmb );

	//and repair our old mbuf
	mbuf_setdata( chain, (char *)mbuf_data( chain ) - copyBytes, mbuf_len( chain ) + copyBytes );
}
Пример #20
0
int
osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
	       int nvecs, int *alength)
{
#ifdef AFS_DARWIN80_ENV
    socket_t asocket = (socket_t)so;
    struct msghdr msg;
    struct sockaddr_storage ss;
    int rlen;
    mbuf_t m;
#else
    struct socket *asocket = (struct socket *)so;
    struct uio u;
#endif
    int i;
    struct iovec iov[RX_MAXIOVECS];
    struct sockaddr *sa = NULL;
    int code;
    size_t resid;

    int haveGlock = ISAFS_GLOCK();
    /*AFS_STATCNT(osi_NetReceive); */

    if (nvecs > RX_MAXIOVECS)
	osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);

    for (i = 0; i < nvecs; i++)
	iov[i] = dvec[i];

    if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
	(afs_termState == AFSOP_STOP_COMPLETE))
	return -1;

    if (haveGlock)
	AFS_GUNLOCK();
#if defined(KERNEL_FUNNEL)
    thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
#ifdef AFS_DARWIN80_ENV
    resid = *alength;
    memset(&msg, 0, sizeof(struct msghdr));
    msg.msg_name = &ss;
    msg.msg_namelen = sizeof(struct sockaddr_storage);
    sa =(struct sockaddr *) &ss;
    code = sock_receivembuf(asocket, &msg, &m, 0, alength);
    if (!code) {
        size_t offset=0,sz;
        resid = *alength;
        for (i=0;i<nvecs && resid;i++) {
            sz=MIN(resid, iov[i].iov_len);
            code = mbuf_copydata(m, offset, sz, iov[i].iov_base);
            if (code)
                break;
            resid-=sz;
            offset+=sz;
        }
    }
    mbuf_freem(m);
#else

    u.uio_iov = &iov[0];
    u.uio_iovcnt = nvecs;
    u.uio_offset = 0;
    u.uio_resid = *alength;
    u.uio_segflg = UIO_SYSSPACE;
    u.uio_rw = UIO_READ;
    u.uio_procp = NULL;
    code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
    resid = u.uio_resid;
#endif

#if defined(KERNEL_FUNNEL)
    thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
#endif
    if (haveGlock)
	AFS_GLOCK();

    if (code)
	return code;
    *alength -= resid;
    if (sa) {
	if (sa->sa_family == AF_INET) {
	    if (addr)
		*addr = *(struct sockaddr_in *)sa;
	} else
	    printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
#ifndef AFS_DARWIN80_ENV
	FREE(sa, M_SONAME);
#endif
    }
    return code;
}
Пример #21
0
Файл: raw.c Проект: B1NG0/cifs
NTSTATUS
SMBRawTransaction(
    SMBHANDLE   inConnection,
    const void *lpInBuffer,
    size_t		nInBufferSize,
    void		*lpOutBuffer,
    size_t		nOutBufferSize,
    size_t		*lpBytesRead)
{
    NTSTATUS            status;
    int                 err;

    void *              hContext;

    struct smb_header   header;
    mbuf_t				words = NULL;
    mbuf_t				bytes = NULL;
    mbuf_t				response = NULL;
	size_t				len;

    const void * ptr;

	bzero(&header, sizeof(header));
    status = SMBServerContext(inConnection, &hContext);
	if (!NT_SUCCESS(status)) {
        return status;
    }

    if ((size_t)nInBufferSize < sizeof(struct smb_header) ||
        (size_t)nOutBufferSize < sizeof(struct smb_header)) {
 		err = STATUS_BUFFER_TOO_SMALL;
        goto errout;
    }

    /* Split the request buffer into the header, the parameter words and the
     * data bytes.
     */
    ptr = lpInBuffer;

    ADVANCE(ptr, sizeof(uint32_t));
    header.command = *(uint8_t *)ptr;

    if ((size_t)nInBufferSize < (sizeof(struct smb_header) + sizeof(uint8_t))) {
 		err = STATUS_BUFFER_TOO_SMALL;
        goto errout;
    }

    ptr = lpInBuffer;
    ADVANCE(ptr, sizeof(struct smb_header));

	len = (*(uint8_t *)ptr) * sizeof(uint16_t);
	ADVANCE(ptr, sizeof(uint8_t));  /* skip word_count field */
	if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &words, (void *)ptr, NULL, len, NULL)) {
		err = STATUS_NO_MEMORY;
        goto errout;
	}
	mbuf_setlen(words, len);
	ADVANCE(ptr, len);      /* skip parameter words */

    if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) ||
        (uintptr_t)ptr < (uintptr_t)mbuf_data(words)) {
		err = STATUS_MARSHALL_OVERFLOW;
        goto errout;
    }

    len = OSReadLittleInt16(ptr, 0);
    ADVANCE(ptr, sizeof(uint16_t)); /* skip byte_count field */
	if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &bytes, (void *)ptr, NULL, len, NULL)) {
		err = STATUS_NO_MEMORY;
        goto errout;
	}
	mbuf_setlen(bytes, len);
    ADVANCE(ptr, len);

    if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) ||
        (uintptr_t)ptr < (uintptr_t)mbuf_data(bytes)) {
		err = STATUS_MARSHALL_OVERFLOW;
        goto errout;
    }

    /* Set up the response buffer so that we leave room to place the
     * SMB header at the front.
     */
    len = (size_t)(nOutBufferSize - sizeof(struct smb_header));
 	if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &response, ((uint8_t *)lpOutBuffer + sizeof(struct smb_header)), NULL, len, NULL)) {
		err = STATUS_NO_MEMORY;
        goto errout;
    }
	
	err = smb_ioc_request(hContext, &header, words, bytes, response);
    if (err) {
		err = STATUS_IO_DEVICE_ERROR;
        goto errout;
    }

    /* Stash the new SMB header at the front of the output buffer so the
     * caller gets the server status code, etc.
     */
    memcpy(lpOutBuffer, lpInBuffer, sizeof(header));
    OSWriteLittleInt32(lpOutBuffer, 0, *(const uint32_t *)(void *)SMB_SIGNATURE);
    OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, status),
                    header.status);
    OSWriteLittleInt16(lpOutBuffer, offsetof(struct smb_header, flags),
					   header.flags);
    OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, flags2),
                    header.flags2);

    *lpBytesRead = mbuf_len(response) + sizeof(struct smb_header);

    /* We return success, even though the server may have failed the call. The
     * caller is responsible for parsing the reply packet and looking at the
     * status field in the header.
     */
    err = STATUS_SUCCESS;
	
errout:
    if (words)
		mbuf_freem(words);
    if (bytes)
		mbuf_freem(bytes);
    if (response)
		mbuf_freem(response);
	return err;
}
Пример #22
0
/**
 * Internal worker for  vboxNetFltDarwinIffInput and vboxNetFltDarwinIffOutput,
 *
 * @returns 0 or EJUSTRETURN.
 * @param   pThis           The instance.
 * @param   pMBuf           The mbuf.
 * @param   pvFrame         The start of the frame, optional.
 * @param   fSrc            Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value.
 * @param   eProtocol       The protocol.
 */
static errno_t vboxNetFltDarwinIffInputOutputWorker(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame,
                                                    uint32_t fSrc, protocol_family_t eProtocol)
{
    /*
     * Drop it immediately?
     */
    Log2(("vboxNetFltDarwinIffInputOutputWorker: pThis=%p pMBuf=%p pvFrame=%p fSrc=%#x cbPkt=%x\n",
          pThis, pMBuf, pvFrame, fSrc, pMBuf ? mbuf_pkthdr_len(pMBuf) : -1));
    if (!pMBuf)
        return 0;
#if 0 /* debugging lost icmp packets */
    if (mbuf_pkthdr_len(pMBuf) > 0x300)
    {
        uint8_t *pb = (uint8_t *)(pvFrame ? pvFrame : mbuf_data(pMBuf));
        Log3(("D=%.6Rhxs  S=%.6Rhxs  T=%04x IFF\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
    }
#endif
    if (vboxNetFltDarwinMBufIsOur(pThis, pMBuf, pvFrame))
        return 0;

    /*
     * Active? Retain the instance and increment the busy counter.
     */
    if (!vboxNetFltTryRetainBusyActive(pThis))
        return 0;

    /*
     * Finalize out-bound packets since the stack puts off finalizing
     * TCP/IP checksums as long as possible.
     * ASSUMES this only applies to outbound IP packets.
     */
    if (    (fSrc & INTNETTRUNKDIR_HOST)
        &&  eProtocol == PF_INET)
    {
        Assert(!pvFrame);
        mbuf_outbound_finalize(pMBuf, eProtocol, sizeof(RTNETETHERHDR));
    }

    /*
     * Create a (scatter/)gather list for the mbuf and feed it to the internal network.
     */
    bool fDropIt = false;
    unsigned cSegs = vboxNetFltDarwinMBufCalcSGSegs(pThis, pMBuf, pvFrame);
    if (cSegs < VBOXNETFLT_DARWIN_MAX_SEGS)
    {
        PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
        vboxNetFltDarwinMBufToSG(pThis, pMBuf, pvFrame, pSG, cSegs, fSrc);

        fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
        if (fDropIt)
        {
            /*
             * Check if this interface is in promiscuous mode. We should not drop
             * any packets before they get to the driver as it passes them to tap
             * callbacks in order for BPF to work properly.
             */
            if (vboxNetFltDarwinIsPromiscuous(pThis))
                fDropIt = false;
            else
                mbuf_freem(pMBuf);
        }
    }

    vboxNetFltRelease(pThis, true /* fBusy */);

    return fDropIt ? EJUSTRETURN : 0;
}
Пример #23
0
IOReturn REACConnection::sendSamples(UInt32 bufSize, UInt8 *sampleBuffer) {
    REACMasterDataStream *masterDataStream = OSDynamicCast(REACMasterDataStream, dataStream);
    const UInt32 ourSamplesSize = REAC_SAMPLES_PER_PACKET*REAC_RESOLUTION*
                                  (NULL != masterDataStream ?
                                   inChannels : deviceInfo->out_channels);
    // TODO This is not complete
    const UInt32 slaveSamplesSize = (NULL != masterDataStream && masterDataStream->isConnectedToSlave()) ? ourSamplesSize : 0;
    const UInt32 sentSamplesSize = ourSamplesSize+slaveSamplesSize;
    const UInt32 sampleOffset = sizeof(EthernetHeader)+sizeof(REACPacketHeader);
    const UInt32 endingOffset = sampleOffset+sentSamplesSize;
    const UInt32 packetLen = endingOffset+sizeof(REACConstants::ENDING);
    REACPacketHeader rph;
    mbuf_t mbuf = NULL;
    IOReturn result = kIOReturnError;
    IOReturn processPacketRet;

    /// Do some argument checks
    if (!(REAC_SLAVE == mode || REAC_MASTER == mode)) {
        result = kIOReturnInvalid;
        goto Done;
    }
    if (ourSamplesSize != bufSize && NULL != sampleBuffer) { // bufSize is ignored when sampleBuffer is NULL
        result = kIOReturnBadArgument;
        goto Done;
    }

    /// Prepare ethernet header
    EthernetHeader header;
    memcpy(header.shost, interfaceAddr, sizeof(header.shost));
    // Don't initialize header.dhost; that's the responsibility of dataStream->processPacket
    memcpy(&header.type, REACConstants::PROTOCOL, sizeof(REACConstants::PROTOCOL));

    /// Do REAC data stream processing
    processPacketRet = dataStream->processPacket(&rph, sizeof(header.dhost), header.dhost);
    if (kIOReturnAborted == processPacketRet) {
        // The REACDataStream indicates to us that it doesn't want us to send a packet.
        goto Done;
    }
    else if (kIOReturnSuccess != processPacketRet) {
        IOLog("REACConnection::sendSamples() - Error: Failed to process packet data stream.\n");
        goto Done;
    }

    /// Allocate mbuf
    if (0 != mbuf_allocpacket(MBUF_DONTWAIT, packetLen, NULL, &mbuf) ||
            kIOReturnSuccess != MbufUtils::setChainLength(mbuf, packetLen)) {
        IOLog("REACConnection::sendSamples() - Error: Failed to allocate packet mbuf.\n");
        goto Done;
    }

    /// Copy ethernet header
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, 0, sizeof(EthernetHeader), &header)) {
        IOLog("REACConnection::sendSamples() - Error: Failed to copy REAC header to packet mbuf.\n");
        goto Done;
    }

    /// Copy REAC header
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, sizeof(EthernetHeader), sizeof(REACPacketHeader), &rph)) {
        IOLog("REACConnection::sendSamples() - Error: Failed to copy REAC header to packet mbuf.\n");
        goto Done;
    }

    /// Copy sample data
    if (NULL != sampleBuffer) {
        if (kIOReturnSuccess != MbufUtils::copyAudioFromBufferToMbuf(mbuf, sampleOffset, bufSize, sampleBuffer)) {
            IOLog("REACConnection::sendSamples() - Error: Failed to copy sample data to packet mbuf.\n");
            goto Done;
        }
    }
    else {
        if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, sampleOffset, ourSamplesSize)) {
            IOLog("REACConnection::sendSamples() - Error: Failed to zero sample data in mbuf.\n");
            goto Done;
        }
    }
    if (NULL != masterDataStream && masterDataStream->isConnectedToSlave()) {
        // TODO This is very incorrect: It doesn't send the slave data, and even if it would, the order of the
        // data would be jumbled, because it has to send the whole first sample first and so on.
        if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, sampleOffset+ourSamplesSize, slaveSamplesSize)) {
            IOLog("REACConnection::sendSamples() - Error: Failed to zero slave sample data in mbuf.\n");
            goto Done;
        }
    }

    /// Copy packet ending
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, endingOffset,
            sizeof(REACConstants::ENDING), (void *)REACConstants::ENDING)) {
        IOLog("REACConnection::sendSamples() - Error: Failed to copy ending to packet mbuf.\n");
        goto Done;
    }

    /// Send packet
    if (0 != ifnet_output_raw(interface, 0, mbuf)) {
        mbuf = NULL; // ifnet_output_raw always frees the mbuf
        IOLog("REACConnection::sendSamples() - Error: Failed to send packet.\n");
        goto Done;
    }

    mbuf = NULL; // ifnet_output_raw always frees the mbuf
    result = kIOReturnSuccess;
Done:
    if (NULL != mbuf) {
        mbuf_freem(mbuf);
        mbuf = NULL;
    }
    return result;
}
Пример #24
0
/*
 * Do a remote procedure call (RPC) and wait for its reply.
 * If from_p is non-null, then we are doing broadcast, and
 * the address from whence the response came is saved there.
 */
int
krpc_call(
	struct sockaddr_in *sa,
	u_int sotype, u_int prog, u_int vers, u_int func,
	mbuf_t *data,			/* input/output */
	struct sockaddr_in *from_p)	/* output */
{
	socket_t so;
	struct sockaddr_in *sin;
	mbuf_t m, nam, mhead;
	struct rpc_call *call;
	struct rpc_reply *reply;
	int error, timo, secs;
	size_t len;
	static u_int32_t xid = ~0xFF;
	u_int16_t tport;
	size_t maxpacket = 1<<16;

	/*
	 * Validate address family.
	 * Sorry, this is INET specific...
	 */
	if (sa->sin_family != AF_INET)
		return (EAFNOSUPPORT);

	/* Free at end if not null. */
	nam = mhead = NULL;

	/*
	 * Create socket and set its recieve timeout.
	 */
	if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so)))
		goto out1;

	{
		struct timeval tv;

		tv.tv_sec = 1;
		tv.tv_usec = 0;

		if ((error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))))
		    goto out;

	}

	/*
	 * Enable broadcast if necessary.
	 */

	if (from_p && (sotype == SOCK_DGRAM)) {
		int on = 1;
		if ((error = sock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))))
			goto out;
	}

	/*
	 * Bind the local endpoint to a reserved port,
	 * because some NFS servers refuse requests from
	 * non-reserved (non-privileged) ports.
	 */
	if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &m)))
		goto out;
	sin = mbuf_data(m);
	bzero(sin, sizeof(*sin));
	mbuf_setlen(m, sizeof(*sin));
	sin->sin_len = sizeof(*sin);
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = INADDR_ANY;
	tport = IPPORT_RESERVED;
	do {
		tport--;
		sin->sin_port = htons(tport);
		error = sock_bind(so, (struct sockaddr*)sin);
	} while (error == EADDRINUSE &&
			 tport > IPPORT_RESERVED / 2);
	mbuf_freem(m);
	m = NULL;
	if (error) {
		printf("bind failed\n");
		goto out;
	}

	/*
	 * Setup socket address for the server.
	 */
	if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &nam)))
		goto out;
	sin = mbuf_data(nam);
	mbuf_setlen(nam, sa->sin_len);
	bcopy((caddr_t)sa, (caddr_t)sin, sa->sin_len);

	if (sotype == SOCK_STREAM) {
		struct timeval tv;
		tv.tv_sec = 60;
		tv.tv_usec = 0;
		error = sock_connect(so, mbuf_data(nam), MSG_DONTWAIT);
		if (error && (error != EINPROGRESS))
			goto out;
		error = sock_connectwait(so, &tv);
		if (error) {
			if (error == EINPROGRESS)
				error = ETIMEDOUT;
			printf("krpc_call: error waiting for TCP socket connect: %d\n", error);
			goto out;
		}
	}

	/*
	 * Prepend RPC message header.
	 */
	m = *data;
	*data = NULL;
#if	DIAGNOSTIC
	if ((mbuf_flags(m) & MBUF_PKTHDR) == 0)
		panic("krpc_call: send data w/o pkthdr");
	if (mbuf_pkthdr_len(m) < mbuf_len(m))
		panic("krpc_call: pkthdr.len not set");
#endif
	len = sizeof(*call);
	if (sotype == SOCK_STREAM)
		len += 4;  /* account for RPC record marker */
	mhead = m;
	if ((error = mbuf_prepend(&mhead, len, MBUF_WAITOK)))
		goto out;
	if ((error = mbuf_pkthdr_setrcvif(mhead, NULL)))
		goto out;

	/*
	 * Fill in the RPC header
	 */
	if (sotype == SOCK_STREAM) {
		/* first, fill in RPC record marker */
		u_int32_t *recmark = mbuf_data(mhead);
		*recmark = htonl(0x80000000 | (mbuf_pkthdr_len(mhead) - 4));
		call = (struct rpc_call *)(recmark + 1);
	} else {
		call = mbuf_data(mhead);
	}
	bzero((caddr_t)call, sizeof(*call));
	xid++;
	call->rp_xid = htonl(xid);
	/* call->rp_direction = 0; */
	call->rp_rpcvers = htonl(2);
	call->rp_prog = htonl(prog);
	call->rp_vers = htonl(vers);
	call->rp_proc = htonl(func);
	/* call->rp_auth = 0; */
	/* call->rp_verf = 0; */

	/*
	 * Send it, repeatedly, until a reply is received,
	 * but delay each re-send by an increasing amount.
	 * If the delay hits the maximum, start complaining.
	 */
	timo = 0;
	for (;;) {
		struct msghdr msg;
		
		/* Send RPC request (or re-send). */
		if ((error = mbuf_copym(mhead, 0, MBUF_COPYALL, MBUF_WAITOK, &m)))
			goto out;
		bzero(&msg, sizeof(msg));
		if (sotype == SOCK_STREAM) {
			msg.msg_name = NULL;
			msg.msg_namelen = 0;
		} else {
			msg.msg_name = mbuf_data(nam);
			msg.msg_namelen = mbuf_len(nam);
		}
		error = sock_sendmbuf(so, &msg, m, 0, 0);
		if (error) {
			printf("krpc_call: sosend: %d\n", error);
			goto out;
		}
		m = NULL;

		/* Determine new timeout. */
		if (timo < MAX_RESEND_DELAY)
			timo++;
            	else
           		printf("RPC timeout for server " IP_FORMAT "\n",
				IP_LIST(&(sin->sin_addr.s_addr)));

		/*
		 * Wait for up to timo seconds for a reply.
		 * The socket receive timeout was set to 1 second.
		 */
		secs = timo;
		while (secs > 0) {
			size_t readlen;
			
			if (m) {
				mbuf_freem(m);
				m = NULL;
			}
			if (sotype == SOCK_STREAM) {
				int maxretries = 60;
				struct iovec aio;
				aio.iov_base = &len;
				aio.iov_len = sizeof(u_int32_t);
				bzero(&msg, sizeof(msg));
				msg.msg_iov = &aio;
				msg.msg_iovlen = 1;
				do {
				   error = sock_receive(so, &msg, MSG_WAITALL, &readlen);
				   if ((error == EWOULDBLOCK) && (--maxretries <= 0))
					error = ETIMEDOUT;
				} while (error == EWOULDBLOCK);
				if (!error && readlen < aio.iov_len) {
				    /* only log a message if we got a partial word */
				    if (readlen != 0)
					    printf("short receive (%ld/%ld) from server " IP_FORMAT "\n",
						 readlen, sizeof(u_int32_t), IP_LIST(&(sin->sin_addr.s_addr)));
				    error = EPIPE;
				}
				if (error)
					goto out;
				len = ntohl(len) & ~0x80000000;
				/*
				 * This is SERIOUS! We are out of sync with the sender
				 * and forcing a disconnect/reconnect is all I can do.
				 */
				if (len > maxpacket) {
				    printf("impossible packet length (%ld) from server " IP_FORMAT "\n",
					len, IP_LIST(&(sin->sin_addr.s_addr)));
				    error = EFBIG;
				    goto out;
				}
				
				do {
				    readlen = len;
				    error = sock_receivembuf(so, NULL, &m, MSG_WAITALL, &readlen);
				} while (error == EWOULDBLOCK);

				if (!error && (len > readlen)) {
				    printf("short receive (%ld/%ld) from server " IP_FORMAT "\n",
					readlen, len, IP_LIST(&(sin->sin_addr.s_addr)));
				    error = EPIPE;
				}
			} else {
				len = maxpacket;
				readlen = len;
				bzero(&msg, sizeof(msg));
				msg.msg_name = from_p;
				msg.msg_namelen = (from_p == NULL) ? 0 : sizeof(*from_p);
				error = sock_receivembuf(so, &msg, &m, 0, &readlen);
			}

			if (error == EWOULDBLOCK) {
				secs--;
				continue;
			}
			if (error)
				goto out;
			len = readlen;

			/* Does the reply contain at least a header? */
			if (len < MIN_REPLY_HDR)
				continue;
			if (mbuf_len(m) < MIN_REPLY_HDR)
				continue;
			reply = mbuf_data(m);

			/* Is it the right reply? */
			if (reply->rp_direction != htonl(RPC_REPLY))
				continue;

			if (reply->rp_xid != htonl(xid))
				continue;
			
			/* Was RPC accepted? (authorization OK) */
			if (reply->rp_astatus != 0) {
				error = ntohl(reply->rp_u.rpu_errno);
				printf("rpc denied, error=%d\n", error);
				/* convert rpc error to errno */
				switch (error) {
				case RPC_MISMATCH:
					error = ERPCMISMATCH;
					break;
				case RPC_AUTHERR:
					error = EAUTH;
					break;
				}
				goto out;
			}


			if (mbuf_len(m) < REPLY_SIZE) {
				error = RPC_SYSTEM_ERR;
			}
			else {
				error = ntohl(reply->rp_u.rpu_ok.rp_rstatus);
			}

			/* Did the call succeed? */
			if (error != 0) {
				printf("rpc status=%d\n", error);
				/* convert rpc error to errno */
				switch (error) {
				case RPC_PROGUNAVAIL:
					error = EPROGUNAVAIL;
					break;
				case RPC_PROGMISMATCH:
					error = EPROGMISMATCH;
					break;
				case RPC_PROCUNAVAIL:
					error = EPROCUNAVAIL;
					break;
				case RPC_GARBAGE:
					error = EINVAL;
					break;
				case RPC_SYSTEM_ERR:
					error = EIO;
					break;
				}
				goto out;
			}

			goto gotreply;	/* break two levels */

		} /* while secs */
	} /* forever send/receive */

	error = ETIMEDOUT;
	goto out;

 gotreply:

	/*
	 * Pull as much as we can into first mbuf, to make
	 * result buffer contiguous.  Note that if the entire
	 * result won't fit into one mbuf, you're out of luck.
	 * XXX - Should not rely on making the entire reply
	 * contiguous (fix callers instead). -gwr
	 */
#if	DIAGNOSTIC
	if ((mbuf_flags(m) & MBUF_PKTHDR) == 0)
		panic("krpc_call: received pkt w/o header?");
#endif
	len = mbuf_pkthdr_len(m);
	if (sotype == SOCK_STREAM)
		len -= 4;  /* the RPC record marker was read separately */
	if (mbuf_len(m) < len) {
		if ((error = mbuf_pullup(&m, len)))
			goto out;
		reply = mbuf_data(m);
	}

	/*
	 * Strip RPC header
	 */
	len = sizeof(*reply);
	if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) {
		len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen);
		len = (len + 3) & ~3; /* XXX? */
	}
	mbuf_adj(m, len);

	/* result */
	*data = m;
 out:
	sock_close(so);
out1:
	if (nam) mbuf_freem(nam);
	if (mhead) mbuf_freem(mhead);
	return error;
}
Пример #25
0
IOReturn REACConnection::sendSplitAnnouncementPacket() {
    const UInt32 fillerSize = 288;
    const UInt32 fillerOffset = sizeof(EthernetHeader)+sizeof(REACPacketHeader);
    const UInt32 endingOffset = fillerOffset+fillerSize;
    const UInt32 packetLen = endingOffset+sizeof(REACConstants::ENDING);
    REACSplitDataStream *splitDataStream;
    REACPacketHeader rph;
    mbuf_t mbuf = NULL;
    int result = kIOReturnError;

    /// Do some argument checks
    if (!REAC_SPLIT == mode) {
        result = kIOReturnInvalid;
        goto Done;
    }

    /// Prepare REAC packet header
    splitDataStream = OSDynamicCast(REACSplitDataStream, dataStream);
    if (NULL == splitDataStream) {
        IOLog("REACConnection::sendSplitAnnouncementPacket(): Internal error!\n");
        result = kIOReturnInternalError;
        goto Done;
    }
    rph.setCounter(splitAnnouncementCounter++);
    if (!splitDataStream->prepareSplitAnnounce(&rph)) {
        goto Done;
    }

    /// Allocate mbuf
    if (0 != mbuf_allocpacket(MBUF_DONTWAIT, packetLen, NULL, &mbuf) ||
            kIOReturnSuccess != MbufUtils::setChainLength(mbuf, packetLen)) {
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to allocate packet mbuf.\n");
        goto Done;
    }

    /// Copy ethernet header
    EthernetHeader header;
    memcpy(header.shost, interfaceAddr, sizeof(header.shost));
    memcpy(header.dhost, deviceInfo->addr, sizeof(header.dhost));
    memcpy(&header.type, REACConstants::PROTOCOL, sizeof(REACConstants::PROTOCOL));
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, 0, sizeof(EthernetHeader), &header)) {
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy REAC header to packet mbuf.\n");
        goto Done;
    }

    /// Copy REAC header
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, sizeof(EthernetHeader), sizeof(REACPacketHeader), &rph)) {
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy REAC header to packet mbuf.\n");
        goto Done;
    }

    /// Copy filler
    if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, fillerOffset, fillerSize)) {
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to zero filler data in mbuf.\n");
        goto Done;
    }

    /// Copy packet ending
    if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, endingOffset,
            sizeof(REACConstants::ENDING), (void *)REACConstants::ENDING)) {
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy ending to packet mbuf.\n");
        goto Done;
    }

    /// Send packet
    if (0 != ifnet_output_raw(interface, 0, mbuf)) {
        mbuf = NULL; // ifnet_output_raw always frees the mbuf
        IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to send packet.\n");
        goto Done;
    }

    mbuf = NULL; // ifnet_output_raw always frees the mbuf
    result = kIOReturnSuccess;
Done:
    if (NULL != mbuf) {
        mbuf_freem(mbuf);
        mbuf = NULL;
    }
    return result;
}
Пример #26
0
void
rx_upcall(socket_t so, void *arg, __unused int waitflag)
{
    mbuf_t m;
    int error = 0;
    int i, flags = 0;
    struct msghdr msg;
    struct sockaddr_storage ss;
    struct sockaddr *sa = NULL;
    struct sockaddr_in from;
    struct rx_packet *p;
    afs_int32 rlen;
    afs_int32 tlen;
    afs_int32 savelen;          /* was using rlen but had aliasing problems */
    size_t nbytes, resid, noffset;

    p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
    rx_computelen(p, tlen);
    rx_SetDataSize(p, tlen);    /* this is the size of the user data area */
    tlen += RX_HEADER_SIZE;     /* now this is the size of the entire packet */
    rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
				 * it once in order to avoid races.  */
    tlen = rlen - tlen;
    if (tlen > 0) {
	tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
	if (tlen > 0) {
	    tlen = rlen - tlen;
	} else
	    tlen = rlen;
    } else
	tlen = rlen;
    /* add some padding to the last iovec, it's just to make sure that the
     * read doesn't return more data than we expect, and is done to get around
     * our problems caused by the lack of a length field in the rx header. */
    savelen = p->wirevec[p->niovecs - 1].iov_len;
    p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;

    resid = nbytes = tlen + sizeof(afs_int32);

    memset(&msg, 0, sizeof(struct msghdr));
    msg.msg_name = &ss;
    msg.msg_namelen = sizeof(struct sockaddr_storage);
    sa =(struct sockaddr *) &ss;

    do {
	m = NULL;
	error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
	if (!error) {
	    size_t sz, offset = 0;
	    noffset = 0;
	    resid = nbytes;
	    for (i=0;i<p->niovecs && resid;i++) {
		sz=MIN(resid, p->wirevec[i].iov_len);
		error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
		if (error)
		    break;
		resid-=sz;
		offset+=sz;
		noffset += sz;
	    }
	}
    } while (0);

    mbuf_freem(m);

    /* restore the vec to its correct state */
    p->wirevec[p->niovecs - 1].iov_len = savelen;

    if (error == EWOULDBLOCK && noffset > 0)
	error = 0;

    if (!error) {
	int host, port;

	nbytes -= resid;

	if (sa->sa_family == AF_INET)
	    from = *(struct sockaddr_in *)sa;

	p->length = nbytes - RX_HEADER_SIZE;;
	if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
	    if (nbytes <= 0) {
		if (rx_stats_active) {
		    MUTEX_ENTER(&rx_stats_mutex);
		    rx_atomic_inc(&rx_stats.bogusPacketOnRead);
		    rx_stats.bogusHost = from.sin_addr.s_addr;
		    MUTEX_EXIT(&rx_stats_mutex);
		}
		dpf(("B: bogus packet from [%x,%d] nb=%d",
		     from.sin_addr.s_addr, from.sin_port, nbytes));
	    }
	    return;
	} else {
	    /* Extract packet header. */
	    rxi_DecodePacketHeader(p);

	    host = from.sin_addr.s_addr;
	    port = from.sin_port;
	    if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
		if (rx_stats_active) {
		    rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]);
		}
	    }

#ifdef RX_TRIMDATABUFS
	    /* Free any empty packet buffers at the end of this packet */
	    rxi_TrimDataBufs(p, 1);
#endif
	    /* receive pcket */
	    p = rxi_ReceivePacket(p, so, host, port, 0, 0);
	}
    }
    /* free packet? */
    if (p)
	rxi_FreePacket(p);

    return;
}
static inline bool analyseSegments(
    mbuf_t packet,        /* input packet mbuf */
    const UInt32 mbufsInCache,  /* number of entries in segsPerMBuf[] */
    const UInt32 segsPerMBuf[], /* segments required per mbuf */
    SInt32 numSegs,               /* total number of segments */
    const UInt32 maxSegs)       /* max controller segments per mbuf */
{
    mbuf_t newPacket;     // output mbuf chain.
    mbuf_t out;           // current output mbuf link.
    SInt32 outSize;               // size of current output mbuf link.
    SInt32 outSegs;               // segments for current output mbuf link.
    SInt32 doneSegs;              // segments for output mbuf chain.
    SInt32 outLen;                // remaining length of input buffer.

    mbuf_t in = packet;   // save the original input packet pointer.
    UInt32 inIndex = 0;
    const uint32_t c_mlen = mbuf_get_mlen();

    // Allocate a mbuf (non header mbuf) to begin the output mbuf chain.
    
    if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &newPacket))
    {
        ERROR_LOG("analyseSegments: MGET() 1 error\n");
        return false;
    }

    /* Initialise outgoing packet controls */
    out = newPacket;
    outSize = c_mlen;
    doneSegs = outSegs = outLen = 0;

    // numSegs stores the delta between the total and the max. For each
    // input mbuf consumed, we decrement numSegs.
    //
    numSegs -= maxSegs;

    // Loop through the input packet mbuf 'in' and construct a new mbuf chain
    // large enough to make (numSegs + doneSegs + outSegs) less than or
    // equal to zero.
    //  
    do {
        uintptr_t vmo;
        
        outLen += mbuf_len(in);

        while (outLen > outSize) {
            // Oh dear the current outgoing length is too big.
            if (outSize != MCLBYTES) {
                // Current mbuf is not yet a cluster so promote, then
                // check for error.

                if(mbuf_mclget(MBUF_DONTWAIT, MT_DATA, &out) || !(mbuf_flags(out) & MBUF_EXT) ) 
				{
                    ERROR_LOG("analyseSegments: MCLGET() error\n");
                    goto bombAnalysis;
                }
                
                outSize = MCLBYTES;
                
                continue;
            }
            
            vmo = (uintptr_t)mbuf_data(out);
            mbuf_setlen(out, MCLBYTES);  /* Fill in target copy size */
            doneSegs += (round_page(vmo + MCLBYTES) - trunc_page(vmo))
                     /   PAGE_SIZE;

            // If the number of segments of the output chain, plus
            // the segment for the mbuf we are about to allocate is greater
            // than maxSegs, then abort.
            //
            if (doneSegs + 1 > (int) maxSegs) {
                ERROR_LOG("analyseSegments: maxSegs limit 1 reached! %ld %ld\n",
                          doneSegs, maxSegs);
                goto bombAnalysis;
            }

            mbuf_t tempmbuf;
			if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &tempmbuf))
            {
                ERROR_LOG("analyseSegments: MGET() error\n");
                goto bombAnalysis;
            }
            mbuf_setnext(out, tempmbuf);
            out = tempmbuf;
            outSize = c_mlen;
            outLen -= MCLBYTES;
        }

        // Compute number of segment in current outgoing mbuf.
        vmo = (uintptr_t)mbuf_data(out);
        outSegs = ((SInt32)round_page(vmo + outLen) - (SInt32)trunc_page(vmo)) / (SInt32)PAGE_SIZE;
        if (doneSegs + outSegs > (int) maxSegs) {
            ERROR_LOG("analyseSegments: maxSegs limit 2 reached! %ld %ld %ld\n",
                      doneSegs, outSegs, maxSegs);
            goto bombAnalysis;
        }

        // Get the number of segments in the current inbuf
        if (inIndex < mbufsInCache)
            numSegs -= segsPerMBuf[inIndex];    // Yeah, in cache
        else {
            // Hmm, we have to recompute from scratch. Copy code from genPhys.
            int thisLen = 0, mbufLen;

            vmo = (uintptr_t)mbuf_data(in);
            for (mbufLen = (SInt32)mbuf_len(in); mbufLen; mbufLen -= thisLen) {
                thisLen = MIN((SInt32)next_page(vmo), (SInt32)(vmo + mbufLen)) - (SInt32)vmo;
                vmo += thisLen;
                numSegs--;
            }
        }

        // Walk the incoming buffer on one.
        in = mbuf_next(in);
        inIndex++;

        // continue looping until the total number of segments has dropped
        // to an acceptable level, or if we ran out of mbuf links.

    } while (in && ((numSegs + doneSegs + outSegs) > 0));

    if ( (int) (numSegs + doneSegs + outSegs) <= 0) {   // success

        mbuf_setlen(out, outLen);    // Set last mbuf with the remaining length.
        
        // The amount to copy is determine by the segment length in each
        // mbuf linked to newPacket. The sum can be smaller than
        // packet->pkthdr.len;
        //
        coalesceSegments(packet, newPacket);
        
        // The initial header mbuf is preserved, its length set to zero, and
        // linked to the new packet chain.
        // coalesceSegments() has already freed the mbufs that it coalesced into the newPacket chain.
		// It also hooked the remaining chain pointed to by "in" to the end of the newPacket chain.
		// All that remains is to set packet's len to 0 (to "free" the contents that coalesceSegments copied out)
		// and make it the head of the new chain.
        
        mbuf_setlen(packet , 0 );
        mbuf_setnext(packet, newPacket);
        
        return true;
    }

bombAnalysis:

    mbuf_freem(newPacket);
    return false;
}