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; }
errno_t kn_tcp_pkt_from_params(mbuf_t *data, u_int8_t tcph_flags, u_int32_t iph_saddr, u_int32_t iph_daddr, u_int16_t tcph_sport, u_int16_t tcph_dport, u_int32_t tcph_seq, u_int32_t tcph_ack, const char* payload, size_t payload_len) { int retval = 0; size_t tot_data_len, tot_buf_len, max_len; // mac osx thing.. to be safe, leave out 14 bytes for ethernet header. void *buf = NULL; struct ip* o_iph; struct tcphdr* o_tcph; u_int16_t csum; mbuf_csum_request_flags_t csum_flags = 0; boolean_t pkt_allocated = FALSE; tot_data_len = sizeof(struct ip) + sizeof(struct tcphdr) + payload_len; tot_buf_len = tot_data_len + ETHHDR_LEN; // allocate the packet retval = mbuf_allocpacket(MBUF_DONTWAIT, tot_buf_len, NULL, data); if (retval != 0) { kn_debug("mbuf_allocpacket returned error %d\n", retval); goto FAILURE; } else { pkt_allocated = TRUE; } max_len = mbuf_maxlen(*data); if (max_len < tot_buf_len) { kn_debug("no enough buffer space, try to request more.\n"); retval = mbuf_prepend(data, tot_buf_len - max_len, MBUF_DONTWAIT); if (retval != 0) { kn_debug("mbuf_prepend returned error %d\n", retval); goto FAILURE; } } mbuf_pkthdr_setlen(*data, tot_data_len); retval = mbuf_pkthdr_setrcvif(*data, NULL); if (retval != 0) { kn_debug("mbuf_pkthdr_setrcvif returned error %d\n", retval); goto FAILURE; } mbuf_setlen(*data, tot_data_len); retval = mbuf_setdata(*data, (mbuf_datastart(*data) + ETHHDR_LEN), tot_data_len); if (retval != 0) { kn_debug("mbuf_setdata returned error %d\n", retval); goto FAILURE; } buf = mbuf_data(*data); mbuf_pkthdr_setheader(*data, buf); o_iph = (struct ip*)buf; memset(o_iph, 0, sizeof(struct ip)); // setup IPv4 header o_iph->ip_hl = sizeof(struct ip) / 4; o_iph->ip_v = 4; o_iph->ip_tos = 0; o_iph->ip_id = 0; o_iph->ip_off = htons(IP_DF); o_iph->ip_p = IPPROTO_TCP; o_iph->ip_len = htons(tot_data_len); o_iph->ip_sum = 0; o_iph->ip_ttl = 64; o_iph->ip_src.s_addr = iph_saddr; o_iph->ip_dst.s_addr = iph_daddr; o_tcph = (struct tcphdr*)((char*)o_iph + sizeof(struct ip)); memset(o_tcph, 0, sizeof(struct tcphdr)); o_tcph->th_sport = tcph_sport; o_tcph->th_dport = tcph_dport; o_tcph->th_seq = tcph_seq; o_tcph->th_ack = tcph_ack; o_tcph->th_flags = tcph_flags; o_tcph->th_win = 0xffffU; o_tcph->th_off = sizeof(struct tcphdr) / 4; o_tcph->th_sum = 0; o_tcph->th_urp = 0; if (payload_len > 0) { memcpy((char*)o_tcph + sizeof(struct tcphdr), payload, payload_len); } mbuf_clear_csum_performed(*data); csum_flags |= MBUF_CSUM_REQ_IP; retval = mbuf_get_csum_requested(*data, &csum_flags, NULL); if (retval != 0) { kn_debug("mbuf_get_csum_requested returned error %d\n", retval); goto FAILURE; } /* calculate TCP checksum */ csum = kn_tcp_sum_calc(sizeof(struct tcphdr) + payload_len, (u_int16_t*)&o_iph->ip_src.s_addr, (u_int16_t*)&o_iph->ip_dst.s_addr, (u_int16_t*)o_tcph); o_tcph->th_sum = csum; return 0; FAILURE: if (pkt_allocated == TRUE) { mbuf_free(*data); } return retval; }
// 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 ); }
errno_t firewire_inet_arp( ifnet_t ifp, u_short arpop, const struct sockaddr_dl* sender_hw, const struct sockaddr* sender_proto, const struct sockaddr_dl* target_hw, const struct sockaddr* target_proto) { mbuf_t m; errno_t result; register struct firewire_header *fwh; register IP1394_ARP *fwa; const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto; const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto; char *datap; IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController(); if(fwIpObj == NULL) return EINVAL; LCB *lcb = fwIpObj->getLcb(); if (target_ip == NULL) return EINVAL; if ((sender_ip && sender_ip->sin_family != AF_INET) || (target_ip && target_ip->sin_family != AF_INET)) return EAFNOSUPPORT; result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m); if (result != 0) return result; mbuf_setlen(m, sizeof(*fwa)); mbuf_pkthdr_setlen(m, sizeof(*fwa)); /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */ datap = (char*)mbuf_datastart(m); datap += mbuf_trailingspace(m); datap -= (((u_long)datap) & 0x3); mbuf_setdata(m, datap, sizeof(*fwa)); fwa = (IP1394_ARP*)mbuf_data(m); bzero((caddr_t)fwa, sizeof(*fwa)); /* Prepend the ethernet header, we will send the raw frame */ result = mbuf_prepend(&m, sizeof(*fwh), MBUF_DONTWAIT); if(result != 0) return result; fwh = (struct firewire_header*)mbuf_data(m); fwh->fw_type = htons(FWTYPE_ARP); /* Fill out the arp packet */ fwa->hardwareType = htons(ARP_HDW_TYPE); fwa->protocolType = htons(FWTYPE_IP); fwa->hwAddrLen = sizeof(IP1394_HDW_ADDR); fwa->ipAddrLen = IPV4_ADDR_SIZE; fwa->opcode = htons(arpop); fwa->senderMaxRec = lcb->ownHardwareAddress.maxRec; fwa->sspd = lcb->ownHardwareAddress.spd; fwa->senderUnicastFifoHi = htons(lcb->ownHardwareAddress.unicastFifoHi); fwa->senderUnicastFifoLo = htonl(lcb->ownHardwareAddress.unicastFifoLo); /* Sender Hardware */ if (sender_hw != NULL) bcopy(CONST_LLADDR(sender_hw), &fwa->senderUniqueID, sizeof(fwa->senderUniqueID)); else ifnet_lladdr_copy_bytes(ifp, &fwa->senderUniqueID, FIREWIRE_ADDR_LEN); ifnet_lladdr_copy_bytes(ifp, fwh->fw_shost, sizeof(fwh->fw_shost)); /* Sender IP */ if (sender_ip != NULL) fwa->senderIpAddress = sender_ip->sin_addr.s_addr; else { ifaddr_t *addresses; struct sockaddr sa; if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) { ifaddr_address( addresses[0], &sa, 16 ); fwa->senderIpAddress = ((UInt32)(sa.sa_data[5] & 0xFF)) << 24; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[4] & 0xFF)) << 16; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[3] & 0xFF)) << 8; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[2] & 0xFF)); ifnet_free_address_list(addresses); } else { mbuf_free(m); return ENXIO; } } /* Target Hardware */ if (target_hw == 0) bcopy(fwbroadcastaddr, fwh->fw_dhost, sizeof(fwh->fw_dhost)); else bcopy(CONST_LLADDR(target_hw), fwh->fw_dhost, sizeof(fwh->fw_dhost)); /* Target IP */ fwa->targetIpAddress = target_ip->sin_addr.s_addr; ifnet_output_raw(ifp, PF_INET, m); return 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; }