1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <linux/kernel.h>
33#include <linux/string.h>
34#include <linux/ctype.h>
35#include <linux/spinlock.h>
36#include <linux/export.h>
37#include <asm/unaligned.h>
38
39#include <scsi/scsi_proto.h>
40
41#include <target/target_core_base.h>
42#include <target/target_core_fabric.h>
43
44#include "target_core_internal.h"
45#include "target_core_pr.h"
46
47
48static int sas_get_pr_transport_id(
49 struct se_node_acl *nacl,
50 int *format_code,
51 unsigned char *buf)
52{
53 int ret;
54
55
56 ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8);
57 if (ret) {
58 pr_debug("%s: invalid hex string\n", __func__);
59 return ret;
60 }
61
62 return 24;
63}
64
65static int fc_get_pr_transport_id(
66 struct se_node_acl *se_nacl,
67 int *format_code,
68 unsigned char *buf)
69{
70 unsigned char *ptr;
71 int i, ret;
72 u32 off = 8;
73
74
75
76
77
78 ptr = &se_nacl->initiatorname[0];
79 for (i = 0; i < 23; ) {
80 if (!strncmp(&ptr[i], ":", 1)) {
81 i++;
82 continue;
83 }
84 ret = hex2bin(&buf[off++], &ptr[i], 1);
85 if (ret < 0) {
86 pr_debug("%s: invalid hex string\n", __func__);
87 return ret;
88 }
89 i += 2;
90 }
91
92
93
94 return 24;
95}
96
97static int sbp_get_pr_transport_id(
98 struct se_node_acl *nacl,
99 int *format_code,
100 unsigned char *buf)
101{
102 int ret;
103
104 ret = hex2bin(&buf[8], nacl->initiatorname, 8);
105 if (ret) {
106 pr_debug("%s: invalid hex string\n", __func__);
107 return ret;
108 }
109
110 return 24;
111}
112
113static int srp_get_pr_transport_id(
114 struct se_node_acl *nacl,
115 int *format_code,
116 unsigned char *buf)
117{
118 const char *p;
119 unsigned len, count, leading_zero_bytes;
120 int rc;
121
122 p = nacl->initiatorname;
123 if (strncasecmp(p, "0x", 2) == 0)
124 p += 2;
125 len = strlen(p);
126 if (len % 2)
127 return -EINVAL;
128
129 count = min(len / 2, 16U);
130 leading_zero_bytes = 16 - count;
131 memset(buf + 8, 0, leading_zero_bytes);
132 rc = hex2bin(buf + 8 + leading_zero_bytes, p, count);
133 if (rc < 0) {
134 pr_debug("hex2bin failed for %s: %d\n", p, rc);
135 return rc;
136 }
137
138 return 24;
139}
140
141static int iscsi_get_pr_transport_id(
142 struct se_node_acl *se_nacl,
143 struct t10_pr_registration *pr_reg,
144 int *format_code,
145 unsigned char *buf)
146{
147 u32 off = 4, padding = 0;
148 int isid_len;
149 u16 len = 0;
150
151 spin_lock_irq(&se_nacl->nacl_sess_lock);
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
168 off += len;
169 if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
170
171
172
173
174 buf[0] |= 0x40;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 buf[off++] = 0x2c;
197 buf[off++] = 0x69;
198 buf[off++] = 0x2c;
199 buf[off++] = 0x30;
200 buf[off++] = 0x78;
201 len += 5;
202
203 isid_len = sprintf(buf + off, "%s", pr_reg->pr_reg_isid);
204 off += isid_len;
205 len += isid_len;
206 }
207 buf[off] = '\0';
208 len += 1;
209 spin_unlock_irq(&se_nacl->nacl_sess_lock);
210
211
212
213
214
215 padding = ((-len) & 3);
216 if (padding != 0)
217 len += padding;
218
219 put_unaligned_be16(len, &buf[2]);
220
221
222
223
224 len += 4;
225
226 return len;
227}
228
229static int iscsi_get_pr_transport_id_len(
230 struct se_node_acl *se_nacl,
231 struct t10_pr_registration *pr_reg,
232 int *format_code)
233{
234 u32 len = 0, padding = 0;
235
236 spin_lock_irq(&se_nacl->nacl_sess_lock);
237 len = strlen(se_nacl->initiatorname);
238
239
240
241 len++;
242
243
244
245
246
247
248
249 if (pr_reg->isid_present_at_reg) {
250 len += 5;
251 len += strlen(pr_reg->pr_reg_isid);
252 *format_code = 1;
253 } else
254 *format_code = 0;
255 spin_unlock_irq(&se_nacl->nacl_sess_lock);
256
257
258
259
260
261 padding = ((-len) & 3);
262 if (padding != 0)
263 len += padding;
264
265
266
267
268 len += 4;
269
270 return len;
271}
272
273static char *iscsi_parse_pr_out_transport_id(
274 struct se_portal_group *se_tpg,
275 char *buf,
276 u32 *out_tid_len,
277 char **port_nexus_ptr)
278{
279 char *p;
280 int i;
281 u8 format_code = (buf[0] & 0xc0);
282
283
284
285
286
287
288
289
290
291
292
293
294
295 if ((format_code != 0x00) && (format_code != 0x40)) {
296 pr_err("Illegal format code: 0x%02x for iSCSI"
297 " Initiator Transport ID\n", format_code);
298 return NULL;
299 }
300
301
302
303
304 if (out_tid_len) {
305
306 *out_tid_len = get_unaligned_be16(&buf[2]);
307
308 *out_tid_len += 4;
309 }
310
311
312
313
314
315
316 if (format_code == 0x40) {
317 p = strstr(&buf[4], ",i,0x");
318 if (!p) {
319 pr_err("Unable to locate \",i,0x\" separator"
320 " for Initiator port identifier: %s\n",
321 &buf[4]);
322 return NULL;
323 }
324 *p = '\0';
325 p += 5;
326
327 *port_nexus_ptr = p;
328
329
330
331
332
333
334 for (i = 0; i < 12; i++) {
335
336
337
338
339
340
341
342 if (*p == '\0')
343 break;
344
345 if (isdigit(*p)) {
346 p++;
347 continue;
348 }
349 *p = tolower(*p);
350 p++;
351 }
352 } else
353 *port_nexus_ptr = NULL;
354
355 return &buf[4];
356}
357
358int target_get_pr_transport_id_len(struct se_node_acl *nacl,
359 struct t10_pr_registration *pr_reg, int *format_code)
360{
361 switch (nacl->se_tpg->proto_id) {
362 case SCSI_PROTOCOL_FCP:
363 case SCSI_PROTOCOL_SBP:
364 case SCSI_PROTOCOL_SRP:
365 case SCSI_PROTOCOL_SAS:
366 break;
367 case SCSI_PROTOCOL_ISCSI:
368 return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code);
369 default:
370 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id);
371 return -EINVAL;
372 }
373
374
375
376
377 *format_code = 0;
378 return 24;
379}
380
381int target_get_pr_transport_id(struct se_node_acl *nacl,
382 struct t10_pr_registration *pr_reg, int *format_code,
383 unsigned char *buf)
384{
385 switch (nacl->se_tpg->proto_id) {
386 case SCSI_PROTOCOL_SAS:
387 return sas_get_pr_transport_id(nacl, format_code, buf);
388 case SCSI_PROTOCOL_SBP:
389 return sbp_get_pr_transport_id(nacl, format_code, buf);
390 case SCSI_PROTOCOL_SRP:
391 return srp_get_pr_transport_id(nacl, format_code, buf);
392 case SCSI_PROTOCOL_FCP:
393 return fc_get_pr_transport_id(nacl, format_code, buf);
394 case SCSI_PROTOCOL_ISCSI:
395 return iscsi_get_pr_transport_id(nacl, pr_reg, format_code,
396 buf);
397 default:
398 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id);
399 return -EINVAL;
400 }
401}
402
403const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg,
404 char *buf, u32 *out_tid_len, char **port_nexus_ptr)
405{
406 u32 offset;
407
408 switch (tpg->proto_id) {
409 case SCSI_PROTOCOL_SAS:
410
411
412
413
414 offset = 4;
415 break;
416 case SCSI_PROTOCOL_SBP:
417 case SCSI_PROTOCOL_SRP:
418 case SCSI_PROTOCOL_FCP:
419 offset = 8;
420 break;
421 case SCSI_PROTOCOL_ISCSI:
422 return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len,
423 port_nexus_ptr);
424 default:
425 pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id);
426 return NULL;
427 }
428
429 *port_nexus_ptr = NULL;
430 *out_tid_len = 24;
431 return buf + offset;
432}
433