?? isns.c
字號:
/* * iSNS functions * * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */#include <errno.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <sys/socket.h>#include <sys/types.h>#include "iscsid.h"#include "isns_proto.h"#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))#define BUFSIZE (1 << 18)struct isns_io { char *buf; int offset;};struct isns_qry_mgmt { char name[ISCSI_NAME_LEN]; uint16_t transaction; struct qelem qlist;};struct isns_initiator { char name[ISCSI_NAME_LEN]; struct qelem ilist;};static LIST_HEAD(qry_list);static uint16_t scn_listen_port;static int use_isns, use_isns_ac, isns_fd, scn_listen_fd, scn_fd;static struct isns_io isns_rx, scn_rx;static char *rxbuf;static uint16_t transaction;static uint32_t current_timeout = 30; /* seconds */static char eid[ISCSI_NAME_LEN];static uint8_t ip[16]; /* IET supoprts only one portal */static struct sockaddr_storage ss;int isns_scn_access(uint32_t tid, int fd, char *name){ struct isns_initiator *ini; struct target *target = target_find_by_id(tid); if (!use_isns || !use_isns_ac) return 0; if (!target) return -EPERM; list_for_each_entry(ini, &target->isns_head, ilist) { if (!strcmp(ini->name, name)) return 0; } return -EPERM;}static int isns_get_ip(int fd){ int err, i; uint32_t addr; struct sockaddr_storage lss; socklen_t slen = sizeof(lss); err = getsockname(fd, (struct sockaddr *) &lss, &slen); if (err) { log_error("getsockname error %s!", gai_strerror(err)); return err; } err = getnameinfo((struct sockaddr *) &lss, sizeof(lss), eid, sizeof(eid), NULL, 0, 0); if (err) { log_error("getaddrinfo error %s!", gai_strerror(err)); return err; } switch (lss.ss_family) { case AF_INET: addr = (((struct sockaddr_in *) &lss)->sin_addr.s_addr); ip[10] = ip[11] = 0xff; ip[15] = 0xff & (addr >> 24); ip[14] = 0xff & (addr >> 16); ip[13] = 0xff & (addr >> 8); ip[12] = 0xff & addr; break; case AF_INET6: for (i = 0; i < ARRAY_SIZE(ip); i++) ip[i] = ((struct sockaddr_in6 *) &lss)->sin6_addr.s6_addr[i]; break; } return 0;}static int isns_connect(void){ int fd, err; fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { log_error("unable to create (%s) %d!", strerror(errno), ss.ss_family); return -1; } err = connect(fd, (struct sockaddr *) &ss, sizeof(ss)); if (err < 0) { log_error("unable to connect (%s) %d!", strerror(errno), ss.ss_family); close(fd); return -1; } log_error("%s %d: new connection %d", __FUNCTION__, __LINE__, fd); if (!strlen(eid)) { err = isns_get_ip(fd); if (err) { close(fd); return -1; } } isns_fd = fd; isns_set_fd(fd, scn_listen_fd, scn_fd); return fd;}static void isns_hdr_init(struct isns_hdr *hdr, uint16_t function, uint16_t length, uint16_t flags, uint16_t trans, uint16_t sequence){ hdr->version = htons(0x0001); hdr->function = htons(function); hdr->length = htons(length); hdr->flags = htons(flags); hdr->transaction = htons(trans); hdr->sequence = htons(sequence);}static int isns_tlv_set(struct isns_tlv **tlv, uint32_t tag, uint32_t length, void *value){ if (length) memcpy((*tlv)->value, value, length); if (length % ISNS_ALIGN) length += (ISNS_ALIGN - (length % ISNS_ALIGN)); (*tlv)->tag = htonl(tag); (*tlv)->length = htonl(length); length += sizeof(struct isns_tlv); *tlv = (struct isns_tlv *) ((char *) *tlv + length); return length;}static int isns_scn_deregister(char *name){ int err; uint16_t flags, length = 0; char buf[2048]; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; if (!isns_fd) if (isns_connect() < 0) return 0; memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_SCN_DEREG, length, flags, ++transaction, 0); err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __FUNCTION__, __LINE__, strerror(errno)); return 0;}#if __BYTE_ORDER == __LITTLE_ENDIAN#define set_scn_flag(x) \{ \ x = (x & 0x55555555) << 1 | (x & 0xaaaaaaaa) >> 1; \ x = (x & 0x33333333) << 2 | (x & 0xcccccccc) >> 2; \ x = (x & 0x0f0f0f0f) << 4 | (x & 0xf0f0f0f0) >> 4; \ x = (x & 0x00ff00ff) << 8 | (x & 0xff00ff00) >> 8; \ x = (x & 0x0000ffff) << 16 | (x & 0xffff0000) >> 16; \}#else#define set_scn_flag(x) (x)#endifstatic int isns_scn_register(void){ int err; uint16_t flags, length = 0; uint32_t scn_flags; char buf[4096]; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; struct target *target; if (list_empty(&targets_list)) return 0; if (!isns_fd) if (isns_connect() < 0) return 0; memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; target = list_entry(targets_list.q_forw, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(target->name), target->name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(target->name), target->name); length += isns_tlv_set(&tlv, 0, 0, 0); scn_flags = ISNS_SCN_FLAG_INITIATOR | ISNS_SCN_FLAG_OBJECT_REMOVE | ISNS_SCN_FLAG_OBJECT_ADDED | ISNS_SCN_FLAG_OBJECT_UPDATED; scn_flags = htonl(set_scn_flag(scn_flags)); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_SCN_BITMAP, sizeof(scn_flags), &scn_flags); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_SCN_REG, length, flags, ++transaction, 0); err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __FUNCTION__, __LINE__, strerror(errno)); return 0;}static int isns_attr_query(char *name){ int err; uint16_t flags, length = 0; char buf[4096]; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; struct target *target; uint32_t node = htonl(ISNS_NODE_INITIATOR); struct isns_qry_mgmt *mgmt; if (list_empty(&targets_list)) return 0; if (!isns_fd) if (isns_connect() < 0) return 0; mgmt = malloc(sizeof(*mgmt)); if (!mgmt) return 0; insque(&mgmt->qlist, &qry_list); memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; if (name) snprintf(mgmt->name, sizeof(mgmt->name), name); else { mgmt->name[0] = '\0'; target = list_entry(targets_list.q_forw, struct target, tlist); name = target->name; } length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, sizeof(node), &node); length += isns_tlv_set(&tlv, 0, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_IP_ADDRESS, 0, 0); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_DEV_ATTR_QRY, length, flags, ++transaction, 0); mgmt->transaction = transaction; err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __FUNCTION__, __LINE__, strerror(errno)); return 0;}static int isns_deregister(void){ int err; uint16_t flags, length = 0; char buf[4096]; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; struct target *target; if (list_empty(&targets_list)) return 0; if (!isns_fd) if (isns_connect() < 0) return 0; memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; target = list_entry(targets_list.q_forw, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(target->name), target->name); length += isns_tlv_set(&tlv, 0, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, strlen(eid), eid); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_DEV_DEREG, length, flags, ++transaction, 0); err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __FUNCTION__, __LINE__, strerror(errno)); return 0;}int isns_target_register(char *name){ char buf[4096]; uint16_t flags = 0, length = 0; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; uint32_t port = htonl(ISCSI_LISTEN_PORT); uint32_t node = htonl(ISNS_NODE_TARGET); uint32_t type = htonl(2); struct target *target; int err, initial = list_length_is_one(&targets_list); if (!use_isns) return 0; if (!isns_fd) if (isns_connect() < 0) return 0; memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; target = list_entry(targets_list.q_back, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(target->name), target->name); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, strlen(eid), eid); length += isns_tlv_set(&tlv, 0, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, strlen(eid), eid); if (initial) { length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_PROTOCOL, sizeof(type), &type); length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_IP_ADDRESS, sizeof(ip), &ip); length += isns_tlv_set(&tlv, ISNS_ATTR_PORTAL_PORT, sizeof(port), &port); flags = ISNS_FLAG_REPLACE; if (scn_listen_port) { uint32_t sport = htonl(scn_listen_port); length += isns_tlv_set(&tlv, ISNS_ATTR_SCN_PORT, sizeof(sport), &sport); } } length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, sizeof(node), &node); flags |= ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_DEV_ATTR_REG, length, flags, ++transaction, 0); err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __FUNCTION__, __LINE__, strerror(errno)); if (scn_listen_port) isns_scn_register(); isns_attr_query(name); return 0;}static void free_all_acl(struct target *target){ struct isns_initiator *ini; while (!list_empty(&target->isns_head)) { ini = list_entry(target->isns_head.q_forw, typeof(*ini), ilist); remque(&ini->ilist); }}static struct target *target_lookup_by_name(char *name){ uint32_t tid; tid = target_find_by_name(name); if (!tid) return NULL; return target_find_by_id(tid);}int isns_target_deregister(char *name){ char buf[4096]; uint16_t flags, length = 0; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; int err, last = list_empty(&targets_list); struct target *target; target = target_lookup_by_name(name); if (target) free_all_acl(target); if (!use_isns) return 0; if (!isns_fd) if (isns_connect() < 0) return 0; isns_scn_deregister(name); memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); length += isns_tlv_set(&tlv, 0, 0, 0); if (last) length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -