/* * Check the CRC in a frame. */ u32 fc_frame_crc_check(struct fc_frame *fp) { u32 crc; u32 error; const u8 *bp; unsigned int len; WARN_ON(!fc_frame_is_linear(fp)); fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ bp = (const u8 *) fr_hdr(fp); crc = ~crc32(~0, bp, len); error = crc ^ fr_crc(fp); return error; }
struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) { struct fc_frame *fp; size_t fill; fill = payload_len % 4; if (fill != 0) fill = 4 - fill; fp = _fc_frame_alloc(payload_len + fill); if (fp) { memset((char *) fr_hdr(fp) + payload_len, 0, fill); /* trim is OK, we just allocated it so there are no fragments */ skb_trim(fp_skb(fp), payload_len + sizeof(struct fc_frame_header)); } return fp; }
static inline int fnic_handle_flogi_resp(struct fnic *fnic, struct fc_frame *fp) { u8 mac[ETH_ALEN] = FC_FCOE_FLOGI_MAC; struct ethhdr *eth_hdr; struct fc_frame_header *fh; int ret = 0; unsigned long flags; struct fc_frame *old_flogi_resp = NULL; fh = (struct fc_frame_header *)fr_hdr(fp); spin_lock_irqsave(&fnic->fnic_lock, flags); if (fnic->state == FNIC_IN_ETH_MODE) { /* * Check if oxid matches on taking the lock. A new Flogi * issued by libFC might have changed the fnic cached oxid */ if (fnic->flogi_oxid != ntohs(fh->fh_ox_id)) { FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "Flogi response oxid not" " matching cached oxid, dropping frame" "\n"); ret = -1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); dev_kfree_skb_irq(fp_skb(fp)); goto handle_flogi_resp_end; } /* Drop older cached flogi response frame, cache this frame */ old_flogi_resp = fnic->flogi_resp; fnic->flogi_resp = fp; fnic->flogi_oxid = FC_XID_UNKNOWN; /* * this frame is part of flogi get the src mac addr from this * frame if the src mac is fcoui based then we mark the * address mode flag to use fcoui base for dst mac addr * otherwise we have to store the fcoe gateway addr */ eth_hdr = (struct ethhdr *)skb_mac_header(fp_skb(fp)); memcpy(mac, eth_hdr->h_source, ETH_ALEN); if (ntoh24(mac) == FC_FCOE_OUI) fnic->fcoui_mode = 1; else { fnic->fcoui_mode = 0; memcpy(fnic->dest_addr, mac, ETH_ALEN); } /* * Except for Flogi frame, all outbound frames from us have the * Eth Src address as FC_FCOE_OUI"our_sid". Flogi frame uses * the vnic MAC address as the Eth Src address */ fc_fcoe_set_mac(fnic->data_src_addr, fh->fh_d_id); /* We get our s_id from the d_id of the flogi resp frame */ fnic->s_id = ntoh24(fh->fh_d_id); /* Change state to reflect transition from Eth to FC mode */ fnic->state = FNIC_IN_ETH_TRANS_FC_MODE; } else { FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "Unexpected fnic state %s while" " processing flogi resp\n", fnic_state_to_str(fnic->state)); ret = -1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); dev_kfree_skb_irq(fp_skb(fp)); goto handle_flogi_resp_end; } spin_unlock_irqrestore(&fnic->fnic_lock, flags); /* Drop older cached frame */ if (old_flogi_resp) dev_kfree_skb_irq(fp_skb(old_flogi_resp)); /* * send flogi reg request to firmware, this will put the fnic in * in FC mode */ ret = fnic_flogi_reg_handler(fnic); if (ret < 0) { int free_fp = 1; spin_lock_irqsave(&fnic->fnic_lock, flags); /* * free the frame is some other thread is not * pointing to it */ if (fnic->flogi_resp != fp) free_fp = 0; else fnic->flogi_resp = NULL; if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) fnic->state = FNIC_IN_ETH_MODE; spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (free_fp) dev_kfree_skb_irq(fp_skb(fp)); } handle_flogi_resp_end: return ret; }