Esempio n. 1
0
/* -----------------------------------------------------------------------------
Handle a CCP packet.  `rcvd' is 1 if the packet was received,
0 if it is about to be transmitted.
mbuf points to the ccp payload (doesn't include FF03 and 80FD)
----------------------------------------------------------------------------- */
void ppp_comp_ccp(struct ppp_if *wan, mbuf_t m, int rcvd)
{
    u_char 	*p = mbuf_data(m);
    int 	slen;
    
    slen = CCP_LENGTH(p);
    if (slen > mbuf_pkthdr_len(m)) {
        LOGDBG(wan->net, ("ppp_comp_ccp: not enough data in mbuf (expected = %d, got = %d)\n",
		   slen, mbuf_pkthdr_len(m)));
	return;
    }
    
    switch (CCP_CODE(p)) {
    case CCP_CONFREQ:
    case CCP_TERMREQ:
    case CCP_TERMACK:
	/* CCP must be going down - disable compression */
        wan->sc_flags &= ~(rcvd ? SC_COMP_RUN : SC_DECOMP_RUN);
	break;

    case CCP_CONFACK:
	if (wan->sc_flags & SC_CCP_OPEN && !(wan->sc_flags & SC_CCP_UP)
	    && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
	    && slen >= CCP_OPT_LENGTH(p + CCP_HDRLEN) + CCP_HDRLEN) {
	    if (rcvd) {
		/* peer is agreeing to send compressed packets. */
		if (wan->rc_state
		    && (*wan->rcomp->decomp_init)
			(wan->rc_state, p + CCP_HDRLEN, slen - CCP_HDRLEN,
			 ifnet_unit(wan->net), 0, wan->mru, ifnet_flags(wan->net) & IFF_DEBUG)) {
		    wan->sc_flags |= SC_DECOMP_RUN;
		    wan->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
		}
	    } else {
		/* we're agreeing to send compressed packets. */
		if (wan->xc_state
		    && (*wan->xcomp->comp_init)
			(wan->xc_state, p + CCP_HDRLEN, slen - CCP_HDRLEN,
			 ifnet_unit(wan->net), 0, ifnet_mtu(wan->net), ifnet_flags(wan->net) & IFF_DEBUG)) {
		    wan->sc_flags |= SC_COMP_RUN;
		}
	    }
	}
	break;

    case CCP_RESETACK:
	if (wan->sc_flags & SC_CCP_UP) {
	    if (rcvd) {
		if (wan->rc_state && (wan->sc_flags & SC_DECOMP_RUN)) {
		    (*wan->rcomp->decomp_reset)(wan->rc_state);
		    wan->sc_flags &= ~SC_DC_ERROR;
		}
	    } else {
		if (wan->xc_state && (wan->sc_flags & SC_COMP_RUN))
		    (*wan->xcomp->comp_reset)(wan->xc_state);
	    }
	}
	break;
    }
}
Esempio n. 2
0
/* -----------------------------------------------------------------------------
called from pppenet_proto when data need to be sent
----------------------------------------------------------------------------- */
int pptp_ip_output(mbuf_t m, u_int32_t from, u_int32_t to)
{
    struct ip 	*ip, ip_data;

#if 0
    u_int8_t 	*d, i;

    d = mtod(m, u_int8_t *);
    for (i = 0; i < 64; i+=16) {
    IOLog("pptp_ip_output: data 0x %x %x %x %x %x %x %x %x - %x %x %x %x %x %x %x %x\n",
        d[i+0],d[i+1],d[i+2],d[i+3],d[i+4],d[i+5], d[i+6], d[i+7],
        d[i+8], d[i+9], d[i+10], d[i+11], d[i+12], d[i+13], d[i+14], d[i+15]);
    }
#endif

    if (mbuf_prepend(&m, sizeof(struct ip), MBUF_WAITOK) != 0)
        return 1;
        
    ip = &ip_data; 
    memcpy(ip, mbuf_data(m), sizeof(ip_data));
    ip->ip_tos = 0;
    ip->ip_off = 0;
    ip->ip_p = IPPROTO_GRE;
    ip->ip_len = mbuf_pkthdr_len(m);
    ip->ip_src.s_addr = from;
    ip->ip_dst.s_addr = to;
    ip->ip_ttl = MAXTTL;
    memcpy(mbuf_data(m), ip, sizeof(ip_data));
 
	lck_mtx_unlock(ppp_domain_mutex);
    ip_gre_output((struct mbuf *)m);
	lck_mtx_lock(ppp_domain_mutex);

    return 0;
}
Esempio n. 3
0
/**
 * Calculates the number of segments required to represent the mbuf.
 *
 * @returns Number of segments.
 * @param   pThis               The instance.
 * @param   pMBuf               The mbuf.
 * @param   pvFrame             The frame pointer, optional.
 */
DECLINLINE(unsigned) vboxNetFltDarwinMBufCalcSGSegs(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
{
    NOREF(pThis);

    /*
     * Count the buffers in the chain.
     */
    unsigned cSegs = 0;
    for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
        if (mbuf_len(pCur))
            cSegs++;
        else if (   !cSegs
                 && pvFrame
                 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
            cSegs++;

#ifdef PADD_RUNT_FRAMES_FROM_HOST
    /*
     * Add one buffer if the total is less than the ethernet minimum 60 bytes.
     * This may allocate a segment too much if the ethernet header is separated,
     * but that shouldn't harm us much.
     */
    if (mbuf_pkthdr_len(pMBuf) < 60)
        cSegs++;
#endif

#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
    /* maximize the number of segments. */
    cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
#endif

    return cSegs ? cSegs : 1;
}
Esempio n. 4
0
int  vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
{
    NOREF(pvIfData);

    int rc = VINF_SUCCESS;
    ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
    if (pIfNet)
    {
        /*
         * Create a mbuf for the gather list and push it onto the wire.
         *
         * Note! If the interface is in the promiscuous mode we need to send the
         *       packet down the stack so it reaches the driver and Berkeley
         *       Packet Filter (see @bugref{5817}).
         */
        if ((fDst & INTNETTRUNKDIR_WIRE) || vboxNetFltDarwinIsPromiscuous(pThis))
        {
            mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
            if (pMBuf)
            {
                errno_t err = ifnet_output_raw(pIfNet, PF_LINK, pMBuf);
                if (err)
                    rc = RTErrConvertFromErrno(err);
            }
            else
                rc = VERR_NO_MEMORY;
        }

        /*
         * Create a mbuf for the gather list and push it onto the host stack.
         */
        if (fDst & INTNETTRUNKDIR_HOST)
        {
            mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
            if (pMBuf)
            {
                /* This is what IONetworkInterface::inputPacket does. */
                unsigned const cbEthHdr = 14;
                mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
                mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
                mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
                mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */

                errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
                if (err)
                    rc = RTErrConvertFromErrno(err);
            }
            else
                rc = VERR_NO_MEMORY;
        }

        vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
    }

    return rc;
}
Esempio n. 5
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;
}
Esempio n. 6
0
__private_extern__ size_t
mbuf_pkt_list_len(mbuf_t m)
{
	size_t len = 0;
	mbuf_t n = m;

	while (n) {
		len += mbuf_pkthdr_len(n);
		n = mbuf_nextpkt(n);
	}
	return (len);
}
Esempio n. 7
0
/* -----------------------------------------------------------------------------
called from l2tp_rfc when data are present
----------------------------------------------------------------------------- */
int l2tp_wan_input(struct ppp_link *link, mbuf_t m)
{
	struct timespec tv;	
    
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
	
    link->lk_ipackets++;
    link->lk_ibytes += mbuf_pkthdr_len(m);
	nanouptime(&tv);
	link->lk_last_recv = tv.tv_sec;
    ppp_link_input(link, m);	
    return 0;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
}
Esempio n. 10
0
/* -----------------------------------------------------------------------------
This gets called at splnet from if_ppp.c at various times
when there is data ready to be sent
----------------------------------------------------------------------------- */
int l2tp_wan_output(struct ppp_link *link, mbuf_t m)
{
    struct l2tp_wan 	*wan = (struct l2tp_wan *)link;
    u_int32_t		len = mbuf_pkthdr_len(m);	// take it now, as output will change the mbuf
    int 		err;
	struct timespec tv;	
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
    
    if (err = l2tp_rfc_output(wan->rfc, m, 0)) {
        link->lk_oerrors++;
        return err;
    }

    link->lk_opackets++;
    link->lk_obytes += len;
	nanouptime(&tv);
	link->lk_last_xmit = tv.tv_sec;
    return 0;
}
Esempio n. 11
0
/* -----------------------------------------------------------------------------
This gets called at splnet from if_ppp.c at various times
when there is data ready to be sent
----------------------------------------------------------------------------- */
int pppoe_wan_output(struct ppp_link *link, mbuf_t m)
{
    struct pppoe_wan 	*wan = (struct pppoe_wan *)link;
    int			err;
	struct timespec tv;	
    
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
	
    if (err = pppoe_rfc_output(wan->rfc, m)) {
        link->lk_oerrors++;
        return err;
    }

    link->lk_opackets++;
    link->lk_obytes += mbuf_pkthdr_len(m);
    //getmicrotime(link->lk_last_xmit);
	nanouptime(&tv);
	link->lk_last_xmit = tv.tv_sec;
    return 0;
}
Esempio n. 12
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;
}
Esempio n. 13
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;
}
Esempio n. 14
0
mbuf_t darwin_iwi3945::mergePacket(mbuf_t m)
{
	mbuf_t nm,nm2;
	int offset;
	if(!mbuf_next(m))
	{
		offset = (4 - ((int)(mbuf_data(m)) & 3)) % 4;    //packet needs to be 4 byte aligned
		if (offset==0) return m;
		IWI_DEBUG_FULL("this packet dont have mbuf_next, merge  is not required\n");
		goto copy_packet;
	}

	/* allocate and Initialize New mbuf */
	nm = allocatePacket(mbuf_pkthdr_len(m));
	if (nm==0) return NULL;
	//if (mbuf_getpacket(MBUF_WAITOK, &nm)!=0) return NULL;
	mbuf_setlen(nm,0);
	mbuf_pkthdr_setlen(nm,0);
	if( mbuf_next(nm)) IWI_ERR("merged mbuf_next\n");
	
	/* merging chains to single mbuf */
	for (nm2 = m; nm2;  nm2 = mbuf_next(nm2)) {
		memcpy (skb_put (nm, mbuf_len(nm2)), (UInt8*)mbuf_data(nm2), mbuf_len(nm2));
	}

	/* checking if merged or not. */
	if( mbuf_len(nm) == mbuf_pkthdr_len(m) ) 
	{
		if (m!=NULL)
		if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m);
		m=NULL;
		return nm;
	}
	/* merging is not completed. */
	IWI_LOG("mergePacket is failed: data copy dont work collectly\n");
	//IWI_LOG("orig_len %d orig_pktlen %d new_len  %d new_pktlen  %d\n",
	//				mbuf_len(m),mbuf_pkthdr_len(m),
	//				mbuf_len(nm),mbuf_pkthdr_len(nm) );
	if (m!=NULL)
	if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m);
	m=NULL;
	if (nm!=NULL)
	if (!(mbuf_type(nm) == MBUF_TYPE_FREE) ) freePacket(nm);
	nm=NULL;
	return NULL;

copy_packet: 
		if (mbuf_dup(m, MBUF_WAITOK , &nm)!=0)
		{
			if (m!=NULL)
			if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m);
			m=NULL;
			return NULL;
		}
		if (m!=NULL)
		if (!(mbuf_type(m) == MBUF_TYPE_FREE) ) freePacket(m);
		m=NULL;
		return nm;
		//return copyPacket(m, 0); 

}
Esempio n. 15
0
static bool mbuf_buffer(IOMemoryDescriptor *buffer, int skip_buffer, mbuf_t m, int skip_mbuf, int copy)
{
  int offset = 0;
  bool isWrite = (buffer->getDirection() == kIODirectionOut);
  
  if (buffer->prepare() != kIOReturnSuccess)
  {
    KINFO("buffer prepare failed");
    return false;
  }
  
  if (isWrite && mbuf_pkthdr_len(m) < skip_mbuf + copy)
    mbuf_pkthdr_setlen(m, skip_mbuf + copy);
  
  for (; m; m = mbuf_next(m))
  {
    if (isWrite && mbuf_len(m) < skip_mbuf + copy && mbuf_trailingspace(m))
      mbuf_setlen(m, min(mbuf_maxlen(m), skip_mbuf + copy));
    
    UInt32 available = mbuf_len(m);
    
    //KDEBUG("available=%d, skip_mbuf=%d", available, skip_mbuf);
    
    if (skip_mbuf >= available)
    {
      skip_mbuf -= available;
      continue;
    }
    
    UInt8 *buf = (UInt8 *)mbuf_data(m) + skip_mbuf;
    IOByteCount len = copy;                       // remaining requested
    len = min(len, available - skip_mbuf);        // available in mbuf
    len = min(len, buffer->getLength() - offset); // available in iomd    
    IOByteCount wrote = 0;
    
    if (!len)
    {
      KDEBUG("no space, %d-%d, %d-%d", available, skip_mbuf, buffer->getLength(), offset);
      break;
    }
    
    //KDEBUG("COPY: skip_buffer=%d, offset=%d, len=%d (remaining=%d)", skip_buffer, offset, len, copy);
    if (isWrite)
      wrote = buffer->readBytes(skip_buffer + offset, buf, len);
    else
      wrote = buffer->writeBytes(skip_buffer + offset, buf, len);

    if (wrote != len)
    {
      KINFO("short IO");
      break;
    }
    
    offset += len;
    copy -= len;
    skip_mbuf = 0;
  }
  
  if (buffer->complete() != kIOReturnSuccess)
  {
    KINFO("buffer complete failed");
    return false;
  }

  if (copy > 0)
  {
    KINFO("failed to copy requested data: %d remaining", copy);
    return false;
  }
  
  return true;
}
// 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 );
}
Esempio n. 17
0
UInt32 CLASS::outputPacket( mbuf_t packet, void * param )
{
    TxDesc *            descNext;
    TxDesc *            descHead;
    TxDesc *            descLast;
    UInt                segCount;
    UInt32              cmdStatus;
    UInt32              tailIndex;
    IOPhysicalSegment   vectors[ kTxMaxSegmentCount ];
    IODebuggerLockState state;

    state = IOKernelDebugger::lock(this);   

    tailIndex = fTxTailIndex;

    // Check if there are enough descriptors to describe the packet
    // buffers. kTxMaxSegmentCount should be large enough to reduce
    // the need to coalesce mbufs.

    if (TX_RING_FREE(fTxHeadIndex, tailIndex) < kTxMaxSegmentCount)
    {
        IOKernelDebugger::unlock(state);
        return kIOReturnOutputStall;
    }

    // Get the next transmit descriptor owned by the driver.

    descHead = &fTxDescBase[tailIndex];
    descNext = descHead;

    // Use the mbuf cursor to generate a list of physical address and
    // length vectors for the network buffers.

    segCount = fTxMbufCursor->getPhysicalSegmentsWithCoalesce(
                              packet, vectors, kTxMaxSegmentCount);
    if (segCount == 0)
    {
        DEBUG_LOG("TX Cursor returned 0 segments\n");
        goto drop_packet;
    }
    assert(segCount <= kTxMaxSegmentCount);

    // Update the first (head) descriptor.
    // Do not set the OWN bit until the rest of the descriptors are done.

    OSWriteLittleInt32(&descHead->bufferPtr, 0, vectors[0].location);
    cmdStatus = (vectors[0].length & kDescBufferSizeMask);
    tailIndex = (tailIndex + 1) & (kTxDescCount - 1);
    descLast  = descHead;
    descNext  = &fTxDescBase[tailIndex];

    for (UInt seg = 1; seg < segCount; seg++)
    {
        // Write cmdStatus for previous descriptor with MORE bit set.

        OSWriteLittleInt32(&descLast->cmdStatus, 0, cmdStatus | kDescMore);

        // Update current descriptor.

        OSWriteLittleInt32(&descNext->bufferPtr, 0, vectors[seg].location);
        cmdStatus = (vectors[seg].length & kDescBufferSizeMask) | kDescOwn;

        tailIndex = (tailIndex + 1) & (kTxDescCount - 1);
        descLast  = descNext;
        descNext  = &fTxDescBase[tailIndex];
    }

    // Last descriptor must have MORE bit cleared.

    if (++fTxInterruptInterval >= (kTxDescCount/kTxMaxSegmentCount/4))
    {
        cmdStatus |= kDescInterrupt;
        fTxInterruptInterval = 0;
    }

    OSWriteLittleInt32(&descLast->cmdStatus, 0, cmdStatus);
    
    // Set OWN bit on head descriptor after all descriptors following it
    // have been prepared.

    descHead->cmdStatus |= OSSwapHostToLittleConstInt32(kDescOwn);

    // Update Head Descriptor.

    descHead->packet    = packet;
    descHead->descLast  = descLast;
    descHead->descCount = segCount;
    descHead->nextIndex = tailIndex;

    // Update free descriptor count after completing the descriptor chain.
    // The order is important otherwise we may race with interrupt handler.

    fTxTailIndex = tailIndex;
    DEBUG_LOG("TX DESC:%d-%ld (size %d)\n",
              descHead-fTxDescBase, fTxTailIndex, mbuf_pkthdr_len(packet));

    // Enable transmitter in case its in txIdle state.

    WriteReg(CR, CR_TXE);

    IOKernelDebugger::unlock(state);
    NET_STAT(outputPackets, 1);
    return kIOReturnOutputSuccess;

drop_packet:
    IOKernelDebugger::unlock(state);
    freePacket(packet);
    ETH_STAT(dot3TxExtraEntry.resourceErrors, 1);
    return kIOReturnOutputDropped;
}
Esempio n. 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;
}
Esempio n. 19
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;
}
Esempio n. 20
0
UInt32 AtherosL1Ethernet::outputPacket(mbuf_t m, void *prm)
{
    u32 buf_len;
    at_adapter *adapter=&adapter_;

    u16 next_to_use;
    u16 tpd_req = 1;
    TpdDescr *pTpd ;
    struct at_buffer *buffer_info;

     if(tpd_avail(&adapter->tpd_ring) < tpd_req) {
        // no enough descriptor
        DbgPrint("no enough resource!!\n");
        freePacket(m);
        return kIOReturnOutputDropped;
    }
    

    // init tpd flags
    struct at_tpd_ring* tpd_ring = &adapter->tpd_ring;
    pTpd = AT_TPD_DESC(tpd_ring,
                       ((u16)atomic_read(&tpd_ring->next_to_use)));
    //memset(pTpd, 0, sizeof(TpdDescr));
    memset(((u8*)pTpd + sizeof(pTpd->addr)), 0, (sizeof(TpdDescr) - sizeof(pTpd->addr))); //addr don't clear

    next_to_use = (u16)atomic_read(&tpd_ring->next_to_use);
    buffer_info = tpd_ring->buffer_info+next_to_use; 
    
    if (!buffer_info->memDesc)
    {
        DbgPrint("Tx buffer is null!!\n");
        freePacket(m);
        return kIOReturnOutputDropped;
    }
    
    if (mbuf_pkthdr_len(m) <= AT_TX_BUF_LEN) buf_len = mbuf_pkthdr_len(m);
    else
    {
        DbgPrint("Tx Packet size is too big, droping\n");
        freePacket(m);
        return kIOReturnOutputDropped;
    }
    
    DbgPrint("outputPacket() length %d next_to_use=%d\n", buf_len, next_to_use);
    
    UInt8 *data_ptr = (UInt8 *)buffer_info->memDesc->getBytesNoCopy();
    UInt32 pkt_snd_len = 0;
    mbuf_t cur_buf = m;

    do
    {
        if (mbuf_data(cur_buf)) bcopy(mbuf_data(cur_buf), data_ptr, mbuf_len(cur_buf));
        data_ptr += mbuf_len(cur_buf);
        pkt_snd_len += mbuf_len(cur_buf);
    }
    while(((cur_buf = mbuf_next(cur_buf)) != NULL) && ((pkt_snd_len + mbuf_len(cur_buf)) <= buf_len));
    
    
    buf_len = pkt_snd_len;
    buffer_info->length = (UInt16)buf_len;
    pTpd->buf_len= OSSwapHostToLittleInt16((UInt16)buf_len);
    pTpd->eop = 1;
    
    if(++next_to_use == tpd_ring->count) next_to_use = 0; 
    
    atomic_set(&tpd_ring->next_to_use, next_to_use);
    
    // update mailbox
    at_update_mailbox(adapter);
    
    OSSynchronizeIO();

    freePacket(m);
    return kIOReturnOutputSuccess;
}
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;
}
Esempio n. 22
0
File: krpc_subr.c Progetto: argp/xnu
/*
 * 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;
}
Esempio n. 23
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;
}
Esempio n. 24
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;	
}
Esempio n. 25
0
UInt32 AttansicL2Ethernet::outputPacket(mbuf_t m, void *prm)
{
    at_adapter *adapter=&adapter_;
    tx_pkt_header_t* txph;
    u32 offset, copy_len;
    int txs_unused;
    int txbuf_unused;

    u32 buf_len;

	if (mbuf_pkthdr_len(m) <= MAX_TX_BUF_LEN) buf_len = mbuf_pkthdr_len(m);
	else
	{
		DbgPrint("Tx Packet size is too big, droping\n");
		freePacket(m);
		return kIOReturnOutputDropped;
	}

	txs_unused = TxsFreeUnit(adapter);
	txbuf_unused = TxdFreeBytes(adapter);

	if (txs_unused < 1  || buf_len  > txbuf_unused) {
		// no enough resource
		DbgPrint("no enough resource!!\n");
		freePacket(m);
		return kIOReturnOutputDropped;
	}

	offset = adapter->txd_write_ptr;
DbgPrint("outputPacket() begin, txd_write_ptr %d txs_next_clear %d length %d \n" , adapter->txd_write_ptr,adapter->txs_next_clear,buf_len);

    txph = (tx_pkt_header_t*) 
            (((u8*)adapter->txd_ring)+offset);

	offset += 4;
	if (offset >= adapter->txd_ring_size)
		offset -= adapter->txd_ring_size;

	u32 pkt_snd_len = 0;
	mbuf_t cur_buf = m;

	do
	{
		if (mbuf_data(cur_buf)){
			copy_len = adapter->txd_ring_size - offset;
			if (copy_len >=mbuf_len(cur_buf)) {
				memcpy((u8*)adapter->txd_ring+offset, mbuf_data(cur_buf), mbuf_len(cur_buf));

			} else {
				memcpy((u8*)adapter->txd_ring+offset, mbuf_data(cur_buf), copy_len);
				memcpy((u8*)adapter->txd_ring,  ((u8*)mbuf_data(cur_buf))+copy_len, mbuf_len(cur_buf)-copy_len);
			}
			offset += mbuf_len(cur_buf);
			if (offset >= adapter->txd_ring_size)
				offset -= adapter->txd_ring_size;
			pkt_snd_len += mbuf_len(cur_buf);
		}
	}
	while(((cur_buf = mbuf_next(cur_buf)) != NULL) && ((pkt_snd_len + mbuf_len(cur_buf)) <= buf_len));
	buf_len = pkt_snd_len;
	
	*(u32*)txph = 0;
	txph->pkt_size = buf_len;
	
    offset =  ((offset+3)&~3);
	
	if (offset >= adapter->txd_ring_size)
		offset -= adapter->txd_ring_size;
	adapter->txd_write_ptr = offset;

	// clear txs before send
	adapter->txs_ring[adapter->txs_next_clear].update = 0;
	if (++adapter->txs_next_clear == adapter->txs_ring_size)
		adapter->txs_next_clear = 0;

	AT_WRITE_REGW(  &adapter->hw, 
             REG_MB_TXD_WR_IDX, 
             (adapter->txd_write_ptr>>2));

	OSSynchronizeIO();
	freePacket(m);
	return kIOReturnOutputSuccess;
}