No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / iscsi / dist / src / lib / parameters.c
blob7c3abe84bae793eaf1661355ba81c947c826293e
1 /*
2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3 * By downloading, copying, installing or using the software you agree
4 * to this license. If you do not agree to this license, do not
5 * download, install, copy or use the software.
7 * Intel License Agreement
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
16 * -Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * -Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the
22 * distribution.
24 * -The name of Intel Corporation may not be used to endorse or
25 * promote products derived from this software without specific prior
26 * written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
41 #include "config.h"
42 #include "compat.h"
44 #ifdef HAVE_CTYPE_H
45 #include <ctype.h>
46 #endif
48 #include <stdio.h>
49 #include <stdlib.h>
51 #ifdef HAVE_STRING_H
52 #include <string.h>
53 #endif
55 #ifdef HAVE_NETINET_IN_H
56 #include <netinet/in.h>
57 #endif
59 #include "iscsi-md5.h"
60 #include "iscsiutil.h"
61 #include "parameters.h"
62 #include "conffile.h"
65 int
66 param_list_add(iscsi_parameter_t ** head, int type, const char *key, const char *dflt, const char *valid)
68 iscsi_parameter_t *param;
70 /* Allocated new parameter type */
72 if (*head == NULL) {
73 if ((*head = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
74 iscsi_err(__FILE__, __LINE__, "out of memory\n");
75 return -1;
77 param = *head;
78 } else {
79 for (param = *head; param->next != NULL; param = param->next) {
81 if ((param->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
82 iscsi_err(__FILE__, __LINE__, "out of memory\n");
83 return -1;
85 param = param->next;
88 /* Initilized parameter */
90 param->type = type; /* type */
91 (void) strlcpy(param->key, key, sizeof(param->key));/* key */
92 (void) strlcpy(param->dflt, dflt, sizeof(param->dflt)); /* default value */
93 (void) strlcpy(param->valid, valid, sizeof(param->valid)); /* list of valid values */
94 param->tx_offer = 0; /* sent offer */
95 param->rx_offer = 0; /* received offer */
96 param->tx_answer = 0; /* sent answer */
97 param->rx_answer = 0; /* received answer */
98 param->reset = 0; /* used to erase value_l on next parse */
99 param->next = NULL; /* terminate list */
101 /* Allocated space for value list and set first item to default; and */
102 /* set offer and answer lists to NULL */
104 if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
105 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
106 return -1;
108 param->value_l->next = NULL;
109 (void) strlcpy(param->value_l->value, dflt, sizeof(param->value_l->value));
111 /* Arg check */
113 switch (type) {
114 case ISCSI_PARAM_TYPE_DECLARATIVE:
115 break;
116 case ISCSI_PARAM_TYPE_DECLARE_MULTI:
117 break;
118 case ISCSI_PARAM_TYPE_BINARY_OR:
119 if (strcmp(valid, "Yes,No") != 0 &&
120 strcmp(valid, "No,Yes") != 0 &&
121 strcmp(valid, "No") != 0 &&
122 strcmp(valid, "Yes") != 0 &&
123 strcmp(valid, "yes,no") != 0 &&
124 strcmp(valid, "no,yes") != 0 &&
125 strcmp(valid, "no") != 0 &&
126 strcmp(valid, "yes") != 0) {
127 iscsi_err(__FILE__, __LINE__, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid);
128 return -1;
130 break;
131 case ISCSI_PARAM_TYPE_BINARY_AND:
132 if (strcmp(valid, "Yes,No") != 0 &&
133 strcmp(valid, "No,Yes") != 0 &&
134 strcmp(valid, "No") != 0 &&
135 strcmp(valid, "Yes") != 0 &&
136 strcmp(valid, "yes,no") != 0 &&
137 strcmp(valid, "no,yes") != 0 &&
138 strcmp(valid, "no") != 0 &&
139 strcmp(valid, "yes") != 0) {
140 iscsi_err(__FILE__, __LINE__, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid);
141 return -1;
143 break;
144 case ISCSI_PARAM_TYPE_NUMERICAL:
145 break;
146 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
147 break;
148 case ISCSI_PARAM_TYPE_LIST:
149 break;
150 default:
151 iscsi_err(__FILE__, __LINE__, "unknown parameter type %d\n", type);
152 return -1;
155 iscsi_trace(TRACE_ISCSI_PARAM, "\"%s\": valid \"%s\", default \"%s\", current \"%s\"\n",
156 param->key, param->valid, param->dflt, param->value_l->value);
157 return 0;
160 int
161 param_list_destroy(iscsi_parameter_t * head)
163 iscsi_parameter_t *ptr, *tmp;
164 iscsi_parameter_value_t *item_ptr, *next;
166 for (ptr = head; ptr != NULL;) {
167 tmp = ptr;
168 ptr = ptr->next;
169 if (tmp->value_l) {
170 for (item_ptr = tmp->value_l; item_ptr != NULL; item_ptr = next) {
171 next = item_ptr->next;
173 * iscsi_trace(TRACE_ISCSI_PARAM, "freeing \"%s\"
174 * (%p)\n", item_ptr->value, item_ptr);
176 iscsi_free_atomic(item_ptr);
179 /* iscsi_trace(TRACE_ISCSI_PARAM, "freeing %p\n", tmp); */
180 iscsi_free_atomic(tmp);
182 return 0;
186 iscsi_parameter_t *
187 param_get(iscsi_parameter_t * head, const char *key)
189 iscsi_parameter_t *ptr;
191 for (ptr = head; ptr != NULL; ptr = ptr->next) {
192 if (strcmp(ptr->key, key) == 0) {
193 return ptr;
196 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
197 return NULL;
200 char *
201 param_val(iscsi_parameter_t * head, const char *key)
203 return param_val_which(head, key, 0);
206 char *
207 param_val_which(iscsi_parameter_t * head, const char *key, int which)
209 iscsi_parameter_t *ptr;
210 iscsi_parameter_value_t *item_ptr;
211 int i = 0;
213 for (ptr = head; ptr != NULL; ptr = ptr->next) {
214 if (strcmp(ptr->key, key) == 0) {
215 item_ptr = ptr->value_l;
216 for (i = 0; i != which; i++) {
217 if (item_ptr == NULL) {
218 iscsi_err(__FILE__, __LINE__, "item %d in value list is NULL\n", i);
219 return NULL;
221 item_ptr = item_ptr->next;
223 if (item_ptr == NULL) {
224 iscsi_err(__FILE__, __LINE__, "item %d in value list is NULL\n", which);
225 return NULL;
227 return item_ptr->value;
230 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
231 return NULL;
234 static int
235 param_val_delete_all(iscsi_parameter_t * head, char *key)
237 iscsi_parameter_t *ptr;
238 iscsi_parameter_value_t *item_ptr, *next;
240 for (ptr = head; ptr != NULL; ptr = ptr->next) {
241 if (strcmp(ptr->key, key) == 0) {
242 for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = next) {
243 next = item_ptr->next;
244 iscsi_free_atomic(item_ptr);
246 ptr->value_l = NULL;
247 return 0;
250 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
251 return -1;
254 int
255 param_val_reset(iscsi_parameter_t * head, const char *key)
257 iscsi_parameter_t *ptr;
259 for (ptr = head; ptr != NULL; ptr = ptr->next) {
260 if (strcmp(ptr->key, key) == 0) {
261 ptr->reset = 1;
262 return 0;
265 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
266 return -1;
269 int
270 param_atoi(iscsi_parameter_t * head, const char *key)
272 iscsi_parameter_t *ptr;
273 char *value;
275 for (ptr = head; ptr != NULL; ptr = ptr->next) {
276 if (strcmp(ptr->key, key) == 0) {
277 if (ptr->value_l) {
278 if ((value = param_val(head, key)) != NULL) {
279 return iscsi_atoi(value);
280 } else {
281 iscsi_err(__FILE__, __LINE__, "value is NULL\n");
282 return 0;
284 } else {
285 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key);
286 return 0;
290 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
291 return 0;
294 int
295 param_equiv(iscsi_parameter_t * head, const char *key, const char *val)
297 iscsi_parameter_t *ptr;
298 char *value;
300 for (ptr = head; ptr != NULL; ptr = ptr->next) {
301 if (strcmp(ptr->key, key) == 0) {
302 if (ptr->value_l == NULL) {
303 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key);
304 return 0;
306 if ((value = param_val(head, key)) == NULL) {
307 iscsi_err(__FILE__, __LINE__, "key \"%s\" value is NULL\n", key);
308 return 0;
310 return (strcmp(value, val) == 0);
313 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
314 return -1;
317 int
318 param_num_vals(iscsi_parameter_t * head, char *key)
320 iscsi_parameter_t *ptr;
321 iscsi_parameter_value_t *item_ptr;
322 int num = 0;
324 for (ptr = head; ptr != NULL; ptr = ptr->next) {
325 if (strcmp(ptr->key, key) == 0) {
326 for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) {
327 num++;
329 return num;
332 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
333 return -1;
336 int
337 param_list_print(iscsi_parameter_t * head)
339 iscsi_parameter_t *ptr;
340 iscsi_parameter_value_t *item_ptr;
342 for (ptr = head; ptr != NULL; ptr = ptr->next) {
343 for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) {
344 printf("\"%s\"=\"%s\"\n", ptr->key, item_ptr->value);
347 return 0;
350 int
351 param_text_print(char *text, uint32_t text_len)
353 char key[256];
354 char *ptr, *eq, *value;
356 for (ptr = text; (uint32_t)(ptr - text) < text_len; ptr += (strlen(ptr) + 1)) {
358 /* Skip over any NULLs */
360 while (!(*ptr) && ((uint32_t)(ptr - text) < text_len))
361 ptr++;
362 if ((uint32_t)(ptr - text) >= text_len)
363 break;
365 if ((eq = strchr(ptr, '=')) == NULL) {
366 iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
367 return -1;
369 strncpy(key, ptr, (unsigned)(eq - ptr));
370 key[(int)(eq - ptr)] = 0x0;
371 value = eq + 1;
372 printf("\"%s\"=\"%s\"\n", key, value);
374 return 0;
377 /* ARGSUSED */
378 int
379 param_text_add(iscsi_parameter_t * head, const char *key, const char *value, char *text, int *len, int size, int offer)
381 int cc;
383 cc = snprintf(text + *len, (unsigned)(size - *len), "%s=%s", key, value);
384 *len += cc + 1;
385 return 0;
388 int
389 driver_atoi(const char *s)
391 int k = 0;
393 while (*s != 0x0 && *s >= '0' && *s <= '9') {
394 k = 10 * k + (*s - '0');
395 s++;
397 return k;
400 /* find the credentials for `user' and put them in `cred' */
401 static int
402 find_credentials(iscsi_cred_t *cred, char *user, const char *auth)
404 conffile_t conf;
405 const char *authtype;
406 unsigned cc;
407 ent_t e;
409 (void) memset(&conf, 0x0, sizeof(conf));
410 (void) memset(&e, 0x0, sizeof(e));
412 if (!conffile_open(&conf, _PATH_ISCSI_PASSWD, "r", ":", "#")) {
413 iscsi_err(__FILE__, __LINE__, "can't open `%s'\n", _PATH_ISCSI_PASSWD);
414 exit(EXIT_FAILURE);
416 while (conffile_getent(&conf, &e)) {
417 if (strcasecmp(e.sv.v[0], user) == 0) {
418 authtype = (e.sv.c == 1) ? "none" : e.sv.v[1];
419 cc = strlen(authtype);
420 if (auth == NULL || (strncasecmp(authtype, auth, cc) == 0 && cc == strlen(auth))) {
421 cred->user = strdup(e.sv.v[0]);
422 cred->auth_type = strdup(authtype);
423 cred->shared_secret = (e.sv.c == 3) ? strdup(e.sv.v[2]) : NULL;
424 conffile_close(&conf);
425 return 1;
429 conffile_close(&conf);
430 (void) fprintf(stderr, "No matching user configuration entry for `%s' was found\n", user);
431 (void) fprintf(stderr, "Please add an entry for `%s' to `%s'\n", user, _PATH_ISCSI_PASSWD);
432 return 0;
435 #if 0
436 /* free any storage allocated in `cred' */
437 static void
438 free_cred(iscsi_cred_t *cred)
440 if (cred) {
441 if (cred->user) {
442 iscsi_free_atomic(cred->user);
444 if (cred->auth_type) {
445 iscsi_free_atomic(cred->auth_type);
447 if (cred->shared_secret) {
448 iscsi_free_atomic(cred->shared_secret);
452 #endif
454 /* Security offering and check */
456 * ret values: =0: succeed or no security >0: security negotiation in process
457 * <0: failed
459 static int
460 param_parse_security(iscsi_parameter_t * head,
461 iscsi_parameter_t * param_in,
462 iscsi_cred_t *cred,
463 char *text_out, int *text_len_out, int textsize)
466 static uint8_t idData;
467 static uint8_t chapdata[ISCSI_CHAP_DATA_LENGTH];
468 static uint8_t respdata[ISCSI_CHAP_DATA_LENGTH];
469 char *chapstring = NULL;
470 iSCSI_MD5_CTX *context = NULL;
471 iscsi_parameter_t *param = NULL;
472 int ret = 1;
474 if ((chapstring = iscsi_malloc(ISCSI_CHAP_STRING_LENGTH)) == NULL) {
475 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
476 return -1;
478 if ((context = iscsi_malloc(sizeof(*context))) == NULL) {
479 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
480 if (chapstring != NULL)
481 iscsi_free(chapstring);
482 return -1;
484 #define PPS_CLEANUP { if (chapstring != NULL) iscsi_free(chapstring);if (context != NULL) iscsi_free(context); }
485 #define PPS_ERROR { PPS_CLEANUP; return (-1); };
487 if (strcmp(param_in->key, "AuthMethod") == 0) {
488 if (param_in->rx_answer && strcmp(param_in->answer_rx, "None") == 0) {
489 PPS_CLEANUP;
490 return 0; /* Proposed None for
491 * Authentication */
493 if (param_in->rx_offer && strcmp(param_in->offer_rx, "None") == 0) {
494 PPS_CLEANUP;
495 return 0;
497 if (!param_in->rx_offer) {
498 param = param_get(head, "CHAP_A");
499 if (param == NULL)
500 PPS_ERROR;
501 param->tx_offer = 1; /* sending an offer */
502 param->rx_offer = 0; /* reset */
503 (void) strlcpy(param->offer_tx, param->valid, sizeof(param->offer_tx));
504 PARAM_TEXT_ADD(head, param->key, param->valid,
505 text_out, text_len_out, textsize, 0, PPS_ERROR);
506 ret++;
508 } else if (strcmp(param_in->key, "CHAP_A") == 0) {
509 if (param_in->rx_offer) {
510 PARAM_TEXT_ADD(head, param_in->key, param_in->offer_rx,
511 text_out, text_len_out, textsize, 0, PPS_ERROR);
513 if ((param = param_get(head, "CHAP_I")) == NULL) {
514 PPS_ERROR;
516 param->tx_offer = 1; /* sending an offer */
517 param->rx_offer = 0; /* reset */
518 GenRandomData(&idData, 1);
519 (void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData);
520 (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
521 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
522 text_out, text_len_out, textsize, 0, PPS_ERROR);
524 if ((param = param_get(head, "CHAP_C")) == NULL) {
525 PPS_ERROR;
527 param->tx_offer = 1; /* sending an offer */
528 param->rx_offer = 0; /* reset */
529 GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH);
530 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
531 chapstring, ISCSI_CHAP_STRING_LENGTH);
532 (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
533 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
534 text_out, text_len_out, textsize, 0, PPS_ERROR);
535 ret++;
537 } else if (strcmp(param_in->key, "CHAP_I") == 0) {
539 idData = driver_atoi((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx);
540 ret++;
542 } else if (strcmp(param_in->key, "CHAP_C") == 0) {
544 HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
545 chapdata, ISCSI_CHAP_DATA_LENGTH);
547 if ((param = param_get(head, "CHAP_N")) == NULL) {
548 PPS_ERROR;
550 param->tx_offer = 1; /* sending an offer */
551 param->rx_offer = 0; /* reset */
553 if (cred->shared_secret == NULL && !find_credentials(cred, cred->user, "chap")) {
554 iscsi_err(__FILE__, __LINE__, "Unknown user `%s'\n", param_in->offer_rx);
555 PPS_ERROR;
558 if (cred->user) {
559 (void) strlcpy(param->offer_tx, cred->user, sizeof(param->offer_tx));
560 } else {
561 iscsi_err(__FILE__, __LINE__, "no valid user credentials\n");
562 PPS_ERROR;
565 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
566 text_out, text_len_out, textsize, 0, PPS_ERROR);
568 if ((param = param_get(head, "CHAP_R")) == NULL) {
569 PPS_ERROR;
571 param->tx_offer = 1; /* sending an offer */
572 param->rx_offer = 0; /* reset */
573 iSCSI_MD5Init(context);
574 iSCSI_MD5Update(context, &idData, 1);
576 if (cred->shared_secret == NULL) {
577 iscsi_err(__FILE__, __LINE__, "null shared secret\n");
578 PPS_ERROR;
579 } else {
580 iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
583 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
584 param->offer_tx, ISCSI_CHAP_STRING_LENGTH);
585 iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH);
586 iSCSI_MD5Final(chapdata, context);
587 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
588 param->offer_tx, ISCSI_CHAP_STRING_LENGTH);
590 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
591 text_out, text_len_out, textsize, 0, PPS_ERROR);
593 if (param_in->rx_offer) {
595 if ((param = param_get(head, "CHAP_I")) == NULL) {
596 PPS_ERROR;
598 param->tx_offer = 1; /* sending an offer */
599 param->rx_offer = 0; /* reset */
600 GenRandomData(&idData, 1);
601 (void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData);
602 (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
603 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
604 text_out, text_len_out, textsize, 0, PPS_ERROR);
606 if ((param = param_get(head, "CHAP_C")) == NULL) {
607 PPS_ERROR;
609 param->tx_offer = 1; /* sending an offer */
610 param->rx_offer = 0; /* reset */
611 GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH);
612 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
613 chapstring, ISCSI_CHAP_STRING_LENGTH);
614 (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
615 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
616 text_out, text_len_out, textsize, 0, PPS_ERROR);
618 ret++;
620 } else if (strcmp(param_in->key, "CHAP_N") == 0) {
621 char *user;
623 user = (param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx;
624 if (!find_credentials(cred, user, "chap")) {
625 iscsi_err(__FILE__, __LINE__, "Unknown user `%s'\n", user);
626 PPS_ERROR;
628 ret++;
630 } else if (strcmp(param_in->key, "CHAP_R") == 0) {
632 iSCSI_MD5Init(context);
634 iSCSI_MD5Update(context, &idData, 1);
636 HexDataToText(&idData, 1, param_in->offer_tx, ISCSI_CHAP_STRING_LENGTH);
637 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
638 chapstring, ISCSI_CHAP_STRING_LENGTH);
640 if (cred->shared_secret == NULL) {
641 iscsi_err(__FILE__, __LINE__, "Null shared secret in initiator\n");
642 PPS_ERROR;
643 } else {
644 iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
647 iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH);
648 iSCSI_MD5Final(chapdata, context);
650 HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
651 respdata, ISCSI_CHAP_DATA_LENGTH);
653 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
654 param_in->offer_rx, ISCSI_CHAP_STRING_LENGTH);
656 if (memcmp(respdata, chapdata, ISCSI_CHAP_DATA_LENGTH) != 0) {
657 iscsi_err(__FILE__, __LINE__, "Initiator authentication failed %x %x\n", *chapdata, *respdata);
658 PPS_ERROR;
659 } else {
660 PPS_CLEANUP;
662 return 0;
664 PPS_CLEANUP;
665 return (ret);
668 int
669 param_text_parse(iscsi_parameter_t * head,
670 iscsi_cred_t *cred,
671 char *text_in, int text_len_in,
672 char *text_out, int *text_len_out,
673 int textsize,
674 int outgoing)
676 static char *key = NULL;
677 char *value = NULL;
678 char *ptr, *eq;
679 iscsi_parameter_t *param;
680 iscsi_parameter_value_t *item_ptr;
681 int offer_i, answer_i, max_i, val1_i, val2_i, negotiated_i;
682 char *p1, *p2, *p3, *p4;
683 char *offer = NULL;
684 char *valid = NULL;
685 char *val1 = NULL;
686 char *val2 = NULL;
687 char *tmp_key = NULL;
688 char c;
689 int ret;
692 * Whether incoming or outgoing, some of the params might be offers
693 * and some answers. Incoming
696 * text has the potential for creating outgoing text - and this will
697 * happen when the incoming
699 /* text has offers that need an answer. */
701 iscsi_trace(TRACE_ISCSI_PARAM, "parsing %d %s bytes of text parameters\n", text_len_in, outgoing ? "outgoing" : "incoming");
703 if ((key = iscsi_malloc(ISCSI_PARAM_KEY_LEN)) == NULL) {
704 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
705 return -1;
707 if ((offer = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
708 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
709 if (key != NULL) {
710 iscsi_free(key);
712 return -1;
714 if ((valid = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
715 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
716 if (key != NULL) {
717 iscsi_free(key);
719 if (offer != NULL) {
720 iscsi_free(offer);
722 return -1;
724 if ((val1 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
725 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
726 if (key != NULL) {
727 iscsi_free(key);
729 if (offer != NULL) {
730 iscsi_free(offer);
732 if (valid != NULL) {
733 iscsi_free(valid);
735 return -1;
737 if ((val2 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
738 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
739 if (key != NULL) {
740 iscsi_free(key);
742 if (offer != NULL) {
743 iscsi_free(offer);
745 if (valid != NULL) {
746 iscsi_free(valid);
748 if (val1 != NULL) {
749 iscsi_free(val1);
751 return -1;
753 #define PTP_CLEANUP { if (key != NULL) iscsi_free(key); \
754 if (offer != NULL) iscsi_free(offer); \
755 if (valid != NULL) iscsi_free(valid); \
756 if (val1 != NULL) iscsi_free(val1); \
757 if (val2 != NULL) iscsi_free(val2); \
758 if (tmp_key != NULL) iscsi_free(tmp_key); }
759 #define PTP_ERROR {PTP_CLEANUP; return -1;}
761 if (!outgoing) {
762 *text_len_out = 0;
765 #if ISCSI_DEBUG
766 printf("**************************************************\n");
767 printf("* PARAMETERS NEGOTIATED *\n");
768 printf("* *\n");
769 #endif
771 for (ptr = text_in; ptr - text_in < text_len_in; ptr += (strlen(ptr) + 1)) {
773 /* Skip over any NULLs */
775 while (!(*ptr) && ((ptr - text_in) < text_len_in)) {
776 ptr++;
778 if ((ptr - text_in) >= text_len_in) {
779 break;
782 /* Extract <key>=<value> token from text_in */
784 if ((eq = strchr(ptr, '=')) == NULL) {
785 iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
786 } else {
787 if ((int)(eq - ptr) >= (ISCSI_PARAM_KEY_LEN - 1)) {
788 if (!outgoing) {
789 tmp_key = iscsi_malloc((unsigned)(eq - ptr));
790 if (tmp_key) {
791 strncpy(tmp_key, ptr, (unsigned)(eq - ptr));
792 tmp_key[(int)(eq - ptr)] = 0x0;
793 /* Key not understood. */
794 PARAM_TEXT_ADD(head, tmp_key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR);
796 } else {
797 printf("ignoring \"%s\"\n", key);
799 goto next;
801 strncpy(key, ptr, (unsigned)(eq - ptr));
802 key[(int)(eq - ptr)] = 0x0;
803 value = eq + 1;
806 /* Find key in param list */
808 for (param = head; param != NULL; param = param->next) {
809 if (strcmp(param->key, key) == 0) {
810 break;
813 if (param == NULL) {
814 if (!outgoing) {
815 /* Key not understood. */
816 PARAM_TEXT_ADD(head, key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR);
817 } else {
818 printf("ignoring \"%s\"\n", key);
820 goto next;
822 if (strlen(value) > ISCSI_PARAM_MAX_LEN) {
823 iscsi_err(__FILE__, __LINE__,
824 "strlen(value) %u\n", strlen(value));
825 PTP_CLEANUP;
826 return -1;
829 /* We're sending|receiving an offer|answer */
830 if (outgoing) {
831 if (param->rx_offer) {
832 param->tx_answer = 1; /* sending an answer */
833 param->rx_answer = 0; /* reset */
834 param->tx_offer = 0; /* reset */
835 param->rx_offer = 0; /* reset */
836 (void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx));
837 iscsi_trace(TRACE_ISCSI_PARAM, "sending answer \"%s\"=\"%s\" for offer \"%s\"\n",
838 param->key, param->answer_tx, param->offer_rx);
839 goto negotiate;
840 } else {
841 param->tx_offer = 1; /* sending an offer */
842 param->tx_answer = 0;
843 param->rx_answer = 0;
844 (void) strlcpy(param->offer_tx, value, sizeof(param->offer_tx));
845 iscsi_trace(TRACE_ISCSI_PARAM, "sending offer \"%s\"=\"%s\"\n", param->key, param->offer_tx);
846 if ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) ||
847 (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI)) {
848 goto negotiate;
850 goto next;
852 } else {
853 if (param->tx_offer) {
854 param->rx_answer = 1; /* received an answer */
855 param->tx_answer = 0;
856 param->rx_offer = 0;
857 param->tx_offer = 0; /* reset */
858 (void) strlcpy(param->answer_rx, value, sizeof(param->answer_rx));
859 iscsi_trace(TRACE_ISCSI_PARAM, "received answer \"%s\"=\"%s\" for offer \"%s\"\n",
860 param->key, param->answer_rx, param->offer_tx);
862 if ((ret = param_parse_security(head, param, cred,
863 text_out, text_len_out, textsize)) > 1) {
864 goto next;
865 } else if (ret == 0) {
867 * FIX ME Happens in initiator code
868 * currently we ignore initiator
869 * authentication status See comments
870 * at the beginning of parse_security
872 goto negotiate;
873 } else if (ret == 1) {
874 goto negotiate;
875 } else {
876 PTP_CLEANUP;
878 return ISCSI_PARAM_STATUS_AUTH_FAILED;
879 } else {
880 param->rx_offer = 1; /* received an offer */
881 param->rx_answer = 0;
882 param->tx_answer = 0;
883 (void) strlcpy(param->offer_rx, value, sizeof(param->offer_rx));
884 iscsi_trace(TRACE_ISCSI_PARAM, "received offer \"%s\"=\"%s\"\n", param->key, param->offer_rx);
886 if ((ret = param_parse_security(head, param, cred,
887 text_out, text_len_out, textsize)) > 1) {
888 goto next;
889 } else if (ret < 0) {
890 iscsi_parameter_t *auth_result;
891 if ((auth_result = param_get(head, "AuthResult")) != 0) {
892 (void) strlcpy(auth_result->value_l->value, "Fail", sizeof(auth_result->value_l->value));
894 PTP_CLEANUP;
895 return (ISCSI_PARAM_STATUS_AUTH_FAILED);
896 } else if (ret == 0) {
897 iscsi_parameter_t *auth_result;
898 if ((auth_result = param_get(head, "AuthResult")) != 0) {
899 (void) strlcpy(auth_result->value_l->value, "Yes", sizeof(auth_result->value_l->value));
903 * Answer the offer if it is an inquiry or
904 * the type is not DECLARATIVE
907 if ((strcmp(param->offer_rx, "?") != 0) && ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) || (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI))) {
908 goto negotiate;
909 } else {
910 goto answer;
915 answer:
917 /* Answer with current value if this is an inquiry (<key>=?) */
919 if (strcmp(value, "?") == 0) {
920 iscsi_trace(TRACE_ISCSI_PARAM, "got inquiry for param \"%s\"\n", param->key);
921 if (param->value_l) {
922 if (param->value_l->value) {
923 (void) strlcpy(param->answer_tx, param->value_l->value, sizeof(param->answer_tx));
924 } else {
925 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l->value\n", param->key);
926 param->answer_tx[0] = 0x0;
928 } else {
929 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l\n", param->key);
930 param->answer_tx[0] = 0x0;
932 goto add_answer;
934 /* Generate answer according to the parameter type */
936 switch (param->type) {
938 case ISCSI_PARAM_TYPE_BINARY_AND:
939 goto binary_or;
941 case ISCSI_PARAM_TYPE_BINARY_OR:
942 binary_or:
943 if (strcmp(value, "yes") != 0 &&
944 strcmp(value, "no") != 0 &&
945 strcmp(value, "Yes") != 0 &&
946 strcmp(value, "No") != 0) {
947 iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid binary value\n", value);
948 (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
949 goto add_answer;
951 if (strchr(param->valid, ',') != NULL) {
952 (void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx)); /* we accept both yes
953 * and no, so answer w/
954 * their offer */
955 } else {
956 (void) strlcpy(param->answer_tx, param->valid, sizeof(param->answer_tx)); /* answer with the only
957 * value we support */
959 break;
961 case ISCSI_PARAM_TYPE_LIST:
964 * Use our default value if it's offered as one of the option
965 * in the parameter list.
967 * We need to do this at least for CHAP because cisco's initiator
968 * could be sending us a parameter value list with "CHAP,None",
969 * even when it doesn't set username/password in its configration
970 * file, in which case we should pick "None" as for no security instead
971 * of pick the first one on the value list. "None" is the default value
972 * for AuthMethod
974 * This fix is working well now, though is arguable. We should keep
975 * this just to make us work with Cisco for now.
977 if (strlen(param->dflt)) {
978 for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
980 if ((p2 = strchr(p1, ',')) != NULL) {
981 strncpy(offer, p1, (unsigned)(p2 - p1));
982 offer[(int)(p2 - p1)] = 0x0;
983 } else {
984 (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
987 if (strcmp(param->dflt, offer) == 0) {
988 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
989 goto add_answer;
993 /* Find the first valid offer that we support */
995 for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
996 if ((p2 = strchr(p1, ',')) != NULL) {
997 strncpy(offer, p1, (unsigned)(p2 - p1));
998 offer[p2 - p1] = 0x0;
999 } else {
1000 (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
1002 if (strlen(param->valid)) {
1003 for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
1004 if ((p4 = strchr(p3, ',')) != NULL) {
1005 strncpy(valid, p3, (unsigned)(p4 - p3));
1006 valid[(int)(p4 - p3)] = 0x0;
1007 } else {
1008 (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1010 if (strcmp(valid, offer) == 0) {
1011 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1012 goto add_answer;
1015 } else {
1016 iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty. Answering with first in offer list\n");
1017 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1018 goto add_answer;
1020 iscsi_trace(TRACE_ISCSI_PARAM, "\"%s\" is not a valid offer for key \"%s\" (must choose from \"%s\")\n", offer, param->key, param->valid);
1022 iscsi_trace(TRACE_ISCSI_PARAM, "No Valid offers: \"%s\" is added as value for key \"%s\")\n", "Reject", param->key);
1023 (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
1024 break;
1026 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1027 goto numerical;
1029 case ISCSI_PARAM_TYPE_NUMERICAL:
1030 numerical:
1031 offer_i = iscsi_atoi(param->offer_rx);
1032 max_i = iscsi_atoi(param->valid);
1033 if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1034 if (max_i == 0) {
1035 answer_i = offer_i; /* we support anything,
1036 * so return whatever
1037 * they offered */
1038 } else if (offer_i == 0) {
1039 answer_i = max_i; /* return only what we
1040 * can support */
1041 } else if (offer_i > max_i) {
1042 answer_i = max_i; /* we are the lower of
1043 * the two */
1044 } else {
1045 answer_i = offer_i; /* they are the lower of
1046 * the two */
1048 } else {
1049 if (offer_i > max_i) {
1050 answer_i = max_i; /* we are the lower of
1051 * the two */
1052 } else {
1053 answer_i = offer_i; /* they are the lower of
1054 * the two */
1057 (void) snprintf(param->answer_tx, sizeof(param->answer_tx), "%d", answer_i);
1058 goto add_answer;
1060 default:
1061 goto next;
1063 add_answer: PARAM_TEXT_ADD(head, key, param->answer_tx, text_out, text_len_out, textsize, 0, PTP_ERROR);
1064 iscsi_trace(TRACE_ISCSI_PARAM, "answering \"%s\"=\"%s\"\n", param->key, param->answer_tx);
1065 goto next;
1068 /* Negotiate after receiving|sending an answer */
1070 negotiate:
1071 switch (param->type) {
1072 case ISCSI_PARAM_TYPE_DECLARE_MULTI:
1073 goto declarative_negotiate;
1074 case ISCSI_PARAM_TYPE_DECLARATIVE:
1075 declarative_negotiate:
1076 if (param->tx_answer) {
1077 (void) strlcpy(param->negotiated, param->answer_tx, sizeof(param->negotiated));
1078 } else if (param->tx_offer) {
1079 (void) strlcpy(param->negotiated, param->offer_tx, sizeof(param->negotiated));
1080 } else if (param->rx_answer) {
1081 (void) strlcpy(param->negotiated, param->answer_rx, sizeof(param->negotiated));
1082 } else if (param->rx_offer) {
1083 (void) strlcpy(param->negotiated, param->offer_rx, sizeof(param->negotiated));
1084 } else {
1085 iscsi_err(__FILE__, __LINE__, "Invalid negotiation!?!?\n");
1087 break;
1088 case ISCSI_PARAM_TYPE_BINARY_AND:
1089 goto binary_or_negotiate;
1090 case ISCSI_PARAM_TYPE_BINARY_OR:
1091 binary_or_negotiate:
1092 if (outgoing) {
1093 (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1094 (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1095 } else {
1096 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1097 (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1098 /* Make sure the answer is valid */
1099 if (strcmp(val1, "Yes") != 0 &&
1100 strcmp(val1, "No") != 0 &&
1101 strcmp(val1, "yes") != 0 &&
1102 strcmp(val1, "no") != 0 &&
1103 strcmp(val1, "Irrelevant") != 0) {
1104 /* Invalid value returned as answer. */
1105 iscsi_err(__FILE__, __LINE__, "Invalid answer (%s) for key (%s)\n",
1106 val1, key);
1107 PTP_ERROR;
1110 if (param->type == ISCSI_PARAM_TYPE_BINARY_OR) {
1111 if (strcmp(val1, "yes") == 0 || strcmp(val2, "yes") == 0 || strcmp(val1, "Yes") == 0 || strcmp(val2, "Yes") == 0) {
1112 (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1113 } else {
1114 (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1116 } else {
1117 if ((strcmp(val1, "yes") == 0 && strcmp(val2, "yes") == 0) || (strcmp(val1, "Yes") == 0 && strcmp(val2, "Yes") == 0)) {
1118 (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1119 } else {
1120 (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1123 break;
1124 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1125 goto numerical_negotiate;
1126 case ISCSI_PARAM_TYPE_NUMERICAL:
1127 numerical_negotiate:
1128 if (outgoing) {
1129 (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1130 (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1131 } else {
1132 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1133 (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1135 val1_i = iscsi_atoi(val1);
1136 val2_i = iscsi_atoi(val2);
1137 if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1138 if (val1_i == 0) {
1139 negotiated_i = val2_i;
1140 } else if (val2_i == 0) {
1141 negotiated_i = val1_i;
1142 } else if (val1_i > val2_i) {
1143 negotiated_i = val2_i;
1144 } else {
1145 negotiated_i = val1_i;
1147 } else {
1148 if (val1_i > val2_i) {
1149 negotiated_i = val2_i;
1150 } else {
1151 negotiated_i = val1_i;
1154 (void) snprintf(param->negotiated, sizeof(param->negotiated), "%d", negotiated_i);
1155 break;
1156 case ISCSI_PARAM_TYPE_LIST:
1157 if (outgoing) {
1158 if (param->tx_offer) {
1159 iscsi_err(__FILE__, __LINE__, "we should not be here\n"); /* error - we're sending
1160 * an offer */
1161 PTP_ERROR;
1162 } else if (param->tx_answer) {
1163 (void) strlcpy(val1, param->answer_tx, ISCSI_PARAM_MAX_LEN); /* we're sending an
1164 * answer */
1165 } else {
1166 iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1167 PTP_ERROR;
1169 } else {
1170 if (param->rx_offer) {
1171 iscsi_err(__FILE__, __LINE__, "we should not be here\n"); /* error - we received
1172 * an offer */
1173 PTP_ERROR;
1174 } else if (param->rx_answer) {
1175 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN); /* we received an answer */
1176 } else {
1177 iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1178 PTP_ERROR;
1182 /* Make sure incoming or outgoing answer is valid */
1184 * None, Reject, Irrelevant and NotUnderstood are
1185 * valid
1187 if ((strcmp(val1, "None") == 0) || (strcmp(val1, "Reject") == 0) ||
1188 (strcmp(val1, "Irrelevant") == 0) || (strcmp(val1, "NotUnderstood") == 0)) {
1189 goto value_ok;
1191 if (strlen(param->valid) > 0) {
1192 for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
1193 if ((p4 = strchr(p3, ',')) != NULL) {
1194 strncpy(valid, p3, (unsigned)(p4 - p3));
1195 valid[(int)(p4 - p3)] = 0x0;
1196 } else {
1197 (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1199 if (strcmp(valid, val1) == 0) {
1200 goto value_ok;
1203 } else {
1204 iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty??\n");
1205 PTP_ERROR;
1207 iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1, param->valid);
1208 PTP_ERROR;
1209 value_ok:
1210 (void) strlcpy(param->negotiated, val1, sizeof(param->negotiated));
1211 break;
1214 iscsi_trace(TRACE_ISCSI_PARAM, "negotiated \"%s\"=\"%s\"\n", param->key, param->negotiated);
1216 /* For inquiries, we don't commit the value. */
1218 if (param->tx_offer && strcmp(param->offer_tx, "?") == 0) {
1219 /* we're offering an inquiry */
1220 iscsi_trace(TRACE_ISCSI_PARAM, "sending an inquiry for \"%s\"\n", param->key);
1221 goto next;
1222 } else if (param->rx_offer && strcmp(param->offer_rx, "?") == 0) {
1223 /* we're receiving an inquiry */
1224 iscsi_trace(TRACE_ISCSI_PARAM, "received an inquiry for \"%s\"\n", param->key);
1225 goto next;
1226 } else if (param->tx_answer && strcmp(param->offer_rx, "?") == 0) {
1227 /* we're answering an inquiry */
1228 iscsi_trace(TRACE_ISCSI_PARAM, "answering an inquiry for \"%s\"\n", param->key);
1229 goto next;
1230 } else if (param->rx_answer && strcmp(param->offer_tx, "?") == 0) {
1231 /* we're receiving an answer for our inquiry */
1232 iscsi_trace(TRACE_ISCSI_PARAM, "received an answer for inquiry on \"%s\"\n", param->key);
1233 goto next;
1235 iscsi_trace(TRACE_ISCSI_PARAM, "automatically committing \"%s\"=\"%s\"\n", param->key, param->negotiated);
1237 c = param->negotiated[19];
1238 param->negotiated[19] = 0x0;
1239 #if ISCSI_DEBUG
1240 printf("* %25s:%20s *\n", param->key, param->negotiated);
1241 #endif
1242 param->negotiated[19] = c;
1244 if (param->reset) {
1245 iscsi_trace(TRACE_ISCSI_PARAM, "deleting value list for \"%s\"\n", param->key);
1246 if (param_val_delete_all(head, param->key) != 0) {
1247 iscsi_err(__FILE__, __LINE__, "param_val_delete_all() failed\n");
1248 PTP_ERROR;
1250 param->reset = 0;
1252 if (param->value_l) {
1253 if (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI) {
1254 for (item_ptr = param->value_l; item_ptr->next != NULL; item_ptr = item_ptr->next) {
1256 if ((item_ptr->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1257 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1258 PTP_ERROR;
1260 item_ptr = item_ptr->next;
1261 item_ptr->next = NULL;
1262 } else {
1263 item_ptr = param->value_l;
1265 } else {
1266 iscsi_trace(TRACE_ISCSI_PARAM, "allocating value ptr\n");
1267 if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1268 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1269 PTP_ERROR;
1271 item_ptr = param->value_l;
1272 item_ptr->next = NULL;
1274 (void) strlcpy(item_ptr->value, param->negotiated, sizeof(item_ptr->value));
1275 next:
1276 continue;
1278 if (!outgoing) {
1279 iscsi_trace(TRACE_ISCSI_PARAM, "generated %d bytes response\n", *text_len_out);
1281 #if ISCSI_DEBUG
1282 printf("**************************************************\n");
1283 #endif
1285 PTP_CLEANUP;
1286 return 0;
1289 void
1290 set_session_parameters(iscsi_parameter_t * head,
1291 iscsi_sess_param_t * sess_params)
1293 /* These parameters are standard and assuming that they are always */
1294 /* present in the list (head). */
1295 memset(sess_params, 0, sizeof(iscsi_sess_param_t));
1296 sess_params->max_burst_length = param_atoi(head, "MaxBurstLength");
1297 sess_params->first_burst_length = param_atoi(head, "FirstBurstLength");
1298 sess_params->max_dataseg_len =
1299 param_atoi(head, "MaxRecvDataSegmentLength");
1300 sess_params->header_digest = (param_equiv(head, "HeaderDigest", "Yes")) ? 1 : 0;
1301 sess_params->data_digest = (param_equiv(head, "DataDigest", "Yes")) ? 1 : 0;
1302 sess_params->initial_r2t = (param_equiv(head, "InitialR2T", "Yes"));
1303 sess_params->immediate_data = (param_equiv(head, "ImmediateData", "Yes"));