LCOV - code coverage report
Current view: top level - lib/iscsi - tgt_node.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 190 668 28.4 %
Date: 2024-07-12 14:29:14 Functions: 18 47 38.3 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
       3             :  *   Copyright (C) 2016 Intel Corporation.
       4             :  *   All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : 
       9             : #include "spdk/sock.h"
      10             : #include "spdk/scsi.h"
      11             : 
      12             : #include "spdk/log.h"
      13             : 
      14             : #include "iscsi/iscsi.h"
      15             : #include "iscsi/conn.h"
      16             : #include "iscsi/tgt_node.h"
      17             : #include "iscsi/portal_grp.h"
      18             : #include "iscsi/init_grp.h"
      19             : #include "iscsi/task.h"
      20             : 
      21             : #define MAX_TMPBUF 4096
      22             : #define MAX_MASKBUF 128
      23             : 
      24             : 
      25             : #define MAX_TMP_NAME_BUF (11 /* TargetName= */ + MAX_TARGET_NAME + 1 /* null */)
      26             : #define MAX_TMP_ADDR_BUF (14 /* TargetAddress= */ + MAX_PORTAL_ADDR + 1 /* : */ + \
      27             :                           MAX_PORTAL_PORT + 1 /* , */ + 10 /* max length of int in Decimal */ + 1 /* null */)
      28             : 
      29             : static bool
      30           9 : iscsi_ipv6_netmask_allow_addr(const char *netmask, const char *addr)
      31             : {
      32           9 :         struct in6_addr in6_mask;
      33           9 :         struct in6_addr in6_addr;
      34           9 :         char mask[MAX_MASKBUF];
      35             :         const char *p;
      36             :         size_t n;
      37             :         int bits, bmask;
      38             :         int i;
      39             : 
      40           9 :         if (netmask[0] != '[') {
      41           0 :                 return false;
      42             :         }
      43           9 :         p = strchr(netmask, ']');
      44           9 :         if (p == NULL) {
      45           0 :                 return false;
      46             :         }
      47           9 :         n = p - (netmask + 1);
      48           9 :         if (n + 1 > sizeof mask) {
      49           0 :                 return false;
      50             :         }
      51             : 
      52           9 :         memcpy(mask, netmask + 1, n);
      53           9 :         mask[n] = '\0';
      54           9 :         p++;
      55             : 
      56           9 :         if (p[0] == '/') {
      57           9 :                 bits = (int) strtol(p + 1, NULL, 10);
      58           9 :                 if (bits <= 0 || bits > 128) {
      59           3 :                         return false;
      60             :                 }
      61             :         } else {
      62           0 :                 bits = 128;
      63             :         }
      64             : 
      65             : #if 0
      66             :         SPDK_DEBUGLOG(iscsi, "input %s\n", addr);
      67             :         SPDK_DEBUGLOG(iscsi, "mask  %s / %d\n", mask, bits);
      68             : #endif
      69             : 
      70             :         /* presentation to network order binary */
      71           6 :         if (inet_pton(AF_INET6, mask, &in6_mask) <= 0
      72           6 :             || inet_pton(AF_INET6, addr, &in6_addr) <= 0) {
      73           0 :                 return false;
      74             :         }
      75             : 
      76             :         /* check 128bits */
      77          61 :         for (i = 0; i < (bits / 8); i++) {
      78          58 :                 if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i]) {
      79           3 :                         return false;
      80             :                 }
      81             :         }
      82           3 :         if (bits % 8) {
      83           0 :                 bmask = (0xffU << (8 - (bits % 8))) & 0xffU;
      84           0 :                 if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask)) {
      85           0 :                         return false;
      86             :                 }
      87             :         }
      88             : 
      89             :         /* match */
      90           3 :         return true;
      91             : }
      92             : 
      93             : static bool
      94          19 : iscsi_ipv4_netmask_allow_addr(const char *netmask, const char *addr)
      95             : {
      96          19 :         struct in_addr in4_mask;
      97          19 :         struct in_addr in4_addr;
      98          19 :         char mask[MAX_MASKBUF];
      99             :         const char *p;
     100             :         uint32_t bmask;
     101             :         size_t n;
     102             :         int bits;
     103             : 
     104          19 :         p = strchr(netmask, '/');
     105          19 :         if (p == NULL) {
     106          11 :                 p = netmask + strlen(netmask);
     107             :         }
     108          19 :         n = p - netmask;
     109          19 :         if (n + 1 > sizeof mask) {
     110           0 :                 return false;
     111             :         }
     112             : 
     113          19 :         memcpy(mask, netmask, n);
     114          19 :         mask[n] = '\0';
     115             : 
     116          19 :         if (p[0] == '/') {
     117           8 :                 bits = (int) strtol(p + 1, NULL, 10);
     118           8 :                 if (bits <= 0 || bits > 32) {
     119           3 :                         return false;
     120             :                 }
     121             :         } else {
     122          11 :                 bits = 32;
     123             :         }
     124             : 
     125             :         /* presentation to network order binary */
     126          16 :         if (inet_pton(AF_INET, mask, &in4_mask) <= 0
     127          16 :             || inet_pton(AF_INET, addr, &in4_addr) <= 0) {
     128           0 :                 return false;
     129             :         }
     130             : 
     131             :         /* check 32bits */
     132          16 :         bmask = (0xffffffffU << (32 - bits)) & 0xffffffffU;
     133          16 :         if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask)) {
     134           9 :                 return false;
     135             :         }
     136             : 
     137             :         /* match */
     138           7 :         return true;
     139             : }
     140             : 
     141             : static bool
     142          16 : iscsi_netmask_allow_addr(const char *netmask, const char *addr)
     143             : {
     144          16 :         if (netmask == NULL || addr == NULL) {
     145           0 :                 return false;
     146             :         }
     147          16 :         if (strcasecmp(netmask, "ANY") == 0) {
     148           2 :                 return true;
     149             :         }
     150          14 :         if (netmask[0] == '[') {
     151             :                 /* IPv6 */
     152           2 :                 if (iscsi_ipv6_netmask_allow_addr(netmask, addr)) {
     153           1 :                         return true;
     154             :                 }
     155             :         } else {
     156             :                 /* IPv4 */
     157          12 :                 if (iscsi_ipv4_netmask_allow_addr(netmask, addr)) {
     158           5 :                         return true;
     159             :                 }
     160             :         }
     161           8 :         return false;
     162             : }
     163             : 
     164             : static bool
     165          11 : iscsi_init_grp_allow_addr(struct spdk_iscsi_init_grp *igp,
     166             :                           const char *addr)
     167             : {
     168             :         struct spdk_iscsi_initiator_netmask *imask;
     169             : 
     170          17 :         TAILQ_FOREACH(imask, &igp->netmask_head, tailq) {
     171          10 :                 SPDK_DEBUGLOG(iscsi, "netmask=%s, addr=%s\n",
     172             :                               imask->mask, addr);
     173          10 :                 if (iscsi_netmask_allow_addr(imask->mask, addr)) {
     174           4 :                         return true;
     175             :                 }
     176             :         }
     177           7 :         return false;
     178             : }
     179             : 
     180             : static int
     181          23 : iscsi_init_grp_allow_iscsi_name(struct spdk_iscsi_init_grp *igp,
     182             :                                 const char *iqn, bool *result)
     183             : {
     184             :         struct spdk_iscsi_initiator_name *iname;
     185             : 
     186          31 :         TAILQ_FOREACH(iname, &igp->initiator_head, tailq) {
     187             :                 /* denied if iqn is matched */
     188          23 :                 if ((iname->name[0] == '!')
     189           3 :                     && (strcasecmp(&iname->name[1], "ANY") == 0
     190           3 :                         || strcasecmp(&iname->name[1], iqn) == 0)) {
     191           3 :                         *result = false;
     192           3 :                         return 0;
     193             :                 }
     194             :                 /* allowed if iqn is matched */
     195          20 :                 if (strcasecmp(iname->name, "ANY") == 0
     196          20 :                     || strcasecmp(iname->name, iqn) == 0) {
     197          12 :                         *result = true;
     198          12 :                         return 0;
     199             :                 }
     200             :         }
     201           8 :         return -1;
     202             : }
     203             : 
     204             : static struct spdk_iscsi_pg_map *iscsi_tgt_node_find_pg_map(struct spdk_iscsi_tgt_node *target,
     205             :                 struct spdk_iscsi_portal_grp *pg);
     206             : 
     207             : bool
     208          12 : iscsi_tgt_node_access(struct spdk_iscsi_conn *conn,
     209             :                       struct spdk_iscsi_tgt_node *target, const char *iqn, const char *addr)
     210             : {
     211             :         struct spdk_iscsi_portal_grp *pg;
     212             :         struct spdk_iscsi_pg_map *pg_map;
     213             :         struct spdk_iscsi_ig_map *ig_map;
     214             :         int rc;
     215          12 :         bool allowed = false;
     216             : 
     217          12 :         if (conn == NULL || target == NULL || iqn == NULL || addr == NULL) {
     218           0 :                 return false;
     219             :         }
     220          12 :         pg = conn->portal->group;
     221             : 
     222          12 :         SPDK_DEBUGLOG(iscsi, "pg=%d, iqn=%s, addr=%s\n",
     223             :                       pg->tag, iqn, addr);
     224          12 :         pg_map = iscsi_tgt_node_find_pg_map(target, pg);
     225          12 :         if (pg_map == NULL) {
     226           0 :                 return false;
     227             :         }
     228          25 :         TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
     229          20 :                 rc = iscsi_init_grp_allow_iscsi_name(ig_map->ig, iqn, &allowed);
     230          20 :                 if (rc == 0) {
     231          14 :                         if (allowed == false) {
     232           3 :                                 goto denied;
     233             :                         } else {
     234          11 :                                 if (iscsi_init_grp_allow_addr(ig_map->ig, addr)) {
     235           4 :                                         return true;
     236             :                                 }
     237             :                         }
     238             :                 } else {
     239             :                         /* netmask is denied in this initiator group */
     240             :                 }
     241             :         }
     242             : 
     243           8 : denied:
     244           8 :         SPDK_DEBUGLOG(iscsi, "access denied from %s (%s) to %s (%s:%s,%d)\n",
     245             :                       iqn, addr, target->name, conn->portal_host,
     246             :                       conn->portal_port, conn->pg_tag);
     247           8 :         return false;
     248             : }
     249             : 
     250             : static bool
     251           2 : iscsi_tgt_node_allow_iscsi_name(struct spdk_iscsi_tgt_node *target, const char *iqn)
     252             : {
     253             :         struct spdk_iscsi_pg_map *pg_map;
     254             :         struct spdk_iscsi_ig_map *ig_map;
     255             :         int rc;
     256           2 :         bool result = false;
     257             : 
     258           2 :         if (target == NULL || iqn == NULL) {
     259           0 :                 return false;
     260             :         }
     261             : 
     262           4 :         TAILQ_FOREACH(pg_map, &target->pg_map_head, tailq) {
     263           5 :                 TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
     264           3 :                         rc = iscsi_init_grp_allow_iscsi_name(ig_map->ig, iqn, &result);
     265           3 :                         if (rc == 0) {
     266           1 :                                 return result;
     267             :                         }
     268             :                 }
     269             :         }
     270             : 
     271           1 :         return false;
     272             : }
     273             : 
     274             : static bool
     275           0 : iscsi_copy_str(char *data, int *total, int alloc_len,
     276             :                int *previous_completed_len, int expected_size, char *src)
     277             : {
     278           0 :         int len = 0;
     279             : 
     280           0 :         assert(*previous_completed_len >= 0);
     281             : 
     282           0 :         if (alloc_len - *total < 1) {
     283           0 :                 return true;
     284             :         }
     285             : 
     286           0 :         if (*previous_completed_len < expected_size) {
     287           0 :                 len = spdk_min(alloc_len - *total, expected_size - *previous_completed_len);
     288           0 :                 memcpy((char *)data + *total, src + *previous_completed_len, len);
     289           0 :                 *total += len;
     290           0 :                 *previous_completed_len = 0;
     291             :         } else {
     292           0 :                 *previous_completed_len -= expected_size;
     293             :         }
     294             : 
     295           0 :         return false;
     296             : }
     297             : 
     298             : static int
     299           0 : iscsi_send_tgt_portals(struct spdk_iscsi_conn *conn,
     300             :                        struct spdk_iscsi_tgt_node *target,
     301             :                        uint8_t *data, int alloc_len, int total,
     302             :                        int *previous_completed_len, bool *no_buf_space)
     303             : {
     304           0 :         char buf[MAX_TARGET_ADDR + 2];
     305             :         struct spdk_iscsi_portal_grp *pg;
     306             :         struct spdk_iscsi_pg_map *pg_map;
     307             :         struct spdk_iscsi_portal *p;
     308             :         char *host;
     309           0 :         char tmp_buf[MAX_TMP_ADDR_BUF];
     310             :         int len;
     311             : 
     312           0 :         TAILQ_FOREACH(pg_map, &target->pg_map_head, tailq) {
     313           0 :                 pg = pg_map->pg;
     314             : 
     315           0 :                 if (pg->is_private) {
     316             :                         /* Skip the private portal group. Portals in the private portal group
     317             :                          * will be returned only by temporary login redirection responses.
     318             :                          */
     319           0 :                         continue;
     320             :                 }
     321             : 
     322           0 :                 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
     323           0 :                         host = p->host;
     324             :                         /* wildcard? */
     325           0 :                         if (strcasecmp(host, "[::]") == 0 || strcasecmp(host, "0.0.0.0") == 0) {
     326           0 :                                 if (spdk_sock_is_ipv6(conn->sock)) {
     327           0 :                                         snprintf(buf, sizeof buf, "[%s]", conn->target_addr);
     328           0 :                                         host = buf;
     329           0 :                                 } else if (spdk_sock_is_ipv4(conn->sock)) {
     330           0 :                                         snprintf(buf, sizeof buf, "%s", conn->target_addr);
     331           0 :                                         host = buf;
     332             :                                 } else {
     333             :                                         /* skip portal for the family */
     334           0 :                                         continue;
     335             :                                 }
     336             :                         }
     337           0 :                         SPDK_DEBUGLOG(iscsi, "TargetAddress=%s:%s,%d\n",
     338             :                                       host, p->port, pg->tag);
     339             : 
     340           0 :                         memset(tmp_buf, 0, sizeof(tmp_buf));
     341             :                         /* Calculate the whole string size */
     342           0 :                         len = snprintf(NULL, 0, "TargetAddress=%s:%s,%d", host, p->port, pg->tag);
     343           0 :                         assert(len < MAX_TMPBUF);
     344             : 
     345             :                         /* string contents are not fully copied */
     346           0 :                         if (*previous_completed_len < len) {
     347             :                                 /* Copy the string into the temporary buffer */
     348           0 :                                 snprintf(tmp_buf, len + 1, "TargetAddress=%s:%s,%d", host, p->port, pg->tag);
     349             :                         }
     350             : 
     351           0 :                         *no_buf_space = iscsi_copy_str(data, &total, alloc_len, previous_completed_len,
     352             :                                                        len + 1, tmp_buf);
     353           0 :                         if (*no_buf_space) {
     354           0 :                                 break;
     355             :                         }
     356             :                 }
     357             :         }
     358             : 
     359           0 :         return total;
     360             : }
     361             : 
     362             : int
     363           0 : iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
     364             :                 const char *tiqn, uint8_t *data, int alloc_len, int data_len)
     365             : {
     366             :         struct spdk_iscsi_tgt_node *target;
     367           0 :         int total;
     368             :         int len;
     369             :         int rc;
     370           0 :         int previous_completed_size = 0;
     371           0 :         bool no_buf_space = false;
     372           0 :         char tmp_buf[MAX_TMP_NAME_BUF];
     373             : 
     374           0 :         if (conn == NULL) {
     375           0 :                 return 0;
     376             :         }
     377           0 :         previous_completed_size = conn->send_tgt_completed_size;
     378             : 
     379           0 :         total = data_len;
     380           0 :         if (alloc_len < 1) {
     381           0 :                 return 0;
     382             :         }
     383           0 :         if (total >= alloc_len) {
     384           0 :                 total = alloc_len;
     385           0 :                 data[total - 1] = '\0';
     386           0 :                 return total;
     387             :         }
     388             : 
     389           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     390           0 :         TAILQ_FOREACH(target, &g_iscsi.target_head, tailq) {
     391           0 :                 if (strcasecmp(tiqn, "ALL") != 0
     392           0 :                     && strcasecmp(tiqn, target->name) != 0) {
     393           0 :                         continue;
     394             :                 }
     395           0 :                 rc = iscsi_tgt_node_allow_iscsi_name(target, iiqn);
     396           0 :                 if (rc == 0) {
     397           0 :                         continue;
     398             :                 }
     399             : 
     400           0 :                 memset(tmp_buf, 0, sizeof(tmp_buf));
     401             :                 /* Calculate the whole string size */
     402           0 :                 len = snprintf(NULL, 0, "TargetName=%s", target->name);
     403           0 :                 assert(len < MAX_TMPBUF);
     404             : 
     405             :                 /* String contents are not copied */
     406           0 :                 if (previous_completed_size < len) {
     407             :                         /* Copy the string into the temporary buffer */
     408           0 :                         snprintf(tmp_buf, len + 1, "TargetName=%s", target->name);
     409             :                 }
     410             : 
     411           0 :                 no_buf_space = iscsi_copy_str(data, &total, alloc_len, &previous_completed_size,
     412             :                                               len + 1, tmp_buf);
     413           0 :                 if (no_buf_space) {
     414           0 :                         break;
     415             :                 }
     416             : 
     417           0 :                 total = iscsi_send_tgt_portals(conn, target, data, alloc_len, total,
     418             :                                                &previous_completed_size, &no_buf_space);
     419           0 :                 if (no_buf_space) {
     420           0 :                         break;
     421             :                 }
     422             :         }
     423           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     424             : 
     425             :         /* Only set it when it is not successfully completed */
     426           0 :         if (no_buf_space) {
     427           0 :                 conn->send_tgt_completed_size += total;
     428             :         } else {
     429           0 :                 conn->send_tgt_completed_size = 0;
     430             :         }
     431             : 
     432           0 :         return total;
     433             : }
     434             : 
     435             : struct spdk_iscsi_tgt_node *
     436           0 : iscsi_find_tgt_node(const char *target_name)
     437             : {
     438             :         struct spdk_iscsi_tgt_node *target;
     439             : 
     440           0 :         if (target_name == NULL) {
     441           0 :                 return NULL;
     442             :         }
     443           0 :         TAILQ_FOREACH(target, &g_iscsi.target_head, tailq) {
     444           0 :                 if (strcasecmp(target_name, target->name) == 0) {
     445           0 :                         return target;
     446             :                 }
     447             :         }
     448           0 :         return NULL;
     449             : }
     450             : 
     451             : static int
     452           0 : iscsi_tgt_node_register(struct spdk_iscsi_tgt_node *target)
     453             : {
     454           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     455             : 
     456           0 :         if (iscsi_find_tgt_node(target->name) != NULL) {
     457           0 :                 pthread_mutex_unlock(&g_iscsi.mutex);
     458           0 :                 return -EEXIST;
     459             :         }
     460             : 
     461           0 :         TAILQ_INSERT_TAIL(&g_iscsi.target_head, target, tailq);
     462             : 
     463           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     464           0 :         return 0;
     465             : }
     466             : 
     467             : static int
     468           0 : iscsi_tgt_node_unregister(struct spdk_iscsi_tgt_node *target)
     469             : {
     470             :         struct spdk_iscsi_tgt_node *t;
     471             : 
     472           0 :         TAILQ_FOREACH(t, &g_iscsi.target_head, tailq) {
     473           0 :                 if (t == target) {
     474           0 :                         TAILQ_REMOVE(&g_iscsi.target_head, t, tailq);
     475           0 :                         return 0;
     476             :                 }
     477             :         }
     478             : 
     479           0 :         return -1;
     480             : }
     481             : 
     482             : static struct spdk_iscsi_ig_map *
     483          12 : iscsi_pg_map_find_ig_map(struct spdk_iscsi_pg_map *pg_map,
     484             :                          struct spdk_iscsi_init_grp *ig)
     485             : {
     486             :         struct spdk_iscsi_ig_map *ig_map;
     487             : 
     488          13 :         TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
     489           7 :                 if (ig_map->ig == ig) {
     490           6 :                         return ig_map;
     491             :                 }
     492             :         }
     493             : 
     494           6 :         return NULL;
     495             : }
     496             : 
     497             : static struct spdk_iscsi_ig_map *
     498           6 : iscsi_pg_map_add_ig_map(struct spdk_iscsi_pg_map *pg_map,
     499             :                         struct spdk_iscsi_init_grp *ig)
     500             : {
     501             :         struct spdk_iscsi_ig_map *ig_map;
     502             : 
     503           6 :         if (iscsi_pg_map_find_ig_map(pg_map, ig) != NULL) {
     504           0 :                 return NULL;
     505             :         }
     506             : 
     507           6 :         ig_map = malloc(sizeof(*ig_map));
     508           6 :         if (ig_map == NULL) {
     509           0 :                 return NULL;
     510             :         }
     511             : 
     512           6 :         ig_map->ig = ig;
     513           6 :         ig->ref++;
     514           6 :         pg_map->num_ig_maps++;
     515           6 :         TAILQ_INSERT_TAIL(&pg_map->ig_map_head, ig_map, tailq);
     516             : 
     517           6 :         return ig_map;
     518             : }
     519             : 
     520             : static void
     521           6 : _iscsi_pg_map_delete_ig_map(struct spdk_iscsi_pg_map *pg_map,
     522             :                             struct spdk_iscsi_ig_map *ig_map)
     523             : {
     524           6 :         TAILQ_REMOVE(&pg_map->ig_map_head, ig_map, tailq);
     525           6 :         pg_map->num_ig_maps--;
     526           6 :         ig_map->ig->ref--;
     527           6 :         free(ig_map);
     528           6 : }
     529             : 
     530             : static int
     531           6 : iscsi_pg_map_delete_ig_map(struct spdk_iscsi_pg_map *pg_map,
     532             :                            struct spdk_iscsi_init_grp *ig)
     533             : {
     534             :         struct spdk_iscsi_ig_map *ig_map;
     535             : 
     536           6 :         ig_map = iscsi_pg_map_find_ig_map(pg_map, ig);
     537           6 :         if (ig_map == NULL) {
     538           0 :                 return -ENOENT;
     539             :         }
     540             : 
     541           6 :         _iscsi_pg_map_delete_ig_map(pg_map, ig_map);
     542           6 :         return 0;
     543             : }
     544             : 
     545             : static void
     546           5 : iscsi_pg_map_delete_all_ig_maps(struct spdk_iscsi_pg_map *pg_map)
     547             : {
     548             :         struct spdk_iscsi_ig_map *ig_map, *tmp;
     549             : 
     550           5 :         TAILQ_FOREACH_SAFE(ig_map, &pg_map->ig_map_head, tailq, tmp) {
     551           0 :                 _iscsi_pg_map_delete_ig_map(pg_map, ig_map);
     552             :         }
     553           5 : }
     554             : 
     555             : static struct spdk_iscsi_pg_map *
     556          22 : iscsi_tgt_node_find_pg_map(struct spdk_iscsi_tgt_node *target,
     557             :                            struct spdk_iscsi_portal_grp *pg)
     558             : {
     559             :         struct spdk_iscsi_pg_map *pg_map;
     560             : 
     561          23 :         TAILQ_FOREACH(pg_map, &target->pg_map_head, tailq) {
     562          18 :                 if (pg_map->pg == pg) {
     563          17 :                         return pg_map;
     564             :                 }
     565             :         }
     566             : 
     567           5 :         return NULL;
     568             : }
     569             : 
     570             : static struct spdk_iscsi_pg_map *
     571           5 : iscsi_tgt_node_add_pg_map(struct spdk_iscsi_tgt_node *target,
     572             :                           struct spdk_iscsi_portal_grp *pg)
     573             : {
     574             :         struct spdk_iscsi_pg_map *pg_map;
     575           5 :         char port_name[MAX_TMPBUF];
     576             :         int rc;
     577             : 
     578           5 :         if (iscsi_tgt_node_find_pg_map(target, pg) != NULL) {
     579           0 :                 return NULL;
     580             :         }
     581             : 
     582           5 :         if (target->num_pg_maps >= SPDK_SCSI_DEV_MAX_PORTS) {
     583           0 :                 SPDK_ERRLOG("Number of PG maps is more than allowed (max=%d)\n",
     584             :                             SPDK_SCSI_DEV_MAX_PORTS);
     585           0 :                 return NULL;
     586             :         }
     587             : 
     588           5 :         pg_map = calloc(1, sizeof(*pg_map));
     589           5 :         if (pg_map == NULL) {
     590           0 :                 return NULL;
     591             :         }
     592             : 
     593          10 :         snprintf(port_name, sizeof(port_name), "%s,t,0x%4.4x",
     594           5 :                  spdk_scsi_dev_get_name(target->dev), pg->tag);
     595           5 :         rc = spdk_scsi_dev_add_port(target->dev, pg->tag, port_name);
     596           5 :         if (rc != 0) {
     597           0 :                 free(pg_map);
     598           0 :                 return NULL;
     599             :         }
     600             : 
     601           5 :         TAILQ_INIT(&pg_map->ig_map_head);
     602           5 :         pg_map->num_ig_maps = 0;
     603           5 :         pg->ref++;
     604           5 :         pg_map->pg = pg;
     605           5 :         target->num_pg_maps++;
     606           5 :         TAILQ_INSERT_TAIL(&target->pg_map_head, pg_map, tailq);
     607             : 
     608           5 :         return pg_map;
     609             : }
     610             : 
     611             : static void
     612           5 : _iscsi_tgt_node_delete_pg_map(struct spdk_iscsi_tgt_node *target,
     613             :                               struct spdk_iscsi_pg_map *pg_map)
     614             : {
     615           5 :         TAILQ_REMOVE(&target->pg_map_head, pg_map, tailq);
     616           5 :         target->num_pg_maps--;
     617           5 :         pg_map->pg->ref--;
     618             : 
     619           5 :         spdk_scsi_dev_delete_port(target->dev, pg_map->pg->tag);
     620             : 
     621           5 :         free(pg_map);
     622           5 : }
     623             : 
     624             : static int
     625           5 : iscsi_tgt_node_delete_pg_map(struct spdk_iscsi_tgt_node *target,
     626             :                              struct spdk_iscsi_portal_grp *pg)
     627             : {
     628             :         struct spdk_iscsi_pg_map *pg_map;
     629             : 
     630           5 :         pg_map = iscsi_tgt_node_find_pg_map(target, pg);
     631           5 :         if (pg_map == NULL) {
     632           0 :                 return -ENOENT;
     633             :         }
     634             : 
     635           5 :         if (pg_map->num_ig_maps > 0) {
     636           0 :                 SPDK_DEBUGLOG(iscsi, "delete %d ig_maps forcefully\n",
     637             :                               pg_map->num_ig_maps);
     638             :         }
     639             : 
     640           5 :         iscsi_pg_map_delete_all_ig_maps(pg_map);
     641           5 :         _iscsi_tgt_node_delete_pg_map(target, pg_map);
     642           5 :         return 0;
     643             : }
     644             : 
     645             : static void
     646           0 : iscsi_tgt_node_delete_ig_maps(struct spdk_iscsi_tgt_node *target,
     647             :                               struct spdk_iscsi_init_grp *ig)
     648             : {
     649             :         struct spdk_iscsi_pg_map *pg_map, *tmp;
     650             : 
     651           0 :         TAILQ_FOREACH_SAFE(pg_map, &target->pg_map_head, tailq, tmp) {
     652           0 :                 iscsi_pg_map_delete_ig_map(pg_map, ig);
     653           0 :                 if (pg_map->num_ig_maps == 0) {
     654           0 :                         _iscsi_tgt_node_delete_pg_map(target, pg_map);
     655             :                 }
     656             :         }
     657           0 : }
     658             : 
     659             : static void
     660           0 : iscsi_tgt_node_delete_all_pg_maps(struct spdk_iscsi_tgt_node *target)
     661             : {
     662             :         struct spdk_iscsi_pg_map *pg_map, *tmp;
     663             : 
     664           0 :         TAILQ_FOREACH_SAFE(pg_map, &target->pg_map_head, tailq, tmp) {
     665           0 :                 iscsi_pg_map_delete_all_ig_maps(pg_map);
     666           0 :                 _iscsi_tgt_node_delete_pg_map(target, pg_map);
     667             :         }
     668           0 : }
     669             : 
     670             : static void
     671           0 : _iscsi_tgt_node_destruct(void *cb_arg, int rc)
     672             : {
     673           0 :         struct spdk_iscsi_tgt_node *target = cb_arg;
     674           0 :         iscsi_tgt_node_destruct_cb destruct_cb_fn = target->destruct_cb_fn;
     675           0 :         void *destruct_cb_arg = target->destruct_cb_arg;
     676             : 
     677           0 :         if (rc != 0) {
     678           0 :                 if (destruct_cb_fn) {
     679           0 :                         destruct_cb_fn(destruct_cb_arg, rc);
     680             :                 }
     681           0 :                 return;
     682             :         }
     683             : 
     684           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     685           0 :         iscsi_tgt_node_delete_all_pg_maps(target);
     686           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     687             : 
     688           0 :         pthread_mutex_destroy(&target->mutex);
     689           0 :         free(target);
     690             : 
     691           0 :         if (destruct_cb_fn) {
     692           0 :                 destruct_cb_fn(destruct_cb_arg, 0);
     693             :         }
     694             : }
     695             : 
     696             : static int
     697           0 : iscsi_tgt_node_check_active_conns(void *arg)
     698             : {
     699           0 :         struct spdk_iscsi_tgt_node *target = arg;
     700             : 
     701           0 :         if (iscsi_get_active_conns(target) != 0) {
     702           0 :                 return SPDK_POLLER_BUSY;
     703             :         }
     704             : 
     705           0 :         spdk_poller_unregister(&target->destruct_poller);
     706             : 
     707           0 :         spdk_scsi_dev_destruct(target->dev, _iscsi_tgt_node_destruct, target);
     708             : 
     709           0 :         return SPDK_POLLER_BUSY;
     710             : }
     711             : 
     712             : static void
     713           0 : iscsi_tgt_node_destruct(struct spdk_iscsi_tgt_node *target,
     714             :                         iscsi_tgt_node_destruct_cb cb_fn, void *cb_arg)
     715             : {
     716           0 :         if (target == NULL) {
     717           0 :                 if (cb_fn) {
     718           0 :                         cb_fn(cb_arg, -ENOENT);
     719             :                 }
     720           0 :                 return;
     721             :         }
     722             : 
     723           0 :         if (target->destructed) {
     724           0 :                 SPDK_ERRLOG("Destructing %s is already started\n", target->name);
     725           0 :                 if (cb_fn) {
     726           0 :                         cb_fn(cb_arg, -EBUSY);
     727             :                 }
     728           0 :                 return;
     729             :         }
     730             : 
     731           0 :         target->destructed = true;
     732           0 :         target->destruct_cb_fn = cb_fn;
     733           0 :         target->destruct_cb_arg = cb_arg;
     734             : 
     735           0 :         iscsi_conns_request_logout(target, -1);
     736             : 
     737           0 :         if (iscsi_get_active_conns(target) != 0) {
     738           0 :                 target->destruct_poller = SPDK_POLLER_REGISTER(iscsi_tgt_node_check_active_conns,
     739             :                                           target, 10);
     740             :         } else {
     741           0 :                 spdk_scsi_dev_destruct(target->dev, _iscsi_tgt_node_destruct, target);
     742             :         }
     743             : 
     744             : }
     745             : 
     746             : static int
     747           0 : iscsi_tgt_node_delete_pg_ig_map(struct spdk_iscsi_tgt_node *target,
     748             :                                 int pg_tag, int ig_tag)
     749             : {
     750             :         struct spdk_iscsi_portal_grp    *pg;
     751             :         struct spdk_iscsi_init_grp      *ig;
     752             :         struct spdk_iscsi_pg_map        *pg_map;
     753             :         struct spdk_iscsi_ig_map        *ig_map;
     754             : 
     755           0 :         pg = iscsi_portal_grp_find_by_tag(pg_tag);
     756           0 :         if (pg == NULL) {
     757           0 :                 SPDK_ERRLOG("%s: PortalGroup%d not found\n", target->name, pg_tag);
     758           0 :                 return -ENOENT;
     759             :         }
     760           0 :         ig = iscsi_init_grp_find_by_tag(ig_tag);
     761           0 :         if (ig == NULL) {
     762           0 :                 SPDK_ERRLOG("%s: InitiatorGroup%d not found\n", target->name, ig_tag);
     763           0 :                 return -ENOENT;
     764             :         }
     765             : 
     766           0 :         pg_map = iscsi_tgt_node_find_pg_map(target, pg);
     767           0 :         if (pg_map == NULL) {
     768           0 :                 SPDK_ERRLOG("%s: PortalGroup%d is not mapped\n", target->name, pg_tag);
     769           0 :                 return -ENOENT;
     770             :         }
     771           0 :         ig_map = iscsi_pg_map_find_ig_map(pg_map, ig);
     772           0 :         if (ig_map == NULL) {
     773           0 :                 SPDK_ERRLOG("%s: InitiatorGroup%d is not mapped\n", target->name, pg_tag);
     774           0 :                 return -ENOENT;
     775             :         }
     776             : 
     777           0 :         _iscsi_pg_map_delete_ig_map(pg_map, ig_map);
     778           0 :         if (pg_map->num_ig_maps == 0) {
     779           0 :                 _iscsi_tgt_node_delete_pg_map(target, pg_map);
     780             :         }
     781             : 
     782           0 :         return 0;
     783             : }
     784             : 
     785             : static int
     786           0 : iscsi_tgt_node_add_pg_ig_map(struct spdk_iscsi_tgt_node *target,
     787             :                              int pg_tag, int ig_tag)
     788             : {
     789             :         struct spdk_iscsi_portal_grp    *pg;
     790             :         struct spdk_iscsi_pg_map        *pg_map;
     791             :         struct spdk_iscsi_init_grp      *ig;
     792             :         struct spdk_iscsi_ig_map        *ig_map;
     793           0 :         bool                            new_pg_map = false;
     794             : 
     795           0 :         pg = iscsi_portal_grp_find_by_tag(pg_tag);
     796           0 :         if (pg == NULL) {
     797           0 :                 SPDK_ERRLOG("%s: PortalGroup%d not found\n", target->name, pg_tag);
     798           0 :                 return -ENOENT;
     799             :         }
     800           0 :         ig = iscsi_init_grp_find_by_tag(ig_tag);
     801           0 :         if (ig == NULL) {
     802           0 :                 SPDK_ERRLOG("%s: InitiatorGroup%d not found\n", target->name, ig_tag);
     803           0 :                 return -ENOENT;
     804             :         }
     805             : 
     806             :         /* get existing pg_map or create new pg_map and add it to target */
     807           0 :         pg_map = iscsi_tgt_node_find_pg_map(target, pg);
     808           0 :         if (pg_map == NULL) {
     809           0 :                 pg_map = iscsi_tgt_node_add_pg_map(target, pg);
     810           0 :                 if (pg_map == NULL) {
     811           0 :                         goto failed;
     812             :                 }
     813           0 :                 new_pg_map = true;
     814             :         }
     815             : 
     816             :         /* create new ig_map and add it to pg_map */
     817           0 :         ig_map = iscsi_pg_map_add_ig_map(pg_map, ig);
     818           0 :         if (ig_map == NULL) {
     819           0 :                 goto failed;
     820             :         }
     821             : 
     822           0 :         return 0;
     823             : 
     824           0 : failed:
     825           0 :         if (new_pg_map) {
     826           0 :                 _iscsi_tgt_node_delete_pg_map(target, pg_map);
     827             :         }
     828             : 
     829           0 :         return -1;
     830             : }
     831             : 
     832             : int
     833           0 : iscsi_target_node_add_pg_ig_maps(struct spdk_iscsi_tgt_node *target,
     834             :                                  int *pg_tag_list, int *ig_tag_list, uint16_t num_maps)
     835             : {
     836             :         uint16_t i;
     837             :         int rc;
     838             : 
     839           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     840           0 :         for (i = 0; i < num_maps; i++) {
     841           0 :                 rc = iscsi_tgt_node_add_pg_ig_map(target, pg_tag_list[i],
     842           0 :                                                   ig_tag_list[i]);
     843           0 :                 if (rc != 0) {
     844           0 :                         SPDK_ERRLOG("could not add map to target\n");
     845           0 :                         goto invalid;
     846             :                 }
     847             :         }
     848           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     849           0 :         return 0;
     850             : 
     851           0 : invalid:
     852           0 :         for (; i > 0; --i) {
     853           0 :                 iscsi_tgt_node_delete_pg_ig_map(target, pg_tag_list[i - 1],
     854           0 :                                                 ig_tag_list[i - 1]);
     855             :         }
     856           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     857           0 :         return -1;
     858             : }
     859             : 
     860             : int
     861           0 : iscsi_target_node_remove_pg_ig_maps(struct spdk_iscsi_tgt_node *target,
     862             :                                     int *pg_tag_list, int *ig_tag_list, uint16_t num_maps)
     863             : {
     864             :         uint16_t i;
     865             :         int rc;
     866             : 
     867           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     868           0 :         for (i = 0; i < num_maps; i++) {
     869           0 :                 rc = iscsi_tgt_node_delete_pg_ig_map(target, pg_tag_list[i],
     870           0 :                                                      ig_tag_list[i]);
     871           0 :                 if (rc != 0) {
     872           0 :                         SPDK_ERRLOG("could not delete map from target\n");
     873           0 :                         goto invalid;
     874             :                 }
     875             :         }
     876           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     877           0 :         return 0;
     878             : 
     879           0 : invalid:
     880           0 :         for (; i > 0; --i) {
     881           0 :                 rc = iscsi_tgt_node_add_pg_ig_map(target, pg_tag_list[i - 1],
     882           0 :                                                   ig_tag_list[i - 1]);
     883           0 :                 if (rc != 0) {
     884           0 :                         iscsi_tgt_node_delete_all_pg_maps(target);
     885           0 :                         break;
     886             :                 }
     887             :         }
     888           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     889           0 :         return -1;
     890             : }
     891             : 
     892             : int
     893           0 : iscsi_tgt_node_redirect(struct spdk_iscsi_tgt_node *target, int pg_tag,
     894             :                         const char *host, const char *port)
     895             : {
     896             :         struct spdk_iscsi_portal_grp *pg;
     897             :         struct spdk_iscsi_pg_map *pg_map;
     898           0 :         struct sockaddr_storage sa;
     899             : 
     900           0 :         if (target == NULL) {
     901           0 :                 return -EINVAL;
     902             :         }
     903             : 
     904           0 :         pg = iscsi_portal_grp_find_by_tag(pg_tag);
     905           0 :         if (pg == NULL) {
     906           0 :                 SPDK_ERRLOG("Portal group %d is not found.\n", pg_tag);
     907           0 :                 return -EINVAL;
     908             :         }
     909             : 
     910           0 :         if (pg->is_private) {
     911           0 :                 SPDK_ERRLOG("Portal group %d is not public portal group.\n", pg_tag);
     912           0 :                 return -EINVAL;
     913             :         }
     914             : 
     915           0 :         pg_map = iscsi_tgt_node_find_pg_map(target, pg);
     916           0 :         if (pg_map == NULL) {
     917           0 :                 SPDK_ERRLOG("Portal group %d is not mapped.\n", pg_tag);
     918           0 :                 return -EINVAL;
     919             :         }
     920             : 
     921           0 :         if (host == NULL && port == NULL) {
     922             :                 /* Clear redirect setting. */
     923           0 :                 memset(pg_map->redirect_host, 0, MAX_PORTAL_ADDR + 1);
     924           0 :                 memset(pg_map->redirect_port, 0, MAX_PORTAL_PORT + 1);
     925             :         } else {
     926           0 :                 if (iscsi_parse_redirect_addr(&sa, host, port) != 0) {
     927           0 :                         SPDK_ERRLOG("IP address-port pair is not valid.\n");
     928           0 :                         return -EINVAL;
     929             :                 }
     930             : 
     931           0 :                 if (iscsi_portal_grp_find_portal_by_addr(pg, port, host) != NULL) {
     932           0 :                         SPDK_ERRLOG("IP address-port pair must be chosen from a "
     933             :                                     "different private portal group\n");
     934           0 :                         return -EINVAL;
     935             :                 }
     936             : 
     937           0 :                 snprintf(pg_map->redirect_host, MAX_PORTAL_ADDR + 1, "%s", host);
     938           0 :                 snprintf(pg_map->redirect_port, MAX_PORTAL_PORT + 1, "%s", port);
     939             :         }
     940             : 
     941           0 :         return 0;
     942             : }
     943             : 
     944             : bool
     945           0 : iscsi_tgt_node_is_redirected(struct spdk_iscsi_conn *conn,
     946             :                              struct spdk_iscsi_tgt_node *target,
     947             :                              char *buf, int buf_len)
     948             : {
     949             :         struct spdk_iscsi_pg_map *pg_map;
     950             : 
     951           0 :         if (conn == NULL || target == NULL || buf == NULL || buf_len == 0) {
     952           0 :                 return false;
     953             :         }
     954             : 
     955           0 :         pg_map = iscsi_tgt_node_find_pg_map(target, conn->portal->group);
     956           0 :         if (pg_map == NULL) {
     957           0 :                 return false;
     958             :         }
     959             : 
     960           0 :         if (pg_map->redirect_host[0] == '\0' || pg_map->redirect_port[0] == '\0') {
     961           0 :                 return false;
     962             :         }
     963             : 
     964           0 :         snprintf(buf, buf_len, "%s:%s", pg_map->redirect_host, pg_map->redirect_port);
     965             : 
     966           0 :         return true;
     967             : }
     968             : 
     969             : static int
     970           0 : check_iscsi_name(const char *name)
     971             : {
     972           0 :         const unsigned char *up = (const unsigned char *) name;
     973             :         size_t n;
     974             : 
     975             :         /* valid iSCSI name no larger than 223 bytes */
     976           0 :         if (strlen(name) > MAX_TARGET_NAME) {
     977           0 :                 return -1;
     978             :         }
     979             : 
     980             :         /* valid iSCSI name? */
     981           0 :         for (n = 0; up[n] != 0; n++) {
     982           0 :                 if (up[n] > 0x00U && up[n] <= 0x2cU) {
     983           0 :                         return -1;
     984             :                 }
     985           0 :                 if (up[n] == 0x2fU) {
     986           0 :                         return -1;
     987             :                 }
     988           0 :                 if (up[n] >= 0x3bU && up[n] <= 0x40U) {
     989           0 :                         return -1;
     990             :                 }
     991           0 :                 if (up[n] >= 0x5bU && up[n] <= 0x60U) {
     992           0 :                         return -1;
     993             :                 }
     994           0 :                 if (up[n] >= 0x7bU && up[n] <= 0x7fU) {
     995           0 :                         return -1;
     996             :                 }
     997           0 :                 if (isspace(up[n])) {
     998           0 :                         return -1;
     999             :                 }
    1000             :         }
    1001             :         /* valid format? */
    1002           0 :         if (strncasecmp(name, "iqn.", 4) == 0) {
    1003             :                 /* iqn.YYYY-MM.reversed.domain.name */
    1004           0 :                 if (!isdigit(up[4]) || !isdigit(up[5]) || !isdigit(up[6])
    1005           0 :                     || !isdigit(up[7]) || up[8] != '-' || !isdigit(up[9])
    1006           0 :                     || !isdigit(up[10]) || up[11] != '.') {
    1007           0 :                         SPDK_ERRLOG("invalid iqn format. "
    1008             :                                     "expect \"iqn.YYYY-MM.reversed.domain.name\"\n");
    1009           0 :                         return -1;
    1010             :                 }
    1011           0 :         } else if (strncasecmp(name, "eui.", 4) == 0) {
    1012             :                 /* EUI-64 -> 16bytes */
    1013             :                 /* XXX */
    1014           0 :         } else if (strncasecmp(name, "naa.", 4) == 0) {
    1015             :                 /* 64bit -> 16bytes, 128bit -> 32bytes */
    1016             :                 /* XXX */
    1017             :         }
    1018             :         /* OK */
    1019           0 :         return 0;
    1020             : }
    1021             : 
    1022             : bool
    1023          10 : iscsi_check_chap_params(bool disable, bool require, bool mutual, int group)
    1024             : {
    1025          10 :         if (group < 0) {
    1026           1 :                 SPDK_ERRLOG("Invalid auth group ID (%d)\n", group);
    1027           1 :                 return false;
    1028             :         }
    1029           9 :         if ((!disable && !require && !mutual) ||        /* Auto */
    1030           4 :             (disable && !require && !mutual) || /* None */
    1031           6 :             (!disable && require && !mutual) || /* CHAP */
    1032           5 :             (!disable && require && mutual)) {  /* CHAP Mutual */
    1033           5 :                 return true;
    1034             :         }
    1035           4 :         SPDK_ERRLOG("Invalid combination of CHAP params (d=%d,r=%d,m=%d)\n",
    1036             :                     disable, require, mutual);
    1037           4 :         return false;
    1038             : }
    1039             : 
    1040           0 : struct spdk_iscsi_tgt_node *iscsi_tgt_node_construct(int target_index,
    1041             :                 const char *name, const char *alias,
    1042             :                 int *pg_tag_list, int *ig_tag_list, uint16_t num_maps,
    1043             :                 const char *bdev_name_list[], int *lun_id_list, int num_luns,
    1044             :                 int queue_depth,
    1045             :                 bool disable_chap, bool require_chap, bool mutual_chap, int chap_group,
    1046             :                 bool header_digest, bool data_digest)
    1047             : {
    1048           0 :         char                            fullname[MAX_TMPBUF];
    1049             :         struct spdk_iscsi_tgt_node      *target;
    1050             :         int                             rc;
    1051             : 
    1052           0 :         if (!iscsi_check_chap_params(disable_chap, require_chap,
    1053             :                                      mutual_chap, chap_group)) {
    1054           0 :                 return NULL;
    1055             :         }
    1056             : 
    1057           0 :         if (num_maps == 0) {
    1058           0 :                 SPDK_ERRLOG("num_maps = 0\n");
    1059           0 :                 return NULL;
    1060             :         }
    1061             : 
    1062           0 :         if (name == NULL) {
    1063           0 :                 SPDK_ERRLOG("TargetName not found\n");
    1064           0 :                 return NULL;
    1065             :         }
    1066             : 
    1067           0 :         if (strncasecmp(name, "iqn.", 4) != 0
    1068           0 :             && strncasecmp(name, "eui.", 4) != 0
    1069           0 :             && strncasecmp(name, "naa.", 4) != 0) {
    1070           0 :                 snprintf(fullname, sizeof(fullname), "%s:%s", g_iscsi.nodebase, name);
    1071             :         } else {
    1072           0 :                 snprintf(fullname, sizeof(fullname), "%s", name);
    1073             :         }
    1074             : 
    1075           0 :         if (check_iscsi_name(fullname) != 0) {
    1076           0 :                 SPDK_ERRLOG("TargetName %s contains an invalid character or format.\n",
    1077             :                             name);
    1078           0 :                 return NULL;
    1079             :         }
    1080             : 
    1081           0 :         target = calloc(1, sizeof(*target));
    1082           0 :         if (!target) {
    1083           0 :                 SPDK_ERRLOG("could not allocate target\n");
    1084           0 :                 return NULL;
    1085             :         }
    1086             : 
    1087           0 :         rc = pthread_mutex_init(&target->mutex, NULL);
    1088           0 :         if (rc != 0) {
    1089           0 :                 SPDK_ERRLOG("tgt_node%d: mutex_init() failed\n", target->num);
    1090           0 :                 iscsi_tgt_node_destruct(target, NULL, NULL);
    1091           0 :                 return NULL;
    1092             :         }
    1093             : 
    1094           0 :         target->num = target_index;
    1095             : 
    1096           0 :         memcpy(target->name, fullname, strlen(fullname));
    1097             : 
    1098           0 :         if (alias != NULL) {
    1099           0 :                 if (strlen(alias) > MAX_TARGET_NAME) {
    1100           0 :                         iscsi_tgt_node_destruct(target, NULL, NULL);
    1101           0 :                         return NULL;
    1102             :                 }
    1103           0 :                 memcpy(target->alias, alias, strlen(alias));
    1104             :         }
    1105             : 
    1106           0 :         target->dev = spdk_scsi_dev_construct(fullname, bdev_name_list, lun_id_list, num_luns,
    1107             :                                               SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL);
    1108           0 :         if (!target->dev) {
    1109           0 :                 SPDK_ERRLOG("Could not construct SCSI device\n");
    1110           0 :                 iscsi_tgt_node_destruct(target, NULL, NULL);
    1111           0 :                 return NULL;
    1112             :         }
    1113             : 
    1114           0 :         TAILQ_INIT(&target->pg_map_head);
    1115           0 :         rc = iscsi_target_node_add_pg_ig_maps(target, pg_tag_list,
    1116             :                                               ig_tag_list, num_maps);
    1117           0 :         if (rc != 0) {
    1118           0 :                 SPDK_ERRLOG("could not add map to target\n");
    1119           0 :                 iscsi_tgt_node_destruct(target, NULL, NULL);
    1120           0 :                 return NULL;
    1121             :         }
    1122             : 
    1123           0 :         target->disable_chap = disable_chap;
    1124           0 :         target->require_chap = require_chap;
    1125           0 :         target->mutual_chap = mutual_chap;
    1126           0 :         target->chap_group = chap_group;
    1127           0 :         target->header_digest = header_digest;
    1128           0 :         target->data_digest = data_digest;
    1129             : 
    1130           0 :         if (queue_depth > 0 && ((uint32_t)queue_depth <= g_iscsi.MaxQueueDepth)) {
    1131           0 :                 target->queue_depth = queue_depth;
    1132             :         } else {
    1133           0 :                 SPDK_DEBUGLOG(iscsi, "QueueDepth %d is invalid and %d is used instead.\n",
    1134             :                               queue_depth, g_iscsi.MaxQueueDepth);
    1135           0 :                 target->queue_depth = g_iscsi.MaxQueueDepth;
    1136             :         }
    1137             : 
    1138           0 :         rc = iscsi_tgt_node_register(target);
    1139           0 :         if (rc != 0) {
    1140           0 :                 SPDK_ERRLOG("register target is failed\n");
    1141           0 :                 iscsi_tgt_node_destruct(target, NULL, NULL);
    1142           0 :                 return NULL;
    1143             :         }
    1144             : 
    1145           0 :         return target;
    1146             : }
    1147             : 
    1148             : void
    1149           0 : iscsi_shutdown_tgt_nodes(void)
    1150             : {
    1151             :         struct spdk_iscsi_tgt_node *target;
    1152             : 
    1153           0 :         pthread_mutex_lock(&g_iscsi.mutex);
    1154           0 :         while (!TAILQ_EMPTY(&g_iscsi.target_head)) {
    1155           0 :                 target = TAILQ_FIRST(&g_iscsi.target_head);
    1156           0 :                 TAILQ_REMOVE(&g_iscsi.target_head, target, tailq);
    1157             : 
    1158           0 :                 pthread_mutex_unlock(&g_iscsi.mutex);
    1159             : 
    1160           0 :                 iscsi_tgt_node_destruct(target, NULL, NULL);
    1161             : 
    1162           0 :                 pthread_mutex_lock(&g_iscsi.mutex);
    1163             :         }
    1164           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
    1165           0 : }
    1166             : 
    1167             : void
    1168           0 : iscsi_shutdown_tgt_node_by_name(const char *target_name,
    1169             :                                 iscsi_tgt_node_destruct_cb cb_fn, void *cb_arg)
    1170             : {
    1171             :         struct spdk_iscsi_tgt_node *target;
    1172             : 
    1173           0 :         pthread_mutex_lock(&g_iscsi.mutex);
    1174           0 :         target = iscsi_find_tgt_node(target_name);
    1175           0 :         if (target != NULL) {
    1176           0 :                 iscsi_tgt_node_unregister(target);
    1177           0 :                 pthread_mutex_unlock(&g_iscsi.mutex);
    1178             : 
    1179           0 :                 iscsi_tgt_node_destruct(target, cb_fn, cb_arg);
    1180             : 
    1181           0 :                 return;
    1182             :         }
    1183           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
    1184             : 
    1185           0 :         if (cb_fn) {
    1186           0 :                 cb_fn(cb_arg, -ENOENT);
    1187             :         }
    1188             : }
    1189             : 
    1190             : bool
    1191           0 : iscsi_tgt_node_is_destructed(struct spdk_iscsi_tgt_node *target)
    1192             : {
    1193           0 :         return target->destructed;
    1194             : }
    1195             : 
    1196             : int
    1197           0 : iscsi_tgt_node_cleanup_luns(struct spdk_iscsi_conn *conn,
    1198             :                             struct spdk_iscsi_tgt_node *target)
    1199             : {
    1200             :         struct spdk_scsi_lun *lun;
    1201             :         struct spdk_iscsi_task *task;
    1202             : 
    1203           0 :         for (lun = spdk_scsi_dev_get_first_lun(target->dev); lun != NULL;
    1204           0 :              lun = spdk_scsi_dev_get_next_lun(lun)) {
    1205             :                 /* we create a fake management task per LUN to cleanup */
    1206           0 :                 task = iscsi_task_get(conn, NULL, iscsi_task_mgmt_cpl);
    1207           0 :                 if (!task) {
    1208           0 :                         SPDK_ERRLOG("Unable to acquire task\n");
    1209           0 :                         return -1;
    1210             :                 }
    1211             : 
    1212           0 :                 task->scsi.target_port = conn->target_port;
    1213           0 :                 task->scsi.initiator_port = conn->initiator_port;
    1214           0 :                 task->scsi.lun = lun;
    1215             : 
    1216           0 :                 iscsi_op_abort_task_set(task, SPDK_SCSI_TASK_FUNC_TARGET_RESET);
    1217             :         }
    1218             : 
    1219           0 :         return 0;
    1220             : }
    1221             : 
    1222             : void
    1223           0 : iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group,
    1224             :                           struct spdk_iscsi_init_grp *initiator_group)
    1225             : {
    1226             :         struct spdk_iscsi_tgt_node *target;
    1227             : 
    1228           0 :         pthread_mutex_lock(&g_iscsi.mutex);
    1229           0 :         TAILQ_FOREACH(target, &g_iscsi.target_head, tailq) {
    1230           0 :                 if (portal_group) {
    1231           0 :                         iscsi_tgt_node_delete_pg_map(target, portal_group);
    1232             :                 }
    1233           0 :                 if (initiator_group) {
    1234           0 :                         iscsi_tgt_node_delete_ig_maps(target, initiator_group);
    1235             :                 }
    1236             :         }
    1237           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
    1238           0 : }
    1239             : 
    1240             : int
    1241           6 : iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target,
    1242             :                        const char *bdev_name, int lun_id)
    1243             : {
    1244             :         struct spdk_scsi_dev *dev;
    1245             :         int rc;
    1246             : 
    1247           6 :         if (target->num_active_conns > 0) {
    1248           1 :                 SPDK_ERRLOG("Target has active connections (count=%d)\n",
    1249             :                             target->num_active_conns);
    1250           1 :                 return -1;
    1251             :         }
    1252             : 
    1253           5 :         if (lun_id < -1) {
    1254           1 :                 SPDK_ERRLOG("Specified LUN ID (%d) is negative\n", lun_id);
    1255           1 :                 return -1;
    1256             :         }
    1257             : 
    1258           4 :         dev = target->dev;
    1259           4 :         if (dev == NULL) {
    1260           2 :                 SPDK_ERRLOG("SCSI device is not found\n");
    1261           2 :                 return -1;
    1262             :         }
    1263             : 
    1264           2 :         rc = spdk_scsi_dev_add_lun(dev, bdev_name, lun_id, NULL, NULL);
    1265           2 :         if (rc != 0) {
    1266           1 :                 SPDK_ERRLOG("spdk_scsi_dev_add_lun failed\n");
    1267           1 :                 return -1;
    1268             :         }
    1269             : 
    1270           1 :         return 0;
    1271             : }
    1272             : 
    1273             : int
    1274           0 : iscsi_tgt_node_set_chap_params(struct spdk_iscsi_tgt_node *target,
    1275             :                                bool disable_chap, bool require_chap,
    1276             :                                bool mutual_chap, int32_t chap_group)
    1277             : {
    1278           0 :         if (!iscsi_check_chap_params(disable_chap, require_chap,
    1279             :                                      mutual_chap, chap_group)) {
    1280           0 :                 return -EINVAL;
    1281             :         }
    1282             : 
    1283           0 :         pthread_mutex_lock(&target->mutex);
    1284           0 :         target->disable_chap = disable_chap;
    1285           0 :         target->require_chap = require_chap;
    1286           0 :         target->mutual_chap = mutual_chap;
    1287           0 :         target->chap_group = chap_group;
    1288           0 :         pthread_mutex_unlock(&target->mutex);
    1289             : 
    1290           0 :         return 0;
    1291             : }
    1292             : 
    1293             : static void
    1294           0 : iscsi_tgt_node_info_json(struct spdk_iscsi_tgt_node *target,
    1295             :                          struct spdk_json_write_ctx *w)
    1296             : {
    1297             :         struct spdk_iscsi_pg_map *pg_map;
    1298             :         struct spdk_iscsi_ig_map *ig_map;
    1299             :         struct spdk_scsi_lun *lun;
    1300             : 
    1301           0 :         spdk_json_write_object_begin(w);
    1302             : 
    1303           0 :         spdk_json_write_named_string(w, "name", target->name);
    1304             : 
    1305           0 :         if (target->alias[0] != '\0') {
    1306           0 :                 spdk_json_write_named_string(w, "alias_name", target->alias);
    1307             :         }
    1308             : 
    1309           0 :         spdk_json_write_named_array_begin(w, "pg_ig_maps");
    1310           0 :         TAILQ_FOREACH(pg_map, &target->pg_map_head, tailq) {
    1311           0 :                 TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
    1312           0 :                         spdk_json_write_object_begin(w);
    1313           0 :                         spdk_json_write_named_int32(w, "pg_tag", pg_map->pg->tag);
    1314           0 :                         spdk_json_write_named_int32(w, "ig_tag", ig_map->ig->tag);
    1315           0 :                         spdk_json_write_object_end(w);
    1316             :                 }
    1317             :         }
    1318           0 :         spdk_json_write_array_end(w);
    1319             : 
    1320           0 :         spdk_json_write_named_array_begin(w, "luns");
    1321           0 :         for (lun = spdk_scsi_dev_get_first_lun(target->dev); lun != NULL;
    1322           0 :              lun = spdk_scsi_dev_get_next_lun(lun)) {
    1323           0 :                 spdk_json_write_object_begin(w);
    1324           0 :                 spdk_json_write_named_string(w, "bdev_name", spdk_scsi_lun_get_bdev_name(lun));
    1325           0 :                 spdk_json_write_named_int32(w, "lun_id", spdk_scsi_lun_get_id(lun));
    1326           0 :                 spdk_json_write_object_end(w);
    1327             :         }
    1328           0 :         spdk_json_write_array_end(w);
    1329             : 
    1330           0 :         spdk_json_write_named_int32(w, "queue_depth", target->queue_depth);
    1331             : 
    1332           0 :         spdk_json_write_named_bool(w, "disable_chap", target->disable_chap);
    1333           0 :         spdk_json_write_named_bool(w, "require_chap", target->require_chap);
    1334           0 :         spdk_json_write_named_bool(w, "mutual_chap", target->mutual_chap);
    1335           0 :         spdk_json_write_named_int32(w, "chap_group", target->chap_group);
    1336             : 
    1337           0 :         spdk_json_write_named_bool(w, "header_digest", target->header_digest);
    1338           0 :         spdk_json_write_named_bool(w, "data_digest", target->data_digest);
    1339             : 
    1340           0 :         spdk_json_write_object_end(w);
    1341           0 : }
    1342             : 
    1343             : static void
    1344           0 : iscsi_tgt_node_config_json(struct spdk_iscsi_tgt_node *target,
    1345             :                            struct spdk_json_write_ctx *w)
    1346             : {
    1347           0 :         spdk_json_write_object_begin(w);
    1348             : 
    1349           0 :         spdk_json_write_named_string(w, "method", "iscsi_create_target_node");
    1350             : 
    1351           0 :         spdk_json_write_name(w, "params");
    1352           0 :         iscsi_tgt_node_info_json(target, w);
    1353             : 
    1354           0 :         spdk_json_write_object_end(w);
    1355           0 : }
    1356             : 
    1357             : void
    1358           0 : iscsi_tgt_nodes_info_json(struct spdk_json_write_ctx *w)
    1359             : {
    1360             :         struct spdk_iscsi_tgt_node *target;
    1361             : 
    1362           0 :         TAILQ_FOREACH(target, &g_iscsi.target_head, tailq) {
    1363           0 :                 iscsi_tgt_node_info_json(target, w);
    1364             :         }
    1365           0 : }
    1366             : 
    1367             : void
    1368           0 : iscsi_tgt_nodes_config_json(struct spdk_json_write_ctx *w)
    1369             : {
    1370             :         struct spdk_iscsi_tgt_node *target;
    1371             : 
    1372           0 :         TAILQ_FOREACH(target, &g_iscsi.target_head, tailq) {
    1373           0 :                 iscsi_tgt_node_config_json(target, w);
    1374             :         }
    1375           0 : }

Generated by: LCOV version 1.15