1171568Sscottl/*- 2211095Sdes * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il> 3171568Sscottl * All rights reserved. 4171568Sscottl * 5171568Sscottl * Redistribution and use in source and binary forms, with or without 6171568Sscottl * modification, are permitted provided that the following conditions 7171568Sscottl * are met: 8171568Sscottl * 1. Redistributions of source code must retain the above copyright 9171568Sscottl * notice, this list of conditions and the following disclaimer. 10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11171568Sscottl * notice, this list of conditions and the following disclaimer in the 12171568Sscottl * documentation and/or other materials provided with the distribution. 13171568Sscottl * 14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17171568Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24171568Sscottl * SUCH DAMAGE. 25171568Sscottl * 26171568Sscottl */ 27171568Sscottl/* 28171568Sscottl | $Id: iscontrol.c,v 2.2 2006/12/01 09:11:56 danny Exp danny $ 29171568Sscottl */ 30171568Sscottl/* 31171568Sscottl | the user level initiator (client) 32171568Sscottl */ 33171568Sscottl 34171568Sscottl#include <sys/cdefs.h> 35171568Sscottl__FBSDID("$FreeBSD$"); 36171568Sscottl 37171568Sscottl#include <sys/param.h> 38171568Sscottl#include <sys/types.h> 39171568Sscottl#include <sys/socket.h> 40171568Sscottl#include <sys/sysctl.h> 41171568Sscottl 42171568Sscottl#include <netinet/in.h> 43171568Sscottl#include <netinet/tcp.h> 44171568Sscottl#include <arpa/inet.h> 45171568Sscottl#include <sys/ioctl.h> 46171568Sscottl#include <netdb.h> 47234425Sjpaetzel#include <err.h> 48234425Sjpaetzel#include <errno.h> 49234425Sjpaetzel#include <fcntl.h> 50234425Sjpaetzel#include <libgen.h> 51234425Sjpaetzel#include <stdio.h> 52171568Sscottl#include <stdlib.h> 53171568Sscottl#include <string.h> 54171568Sscottl#include <time.h> 55234425Sjpaetzel#include <unistd.h> 56171568Sscottl#include <camlib.h> 57171568Sscottl 58254657Strasz#include <dev/iscsi_initiator/iscsi.h> 59171568Sscottl#include "iscontrol.h" 60171568Sscottl 61234233Sjpaetzelstatic char version[] = "2.3.1"; // keep in sync with iscsi_initiator 62234233Sjpaetzel 63211095Sdes#define USAGE "[-v] [-d] [-c config] [-n name] [-t target] [-p pidfile]" 64211095Sdes#define OPTIONS "vdc:t:n:p:" 65171568Sscottl 66171568Sscottltoken_t AuthMethods[] = { 67171568Sscottl {"None", NONE}, 68171568Sscottl {"KRB5", KRB5}, 69171568Sscottl {"SPKM1", SPKM1}, 70171568Sscottl {"SPKM2", SPKM2}, 71171568Sscottl {"SRP", SRP}, 72171568Sscottl {"CHAP", CHAP}, 73211095Sdes {0, 0} 74171568Sscottl}; 75171568Sscottl 76171568Sscottltoken_t DigestMethods[] = { 77171568Sscottl {"None", 0}, 78171568Sscottl {"CRC32", 1}, 79171568Sscottl {"CRC32C", 1}, 80211095Sdes {0, 0} 81171568Sscottl}; 82171568Sscottl 83171568Sscottlu_char isid[6 + 6]; 84171568Sscottl/* 85171568Sscottl | Default values 86171568Sscottl */ 87171568Sscottlisc_opt_t opvals = { 88171568Sscottl .port = 3260, 89171568Sscottl .sockbufsize = 128, 90171568Sscottl .iqn = "iqn.2005-01.il.ac.huji.cs:", 91171568Sscottl 92171568Sscottl .sessionType = "Normal", 93171568Sscottl .targetAddress = 0, 94171568Sscottl .targetName = 0, 95171568Sscottl .initiatorName = 0, 96171568Sscottl .authMethod = "None", 97171568Sscottl .headerDigest = "None,CRC32C", 98171568Sscottl .dataDigest = "None,CRC32C", 99171568Sscottl .maxConnections = 1, 100171568Sscottl .maxRecvDataSegmentLength = 64 * 1024, 101171568Sscottl .maxXmitDataSegmentLength = 8 * 1024, // 64 * 1024, 102171568Sscottl .maxBurstLength = 128 * 1024, 103171568Sscottl .firstBurstLength = 64 * 1024, // must be less than maxBurstLength 104171568Sscottl .defaultTime2Wait = 0, 105171568Sscottl .defaultTime2Retain = 0, 106171568Sscottl .maxOutstandingR2T = 1, 107171568Sscottl .errorRecoveryLevel = 0, 108171568Sscottl 109171568Sscottl .dataPDUInOrder = TRUE, 110171568Sscottl .dataSequenceInOrder = TRUE, 111171568Sscottl 112171568Sscottl .initialR2T = TRUE, 113171568Sscottl .immediateData = TRUE, 114171568Sscottl}; 115171568Sscottl 116234425Sjpaetzelstatic void 117234425Sjpaetzelusage(const char *pname) 118234425Sjpaetzel{ 119234425Sjpaetzel fprintf(stderr, "usage: %s " USAGE "\n", pname); 120234425Sjpaetzel exit(1); 121234425Sjpaetzel} 122234425Sjpaetzel 123171568Sscottlint 124171568Sscottllookup(token_t *tbl, char *m) 125171568Sscottl{ 126171568Sscottl token_t *tp; 127171568Sscottl 128171568Sscottl for(tp = tbl; tp->name != NULL; tp++) 129171568Sscottl if(strcasecmp(tp->name, m) == 0) 130171568Sscottl return tp->val; 131171568Sscottl return 0; 132171568Sscottl} 133171568Sscottl 134171568Sscottlint 135171568Sscottlmain(int cc, char **vv) 136171568Sscottl{ 137171568Sscottl int ch, disco; 138234233Sjpaetzel char *pname, *pidfile, *p, *q, *ta, *kw, *v; 139171568Sscottl isc_opt_t *op; 140171568Sscottl FILE *fd; 141234233Sjpaetzel size_t n; 142171568Sscottl 143171568Sscottl op = &opvals; 144171568Sscottl iscsidev = "/dev/"ISCSIDEV; 145171568Sscottl fd = NULL; 146171568Sscottl pname = vv[0]; 147234425Sjpaetzel if ((pname = basename(pname)) == NULL) 148234425Sjpaetzel err(1, "basename"); 149171568Sscottl 150171568Sscottl kw = ta = 0; 151171568Sscottl disco = 0; 152211095Sdes pidfile = NULL; 153234233Sjpaetzel /* 154234233Sjpaetzel | check for driver & controller version match 155234233Sjpaetzel */ 156234233Sjpaetzel n = 0; 157234425Sjpaetzel#define VERSION_OID_S "net.iscsi_initiator.driver_version" 158234425Sjpaetzel if (sysctlbyname(VERSION_OID_S, 0, &n, 0, 0) != 0) { 159234425Sjpaetzel if (errno == ENOENT) 160234425Sjpaetzel errx(1, "sysctlbyname(\"" VERSION_OID_S "\") " 161234425Sjpaetzel "failed; is the iscsi driver loaded?"); 162234425Sjpaetzel err(1, "sysctlbyname(\"" VERSION_OID_S "\")"); 163234425Sjpaetzel } 164234233Sjpaetzel v = malloc(n+1); 165234425Sjpaetzel if (v == NULL) 166234425Sjpaetzel err(1, "malloc"); 167234425Sjpaetzel if (sysctlbyname(VERSION_OID_S, v, &n, 0, 0) != 0) 168234425Sjpaetzel err(1, "sysctlbyname"); 169171568Sscottl 170234425Sjpaetzel if (strncmp(version, v, 3) != 0) 171234425Sjpaetzel errx(1, "versions mismatch"); 172234233Sjpaetzel 173171568Sscottl while((ch = getopt(cc, vv, OPTIONS)) != -1) { 174171568Sscottl switch(ch) { 175171568Sscottl case 'v': 176171568Sscottl vflag++; 177171568Sscottl break; 178171568Sscottl case 'c': 179171568Sscottl fd = fopen(optarg, "r"); 180234425Sjpaetzel if (fd == NULL) 181234425Sjpaetzel err(1, "fopen(\"%s\")", optarg); 182171568Sscottl break; 183171568Sscottl case 'd': 184171568Sscottl disco = 1; 185171568Sscottl break; 186171568Sscottl case 't': 187171568Sscottl ta = optarg; 188171568Sscottl break; 189171568Sscottl case 'n': 190171568Sscottl kw = optarg; 191171568Sscottl break; 192211095Sdes case 'p': 193211095Sdes pidfile = optarg; 194211095Sdes break; 195171568Sscottl default: 196234425Sjpaetzel usage(pname); 197171568Sscottl } 198171568Sscottl } 199171568Sscottl if(fd == NULL) 200171568Sscottl fd = fopen("/etc/iscsi.conf", "r"); 201171568Sscottl 202171568Sscottl if(fd != NULL) { 203171568Sscottl parseConfig(fd, kw, op); 204171568Sscottl fclose(fd); 205171568Sscottl } 206171568Sscottl cc -= optind; 207171568Sscottl vv += optind; 208171568Sscottl if(cc > 0) { 209171568Sscottl if(vflag) 210171568Sscottl printf("adding '%s'\n", *vv); 211171568Sscottl parseArgs(cc, vv, op); 212171568Sscottl } 213171568Sscottl if(ta) 214171568Sscottl op->targetAddress = ta; 215171568Sscottl 216171568Sscottl if(op->targetAddress == NULL) { 217234425Sjpaetzel warnx("no target specified!"); 218234425Sjpaetzel usage(pname); 219171568Sscottl } 220185289Sscottl q = op->targetAddress; 221185289Sscottl if(*q == '[' && (q = strchr(q, ']')) != NULL) { 222185289Sscottl *q++ = '\0'; 223185289Sscottl op->targetAddress++; 224185289Sscottl } else 225185289Sscottl q = op->targetAddress; 226185289Sscottl if((p = strchr(q, ':')) != NULL) { 227171568Sscottl *p++ = 0; 228171568Sscottl op->port = atoi(p); 229171568Sscottl p = strchr(p, ','); 230171568Sscottl } 231185289Sscottl if(p || ((p = strchr(q, ',')) != NULL)) { 232171568Sscottl *p++ = 0; 233171568Sscottl op->targetPortalGroupTag = atoi(p); 234171568Sscottl } 235171568Sscottl if(op->initiatorName == 0) { 236234425Sjpaetzel char hostname[MAXHOSTNAMELEN]; 237171568Sscottl 238171568Sscottl if(op->iqn) { 239171568Sscottl if(gethostname(hostname, sizeof(hostname)) == 0) 240171568Sscottl asprintf(&op->initiatorName, "%s:%s", op->iqn, hostname); 241171568Sscottl else 242171568Sscottl asprintf(&op->initiatorName, "%s:%d", op->iqn, (int)time(0) & 0xff); // XXX: 243171568Sscottl } 244171568Sscottl else { 245171568Sscottl if(gethostname(hostname, sizeof(hostname)) == 0) 246171568Sscottl asprintf(&op->initiatorName, "%s", hostname); 247171568Sscottl else 248171568Sscottl asprintf(&op->initiatorName, "%d", (int)time(0) & 0xff); // XXX: 249171568Sscottl } 250171568Sscottl } 251171568Sscottl if(disco) { 252171568Sscottl op->sessionType = "Discovery"; 253171568Sscottl op->targetName = 0; 254171568Sscottl } 255211095Sdes op->pidfile = pidfile; 256171568Sscottl fsm(op); 257171568Sscottl 258171568Sscottl exit(0); 259171568Sscottl} 260