/** * fnic_import_rq_eth_pkt() - handle received FCoE or FIP frame. * @fnic: fnic instance. * @skb: Ethernet Frame. */ static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, struct sk_buff *skb) { struct fc_frame *fp; struct ethhdr *eh; struct fcoe_hdr *fcoe_hdr; struct fcoe_crc_eof *ft; /* * Undo VLAN encapsulation if present. */ eh = (struct ethhdr *)skb->data; if (eh->h_proto == htons(ETH_P_8021Q)) { memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); skb_reset_mac_header(skb); } if (eh->h_proto == htons(ETH_P_FIP)) { skb_pull(skb, sizeof(*eh)); fcoe_ctlr_recv(&fnic->ctlr, skb); return 1; /* let caller know packet was used */ } if (eh->h_proto != htons(ETH_P_FCOE)) goto drop; skb_set_network_header(skb, sizeof(*eh)); skb_pull(skb, sizeof(*eh)); fcoe_hdr = (struct fcoe_hdr *)skb->data; if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER) goto drop; fp = (struct fc_frame *)skb; fc_frame_init(fp); fr_sof(fp) = fcoe_hdr->fcoe_sof; skb_pull(skb, sizeof(struct fcoe_hdr)); skb_reset_transport_header(skb); ft = (struct fcoe_crc_eof *)(skb->data + skb->len - sizeof(*ft)); fr_eof(fp) = ft->fcoe_eof; skb_trim(skb, skb->len - sizeof(*ft)); return 0; drop: dev_kfree_skb_irq(skb); return -1; }
static inline int fnic_import_rq_eth_pkt(struct sk_buff *skb, u32 len) { struct fc_frame *fp; struct ethhdr *eh; struct vlan_ethhdr *vh; struct fcoe_hdr *fcoe_hdr; struct fcoe_crc_eof *ft; u32 transport_len = 0; eh = (struct ethhdr *)skb->data; vh = (struct vlan_ethhdr *)skb->data; if (vh->h_vlan_proto == htons(ETH_P_8021Q) && vh->h_vlan_encapsulated_proto == htons(ETH_P_FCOE)) { skb_pull(skb, sizeof(struct vlan_ethhdr)); transport_len += sizeof(struct vlan_ethhdr); } else if (eh->h_proto == htons(ETH_P_FCOE)) { transport_len += sizeof(struct ethhdr); skb_pull(skb, sizeof(struct ethhdr)); } else return -1; fcoe_hdr = (struct fcoe_hdr *)skb->data; if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER) return -1; fp = (struct fc_frame *)skb; fc_frame_init(fp); fr_sof(fp) = fcoe_hdr->fcoe_sof; skb_pull(skb, sizeof(struct fcoe_hdr)); transport_len += sizeof(struct fcoe_hdr); ft = (struct fcoe_crc_eof *)(skb->data + len - transport_len - sizeof(*ft)); fr_eof(fp) = ft->fcoe_eof; skb_trim(skb, len - transport_len - sizeof(*ft)); return 0; }