1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright(c) 2007 Intel Corporation. All rights reserved. |
4 | * |
5 | * Maintained at www.Open-FCoE.org |
6 | */ |
7 | |
8 | /* |
9 | * Frame allocation. |
10 | */ |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/skbuff.h> |
14 | #include <linux/crc32.h> |
15 | #include <linux/gfp.h> |
16 | |
17 | #include <scsi/fc_frame.h> |
18 | |
19 | /* |
20 | * Check the CRC in a frame. |
21 | */ |
22 | u32 fc_frame_crc_check(struct fc_frame *fp) |
23 | { |
24 | u32 crc; |
25 | u32 error; |
26 | const u8 *bp; |
27 | unsigned int len; |
28 | |
29 | WARN_ON(!fc_frame_is_linear(fp)); |
30 | fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; |
31 | len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ |
32 | bp = (const u8 *) fr_hdr(fp); |
33 | crc = ~crc32(~0, bp, len); |
34 | error = crc ^ fr_crc(fp); |
35 | return error; |
36 | } |
37 | EXPORT_SYMBOL(fc_frame_crc_check); |
38 | |
39 | /* |
40 | * Allocate a frame intended to be sent. |
41 | * Get an sk_buff for the frame and set the length. |
42 | */ |
43 | struct fc_frame *_fc_frame_alloc(size_t len) |
44 | { |
45 | struct fc_frame *fp; |
46 | struct sk_buff *skb; |
47 | |
48 | WARN_ON((len % sizeof(u32)) != 0); |
49 | len += sizeof(struct fc_frame_header); |
50 | skb = alloc_skb_fclone(size: len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM + |
51 | NET_SKB_PAD, GFP_ATOMIC); |
52 | if (!skb) |
53 | return NULL; |
54 | skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM); |
55 | fp = (struct fc_frame *) skb; |
56 | fc_frame_init(fp); |
57 | skb_put(skb, len); |
58 | return fp; |
59 | } |
60 | EXPORT_SYMBOL(_fc_frame_alloc); |
61 | |
62 | struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) |
63 | { |
64 | struct fc_frame *fp; |
65 | size_t fill; |
66 | |
67 | fill = payload_len % 4; |
68 | if (fill != 0) |
69 | fill = 4 - fill; |
70 | fp = _fc_frame_alloc(payload_len + fill); |
71 | if (fp) { |
72 | memset((char *) fr_hdr(fp) + payload_len, 0, fill); |
73 | /* trim is OK, we just allocated it so there are no fragments */ |
74 | skb_trim(fp_skb(fp), |
75 | len: payload_len + sizeof(struct fc_frame_header)); |
76 | } |
77 | return fp; |
78 | } |
79 | EXPORT_SYMBOL(fc_frame_alloc_fill); |
80 | |