////////////////////////////////////////////////////////////////////////////////
//
//  inet_firewire_pre_output
//
//   IN:	ifnet_t ifp
//   IN:	struct mbuf **m0
//   IN:	struct sockaddr dst_netaddr
//   IN:	caddr_t	route
//   OUT:	char *type
//	 OUT:	char *edst
//	 IN:	u_long dl_tag
// 
// Invoked by : 
//  Invoked by dlil.c for dlil_output=>(*proto)->dl_pre_output=> 
//  inet_firewire_pre_output=>
//
// Process a received firewire ARP/IP packet, the packet is in the mbuf 
// chain m
//
////////////////////////////////////////////////////////////////////////////////
int
inet_firewire_pre_output(
	ifnet_t						interface,
	__unused protocol_family_t	protocol_family,
	mbuf_t						*m0,
	const struct sockaddr		*dst_netaddr,
	void*						route,
	char						*type,
	char						*edst)
{
    mbuf_t m = *m0;
    errno_t	result = 0;
	    
    if ((ifnet_flags(interface) & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 
		return ENETDOWN;
	
	// Tell firewire_frameout it's ok to loop packet unless negated below.
    mbuf_setflags(m, mbuf_flags(m) | MBUF_LOOP);

    switch (dst_netaddr->sa_family) 
	{
    	case AF_INET: 
		{
			struct sockaddr_dl	ll_dest;
			result = inet_arp_lookup(interface, (const struct sockaddr_in*)dst_netaddr,
								   &ll_dest, sizeof(ll_dest), (route_t)route, *m0);
			if (result == 0) 
			{
				bcopy(LLADDR(&ll_dest), edst, FIREWIRE_ADDR_LEN);
				*(u_int16_t*)type = htons(FWTYPE_IP);
			}
		}
		break;

        case AF_UNSPEC:
		{
            mbuf_setflags(m, mbuf_flags(m) & ~MBUF_LOOP);
            register struct firewire_header *fwh = (struct firewire_header *)dst_netaddr->sa_data;
			(void)memcpy(edst, fwh->fw_dhost, FIREWIRE_ADDR_LEN);
            *(u_short *)type = fwh->fw_type;
		}
		break;

        default:
            return EAFNOSUPPORT;
    }

	return result;
}
Exemple #2
0
////////////////////////////////////////////////////////////////////////////////
//
// firewire_arpintr
//
// IN: register mbuf_t m
//
// Invoked by :
// inet_firewire_input in firewire_inet_pr_module.c and it will be called from
// the context of dlil_input_thread queue
//
// Common length and type checks are done here, then the protocol-specific
// routine is called.
//
////////////////////////////////////////////////////////////////////////////////
void
firewire_arpintr(register mbuf_t m)
{
    if (m == 0 || (mbuf_flags(m) & MBUF_PKTHDR) == 0)
        panic("arpintr");

    inet_firewire_arp_input(m);
}
Exemple #3
0
UInt32 darwin_iwi3945::outputPacket(mbuf_t m, void * param)
{
	//IOLog("outputPacket\n");
	if((fNetif->getFlags() & IFF_RUNNING)!=0 || m==NULL)
	{
		if (m)
		if (!(mbuf_type(m) == MBUF_TYPE_FREE) ) freePacket(m);
		m=NULL;
		netStats->outputErrors++;
		return kIOReturnOutputDropped;
	}
	
	
	mbuf_t nm;
	int ret = kIOReturnOutputDropped;

	//checking supported packet
	
	IWI_DEBUG("outputPacket t: %d f:%04x\n",mbuf_type(m),mbuf_flags(m));
	
	//drop mbuf is not PKTHDR
	if (!(mbuf_flags(m) & MBUF_PKTHDR) ){
		IWI_ERR("BUG: dont support mbuf without pkthdr and dropped \n");
		netStats->outputErrors++;
		goto finish;
	}
	
	if(mbuf_type(m) == MBUF_TYPE_FREE){
		IWI_ERR("BUG: this is freed packet and dropped \n");
		netStats->outputErrors++;
		goto finish;
	}
	
	nm = mergePacket(m);
	
	if (nm==NULL) 
	{
		netStats->outputErrors++;
		goto finish;
	}
	
	if(mbuf_next(nm)){
		IWI_ERR("BUG: dont support chains mbuf\n");
		IWI_ERR("BUG: tx packet is not single mbuf mbuf_len(%d) mbuf_pkthdr_len(%d)\n",mbuf_len(nm) , mbuf_pkthdr_len(nm) );
		IWI_ERR("BUG: next mbuf size %d\n",mbuf_len(mbuf_next(nm)));
	}
	
	IWI_DEBUG_FULL("call ieee80211_xmit - not done yet\n");
	//ret  = ieee80211_xmit(nm,priv->net_dev);
	//struct ieee80211_tx_control ctrl;
	//ret=ipw_tx_skb(priv, nm, &ctrl);

finish:	
	
	/* free finished packet */
	//freePacket(m);
	//m=NULL;
	if (ret ==  kIOReturnOutputDropped) { 
		//if (nm)
		//if (!(mbuf_type(nm) == MBUF_TYPE_FREE) ) freePacket(nm);
		//nm=NULL;
	}
	return ret;	
}
Exemple #4
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;
}
////////////////////////////////////////////////////////////////////////////////
//
// firewire_frameout
//
// IN:	ifnet_t ifp,struct mbuf **m
// IN:  struct sockaddr *ndest - contains the destination IP Address 
// IN:	char *edst - filled by firewire_arpresolve function in if_firewire.c
// IN:  char *fw_type 
//
// Invoked by : 
//  dlil.c for dlil_output, Its called after inet_firewire_pre_output
//
// Encapsulate a packet of type family for the local net.
// Use trailer local net encapsulation if enough data in first
// packet leaves a multiple of 512 bytes of data in remainder.
//
////////////////////////////////////////////////////////////////////////////////
__private_extern__ int
firewire_frameout(ifnet_t ifp, mbuf_t *m, 
					const struct sockaddr *ndest, const char *edst, const char *fw_type)
{
	register struct firewire_header *fwh;
		
	/*
	 * If a simplex interface, and the packet is being sent to our
	 * Ethernet address or a broadcast address, loopback a copy.
	 * XXX To make a simplex device behave exactly like a duplex
	 * device, we should copy in the case of sending to our own
	 * ethernet address (thus letting the original actually appear
	 * on the wire). However, we don't do that here for security
	 * reasons and compatibility with the original behavior.
	 */
	 
	if ((ifnet_flags(ifp) & IFF_SIMPLEX) &&
	    (mbuf_flags(*m) & MBUF_LOOP))
	{
		if (loop_ifp == NULL) {
			ifnet_find_by_name("lo0", &loop_ifp);
			
			/*
			 * We make an assumption here that lo0 will never go away. This
			 * means we don't have to worry about releasing the reference
			 * later and we don't have to worry about leaking a reference
			 * every time we are loaded.
			 */
			ifnet_release(loop_ifp);
		}
		
	    if (loop_ifp) 
		{
            if (mbuf_flags(*m) & MBUF_BCAST)
			{
                mbuf_t n;
                
                if (mbuf_copym(*m, 0, MBUF_COPYALL, MBUF_WAITOK, &n) == 0)
                    ifnet_output(loop_ifp, PF_INET, n, 0, ndest);
            } 
            else 
            {
				if (bcmp(edst, ifnet_lladdr(ifp), FIREWIRE_ADDR_LEN) == 0) 
				{
                    ifnet_output(loop_ifp, PF_INET, *m, 0, ndest);
                    return EJUSTRETURN;
                }
            }
	    }
	}

	//
	// Add local net header.  If no space in first mbuf,
	// allocate another.
	//
	if (mbuf_prepend(m, sizeof(struct firewire_header), MBUF_DONTWAIT) != 0)
	    return (EJUSTRETURN);

	//
	// Lets put this intelligent here into the mbuf 
	// so we can demux on our output path
	//
	fwh = (struct firewire_header*)mbuf_data(*m);
	(void)memcpy(&fwh->fw_type, fw_type,sizeof(fwh->fw_type));
	memcpy(fwh->fw_dhost, edst, FIREWIRE_ADDR_LEN);
	(void)memcpy(fwh->fw_shost, ifnet_lladdr(ifp), sizeof(fwh->fw_shost));
	
	return 0;
}
UInt32 IOMbufMemoryCursor::genPhysicalSegments(mbuf_t packet, void *vector,
                                               UInt32 maxSegs, bool doCoalesce)
{
    bool doneCoalesce = false;

    if (!packet || !(mbuf_flags(packet) & MBUF_PKTHDR))
        return 0;

    if (!maxSegs)
    {
        maxSegs = maxNumSegments;
        if (!maxSegs) return 0;
    }

    if ( mbuf_next(packet) == 0 )
    {
        uintptr_t               src;
        struct IOPhysicalSegment  physSeg;

        /*
         * the packet consists of only 1 mbuf
         * so if the data buffer doesn't span a page boundary
         * we can take the simple way out
         */
        src = (uintptr_t)mbuf_data(packet);

        if ( trunc_page(src) == trunc_page(src + mbuf_len(packet) - 1) )
        {
            physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)src);
            if ( physSeg.location )
            {
                physSeg.length = mbuf_len(packet);
                (*outSeg)(physSeg, vector, 0);
                return 1;
            }
            
            maxSegs = 1;
            if ( doCoalesce == false ) return 0;
        }
    }

    if ( doCoalesce == true && maxSegs == 1 )
    {
        uintptr_t               src;
        uintptr_t               dst;
        mbuf_t               m;
        mbuf_t               mnext;
        mbuf_t               out;
        UInt32                    len = 0;
        struct IOPhysicalSegment  physSeg;

        if ( mbuf_pkthdr_len(packet) > MCLBYTES ) return 0;

        m = packet;

        // Allocate a non-header mbuf + cluster.
        if (mbuf_getpacket( MBUF_DONTWAIT, &out ))
			return 0;
		mbuf_setflags( out, mbuf_flags( out ) & ~MBUF_PKTHDR );
        dst = (uintptr_t)mbuf_data(out);

        do
        {
            src = (uintptr_t)mbuf_data(m);
            BCOPY( src, dst, mbuf_len(m) );
            dst += mbuf_len(m);
            len += mbuf_len(m);
        } while ( (m = mbuf_next(m)) != 0 );

        mbuf_setlen(out , len);

        dst = (uintptr_t)mbuf_data(out);
        physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)dst);
        if (!physSeg.location)
        {
            mbuf_free(out);
            return 0;
        }
        physSeg.length = mbuf_len(out);
        (*outSeg)(physSeg, vector, 0);

        m = mbuf_next(packet);
        while (m != 0)
        {
            mnext = mbuf_next(m);
            mbuf_free(m);
            m = mnext;
        }

        // The initial header mbuf is preserved, its length set to zero,
        // and linked to the new packet chain.

        mbuf_setlen(packet , 0);
        mbuf_setnext(packet , out);
        mbuf_setnext(out , 0);

        return 1;
    }

    //
    // Iterate over the mbuf, translating segments were allowed.  When we
    // are not allowed to translate segments then accumulate segment
    // statistics up to kMBufDataCacheSize of mbufs.  Finally
    // if we overflow our cache just count how many segments this
    // packet represents.
    //
    UInt32 segsPerMBuf[kMBufDataCacheSize];

tryAgain:
    UInt32 curMBufIndex = 0;
    UInt32 curSegIndex  = 0;
    UInt32 lastSegCount = 0;
    mbuf_t m = packet;

    // For each mbuf in incoming packet.
    do {
        vm_size_t   mbufLen, thisLen = 0;
        uintptr_t src;

        // Step through each segment in the current mbuf
        for (mbufLen = mbuf_len(m), src = (uintptr_t)mbuf_data(m);
             mbufLen;
             src += thisLen, mbufLen -= thisLen)
        {
            // If maxSegmentSize is atleast PAGE_SIZE, then
            // thisLen = MIN(next_page(src), src + mbufLen) - src;

            thisLen = MIN(mbufLen, maxSegmentSize);
            thisLen = MIN(next_page(src), src + thisLen) - src;

            // If room left then find the current segment addr and output
            if (curSegIndex < maxSegs) {
                struct IOPhysicalSegment physSeg;

                physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)src);
                if ( physSeg.location == 0 )
                {
                    return doCoalesce ?
                           genPhysicalSegments(packet, vector, 1, true) : 0;
                }
                physSeg.length = thisLen;
                (*outSeg)(physSeg, vector, curSegIndex);
            }

            // Count segments if we are coalescing. 
            curSegIndex++;
        }

        // Cache the segment count data if room is available.
        if (curMBufIndex < kMBufDataCacheSize) {
            segsPerMBuf[curMBufIndex] = curSegIndex - lastSegCount;
            lastSegCount = curSegIndex;
        }

        // Move on to next imcoming mbuf
        curMBufIndex++;
        m = mbuf_next(m);
    } while (m);

    // If we finished cleanly return number of segments found
    if (curSegIndex <= maxSegs)
        return curSegIndex;
    if (!doCoalesce)
        return 0;   // if !coalescing we've got a problem.

    // If we are coalescing and it is possible then attempt coalesce, 
    if (!doneCoalesce
    &&  (UInt) mbuf_pkthdr_len(packet) <= maxSegs * maxSegmentSize) {
        // Hmm, we have to do some coalescing.
        bool analysisRet;
            
        analysisRet = analyseSegments(packet,
                                      MIN(curMBufIndex, kMBufDataCacheSize),
                                      segsPerMBuf,
                                      curSegIndex, maxSegs);
        if (analysisRet) {
            doneCoalesce = true;
            coalesceCount++;
            goto tryAgain;
        }
    }

    assert(!doneCoalesce);  // Problem in Coalesce code.
    packetTooBigErrors++;
    return 0;
}
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;
}