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 *out_tid_len, 294 char **port_nexus_ptr, 295 char *i_str) 296 { 297 char *p; 298 int i; 299 u8 format_code = (buf[0] & 0xc0); 300 /* 301 * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6: 302 * 303 * TransportID for initiator ports using SCSI over iSCSI, 304 * from Table 388 -- iSCSI TransportID formats. 305 * 306 * 00b Initiator port is identified using the world wide unique 307 * SCSI device name of the iSCSI initiator 308 * device containing the initiator port (see table 389). 309 * 01b Initiator port is identified using the world wide unique 310 * initiator port identifier (see table 390).10b to 11b 311 * Reserved 312 */ 313 if ((format_code != 0x00) && (format_code != 0x40)) { 314 pr_err("Illegal format code: 0x%02x for iSCSI" 315 " Initiator Transport ID\n", format_code); 316 return false; 317 } 318 /* 319 * If the caller wants the TransportID Length, we set that value for the 320 * entire iSCSI Tarnsport ID now. 321 */ 322 if (out_tid_len) { 323 /* The shift works thanks to integer promotion rules */ 324 *out_tid_len = get_unaligned_be16(&buf[2]); 325 /* Add four bytes for iSCSI Transport ID header */ 326 *out_tid_len += 4; 327 } 328 329 /* 330 * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator 331 * Session ID as defined in Table 390 - iSCSI initiator port TransportID 332 * format. 333 */ 334 if (format_code == 0x40) { 335 p = strstr(&buf[4], ",i,0x"); 336 if (!p) { 337 pr_err("Unable to locate \",i,0x\" separator" 338 " for Initiator port identifier: %s\n", 339 &buf[4]); 340 return false; 341 } 342 *p = '\0'; /* Terminate iSCSI Name */ 343 p += 5; /* Skip over ",i,0x" separator */ 344 345 *port_nexus_ptr = p; 346 /* 347 * Go ahead and do the lower case conversion of the received 348 * 12 ASCII characters representing the ISID in the TransportID 349 * for comparison against the running iSCSI session's ISID from 350 * iscsi_target.c:lio_sess_get_initiator_sid() 351 */ 352 for (i = 0; i < 12; i++) { 353 /* 354 * The first ISCSI INITIATOR SESSION ID field byte 355 * containing an ASCII null character terminates the 356 * ISCSI INITIATOR SESSION ID field without regard for 357 * the specified length of the iSCSI TransportID or the 358 * contents of the ADDITIONAL LENGTH field. 359 */ 360 if (*p == '\0') 361 break; 362 363 if (isdigit(*p)) { 364 p++; 365 continue; 366 } 367 *p = tolower(*p); 368 p++; 369 } 370 } else 371 *port_nexus_ptr = NULL; 372 373 strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN); 374 return true; 375 } 376 377 int target_get_pr_transport_id_len(struct se_node_acl *nacl, 378 struct t10_pr_registration *pr_reg, int *format_code) 379 { 380 switch (nacl->se_tpg->proto_id) { 381 case SCSI_PROTOCOL_FCP: 382 case SCSI_PROTOCOL_SBP: 383 case SCSI_PROTOCOL_SRP: 384 case SCSI_PROTOCOL_SAS: 385 break; 386 case SCSI_PROTOCOL_ISCSI: 387 return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code); 388 default: 389 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); 390 return -EINVAL; 391 } 392 393 /* 394 * Most transports use a fixed length 24 byte identifier. 395 */ 396 *format_code = 0; 397 return 24; 398 } 399 400 int target_get_pr_transport_id(struct se_node_acl *nacl, 401 struct t10_pr_registration *pr_reg, int *format_code, 402 unsigned char *buf) 403 { 404 switch (nacl->se_tpg->proto_id) { 405 case SCSI_PROTOCOL_SAS: 406 return sas_get_pr_transport_id(nacl, format_code, buf); 407 case SCSI_PROTOCOL_SBP: 408 return sbp_get_pr_transport_id(nacl, format_code, buf); 409 case SCSI_PROTOCOL_SRP: 410 return srp_get_pr_transport_id(nacl, format_code, buf); 411 case SCSI_PROTOCOL_FCP: 412 return fc_get_pr_transport_id(nacl, format_code, buf); 413 case SCSI_PROTOCOL_ISCSI: 414 return iscsi_get_pr_transport_id(nacl, pr_reg, format_code, 415 buf); 416 default: 417 pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); 418 return -EINVAL; 419 } 420 } 421 422 bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, 423 char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str) 424 { 425 switch (tpg->proto_id) { 426 case SCSI_PROTOCOL_SAS: 427 /* 428 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID 429 * for initiator ports using SCSI over SAS Serial SCSI Protocol. 430 */ 431 sas_parse_pr_out_transport_id(buf, i_str); 432 break; 433 case SCSI_PROTOCOL_SRP: 434 srp_parse_pr_out_transport_id(buf, i_str); 435 break; 436 case SCSI_PROTOCOL_FCP: 437 fcp_parse_pr_out_transport_id(buf, i_str); 438 break; 439 case SCSI_PROTOCOL_SBP: 440 sbp_parse_pr_out_transport_id(buf, i_str); 441 break; 442 case SCSI_PROTOCOL_ISCSI: 443 return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len, 444 port_nexus_ptr, i_str); 445 default: 446 pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); 447 return false; 448 } 449 450 *port_nexus_ptr = NULL; 451 *out_tid_len = 24; 452 return true; 453 } 454