1*a61127c2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
242e9a92fSRobert Love /*
342e9a92fSRobert Love * Copyright(c) 2007 Intel Corporation. All rights reserved.
442e9a92fSRobert Love *
542e9a92fSRobert Love * Maintained at www.Open-FCoE.org
642e9a92fSRobert Love */
742e9a92fSRobert Love
842e9a92fSRobert Love /*
942e9a92fSRobert Love * Frame allocation.
1042e9a92fSRobert Love */
1142e9a92fSRobert Love #include <linux/module.h>
1242e9a92fSRobert Love #include <linux/kernel.h>
1342e9a92fSRobert Love #include <linux/skbuff.h>
1442e9a92fSRobert Love #include <linux/crc32.h>
155a0e3ad6STejun Heo #include <linux/gfp.h>
1642e9a92fSRobert Love
1742e9a92fSRobert Love #include <scsi/fc_frame.h>
1842e9a92fSRobert Love
1942e9a92fSRobert Love /*
2042e9a92fSRobert Love * Check the CRC in a frame.
2142e9a92fSRobert Love */
fc_frame_crc_check(struct fc_frame * fp)2242e9a92fSRobert Love u32 fc_frame_crc_check(struct fc_frame *fp)
2342e9a92fSRobert Love {
2442e9a92fSRobert Love u32 crc;
2542e9a92fSRobert Love u32 error;
2642e9a92fSRobert Love const u8 *bp;
2742e9a92fSRobert Love unsigned int len;
2842e9a92fSRobert Love
2942e9a92fSRobert Love WARN_ON(!fc_frame_is_linear(fp));
3042e9a92fSRobert Love fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
3142e9a92fSRobert Love len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */
3242e9a92fSRobert Love bp = (const u8 *) fr_hdr(fp);
3342e9a92fSRobert Love crc = ~crc32(~0, bp, len);
3442e9a92fSRobert Love error = crc ^ fr_crc(fp);
3542e9a92fSRobert Love return error;
3642e9a92fSRobert Love }
3742e9a92fSRobert Love EXPORT_SYMBOL(fc_frame_crc_check);
3842e9a92fSRobert Love
3942e9a92fSRobert Love /*
401bd49b48SVasu Dev * Allocate a frame intended to be sent.
4142e9a92fSRobert Love * Get an sk_buff for the frame and set the length.
4242e9a92fSRobert Love */
_fc_frame_alloc(size_t len)43a7bbc7f4SVasu Dev struct fc_frame *_fc_frame_alloc(size_t len)
4442e9a92fSRobert Love {
4542e9a92fSRobert Love struct fc_frame *fp;
4642e9a92fSRobert Love struct sk_buff *skb;
4742e9a92fSRobert Love
4842e9a92fSRobert Love WARN_ON((len % sizeof(u32)) != 0);
4942e9a92fSRobert Love len += sizeof(struct fc_frame_header);
5018fa11efSChris Leech skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM +
5118fa11efSChris Leech NET_SKB_PAD, GFP_ATOMIC);
5242e9a92fSRobert Love if (!skb)
5342e9a92fSRobert Love return NULL;
5418fa11efSChris Leech skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM);
5542e9a92fSRobert Love fp = (struct fc_frame *) skb;
5642e9a92fSRobert Love fc_frame_init(fp);
5742e9a92fSRobert Love skb_put(skb, len);
5842e9a92fSRobert Love return fp;
5942e9a92fSRobert Love }
60a7bbc7f4SVasu Dev EXPORT_SYMBOL(_fc_frame_alloc);
6142e9a92fSRobert Love
fc_frame_alloc_fill(struct fc_lport * lp,size_t payload_len)6242e9a92fSRobert Love struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
6342e9a92fSRobert Love {
6442e9a92fSRobert Love struct fc_frame *fp;
6542e9a92fSRobert Love size_t fill;
6642e9a92fSRobert Love
6742e9a92fSRobert Love fill = payload_len % 4;
6842e9a92fSRobert Love if (fill != 0)
6942e9a92fSRobert Love fill = 4 - fill;
70a7bbc7f4SVasu Dev fp = _fc_frame_alloc(payload_len + fill);
7142e9a92fSRobert Love if (fp) {
7242e9a92fSRobert Love memset((char *) fr_hdr(fp) + payload_len, 0, fill);
7342e9a92fSRobert Love /* trim is OK, we just allocated it so there are no fragments */
7442e9a92fSRobert Love skb_trim(fp_skb(fp),
7542e9a92fSRobert Love payload_len + sizeof(struct fc_frame_header));
7642e9a92fSRobert Love }
7742e9a92fSRobert Love return fp;
7842e9a92fSRobert Love }
79dc8596d3SChris Leech EXPORT_SYMBOL(fc_frame_alloc_fill);
80