| // SPDX-License-Identifier: GPL-2.0-only | |
| /* | |
| * Copyright(c) 2007 Intel Corporation. All rights reserved. | |
| * | |
| * Maintained at www.Open-FCoE.org | |
| */ | |
| /* | |
| * Frame allocation. | |
| */ | |
| #include <linux/module.h> | |
| #include <linux/kernel.h> | |
| #include <linux/skbuff.h> | |
| #include <linux/crc32.h> | |
| #include <linux/gfp.h> | |
| #include <scsi/fc_frame.h> | |
| /* | |
| * 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; | |
| } | |
| EXPORT_SYMBOL(fc_frame_crc_check); | |
| /* | |
| * Allocate a frame intended to be sent. | |
| * 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; | |
| } | |
| EXPORT_SYMBOL(_fc_frame_alloc); | |
| 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; | |
| } | |
| EXPORT_SYMBOL(fc_frame_alloc_fill); |