static int linux_if_rx(struct vr_interface *vif, struct vr_packet *pkt) { int rc; struct net_device *dev = (struct net_device *)vif->vif_os; struct sk_buff *skb = vp_os_packet(pkt); struct vr_ip *ip; unsigned short network_off, transport_off, cksum_off = 0; skb->data = pkt->vp_head + pkt->vp_data; skb->len = pkt_len(pkt); skb_set_tail_pointer(skb, pkt_head_len(pkt)); if (!dev) { kfree_skb(skb); goto exit_rx; } (void)__sync_fetch_and_add(&dev->stats.rx_bytes, skb->len); (void)__sync_fetch_and_add(&dev->stats.rx_packets, 1); /* this is only needed for mirroring */ if ((pkt->vp_flags & VP_FLAG_FROM_DP) && (pkt->vp_flags & VP_FLAG_CSUM_PARTIAL)) { network_off = pkt_get_network_header_off(pkt); ip = (struct vr_ip *)(pkt_data_at_offset(pkt, network_off)); transport_off = network_off + (ip->ip_hl * 4); if (ip->ip_proto == VR_IP_PROTO_TCP) cksum_off = offsetof(struct vr_tcp, tcp_csum); else if (ip->ip_proto == VR_IP_PROTO_UDP)
/* * This funciton parses the ethernet packet and assigns the * pkt->vp_type, network protocol of the packet. The ethernet header can * start from an offset from vp_data */ int vr_pkt_type(struct vr_packet *pkt, unsigned short offset, struct vr_forwarding_md *fmd) { unsigned char *eth = pkt_data(pkt) + offset; unsigned short eth_proto; int pull_len, pkt_len = pkt_head_len(pkt) - offset; struct vr_vlan_hdr *vlan; pull_len = VR_ETHER_HLEN; if (pkt_len < pull_len) return -1; pkt->vp_flags &= ~(VP_FLAG_MULTICAST); /* L2 broadcast/multicast packets are multicast packets */ if (IS_MAC_BMCAST(eth)) pkt->vp_flags |= VP_FLAG_MULTICAST; eth_proto = ntohs(*(unsigned short *)(eth + VR_ETHER_PROTO_OFF)); while (eth_proto == VR_ETH_PROTO_VLAN) { if (pkt_len < (pull_len + sizeof(*vlan))) return -1; vlan = (struct vr_vlan_hdr *)(eth + pull_len); if (fmd && (fmd->fmd_vlan == VLAN_ID_INVALID)) fmd->fmd_vlan = vlan->vlan_tag & 0xFFF; eth_proto = ntohs(vlan->vlan_proto); pull_len += sizeof(*vlan); } pkt_set_network_header(pkt, pkt->vp_data + offset + pull_len); pkt_set_inner_network_header(pkt, pkt->vp_data + offset + pull_len); pkt->vp_type = vr_eth_proto_to_pkt_type(eth_proto); return 0; }