]>
Commit | Line | Data |
---|---|---|
8f69975d BS |
1 | From: Chris Leech <christopher.leech@intel.com> |
2 | Subject: [FcOE] make sure we access the CRC safely | |
3 | References: bnc #459142 | |
4 | ||
5 | Even when fcoe verified that the EOF and CRC trailer bytes were there, when | |
6 | the CRC check was delayed for solicited SCSI data libfc would look past what | |
7 | was marked as valid data in the frame to find the CRC in the FCoE trailer. | |
8 | ||
9 | Instead, pass the CRC to libfc in the context block. | |
10 | ||
11 | Signed-off-by: Chris Leech <christopher.leech@intel.com> | |
12 | Acked-by: Bernhard Walle <bwalle@suse.de> | |
13 | --- | |
14 | ||
15 | drivers/scsi/fcoe/libfcoe.c | 20 ++++++++++++++------ | |
16 | drivers/scsi/libfc/fc_fcp.c | 2 +- | |
17 | drivers/scsi/libfc/fc_frame.c | 2 +- | |
18 | include/scsi/fc_frame.h | 3 +++ | |
19 | 4 files changed, 19 insertions(+), 8 deletions(-) | |
20 | ||
21 | ||
22 | --- a/drivers/scsi/fcoe/libfcoe.c | |
23 | +++ b/drivers/scsi/fcoe/libfcoe.c | |
24 | @@ -527,7 +527,7 @@ int fcoe_percpu_receive_thread(void *arg | |
25 | struct fcoe_dev_stats *stats; | |
26 | struct fc_frame_header *fh; | |
27 | struct sk_buff *skb; | |
28 | - struct fcoe_crc_eof *cp; | |
29 | + struct fcoe_crc_eof crc_eof; | |
30 | struct fc_frame *fp; | |
31 | u8 *mac = NULL; | |
32 | struct fcoe_softc *fc; | |
33 | @@ -604,13 +604,21 @@ int fcoe_percpu_receive_thread(void *arg | |
34 | } | |
35 | ||
36 | fp = (struct fc_frame *)skb; | |
37 | - cp = (struct fcoe_crc_eof *)(skb->data + fr_len); | |
38 | fc_frame_init(fp); | |
39 | fr_dev(fp) = lp; | |
40 | fr_sof(fp) = hp->fcoe_sof; | |
41 | - fr_eof(fp) = cp->fcoe_eof; | |
42 | - /* trim off the CRC and EOF trailer*/ | |
43 | - skb_trim(skb, fr_len); | |
44 | + | |
45 | + /* Copy out the CRC and EOF trailer for access */ | |
46 | + if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { | |
47 | + kfree_skb(skb); | |
48 | + continue; | |
49 | + } | |
50 | + fr_eof(fp) = crc_eof.fcoe_eof; | |
51 | + fr_crc(fp) = crc_eof.fcoe_crc32; | |
52 | + if (pskb_trim(skb, fr_len)) { | |
53 | + kfree_skb(skb); | |
54 | + continue; | |
55 | + } | |
56 | ||
57 | /* | |
58 | * We only check CRC if no offload is available and if it is | |
59 | @@ -629,7 +637,7 @@ int fcoe_percpu_receive_thread(void *arg | |
60 | continue; | |
61 | } | |
62 | if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { | |
63 | - if (le32_to_cpu(cp->fcoe_crc32) != | |
64 | + if (le32_to_cpu(fr_crc(fp)) != | |
65 | ~crc32(~0, skb->data, fr_len)) { | |
66 | if (debug_fcoe || stats->InvalidCRCCount < 5) | |
67 | printk(KERN_WARNING "fcoe: dropping " | |
68 | --- a/drivers/scsi/libfc/fc_fcp.c | |
69 | +++ b/drivers/scsi/libfc/fc_fcp.c | |
70 | @@ -356,7 +356,7 @@ static void fc_fcp_recv_data(struct fc_f | |
71 | len += 4 - (len % 4); | |
72 | } | |
73 | ||
74 | - if (~crc != le32_to_cpu(*(__le32 *)(buf + len))) { | |
75 | + if (~crc != le32_to_cpu(fr_crc(fp))) { | |
76 | crc_err: | |
77 | stats = lp->dev_stats[smp_processor_id()]; | |
78 | stats->ErrorFrames++; | |
79 | --- a/drivers/scsi/libfc/fc_frame.c | |
80 | +++ b/drivers/scsi/libfc/fc_frame.c | |
81 | @@ -42,7 +42,7 @@ u32 fc_frame_crc_check(struct fc_frame * | |
82 | len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ | |
83 | bp = (const u8 *) fr_hdr(fp); | |
84 | crc = ~crc32(~0, bp, len); | |
85 | - error = crc ^ *(u32 *) (bp + len); | |
86 | + error = crc ^ fr_crc(fp); | |
87 | return error; | |
88 | } | |
89 | EXPORT_SYMBOL(fc_frame_crc_check); | |
90 | --- a/include/scsi/fc_frame.h | |
91 | +++ b/include/scsi/fc_frame.h | |
92 | @@ -56,6 +56,7 @@ | |
93 | #define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) | |
94 | #define fr_cmd(fp) (fr_cb(fp)->fr_cmd) | |
95 | #define fr_dir(fp) (fr_cmd(fp)->sc_data_direction) | |
96 | +#define fr_crc(fp) (fr_cb(fp)->fr_crc) | |
97 | ||
98 | struct fc_frame { | |
99 | struct sk_buff skb; | |
100 | @@ -66,12 +67,14 @@ struct fcoe_rcv_info { | |
101 | struct fc_lport *fr_dev; /* transport layer private pointer */ | |
102 | struct fc_seq *fr_seq; /* for use with exchange manager */ | |
103 | struct scsi_cmnd *fr_cmd; /* for use of scsi command */ | |
104 | + u32 fr_crc; | |
105 | u16 fr_max_payload; /* max FC payload */ | |
106 | enum fc_sof fr_sof; /* start of frame delimiter */ | |
107 | enum fc_eof fr_eof; /* end of frame delimiter */ | |
108 | u8 fr_flags; /* flags - see below */ | |
109 | }; | |
110 | ||
111 | + | |
112 | /* | |
113 | * Get fc_frame pointer for an skb that's already been imported. | |
114 | */ |