static void qedf_process_l2_frame_compl(struct qedf_rport *fcport, struct fc_frame *fp, u16 l2_oxid) { struct fc_lport *lport = fcport->qedf->lport; struct fc_frame_header *fh; u32 crc; fh = (struct fc_frame_header *)fc_frame_header_get(fp); /* Set the OXID we return to what libfc used */ if (l2_oxid != FC_XID_UNKNOWN) fh->fh_ox_id = htons(l2_oxid); /* Setup header fields */ fh->fh_r_ctl = FC_RCTL_ELS_REP; fh->fh_type = FC_TYPE_ELS; /* Last sequence, end sequence */ fh->fh_f_ctl[0] = 0x98; hton24(fh->fh_d_id, lport->port_id); hton24(fh->fh_s_id, fcport->rdata->ids.port_id); fh->fh_rx_id = 0xffff; /* Set frame attributes */ crc = fcoe_fc_crc(fp); fc_frame_init(fp); fr_dev(fp) = lport; fr_sof(fp) = FC_SOF_I3; fr_eof(fp) = FC_EOF_T; fr_crc(fp) = cpu_to_le32(~crc); /* Send completed request to libfc */ fc_exch_recv(lport, fp); }
/* * Allocate a frame intended to be sent via fcoe_xmit. * Get an sk_buff for the frame and set the length. */ struct fc_frame *__fc_frame_alloc(size_t len) { struct fc_frame *fp; struct sk_buff *skb; WARN_ON((len % sizeof(u32)) != 0); len += sizeof(struct fc_frame_header); skb = dev_alloc_skb(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM); if (!skb) return NULL; fp = (struct fc_frame *) skb; fc_frame_init(fp); skb_reserve(skb, FC_FRAME_HEADROOM); skb_put(skb, len); return fp; }
/* * Allocate a frame intended to be sent via fcoe_xmit. * Get an sk_buff for the frame and set the length. */ struct fc_frame *_fc_frame_alloc(size_t len) { struct fc_frame *fp; struct sk_buff *skb; WARN_ON((len % sizeof(u32)) != 0); len += sizeof(struct fc_frame_header); skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM + NET_SKB_PAD, GFP_ATOMIC); if (!skb) return NULL; skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM); fp = (struct fc_frame *) skb; fc_frame_init(fp); skb_put(skb, len); return fp; }
/** * 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; }