1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /******************************************************************************* 3 * Filename: target_core_fabric_lib.c 4 * 5 * This file contains generic high level protocol identifier and PR 6 * handlers for TCM fabric modules 7 * 8 * (c) Copyright 2010-2013 Datera, Inc. 9 * 10 * Nicholas A. Bellinger <nab@linux-iscsi.org> 11 * 12 ******************************************************************************/ 13 14 /* 15 * See SPC4, section 7.5 "Protocol specific parameters" for details 16 * on the formats implemented in this file. 17 */ 18 19 #include <linux/hex.h> 20 #include <linux/kernel.h> 21 #include <linux/string.h> 22 #include <linux/ctype.h> 23 #include <linux/spinlock.h> 24 #include <linux/export.h> 25 #include <linux/unaligned.h> 26 27 #include <scsi/scsi_proto.h> 28 29 #include <target/target_core_base.h> 30 #include <target/target_core_fabric.h> 31 32 #include "target_core_internal.h" 33 #include "target_core_pr.h" 34 35 36 static int sas_get_pr_transport_id( 37 struct se_node_acl *nacl, 38 int *format_code, 39 unsigned char *buf) 40 { 41 int ret; 42 43 /* Skip over 'naa. prefix */ 44 ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8); 45 if (ret) { 46 pr_debug("%s: invalid hex string\n", __func__); 47 return ret; 48 } 49 50 return 24; 51 } 52 53 static int fc_get_pr_transport_id( 54 struct se_node_acl *se_nacl, 55 int *format_code, 56 unsigned char *buf) 57 { 58 unsigned char *ptr; 59 int i, ret; 60 u32 off = 8; 61 62 /* 63 * We convert the ASCII formatted N Port name into a binary 64 * encoded TransportID. 65 */ 66 ptr = &se_nacl->initiatorname[0]; 67 for (i = 0; i < 23; ) { 68 if (!strncmp(&ptr[i], ":", 1)) { 69 i++; 70 continue; 71 } 72 ret = hex2bin(&buf[off++], &ptr[i], 1); 73 if (ret < 0) { 74 pr_debug("%s: invalid hex string\n", __func__); 75 return ret; 76 } 77 i += 2; 78 } 79 /* 80 * The FC Transport ID is a hardcoded 24-byte length 81 */ 82 return 24; 83 } 84 85 static int sbp_get_pr_transport_id( 86 struct se_node_acl *nacl, 87 int *format_code, 88 unsigned char *buf) 89 { 90 int ret; 91 92 ret = hex2bin(&buf[8], nacl->initiatorname, 8); 93 if (ret) { 94 pr_debug("%s: invalid hex string\n", __func__); 95 return ret; 96 } 97 98 return 24; 99 } 100 101 static int srp_get_pr_transport_id( 102 struct se_node_acl *nacl, 103 int *format_code, 104 unsigned char *buf) 105 { 106 const char *p; 107 unsigned len, count, leading_zero_bytes; 108 int rc; 109 110 p = nacl->initiatorname; 111 if (strncasecmp(p, "0x", 2) == 0) 112 p += 2; 113 len = strlen(p); 114 if (len % 2) 115 return -EINVAL; 116 117 count = min(len / 2, 16U); 118 leading_zero_bytes = 16 - count; 119 memset(buf + 8, 0, leading_zero_bytes); 120 rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); 121 if (rc < 0) { 122 pr_debug("hex2bin failed for %s: %d\n", p, rc); 123 return rc; 124 } 125 126 return 24; 127 } 128 129 static int iscsi_get_pr_transport_id( 130 struct se_node_acl *se_nacl, 131 struct t10_pr_registration *pr_reg, 132 int *format_code, 133 unsigned char *buf) 134 { 135 u32 off = 4, padding = 0; 136 int isid_len; 137 u16 len = 0; 138 139 spin_lock_irq(&se_nacl->nacl_sess_lock); 140 /* 141 * Only null terminate the last field. 142 * 143 * From spc4r37 section 7.6.4.6: TransportID for initiator ports using 144 * SCSI over iSCSI. 145 * 146 * Table 507 TPID=0 Initiator device TransportID 147 * 148 * The null-terminated, null-padded (see 4.3.2) ISCSI NAME field shall 149 * contain the iSCSI name of an iSCSI initiator node (see RFC 7143). 150 * The first ISCSI NAME field byte containing an ASCII null character 151 * terminates the ISCSI NAME field without regard for the specified 152 * length of the iSCSI TransportID or the contents of the ADDITIONAL 153 * LENGTH field. 154 */ 155 len = sprintf(&buf[off], "%s", se_nacl->initiatorname); 156 off += len; 157 if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) { 158 /* 159 * Set FORMAT CODE 01b for iSCSI Initiator port TransportID 160 * format. 161 */ 162 buf[0] |= 0x40; 163 /* 164 * From spc4r37 Section 7.6.4.6 165 * 166 * Table 508 TPID=1 Initiator port TransportID. 167 * 168 * The ISCSI NAME field shall not be null-terminated 169 * (see 4.3.2) and shall not be padded. 170 * 171 * The SEPARATOR field shall contain the five ASCII 172 * characters ",i,0x". 173 * 174 * The null-terminated, null-padded ISCSI INITIATOR SESSION ID 175 * field shall contain the iSCSI initiator session identifier 176 * (see RFC 3720) in the form of ASCII characters that are the 177 * hexadecimal digits converted from the binary iSCSI initiator 178 * session identifier value. The first ISCSI INITIATOR SESSION 179 * ID field byte containing an ASCII null character terminates 180 * the ISCSI INITIATOR SESSION ID field without regard for the 181 * specified length of the iSCSI TransportID or the contents 182 * of the ADDITIONAL LENGTH field. 183 */ 184 buf[off++] = 0x2c; /* ASCII Character: "," */ 185 buf[off++] = 0x69; /* ASCII Character: "i" */ 186 buf[off++] = 0x2c; /* ASCII Character: "," */ 187 buf[off++] = 0x30; /* ASCII Character: "0" */ 188 buf[off++] = 0x78; /* ASCII Character: "x" */ 189 len += 5; 190 191 isid_len = sprintf(buf + off, "%s", pr_reg->pr_reg_isid); 192 off += isid_len; 193 len += isid_len; 194 } 195 buf[off] = '\0'; 196 len += 1; 197 spin_unlock_irq(&se_nacl->nacl_sess_lock); 198 /* 199 * The ADDITIONAL LENGTH field specifies the number of bytes that follow 200 * in the TransportID. The additional length shall be at least 20 and 201 * shall be a multiple of four. 202 */ 203 padding = ((-len) & 3); 204 if (padding != 0) 205 len += padding; 206 207 put_unaligned_be16(len, &buf[2]); 208 /* 209 * Increment value for total payload + header length for 210 * full status descriptor 211 */ 212 len += 4; 213 214 return len; 215 } 216 217 static int iscsi_get_pr_transport_id_len( 218 struct se_node_acl *se_nacl, 219 struct t10_pr_registration *pr_reg, 220 int *format_code) 221 { 222 u32 len = 0, padding = 0; 223 224 spin_lock_irq(&se_nacl->nacl_sess_lock); 225 len = strlen(se_nacl->initiatorname); 226 /* 227 * Add extra byte for NULL terminator 228 */ 229 len++; 230 /* 231 * If there is ISID present with the registration, use format code: 232 * 01b: iSCSI Initiator port TransportID format 233 * 234 * If there is not an active iSCSI session, use format code: 235 * 00b: iSCSI Initiator device TransportID format 236 */ 237 if (pr_reg->isid_present_at_reg) { 238 len += 5; /* For ",i,0x" ASCII separator */ 239 len += strlen(pr_reg->pr_reg_isid); 240 *format_code = 1; 241 } else 242 *format_code = 0; 243 spin_unlock_irq(&se_nacl->nacl_sess_lock); 244 /* 245 * The ADDITIONAL LENGTH field specifies the number of bytes that follow 246 * in the TransportID. The additional length shall be at least 20 and 247 * shall be a multiple of four. 248 */ 249 padding = ((-len) & 3); 250 if (padding != 0) 251 len += padding; 252 /* 253 * Increment value for total payload + header length for 254 * full status descriptor 255 */ 256 len += 4; 257 258 return len; 259 } 260 261 static void sas_parse_pr_out_transport_id(char *buf, char *i_str) 262 { 263 char hex[17] = {}; 264 265 bin2hex(hex, buf + 4, 8); 266 snprintf(i_str, TRANSPORT_IQN_LEN, "naa.%s", hex); 267 } 268 269 static void srp_parse_pr_out_transport_id(char *buf, char *i_str) 270 { 271 char hex[33] = {}; 272 273 bin2hex(hex, buf + 8, 16); 274 snprintf(i_str, TRANSPORT_IQN_LEN, "0x%s", hex); 275 } 276 277 static void fcp_parse_pr_out_transport_id(char *buf, char *i_str) 278 { 279 snprintf(i_str, TRANSPORT_IQN_LEN, "%8phC", buf + 8); 280 } 281 282 static void sbp_parse_pr_out_transport_id(char *buf, char *i_str) 283 { 284 char hex[17] = {}; 285 286 bin2hex(hex, buf + 8, 8); 287 snprintf(i_str, TRANSPORT_IQN_LEN, "%s", hex); 288 } 289 290 static bool iscsi_parse_pr_out_transport_id( 291 struct se_portal_group *se_tpg, 292 char *buf, 293 u32 buf_len, 294 u32 *out_tid_len, 295 char **port_nexus_ptr, 296 char *i_str) 297 { 298 char *p; 299 u32 tid_len; 300 int i; 301 u8 format_code; 302 303 /* 304 * The 4-byte iSCSI TransportID header (FORMAT CODE + 2-byte ADDITIONAL 305 * LENGTH) must be present before any of it can be parsed. 306 */ 307 if (buf_len < 4) 308 return false; 309 310 format_code = buf[0] & 0xc0; 311 /* 312 * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6: 313 * 314 * TransportID for initiator ports using SCSI over iSCSI, 315 * from Table 388 -- iSCSI TransportID formats. 316 * 317 * 00b Initiator port is identified using the world wide unique 318 * SCSI device name of the iSCSI initiator 319 * device containing the initiator port (see table 389). 320 * 01b Initiator port is identified using the world wide unique 321 * initiator port identifier (see table 390).10b to 11b 322 * Reserved 323 */ 324 if ((format_code != 0x00) && (format_code != 0x40)) { 325 pr_err("Illegal format code: 0x%02x for iSCSI" 326 " Initiator Transport ID\n", format_code); 327 return false; 328 } 329 /* 330 * Reconstruct the self-described TransportID length from the ADDITIONAL 331 * LENGTH field plus the 4-byte header. Reject it if it is below the 332 * spc4r17 section 7.5.4.6 minimum (ADDITIONAL LENGTH shall be at least 333 * 20) or if it runs past the bytes actually received, so that every 334 * access below stays inside the TransportID. 335 */ 336 tid_len = get_unaligned_be16(&buf[2]) + 4; 337 if (tid_len < 24 || tid_len > buf_len) 338 return false; 339 if (out_tid_len) 340 *out_tid_len = tid_len; 341 342 /* 343 * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator 344 * Session ID as defined in Table 390 - iSCSI initiator port TransportID 345 * format. 346 */ 347 if (format_code == 0x40) { 348 p = strnstr(&buf[4], ",i,0x", tid_len - 4); 349 if (!p) { 350 pr_err("Unable to locate \",i,0x\" separator in iSCSI TransportID\n"); 351 return false; 352 } 353 /* 354 * The iSCSI name runs from &buf[4] up to the separator; reject it 355 * if it cannot fit in i_str[TRANSPORT_IQN_LEN]. 356 */ 357 if (p - &buf[4] >= TRANSPORT_IQN_LEN) { 358 pr_err("iSCSI Initiator port name too long in TransportID\n"); 359 return false; 360 } 361 *p = '\0'; /* Terminate iSCSI Name */ 362 p += 5; /* Skip over ",i,0x" separator */ 363 364 /* 365 * The ISID must follow the separator. A ",i,0x" sitting at the 366 * very end of the TransportID leaves no ISID and would point the 367 * port nexus at buf + tid_len, i.e. past the descriptor, which 368 * the registration code then reads as the ISID string. 369 */ 370 if (p >= buf + tid_len) { 371 pr_err("Missing ISID in iSCSI Initiator port TransportID\n"); 372 return false; 373 } 374 *port_nexus_ptr = p; 375 /* 376 * Go ahead and do the lower case conversion of the received 377 * 12 ASCII characters representing the ISID in the TransportID 378 * for comparison against the running iSCSI session's ISID from 379 * iscsi_target.c:lio_sess_get_initiator_sid() 380 */ 381 for (i = 0; i < 12 && p < buf + tid_len; i++) { 382 /* 383 * The first ISCSI INITIATOR SESSION ID field byte 384 * containing an ASCII null character terminates the 385 * ISCSI INITIATOR SESSION ID field without regard for 386 * the specified length of the iSCSI TransportID or the 387 * contents of the ADDITIONAL LENGTH field. 388 */ 389 if (*p == '\0') 390 break; 391 392 if (isdigit(*p)) { 393 p++; 394 continue; 395 } 396 *p = tolower(*p); 397 p++; 398 } 399 strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN); 400 } else { 401 *port_nexus_ptr = NULL; 402 /* 403 * FORMAT CODE 00b: the name occupies buf[4..tid_len-1]. The 404 * declared length tid_len - 4 must fit in i_str[TRANSPORT_IQN_LEN]. 405 * (For 01b the same tid_len bound would be over-restrictive: the 406 * descriptor also carries the separator and ISID, so a legal 407 * <=223-byte name gives tid_len up to 244.) 408 */ 409 if (tid_len - 4 >= TRANSPORT_IQN_LEN) { 410 pr_err("iSCSI Initiator port name too long in TransportID\n"); 411 return false; 412 } 413 strscpy(i_str, &buf[4], tid_len - 4); 414 } 415 return true; 416 } 417 418 int target_get_pr_transport_id_len(struct se_node_acl *nacl, 419 struct t10_pr_registration *pr_reg, int *format_code) 420 { 421 switch (nacl->se_tpg->proto_id) { 422 case SCSI_PROTOCOL_FCP: 423 case SCSI_PROTOCOL_SBP: 424 case SCSI_PROTOCOL_SRP: 425 case SCSI_PROTOCOL_SAS: 426 break; 427 case SCSI_PROTOCOL_ISCSI: 428 return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code); 429 default: 430 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); 431 return -EINVAL; 432 } 433 434 /* 435 * Most transports use a fixed length 24 byte identifier. 436 */ 437 *format_code = 0; 438 return 24; 439 } 440 441 int target_get_pr_transport_id(struct se_node_acl *nacl, 442 struct t10_pr_registration *pr_reg, int *format_code, 443 unsigned char *buf) 444 { 445 switch (nacl->se_tpg->proto_id) { 446 case SCSI_PROTOCOL_SAS: 447 return sas_get_pr_transport_id(nacl, format_code, buf); 448 case SCSI_PROTOCOL_SBP: 449 return sbp_get_pr_transport_id(nacl, format_code, buf); 450 case SCSI_PROTOCOL_SRP: 451 return srp_get_pr_transport_id(nacl, format_code, buf); 452 case SCSI_PROTOCOL_FCP: 453 return fc_get_pr_transport_id(nacl, format_code, buf); 454 case SCSI_PROTOCOL_ISCSI: 455 return iscsi_get_pr_transport_id(nacl, pr_reg, format_code, 456 buf); 457 default: 458 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); 459 return -EINVAL; 460 } 461 } 462 463 bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, 464 char *buf, u32 buf_len, u32 *out_tid_len, 465 char **port_nexus_ptr, char *i_str) 466 { 467 /* 468 * The fixed-length SAS/SRP/FCP/SBP TransportIDs are 24 bytes; the iSCSI 469 * format is variable and bounds itself against buf_len below. 470 */ 471 if (tpg->proto_id != SCSI_PROTOCOL_ISCSI && buf_len < 24) 472 return false; 473 474 switch (tpg->proto_id) { 475 case SCSI_PROTOCOL_SAS: 476 /* 477 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID 478 * for initiator ports using SCSI over SAS Serial SCSI Protocol. 479 */ 480 sas_parse_pr_out_transport_id(buf, i_str); 481 break; 482 case SCSI_PROTOCOL_SRP: 483 srp_parse_pr_out_transport_id(buf, i_str); 484 break; 485 case SCSI_PROTOCOL_FCP: 486 fcp_parse_pr_out_transport_id(buf, i_str); 487 break; 488 case SCSI_PROTOCOL_SBP: 489 sbp_parse_pr_out_transport_id(buf, i_str); 490 break; 491 case SCSI_PROTOCOL_ISCSI: 492 return iscsi_parse_pr_out_transport_id(tpg, buf, buf_len, 493 out_tid_len, port_nexus_ptr, i_str); 494 default: 495 pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); 496 return false; 497 } 498 499 *port_nexus_ptr = NULL; 500 *out_tid_len = 24; 501 return true; 502 } 503