GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/iscsictl/parse.y Lines: 0 244 0.0 %
Date: 2017-11-13 Branches: 0 189 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.y,v 1.10 2017/01/05 13:53:09 krw Exp $ */
2
3
/*
4
 * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
5
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7
 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
9
 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
10
 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
11
 *
12
 * Permission to use, copy, modify, and distribute this software for any
13
 * purpose with or without fee is hereby granted, provided that the above
14
 * copyright notice and this permission notice appear in all copies.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
 */
24
25
%{
26
#include <sys/types.h>
27
#include <sys/queue.h>
28
#include <sys/socket.h>
29
#include <sys/stat.h>
30
#include <sys/uio.h>
31
#include <netinet/in.h>
32
#include <arpa/inet.h>
33
#include <ctype.h>
34
#include <err.h>
35
#include <errno.h>
36
#include <event.h>
37
#include <limits.h>
38
#include <netdb.h>
39
#include <stdarg.h>
40
#include <stdio.h>
41
#include <string.h>
42
#include <unistd.h>
43
44
#include <scsi/iscsi.h>
45
#include "iscsid.h"
46
#include "iscsictl.h"
47
48
TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
49
static struct file {
50
	TAILQ_ENTRY(file)	 entry;
51
	FILE			*stream;
52
	char			*name;
53
	int			 lineno;
54
	int			 errors;
55
} *file, *topfile;
56
struct file	*pushfile(const char *, int);
57
int		 popfile(void);
58
int		 yyparse(void);
59
int		 yylex(void);
60
int		 yyerror(const char *, ...)
61
    __attribute__((__format__ (printf, 1, 2)))
62
    __attribute__((__nonnull__ (1)));
63
int		 kw_cmp(const void *, const void *);
64
int		 lookup(char *);
65
int		 lgetc(int);
66
int		 lungetc(int);
67
int		 findeol(void);
68
69
void		 clear_config(struct iscsi_config *);
70
71
TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
72
struct sym {
73
	TAILQ_ENTRY(sym)	 entry;
74
	int			 used;
75
	int			 persist;
76
	char			*nam;
77
	char			*val;
78
};
79
int		 symset(const char *, const char *, int);
80
char		*symget(const char *);
81
82
static int			 errors;
83
static struct iscsi_config	*conf;
84
static struct session_config	*session;
85
86
struct addrinfo_opts {
87
	int	af;
88
	char	*port;
89
} addrinfo_opts;
90
91
typedef struct {
92
	union {
93
		int			 i;
94
		int64_t			 number;
95
		char			*string;
96
		struct addrinfo_opts	 addrinfo_opts;
97
		struct addrinfo		*addrinfo;
98
	} v;
99
	int lineno;
100
} YYSTYPE;
101
102
%}
103
104
%token  TARGET TARGETNAME TARGETADDR
105
%token	INITIATORNAME INITIATORADDR ISID
106
%token	ENABLED DISABLED NORMAL DISCOVERY
107
%token  ADDRESS INET INET6 PORT
108
%token	INCLUDE
109
%token	ERROR
110
%token	<v.string>		STRING
111
%token	<v.number>		NUMBER
112
%type	<v.i>			af state type
113
%type	<v.string>		port
114
%type	<v.addrinfo>		addrinfo
115
%type	<v.addrinfo_opts>	addrinfo_opts addrinfo_opts_l addrinfo_opt
116
%type	<v.string>		string
117
118
%%
119
120
grammar		: /* empty */
121
		| grammar '\n'
122
		| grammar include '\n'
123
		| grammar varset '\n'
124
		| grammar initiator '\n'
125
		| grammar target '\n'
126
		| grammar error '\n'		{ file->errors++; }
127
		;
128
129
include		: INCLUDE STRING		{
130
			struct file	*nfile;
131
132
			if ((nfile = pushfile($2, 1)) == NULL) {
133
				yyerror("failed to include file %s", $2);
134
				free($2);
135
				YYERROR;
136
			}
137
			free($2);
138
139
			file = nfile;
140
			lungetc('\n');
141
		}
142
		;
143
144
string		: string STRING	{
145
			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
146
				free($1);
147
				free($2);
148
				yyerror("string: asprintf");
149
				YYERROR;
150
			}
151
			free($1);
152
			free($2);
153
		}
154
		| STRING
155
		;
156
157
varset		: STRING '=' string		{
158
			char *s = $1;
159
			while (*s++) {
160
				if (isspace((unsigned char)*s)) {
161
					yyerror("macro name cannot contain "
162
					    "whitespace");
163
					YYERROR;
164
				}
165
			}
166
			if (symset($1, $3, 0) == -1)
167
				err(1, "cannot store variable");
168
			free($1);
169
			free($3);
170
		}
171
		;
172
173
optnl		: '\n' optnl
174
		|
175
		;
176
177
nl		: '\n' optnl		/* one or more newlines */
178
		;
179
180
initiator	: ISID STRING NUMBER NUMBER {
181
			u_int32_t mask1, mask2;
182
183
			if (!strcasecmp($2, "oui")) {
184
				conf->initiator.isid_base = ISCSI_ISID_OUI;
185
				mask1 = 0x3fffff00;
186
				mask2 = 0x000000ff;
187
			} else if (!strcasecmp($2, "en")) {
188
				conf->initiator.isid_base = ISCSI_ISID_EN;
189
				mask1 = 0x00ffffff;
190
				mask2 = 0;
191
			} else if (!strcasecmp($2, "rand")) {
192
				conf->initiator.isid_base = ISCSI_ISID_RAND;
193
				mask1 = 0x00ffffff;
194
				mask2 = 0;
195
			} else {
196
				yyerror("isid type %s unknown", $2);
197
				free($2);
198
				YYERROR;
199
			}
200
			free($2);
201
			conf->initiator.isid_base |= $3 & mask1;
202
			conf->initiator.isid_base |= ($4 >> 16) & mask2;
203
			conf->initiator.isid_qual = $4;
204
		}
205
		;
206
207
target		: TARGET STRING {
208
			struct session_ctlcfg *scelm;
209
210
			scelm = calloc(1, sizeof(*scelm));
211
			session = &scelm->session;
212
			if (strlcpy(session->SessionName, $2,
213
			    sizeof(session->SessionName)) >=
214
			    sizeof(session->SessionName)) {
215
				yyerror("target name \"%s\" too long", $2);
216
				free($2);
217
				free(scelm);
218
				YYERROR;
219
			}
220
			free($2);
221
			SIMPLEQ_INSERT_TAIL(&conf->sessions, scelm, entry);
222
		} '{' optnl targetopts_l '}'
223
		;
224
225
targetopts_l	: targetopts_l targetoptsl nl
226
		| targetoptsl optnl
227
		;
228
229
targetoptsl	: state			{ session->disabled = $1; }
230
		| type			{ session->SessionType = $1; }
231
		| TARGETNAME STRING	{ session->TargetName = $2; }
232
		| INITIATORNAME STRING	{ session->InitiatorName = $2; }
233
		| TARGETADDR addrinfo	{
234
			bcopy($2->ai_addr, &session->connection.TargetAddr,
235
			    $2->ai_addr->sa_len);
236
			freeaddrinfo($2);
237
		}
238
		| INITIATORADDR addrinfo {
239
			((struct sockaddr_in *)$2->ai_addr)->sin_port = 0;
240
			bcopy($2->ai_addr, &session->connection.LocalAddr,
241
			    $2->ai_addr->sa_len);
242
			freeaddrinfo($2);
243
		}
244
		;
245
246
addrinfo	: STRING addrinfo_opts {
247
			struct addrinfo hints;
248
			char *hostname;
249
			int error;
250
251
			$$ = NULL;
252
253
			if ($2.port == NULL) {
254
				if (($2.port = strdup("iscsi")) == NULL) {
255
					free($1);
256
					yyerror("port strdup");
257
					YYERROR;
258
				}
259
			}
260
261
			memset(&hints, 0, sizeof(hints));
262
			hints.ai_family = $2.af;
263
			hints.ai_socktype = SOCK_STREAM;
264
			hints.ai_protocol = IPPROTO_TCP;
265
266
			if (strcmp($1, "*") == 0) {
267
				hostname = NULL;
268
				hints.ai_flags = AI_PASSIVE;
269
			} else
270
				hostname = $1;
271
272
			error = getaddrinfo(hostname, $2.port, &hints, &$$);
273
			if (error) {
274
				yyerror("%s (%s %s)", gai_strerror(error),
275
				    $1, $2.port);
276
				free($1);
277
				free($2.port);
278
				YYERROR;
279
			}
280
281
			free($1);
282
			free($2.port);
283
		}
284
		;
285
286
addrinfo_opts	: {
287
			addrinfo_opts.port = NULL;
288
			addrinfo_opts.af = PF_UNSPEC;
289
		}
290
			addrinfo_opts_l { $$ = addrinfo_opts; }
291
		| /* empty */ {
292
			addrinfo_opts.port = NULL;
293
			addrinfo_opts.af = PF_UNSPEC;
294
			$$ = addrinfo_opts;
295
		}
296
		;
297
298
addrinfo_opts_l	: addrinfo_opts_l addrinfo_opt
299
		| addrinfo_opt
300
		;
301
302
addrinfo_opt	: port {
303
			if (addrinfo_opts.port != NULL) {
304
				yyerror("port cannot be redefined");
305
				YYERROR;
306
			}
307
			addrinfo_opts.port = $1;
308
		}
309
		| af {
310
			if (addrinfo_opts.af != PF_UNSPEC) {
311
				yyerror("address family cannot be redefined");
312
				YYERROR;
313
			}
314
			addrinfo_opts.af = $1;
315
		}
316
		;
317
318
port		: PORT STRING			{ $$ = $2; }
319
		;
320
321
af		: INET				{ $$ = PF_INET; }
322
		| INET6				{ $$ = PF_INET6; }
323
		;
324
325
state		: ENABLED			{ $$ = 0; }
326
		| DISABLED			{ $$ = 1; }
327
		;
328
329
type		: NORMAL			{ $$ = SESSION_TYPE_NORMAL; }
330
		| DISCOVERY			{ $$ = SESSION_TYPE_DISCOVERY; }
331
		;
332
333
334
%%
335
336
struct keywords {
337
	const char	*k_name;
338
	int		 k_val;
339
};
340
341
int
342
yyerror(const char *fmt, ...)
343
{
344
	va_list	ap;
345
346
	file->errors++;
347
	va_start(ap, fmt);
348
	fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
349
	vfprintf(stderr, fmt, ap);
350
	fprintf(stderr, "\n");
351
	va_end(ap);
352
	return (0);
353
}
354
355
int
356
kw_cmp(const void *k, const void *e)
357
{
358
	return (strcmp(k, ((const struct keywords *)e)->k_name));
359
}
360
361
int
362
lookup(char *s)
363
{
364
	/* this has to be sorted always */
365
	static const struct keywords keywords[] = {
366
		{"address",		ADDRESS},
367
		{"disabled",		DISABLED},
368
		{"discovery",		DISCOVERY},
369
		{"enabled",		ENABLED},
370
		{"include",		INCLUDE},
371
		{"inet",		INET},
372
		{"inet4",		INET},
373
		{"inet6",		INET6},
374
		{"initiatoraddr",	INITIATORADDR},
375
		{"initiatorname",	INITIATORNAME},
376
		{"isid",		ISID},
377
		{"normal",		NORMAL},
378
		{"port",		PORT},
379
		{"target",		TARGET},
380
		{"targetaddr",		TARGETADDR},
381
		{"targetname",		TARGETNAME}
382
	};
383
	const struct keywords	*p;
384
385
	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
386
	    sizeof(keywords[0]), kw_cmp);
387
388
	if (p)
389
		return (p->k_val);
390
	else
391
		return (STRING);
392
}
393
394
#define MAXPUSHBACK	128
395
396
u_char	*parsebuf;
397
int	 parseindex;
398
u_char	 pushback_buffer[MAXPUSHBACK];
399
int	 pushback_index;
400
401
int
402
lgetc(int quotec)
403
{
404
	int		c, next;
405
406
	if (parsebuf) {
407
		/* Read character from the parsebuffer instead of input. */
408
		if (parseindex >= 0) {
409
			c = parsebuf[parseindex++];
410
			if (c != '\0')
411
				return (c);
412
			parsebuf = NULL;
413
		} else
414
			parseindex++;
415
	}
416
417
	if (pushback_index)
418
		return (pushback_buffer[--pushback_index]);
419
420
	if (quotec) {
421
		if ((c = getc(file->stream)) == EOF) {
422
			yyerror("reached end of file while parsing "
423
			    "quoted string");
424
			if (file == topfile || popfile() == EOF)
425
				return (EOF);
426
			return (quotec);
427
		}
428
		return (c);
429
	}
430
431
	while ((c = getc(file->stream)) == '\\') {
432
		next = getc(file->stream);
433
		if (next != '\n') {
434
			c = next;
435
			break;
436
		}
437
		yylval.lineno = file->lineno;
438
		file->lineno++;
439
	}
440
441
	while (c == EOF) {
442
		if (file == topfile || popfile() == EOF)
443
			return (EOF);
444
		c = getc(file->stream);
445
	}
446
	return (c);
447
}
448
449
int
450
lungetc(int c)
451
{
452
	if (c == EOF)
453
		return (EOF);
454
	if (parsebuf) {
455
		parseindex--;
456
		if (parseindex >= 0)
457
			return (c);
458
	}
459
	if (pushback_index < MAXPUSHBACK-1)
460
		return (pushback_buffer[pushback_index++] = c);
461
	else
462
		return (EOF);
463
}
464
465
int
466
findeol(void)
467
{
468
	int	c;
469
470
	parsebuf = NULL;
471
472
	/* skip to either EOF or the first real EOL */
473
	while (1) {
474
		if (pushback_index)
475
			c = pushback_buffer[--pushback_index];
476
		else
477
			c = lgetc(0);
478
		if (c == '\n') {
479
			file->lineno++;
480
			break;
481
		}
482
		if (c == EOF)
483
			break;
484
	}
485
	return (ERROR);
486
}
487
488
int
489
yylex(void)
490
{
491
	u_char	 buf[8096];
492
	u_char	*p, *val;
493
	int	 quotec, next, c;
494
	int	 token;
495
496
top:
497
	p = buf;
498
	while ((c = lgetc(0)) == ' ' || c == '\t')
499
		; /* nothing */
500
501
	yylval.lineno = file->lineno;
502
	if (c == '#')
503
		while ((c = lgetc(0)) != '\n' && c != EOF)
504
			; /* nothing */
505
	if (c == '$' && parsebuf == NULL) {
506
		while (1) {
507
			if ((c = lgetc(0)) == EOF)
508
				return (0);
509
510
			if (p + 1 >= buf + sizeof(buf) - 1) {
511
				yyerror("string too long");
512
				return (findeol());
513
			}
514
			if (isalnum(c) || c == '_') {
515
				*p++ = c;
516
				continue;
517
			}
518
			*p = '\0';
519
			lungetc(c);
520
			break;
521
		}
522
		val = symget(buf);
523
		if (val == NULL) {
524
			yyerror("macro '%s' not defined", buf);
525
			return (findeol());
526
		}
527
		parsebuf = val;
528
		parseindex = 0;
529
		goto top;
530
	}
531
532
	switch (c) {
533
	case '\'':
534
	case '"':
535
		quotec = c;
536
		while (1) {
537
			if ((c = lgetc(quotec)) == EOF)
538
				return (0);
539
			if (c == '\n') {
540
				file->lineno++;
541
				continue;
542
			} else if (c == '\\') {
543
				if ((next = lgetc(quotec)) == EOF)
544
					return (0);
545
				if (next == quotec || c == ' ' || c == '\t')
546
					c = next;
547
				else if (next == '\n') {
548
					file->lineno++;
549
					continue;
550
				} else
551
					lungetc(next);
552
			} else if (c == quotec) {
553
				*p = '\0';
554
				break;
555
			} else if (c == '\0') {
556
				yyerror("syntax error");
557
				return (findeol());
558
			}
559
			if (p + 1 >= buf + sizeof(buf) - 1) {
560
				yyerror("string too long");
561
				return (findeol());
562
			}
563
			*p++ = c;
564
		}
565
		yylval.v.string = strdup(buf);
566
		if (yylval.v.string == NULL)
567
			err(1, "yylex: strdup");
568
		return (STRING);
569
	}
570
571
#define allowed_to_end_number(x) \
572
	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
573
574
	if (c == '-' || isdigit(c)) {
575
		do {
576
			*p++ = c;
577
			if ((unsigned)(p-buf) >= sizeof(buf)) {
578
				yyerror("string too long");
579
				return (findeol());
580
			}
581
		} while ((c = lgetc(0)) != EOF && isdigit(c));
582
		lungetc(c);
583
		if (p == buf + 1 && buf[0] == '-')
584
			goto nodigits;
585
		if (c == EOF || allowed_to_end_number(c)) {
586
			const char *errstr = NULL;
587
588
			*p = '\0';
589
			yylval.v.number = strtonum(buf, LLONG_MIN,
590
			    LLONG_MAX, &errstr);
591
			if (errstr) {
592
				yyerror("\"%s\" invalid number: %s",
593
				    buf, errstr);
594
				return (findeol());
595
			}
596
			return (NUMBER);
597
		} else {
598
nodigits:
599
			while (p > buf + 1)
600
				lungetc(*--p);
601
			c = *--p;
602
			if (c == '-')
603
				return (c);
604
		}
605
	}
606
607
#define allowed_in_string(x) \
608
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
609
	x != '{' && x != '}' && \
610
	x != '!' && x != '=' && x != '#' && \
611
	x != ','))
612
613
	if (isalnum(c) || c == ':' || c == '_') {
614
		do {
615
			*p++ = c;
616
			if ((unsigned)(p-buf) >= sizeof(buf)) {
617
				yyerror("string too long");
618
				return (findeol());
619
			}
620
		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
621
		lungetc(c);
622
		*p = '\0';
623
		if ((token = lookup(buf)) == STRING)
624
			if ((yylval.v.string = strdup(buf)) == NULL)
625
				err(1, "yylex: strdup");
626
		return (token);
627
	}
628
	if (c == '\n') {
629
		yylval.lineno = file->lineno;
630
		file->lineno++;
631
	}
632
	if (c == EOF)
633
		return (0);
634
	return (c);
635
}
636
637
struct file *
638
pushfile(const char *name, int secret)
639
{
640
	struct file	*nfile;
641
642
	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
643
		warn("malloc");
644
		return (NULL);
645
	}
646
	if ((nfile->name = strdup(name)) == NULL) {
647
		warn("malloc");
648
		free(nfile);
649
		return (NULL);
650
	}
651
	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
652
		warn("%s", nfile->name);
653
		free(nfile->name);
654
		free(nfile);
655
		return (NULL);
656
	}
657
	nfile->lineno = 1;
658
	TAILQ_INSERT_TAIL(&files, nfile, entry);
659
	return (nfile);
660
}
661
662
int
663
popfile(void)
664
{
665
	struct file	*prev;
666
667
	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
668
		prev->errors += file->errors;
669
670
	TAILQ_REMOVE(&files, file, entry);
671
	fclose(file->stream);
672
	free(file->name);
673
	free(file);
674
	file = prev;
675
	return (file ? 0 : EOF);
676
}
677
678
struct iscsi_config *
679
parse_config(char *filename)
680
{
681
	struct sym	*sym, *next;
682
683
	file = pushfile(filename, 1);
684
	if (file == NULL)
685
		return (NULL);
686
	topfile = file;
687
688
	conf = calloc(1, sizeof(struct iscsi_config));
689
	if (conf == NULL)
690
		return (NULL);
691
	SIMPLEQ_INIT(&conf->sessions);
692
693
	yyparse();
694
	errors = file->errors;
695
	popfile();
696
697
	/* Free macros and check which have not been used. */
698
	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
699
		if (!sym->persist) {
700
			free(sym->nam);
701
			free(sym->val);
702
			TAILQ_REMOVE(&symhead, sym, entry);
703
			free(sym);
704
		}
705
	}
706
707
	if (errors) {
708
		clear_config(conf);
709
		return (NULL);
710
	}
711
712
	return (conf);
713
}
714
715
int
716
cmdline_symset(char *s)
717
{
718
	char	*sym, *val;
719
	int	ret;
720
	size_t	len;
721
722
	if ((val = strrchr(s, '=')) == NULL)
723
		return (-1);
724
725
	len = strlen(s) - strlen(val) + 1;
726
	if ((sym = malloc(len)) == NULL)
727
		errx(1, "cmdline_symset: malloc");
728
729
	strlcpy(sym, s, len);
730
731
	ret = symset(sym, val + 1, 1);
732
	free(sym);
733
734
	return (ret);
735
}
736
737
char *
738
symget(const char *nam)
739
{
740
	struct sym	*sym;
741
742
	TAILQ_FOREACH(sym, &symhead, entry) {
743
		if (strcmp(nam, sym->nam) == 0) {
744
			sym->used = 1;
745
			return (sym->val);
746
		}
747
	}
748
	return (NULL);
749
}
750
751
int
752
symset(const char *nam, const char *val, int persist)
753
{
754
	struct sym	*sym;
755
756
	TAILQ_FOREACH(sym, &symhead, entry) {
757
		if (strcmp(nam, sym->nam) == 0)
758
			break;
759
	}
760
761
	if (sym != NULL) {
762
		if (sym->persist == 1)
763
			return (0);
764
		else {
765
			free(sym->nam);
766
			free(sym->val);
767
			TAILQ_REMOVE(&symhead, sym, entry);
768
			free(sym);
769
		}
770
	}
771
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
772
		return (-1);
773
774
	sym->nam = strdup(nam);
775
	if (sym->nam == NULL) {
776
		free(sym);
777
		return (-1);
778
	}
779
	sym->val = strdup(val);
780
	if (sym->val == NULL) {
781
		free(sym->nam);
782
		free(sym);
783
		return (-1);
784
	}
785
	sym->used = 0;
786
	sym->persist = persist;
787
	TAILQ_INSERT_TAIL(&symhead, sym, entry);
788
	return (0);
789
}
790
791
void
792
clear_config(struct iscsi_config *c)
793
{
794
	struct session_ctlcfg *s;
795
796
	while ((s = SIMPLEQ_FIRST(&c->sessions))) {
797
		SIMPLEQ_REMOVE_HEAD(&c->sessions, entry);
798
		free(s->session.TargetName);
799
		free(s->session.InitiatorName);
800
		free(s);
801
	}
802
803
	free(c);
804
}