Patch from Bart Van Assche <bart.vanassche@gmail.com>:
[mirror/scst/.git] / iscsi-scst / usr / isns.c
1 /*
2  * iSNS functions
3  *
4  * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
5  * Copyright (C) 2007 Vladislav Bolkhovitin
6  * Copyright (C) 2007 CMS Distribution Limited
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include <errno.h>
25 #include <netdb.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34
35 #include "iscsid.h"
36 #include "isns_proto.h"
37
38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
39 #define BUFSIZE (1 << 18)
40
41 struct isns_io {
42         char *buf;
43         int offset;
44 };
45
46 struct isns_qry_mgmt {
47         char name[ISCSI_NAME_LEN];
48         uint16_t transaction;
49         struct qelem qlist;
50 };
51
52 struct isns_initiator {
53         char name[ISCSI_NAME_LEN];
54         struct qelem ilist;
55 };
56
57 static LIST_HEAD(qry_list);
58 static uint16_t scn_listen_port;
59 static int use_isns, use_isns_ac, isns_fd, scn_listen_fd, scn_fd;
60 static struct isns_io isns_rx, scn_rx;
61 static char *rxbuf;
62 static uint16_t transaction;
63 static uint32_t current_timeout = 30; /* seconds */
64 static char eid[ISCSI_NAME_LEN];
65 static uint8_t ip[16]; /* SCST iSCSI supports only one portal */
66 static struct sockaddr_storage ss;
67
68 int isns_scn_access(uint32_t tid, int fd, char *name)
69 {
70         struct isns_initiator *ini;
71         struct target *target = target_find_by_id(tid);
72
73         if (!use_isns || !use_isns_ac)
74                 return 0;
75
76         if (!target)
77                 return -EPERM;
78
79         list_for_each_entry(ini, &target->isns_head, ilist) {
80                 if (!strcmp(ini->name, name))
81                         return 0;
82         }
83         return -EPERM;
84 }
85
86 static int isns_get_ip(int fd)
87 {
88         int err, i;
89         uint32_t addr;
90         struct sockaddr_storage lss;
91         socklen_t slen = sizeof(lss);
92
93         err = getsockname(fd, (struct sockaddr *) &lss, &slen);
94         if (err) {
95                 log_error("getsockname error %s!", gai_strerror(err));
96                 return err;
97         }
98
99         err = getnameinfo((struct sockaddr *) &lss, sizeof(lss),
100                           eid, sizeof(eid), NULL, 0, 0);
101         if (err) {
102                 log_error("getaddrinfo error %s!", gai_strerror(err));
103                 return err;
104         }
105
106         switch (lss.ss_family) {
107         case AF_INET:
108                 addr = (((struct sockaddr_in *) &lss)->sin_addr.s_addr);
109
110                 ip[10] = ip[11] = 0xff;
111                 ip[15] = 0xff & (addr >> 24);
112                 ip[14] = 0xff & (addr >> 16);
113                 ip[13] = 0xff & (addr >> 8);
114                 ip[12] = 0xff & addr;
115                 break;
116         case AF_INET6:
117                 for (i = 0; i < ARRAY_SIZE(ip); i++)
118                         ip[i] = ((struct sockaddr_in6 *) &lss)->sin6_addr.s6_addr[i];
119                 break;
120         }
121
122         return 0;
123 }
124
125 static int isns_connect(void)
126 {
127         int fd, err;
128
129         fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
130         if (fd < 0) {
131                 log_error("unable to create (%s) %d!", strerror(errno),
132                           ss.ss_family);
133                 return -1;
134         }
135
136         err = connect(fd, (struct sockaddr *) &ss, sizeof(ss));
137         if (err < 0) {
138                 log_error("unable to connect (%s) %d!", strerror(errno),
139                           ss.ss_family);
140                 close(fd);
141                 return -1;
142         }
143
144         log_error("%s %d: new connection %d", __func__, __LINE__, fd);
145
146         if (!strlen(eid)) {
147                 err = isns_get_ip(fd);
148                 if (err) {
149                         close(fd);
150                         return -1;
151                 }
152         }
153
154         isns_fd = fd;
155         isns_set_fd(fd, scn_listen_fd, scn_fd);
156
157         return fd;
158 }
159
160 static void isns_hdr_init(struct isns_hdr *hdr, uint16_t function,
161                           uint16_t length, uint16_t flags,
162                           uint16_t trans, uint16_t sequence)
163 {
164         hdr->version = htons(0x0001);
165         hdr->function = htons(function);
166         hdr->length = htons(length);
167         hdr->flags = htons(flags);
168         hdr->transaction = htons(trans);
169         hdr->sequence = htons(sequence);
170 }
171
172 static int isns_tlv_set(struct isns_tlv **tlv, uint32_t tag, uint32_t length,
173                         void *value)
174 {
175         if (length)
176                 memcpy((*tlv)->value, value, length);
177         if (length % ISNS_ALIGN)
178                 length += (ISNS_ALIGN - (length % ISNS_ALIGN));
179
180         (*tlv)->tag = htonl(tag);
181         (*tlv)->length = htonl(length);
182
183         length += sizeof(struct isns_tlv);
184         *tlv = (struct isns_tlv *) ((char *) *tlv + length);
185
186         return length;
187 }
188
189 static int isns_scn_deregister(char *name)
190 {
191         int err;
192         uint16_t flags, length = 0;
193         char buf[2048];
194         struct isns_hdr *hdr = (struct isns_hdr *) buf;
195         struct isns_tlv *tlv;
196
197         if (!isns_fd)
198                 if (isns_connect() < 0)
199                         return 0;
200
201         memset(buf, 0, sizeof(buf));
202         tlv = (struct isns_tlv *) hdr->pdu;
203
204         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
205         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
206
207         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
208         isns_hdr_init(hdr, ISNS_FUNC_SCN_DEREG, length, flags,
209                       ++transaction, 0);
210
211         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
212         if (err < 0)
213                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
214
215         return 0;
216 }
217
218 #if __BYTE_ORDER == __LITTLE_ENDIAN
219 #define set_scn_flag(x)                                         \
220 {                                                               \
221         x = (x & 0x55555555) << 1 | (x & 0xaaaaaaaa) >> 1;      \
222         x = (x & 0x33333333) << 2 | (x & 0xcccccccc) >> 2;      \
223         x = (x & 0x0f0f0f0f) << 4 | (x & 0xf0f0f0f0) >> 4;      \
224         x = (x & 0x00ff00ff) << 8 | (x & 0xff00ff00) >> 8;      \
225         x = (x & 0x0000ffff) << 16 | (x & 0xffff0000) >> 16;    \
226 }
227 #else
228 #define set_scn_flag(x) (x)
229 #endif
230
231 static int isns_scn_register(void)
232 {
233         int err;
234         uint16_t flags, length = 0;
235         uint32_t scn_flags;
236         char buf[4096];
237         struct isns_hdr *hdr = (struct isns_hdr *) buf;
238         struct isns_tlv *tlv;
239         struct target *target;
240
241         if (list_empty(&targets_list))
242                 return 0;
243
244         if (!isns_fd)
245                 if (isns_connect() < 0)
246                         return 0;
247
248         memset(buf, 0, sizeof(buf));
249         tlv = (struct isns_tlv *) hdr->pdu;
250
251         target = list_entry(targets_list.q_forw, struct target, tlist);
252
253         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME,
254                                strlen(target->name), target->name);
255         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME,
256                                strlen(target->name), target->name);
257         length += isns_tlv_set(&tlv, 0, 0, 0);
258
259         scn_flags = ISNS_SCN_FLAG_INITIATOR | ISNS_SCN_FLAG_OBJECT_REMOVE |
260                 ISNS_SCN_FLAG_OBJECT_ADDED | ISNS_SCN_FLAG_OBJECT_UPDATED;
261         set_scn_flag(scn_flags);
262         scn_flags = htonl(scn_flags);
263
264         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_SCN_BITMAP,
265                                sizeof(scn_flags), &scn_flags);
266
267         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
268         isns_hdr_init(hdr, ISNS_FUNC_SCN_REG, length, flags, ++transaction, 0);
269
270         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
271         if (err < 0)
272                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
273
274         return 0;
275 }
276
277 static int isns_attr_query(char *name)
278 {
279         int err;
280         uint16_t flags, length = 0;
281         char buf[4096];
282         struct isns_hdr *hdr = (struct isns_hdr *) buf;
283         struct isns_tlv *tlv;
284         struct target *target;
285         uint32_t node = htonl(ISNS_NODE_INITIATOR);
286         struct isns_qry_mgmt *mgmt;
287
288         if (list_empty(&targets_list))
289                 return 0;
290
291         if (!isns_fd)
292                 if (isns_connect() < 0)
293                         return 0;
294
295         mgmt = malloc(sizeof(*mgmt));
296         if (!mgmt)
297                 return 0;
298         insque(&mgmt->qlist, &qry_list);
299
300         memset(buf, 0, sizeof(buf));
301         tlv = (struct isns_tlv *) hdr->pdu;
302
303         if (name)
304                 snprintf(mgmt->name, sizeof(mgmt->name), name);
305         else {
306                 mgmt->name[0] = '\0';
307                 target = list_entry(targets_list.q_forw, struct target, tlist);
308                 name = target->name;
309         }
310
311         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
312         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE,
313                                sizeof(node), &node);
314         length += isns_tlv_set(&tlv, 0, 0, 0);
315         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, 0, 0);
316         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, 0, 0);
317         length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_IP_ADDRESS, 0, 0);
318
319         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
320         isns_hdr_init(hdr, ISNS_FUNC_DEV_ATTR_QRY, length, flags,
321                       ++transaction, 0);
322         mgmt->transaction = transaction;
323
324         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
325         if (err < 0)
326                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
327
328         return 0;
329 }
330
331 static int isns_deregister(void)
332 {
333         int err;
334         uint16_t flags, length = 0;
335         char buf[4096];
336         struct isns_hdr *hdr = (struct isns_hdr *) buf;
337         struct isns_tlv *tlv;
338         struct target *target;
339
340         if (list_empty(&targets_list))
341                 return 0;
342
343         if (!isns_fd)
344                 if (isns_connect() < 0)
345                         return 0;
346
347         memset(buf, 0, sizeof(buf));
348         tlv = (struct isns_tlv *) hdr->pdu;
349
350         target = list_entry(targets_list.q_forw, struct target, tlist);
351
352         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME,
353                                strlen(target->name), target->name);
354         length += isns_tlv_set(&tlv, 0, 0, 0);
355         length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER,
356                                strlen(eid), eid);
357
358         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
359         isns_hdr_init(hdr, ISNS_FUNC_DEV_DEREG, length, flags,
360                       ++transaction, 0);
361
362         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
363         if (err < 0)
364                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
365         return 0;
366 }
367
368 int isns_target_register(char *name)
369 {
370         char buf[4096];
371         uint16_t flags = 0, length = 0;
372         struct isns_hdr *hdr = (struct isns_hdr *) buf;
373         struct isns_tlv *tlv;
374         uint32_t port = htonl(ISCSI_LISTEN_PORT);
375         uint32_t node = htonl(ISNS_NODE_TARGET);
376         uint32_t type = htonl(2);
377         struct target *target;
378         int err, initial = list_length_is_one(&targets_list);
379
380         if (!use_isns)
381                 return 0;
382
383         if (!isns_fd)
384                 if (isns_connect() < 0)
385                         return 0;
386
387         memset(buf, 0, sizeof(buf));
388         tlv = (struct isns_tlv *) hdr->pdu;
389
390         target = list_entry(targets_list.q_back, struct target, tlist);
391         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME,
392                                strlen(target->name), target->name);
393
394         length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER,
395                                strlen(eid), eid);
396
397         length += isns_tlv_set(&tlv, 0, 0, 0);
398         length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER,
399                                strlen(eid), eid);
400         if (initial) {
401                 length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_PROTOCOL,
402                                        sizeof(type), &type);
403                 length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_IP_ADDRESS,
404                                        sizeof(ip), &ip);
405                 length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_PORT,
406                                        sizeof(port), &port);
407                 flags = ISNS_FLAG_REPLACE;
408
409                 if (scn_listen_port) {
410                         uint32_t sport = htonl(scn_listen_port);
411                         length += isns_tlv_set(&tlv, ISNS_ATTR_SCN_PORT,
412                                                sizeof(sport), &sport);
413                 }
414         }
415
416         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
417         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE,
418                                sizeof(node), &node);
419
420         flags |= ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
421         isns_hdr_init(hdr, ISNS_FUNC_DEV_ATTR_REG, length, flags,
422                       ++transaction, 0);
423
424         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
425         if (err < 0)
426                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
427
428         if (scn_listen_port)
429                 isns_scn_register();
430
431         isns_attr_query(name);
432
433         return 0;
434 }
435
436 static void free_all_acl(struct target *target)
437 {
438         struct isns_initiator *ini;
439
440         while (!list_empty(&target->isns_head)) {
441                 ini = list_entry(target->isns_head.q_forw, typeof(*ini), ilist);
442                 remque(&ini->ilist);
443         }
444 }
445
446 static struct target *target_lookup_by_name(char *name)
447 {
448         uint32_t tid;
449
450         tid = target_find_by_name(name);
451         if (!tid)
452                 return NULL;
453         return target_find_by_id(tid);
454 }
455
456 int isns_target_deregister(char *name)
457 {
458         char buf[4096];
459         uint16_t flags, length = 0;
460         struct isns_hdr *hdr = (struct isns_hdr *) buf;
461         struct isns_tlv *tlv;
462         int err, last = list_empty(&targets_list);
463         struct target *target;
464
465         target = target_lookup_by_name(name);
466         if (target)
467                 free_all_acl(target);
468
469         if (!use_isns)
470                 return 0;
471
472         if (!isns_fd)
473                 if (isns_connect() < 0)
474                         return 0;
475
476         isns_scn_deregister(name);
477
478         memset(buf, 0, sizeof(buf));
479         tlv = (struct isns_tlv *) hdr->pdu;
480
481         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
482         length += isns_tlv_set(&tlv, 0, 0, 0);
483         if (last)
484                 length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER,
485                                        strlen(eid), eid);
486         else
487                 length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME,
488                                        strlen(name), name);
489
490         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
491         isns_hdr_init(hdr, ISNS_FUNC_DEV_DEREG, length, flags,
492                       ++transaction, 0);
493
494         err = write(isns_fd, buf, length + sizeof(struct isns_hdr));
495         if (err < 0)
496                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
497
498         return 0;
499 }
500
501 static int recv_hdr(int fd, struct isns_io *rx, struct isns_hdr *hdr)
502 {
503         int err;
504
505         if (rx->offset < sizeof(*hdr)) {
506                 err = read(fd, rx->buf + rx->offset,
507                            sizeof(*hdr) - rx->offset);
508                 if (err < 0) {
509                         if (errno == EAGAIN || errno == EINTR)
510                                 return -EAGAIN;
511                         log_error("header read error %d %d %d %d",
512                                   fd, err, errno, rx->offset);
513                         return -1;
514                 } else if (err == 0)
515                         return -1;
516
517                 log_debug(1, "header %d %d bytes!", fd, err);
518                 rx->offset += err;
519
520                 if (rx->offset < sizeof(*hdr)) {
521                         log_debug(1, "header wait %d %d", rx->offset, err);
522                         return -EAGAIN;
523                 }
524         }
525
526         return 0;
527 }
528
529 #define get_hdr_param(hdr, function, length, flags, transaction, sequence)      \
530 {                                                                               \
531         function = ntohs(hdr->function);                                        \
532         length = ntohs(hdr->length);                                            \
533         flags = ntohs(hdr->flags);                                              \
534         transaction = ntohs(hdr->transaction);                                  \
535         sequence = ntohs(hdr->sequence);                                        \
536 }
537
538 static int recv_pdu(int fd, struct isns_io *rx, struct isns_hdr *hdr)
539 {
540         uint16_t function, length, flags, transaction, sequence;
541         int err;
542
543         err = recv_hdr(fd, rx, hdr);
544         if (err)
545                 return err;
546
547         /* Now we got a complete header */
548         get_hdr_param(hdr, function, length, flags, transaction, sequence);
549         log_debug(1, "got a header %x %u %x %u %u", function, length, flags,
550                   transaction, sequence);
551
552         if (length + sizeof(*hdr) > BUFSIZE) {
553                 log_error("FIXME we cannot handle this yet %u!", length);
554                 return -1;
555         }
556
557         if (rx->offset < length + sizeof(*hdr)) {
558                 err = read(fd, rx->buf + rx->offset,
559                            length + sizeof(*hdr) - rx->offset);
560                 if (err < 0) {
561                         if (errno == EAGAIN || errno == EINTR)
562                                 return -EAGAIN;
563                         log_error("pdu read error %d %d %d %d",
564                                   fd, err, errno, rx->offset);
565                         return -1;
566                 } else if (err == 0)
567                         return -1;
568
569                 log_debug(1, "pdu %u %u", fd, err);
570                 rx->offset += err;
571
572                 if (rx->offset < length + sizeof(*hdr)) {
573                         log_error("pdu wait %d %d", rx->offset, err);
574                         return -EAGAIN;
575                 }
576         }
577
578         /* Now we got everything. */
579         rx->offset = 0;
580
581         return 0;
582 }
583
584 #define print_unknown_pdu(hdr)                                          \
585 {                                                                       \
586         uint16_t function, length, flags, transaction, sequence;        \
587         get_hdr_param(hdr, function, length, flags, transaction,        \
588                       sequence)                                         \
589         log_error("%s %d: unknown function %x %u %x %u %u",             \
590                   __func__, __LINE__,                           \
591                   function, length, flags, transaction, sequence);      \
592 }
593
594 static char *print_scn_pdu(struct isns_hdr *hdr)
595 {
596         struct isns_tlv *tlv = (struct isns_tlv *) hdr->pdu;
597         uint16_t function, length, flags, transaction, sequence;
598         char *name = NULL;
599
600         get_hdr_param(hdr, function, length, flags, transaction, sequence);
601
602         while (length) {
603                 uint32_t vlen = ntohl(tlv->length);
604
605                 switch (ntohl(tlv->tag)) {
606                 case ISNS_ATTR_ISCSI_NAME:
607                         log_error("scn name: %u, %s", vlen, (char *) tlv->value);
608                         if (!name)
609                                 name = (char *) tlv->value;
610                         break;
611                 case ISNS_ATTR_TIMESTAMP:
612 /*                      log_error("%u : %u : %" PRIx64, ntohl(tlv->tag), vlen, */
613 /*                                *((uint64_t *) tlv->value)); */
614                         break;
615                 case ISNS_ATTR_ISCSI_SCN_BITMAP:
616                         log_error("scn bitmap : %x", *((uint32_t *) tlv->value));
617                         break;
618                 }
619
620                 length -= (sizeof(*tlv) + vlen);
621                 tlv = (struct isns_tlv *) ((char *) tlv->value + vlen);
622         }
623
624         return name;
625 }
626
627 static void qry_rsp_handle(struct isns_hdr *hdr)
628 {
629         struct isns_tlv *tlv;
630         uint16_t function, length, flags, transaction, sequence;
631         uint32_t status = (uint32_t) (*hdr->pdu);
632         struct isns_qry_mgmt *mgmt, *n;
633         struct target *target;
634         struct isns_initiator *ini;
635         char *name = NULL;
636
637         get_hdr_param(hdr, function, length, flags, transaction, sequence);
638
639         list_for_each_entry_safe(mgmt, n, &qry_list, qlist) {
640                 if (mgmt->transaction == transaction) {
641                         remque(&mgmt->qlist);
642                         goto found;
643                 }
644         }
645
646         log_error("%s %d: transaction not found %u",
647                   __func__, __LINE__, transaction);
648
649         return;
650 found:
651
652         if (status) {
653                 log_error("%s %d: error response %u",
654                           __func__, __LINE__, status);
655
656                 goto free_qry_mgmt;
657         }
658
659         if (!strlen(mgmt->name)) {
660                 log_debug(1, "%s %d: skip %u",
661                           __func__, __LINE__, transaction);
662                 goto free_qry_mgmt;
663         }
664
665         target = target_lookup_by_name(mgmt->name);
666         if (!target) {
667                 log_error("%s %d: invalid tid %s",
668                           __func__, __LINE__, mgmt->name);
669                 goto free_qry_mgmt;
670         }
671
672         free_all_acl(target);
673
674         /* skip status */
675         tlv = (struct isns_tlv *) ((char *) hdr->pdu + 4);
676         length -= 4;
677
678         while (length) {
679                 uint32_t vlen = ntohl(tlv->length);
680
681                 switch (ntohl(tlv->tag)) {
682                 case ISNS_ATTR_ISCSI_NAME:
683                         name = (char *) tlv->value;
684                         break;
685                 case ISNS_ATTR_ISCSI_NODE_TYPE:
686                         if (ntohl(*(tlv->value)) == ISNS_NODE_INITIATOR && name) {
687                                 log_error("%s %d: %s", __func__, __LINE__,
688                                           (char *) name);
689                                 ini = malloc(sizeof(*ini));
690                                 if (!ini)
691                                         goto free_qry_mgmt;
692                                 snprintf(ini->name, sizeof(ini->name), name);
693                                 insque(&ini->ilist, &target->isns_head);
694                         } else
695                                 name = NULL;
696                         break;
697                 default:
698                         name = NULL;
699                         break;
700                 }
701
702                 length -= (sizeof(*tlv) + vlen);
703                 tlv = (struct isns_tlv *) ((char *) tlv->value + vlen);
704         }
705
706 free_qry_mgmt:
707         free(mgmt);
708 }
709
710 int isns_handle(int is_timeout, int *timeout)
711 {
712         int err;
713         struct isns_io *rx = &isns_rx;
714         struct isns_hdr *hdr = (struct isns_hdr *) rx->buf;
715         uint32_t result;
716         uint16_t function, length, flags, transaction, sequence;
717         char *name = NULL;
718
719         if (is_timeout)
720                 return isns_attr_query(NULL);
721
722         err = recv_pdu(isns_fd, rx, hdr);
723         if (err) {
724                 if (err == -EAGAIN)
725                         return err;
726                 log_debug(1, "%s %d: close connection %d", __func__, __LINE__,
727                           isns_fd);
728                 close(isns_fd);
729                 isns_fd = 0;
730                 isns_set_fd(0, scn_listen_fd, scn_fd);
731                 return err;
732         }
733
734         get_hdr_param(hdr, function, length, flags, transaction, sequence);
735         result = ntohl((uint32_t) hdr->pdu[0]);
736
737         switch (function) {
738         case ISNS_FUNC_DEV_ATTR_REG_RSP:
739                 break;
740         case ISNS_FUNC_DEV_ATTR_QRY_RSP:
741                 qry_rsp_handle(hdr);
742                 break;
743         case ISNS_FUNC_DEV_DEREG_RSP:
744         case ISNS_FUNC_SCN_REG_RSP:
745                 break;
746         case ISNS_FUNC_SCN:
747                 name = print_scn_pdu(hdr);
748                 if (name) {
749                         log_error("%s %d: %s", __func__, __LINE__, name);
750                         isns_attr_query(name);
751                 }
752                 break;
753         default:
754                 print_unknown_pdu(hdr);
755         }
756
757         return 0;
758 }
759
760 static int scn_accept_connection(void)
761 {
762         struct sockaddr_storage from;
763         socklen_t slen;
764         int fd, err, opt = 1;
765
766         slen = sizeof(from);
767         fd = accept(scn_listen_fd, (struct sockaddr *) &from, &slen);
768         if (fd < 0) {
769                 log_error("%s %d: accept error %s", __func__, __LINE__,
770                           strerror(errno));
771                 return -errno;
772         }
773         log_error("Accept scn connection %d", fd);
774
775         err = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
776         if (err)
777                 log_error("%s %d: %s\n", __func__, __LINE__,
778                           strerror(errno));
779         /* not critical, so ignore. */
780
781         scn_fd = fd;
782         isns_set_fd(isns_fd, scn_listen_fd, scn_fd);
783
784         return 0;
785 }
786
787 static void send_scn_rsp(char *name, uint16_t transaction)
788 {
789         char buf[1024];
790         struct isns_hdr *hdr = (struct isns_hdr *) buf;
791         struct isns_tlv *tlv;
792         uint16_t flags, length = 0;
793         int err;
794
795         memset(buf, 0, sizeof(buf));
796         *((uint32_t *) hdr->pdu) = 0;
797         tlv = (struct isns_tlv *) ((char *) hdr->pdu + 4);
798         length +=4;
799
800         length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name);
801
802         flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU;
803         isns_hdr_init(hdr, ISNS_FUNC_SCN_RSP, length, flags, transaction, 0);
804
805         err = write(scn_fd, buf, length + sizeof(struct isns_hdr));
806         if (err < 0)
807                 log_error("%s %d: %s", __func__, __LINE__, strerror(errno));
808 }
809
810 int isns_scn_handle(int is_accept)
811 {
812         int err;
813         struct isns_io *rx = &scn_rx;
814         struct isns_hdr *hdr = (struct isns_hdr *) rx->buf;
815         uint16_t function, length, flags, transaction, sequence;
816         char *name = NULL;
817
818         log_error("%s %d: %d", __func__, __LINE__, is_accept);
819
820         if (is_accept)
821                 return scn_accept_connection();
822
823         err = recv_pdu(scn_fd, rx, hdr);
824         if (err) {
825                 if (err == -EAGAIN)
826                         return err;
827                 log_debug(1, "%s %d: close connection %d", __func__, __LINE__,
828                           scn_fd);
829                 close(scn_fd);
830                 scn_fd = 0;
831                 isns_set_fd(isns_fd, scn_listen_fd, 0);
832                 return err;
833         }
834
835         get_hdr_param(hdr, function, length, flags, transaction, sequence);
836
837         switch (function) {
838         case ISNS_FUNC_SCN:
839                 name = print_scn_pdu(hdr);
840                 break;
841         default:
842                 print_unknown_pdu(hdr);
843         }
844
845         if (name) {
846                 send_scn_rsp(name, transaction);
847                 isns_attr_query(name);
848         }
849
850         return 0;
851 }
852
853 static int scn_init(char *addr)
854 {
855         int fd, opt, err;
856         struct sockaddr_storage lss;
857         socklen_t slen;
858
859         fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
860         if (fd < 0) {
861                 log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
862                 return -errno;
863         }
864
865         opt = 1;
866         if (ss.ss_family == AF_INET6) {
867                 err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
868                 if (err)
869                         log_error("%s %d: %s\n", __func__, __LINE__,
870                                   strerror(errno));
871                 goto out;
872         }
873
874         err = listen(fd, 5);
875         if (err) {
876                 log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
877                 goto out;
878         }
879
880         slen = sizeof(lss);
881         err = getsockname(fd, (struct sockaddr *) &lss, &slen);
882         if (err) {
883                 log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
884                 goto out;
885         }
886
887         /* protocol independent way ? */
888         if (lss.ss_family == AF_INET6)
889                 scn_listen_port = ntohs(((struct sockaddr_in6 *) &lss)->sin6_port);
890         else
891                 scn_listen_port = ntohs(((struct sockaddr_in *) &lss)->sin_port);
892
893         log_error("scn listen port %u %d %d\n", scn_listen_port, fd, err);
894 out:
895         if (err)
896                 close(fd);
897         else {
898                 scn_listen_fd = fd;
899                 isns_set_fd(isns_fd, scn_listen_fd, scn_fd);
900         }
901
902         return err;
903 }
904
905 int isns_init(char *addr, int isns_ac)
906 {
907         int err;
908         char port[8];
909         struct addrinfo hints, *res;
910
911         snprintf(port, sizeof(port), "%d", ISNS_PORT);
912         memset(&hints, 0, sizeof(hints));
913         hints.ai_socktype = SOCK_STREAM;
914         err = getaddrinfo(addr, (char *) &port, &hints, &res);
915         if (err) {
916                 log_error("getaddrinfo error %s, %s", gai_strerror(err), addr);
917                 return -1;
918         }
919         memcpy(&ss, res->ai_addr, sizeof(ss));
920         freeaddrinfo(res);
921
922         rxbuf = calloc(2, BUFSIZE);
923         if (!rxbuf) {
924                 log_error("oom!");
925                 return -1;
926         }
927
928         scn_init(addr);
929
930         isns_rx.buf = rxbuf;
931         isns_rx.offset = 0;
932         scn_rx.buf = rxbuf + BUFSIZE;
933         scn_rx.offset = 0;
934
935         use_isns = 1;
936         use_isns_ac = isns_ac;
937
938         return current_timeout * 1000;
939 }
940
941 void isns_exit(void)
942 {
943         struct target *target;
944
945         if (!use_isns)
946                 return;
947
948         list_for_each_entry(target, &targets_list, tlist)
949                 isns_scn_deregister(target->name);
950
951         isns_deregister();
952         /* we can't receive events any more. */
953         isns_set_fd(0, 0, 0);
954
955         if (isns_fd)
956                 close(isns_fd);
957         if (scn_listen_fd)
958                 close(scn_listen_fd);
959         if (scn_fd)
960                 close(scn_fd);
961
962         free(rxbuf);
963 }