xref: /netbsd-src/sys/dev/iscsi/iscsi_text.c (revision cb7270a43602fb111e8c5b6fab5fd53ec6114b03)
1*cb7270a4Sandvar /*	$NetBSD: iscsi_text.c,v 1.15 2024/02/08 19:44:08 andvar Exp $	*/
2e01460c0Sagc 
3e01460c0Sagc /*-
4e01460c0Sagc  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
5e01460c0Sagc  * All rights reserved.
6e01460c0Sagc  *
7e01460c0Sagc  * This code is derived from software contributed to The NetBSD Foundation
8e01460c0Sagc  * by Wasabi Systems, Inc.
9e01460c0Sagc  *
10e01460c0Sagc  * Redistribution and use in source and binary forms, with or without
11e01460c0Sagc  * modification, are permitted provided that the following conditions
12e01460c0Sagc  * are met:
13e01460c0Sagc  * 1. Redistributions of source code must retain the above copyright
14e01460c0Sagc  *    notice, this list of conditions and the following disclaimer.
15e01460c0Sagc  * 2. Redistributions in binary form must reproduce the above copyright
16e01460c0Sagc  *    notice, this list of conditions and the following disclaimer in the
17e01460c0Sagc  *    documentation and/or other materials provided with the distribution.
18e01460c0Sagc  *
19e01460c0Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e01460c0Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e01460c0Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e01460c0Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e01460c0Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e01460c0Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e01460c0Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e01460c0Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e01460c0Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e01460c0Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e01460c0Sagc  * POSSIBILITY OF SUCH DAMAGE.
30e01460c0Sagc  */
31e01460c0Sagc 
32e01460c0Sagc #include "iscsi_globals.h"
33e01460c0Sagc #include "base64.h"
34e01460c0Sagc #include <sys/md5.h>
3538f95ba1Stls #include <sys/cprng.h>
36e01460c0Sagc 
37e01460c0Sagc #define isdigit(x) ((x) >= '0' && (x) <= '9')
38e01460c0Sagc #define toupper(x) ((x) & ~0x20)
39e01460c0Sagc 
40e01460c0Sagc /*****************************************************************************/
41e01460c0Sagc 
42e01460c0Sagc #define MAX_STRING   255	/* Maximum length of parameter value */
43e01460c0Sagc #define MAX_LIST     4		/* Maximum number of list elements we'll ever send */
44e01460c0Sagc 
45e01460c0Sagc /* Maximum number of negotiation parameters in the operational negotiation phase */
46e01460c0Sagc /* 48 should be more than enough even with the target defining its own keys */
47e01460c0Sagc #define MAX_NEG      48
48e01460c0Sagc 
49e01460c0Sagc #define CHAP_CHALLENGE_LEN    32	/* Number of bytes to send in challenge */
50e01460c0Sagc #define CHAP_MD5_SIZE         16	/* Number of bytes in MD5 hash */
51e01460c0Sagc 
52e01460c0Sagc /*****************************************************************************/
53e01460c0Sagc 
54e01460c0Sagc /* authentication states */
55e01460c0Sagc 
56e01460c0Sagc typedef enum
57e01460c0Sagc {
58e01460c0Sagc 	AUTH_INITIAL,				/* sending choice of algorithms */
59e01460c0Sagc 	AUTH_METHOD_SELECTED,		/* received choice, sending first parameter */
60e01460c0Sagc 	/* from here it's alg dependent */
61e01460c0Sagc 	AUTH_CHAP_ALG_SENT,			/* CHAP: Algorithm selected */
62e01460c0Sagc 	AUTH_CHAP_RSP_SENT,			/* CHAP: Response sent */
63e01460c0Sagc 	/* for all algorithms */
64e01460c0Sagc 	AUTH_DONE					/* in parameter negotiation stage */
65e01460c0Sagc } auth_state_t;
66e01460c0Sagc 
67e01460c0Sagc 
68e01460c0Sagc /* enumeration of all the keys we know, and a place for the ones we don't */
69e01460c0Sagc 
70e01460c0Sagc typedef enum
71e01460c0Sagc {
72e01460c0Sagc 	K_AuthMethod,
73e01460c0Sagc 	K_Auth_CHAP_Algorithm,
74e01460c0Sagc 	K_Auth_CHAP_Challenge,
75e01460c0Sagc 	K_Auth_CHAP_Identifier,
76e01460c0Sagc 	K_Auth_CHAP_Name,
77e01460c0Sagc 	K_Auth_CHAP_Response,
78e01460c0Sagc 	K_DataDigest,
79e01460c0Sagc 	K_DataPDUInOrder,
80e01460c0Sagc 	K_DataSequenceInOrder,
81e01460c0Sagc 	K_DefaultTime2Retain,
82e01460c0Sagc 	K_DefaultTime2Wait,
83e01460c0Sagc 	K_ErrorRecoveryLevel,
84e01460c0Sagc 	K_FirstBurstLength,
85e01460c0Sagc 	K_HeaderDigest,
86e01460c0Sagc 	K_IFMarker,
87e01460c0Sagc 	K_IFMarkInt,
88e01460c0Sagc 	K_ImmediateData,
89e01460c0Sagc 	K_InitialR2T,
90e01460c0Sagc 	K_InitiatorAlias,
91e01460c0Sagc 	K_InitiatorName,
92e01460c0Sagc 	K_MaxBurstLength,
93e01460c0Sagc 	K_MaxConnections,
94e01460c0Sagc 	K_MaxOutstandingR2T,
95e01460c0Sagc 	K_MaxRecvDataSegmentLength,
96e01460c0Sagc 	K_OFMarker,
97e01460c0Sagc 	K_OFMarkInt,
98e01460c0Sagc 	K_SendTargets,
99e01460c0Sagc 	K_SessionType,
100e01460c0Sagc 	K_TargetAddress,
101e01460c0Sagc 	K_TargetAlias,
102e01460c0Sagc 	K_TargetName,
103e01460c0Sagc 	K_TargetPortalGroupTag,
104e01460c0Sagc 	K_NotUnderstood
105e01460c0Sagc } text_key_t;
106e01460c0Sagc 
107e01460c0Sagc /* maximum known key */
108e01460c0Sagc #define MAX_KEY   K_TargetPortalGroupTag
109e01460c0Sagc 
110e01460c0Sagc /* value types */
111e01460c0Sagc typedef enum
112e01460c0Sagc {						/* Value is... */
113e01460c0Sagc 	T_NUM,					/* numeric */
114e01460c0Sagc 	T_BIGNUM,				/* large numeric */
115e01460c0Sagc 	T_STRING,				/* string */
116e01460c0Sagc 	T_YESNO,				/* boolean (Yes or No) */
117e01460c0Sagc 	T_AUTH,					/* authentication type (CHAP or None for now) */
118e01460c0Sagc 	T_DIGEST,				/* digest (None or CRC32C) */
119e01460c0Sagc 	T_RANGE,				/* numeric range */
120e01460c0Sagc 	T_SENDT,				/* send target options (ALL, target-name, empty) */
121e01460c0Sagc 	T_SESS					/* session type (Discovery or Normal) */
122e01460c0Sagc } val_kind_t;
123e01460c0Sagc 
124e01460c0Sagc 
125e01460c0Sagc /* table of negotiation key strings with value type and default */
126e01460c0Sagc 
127e01460c0Sagc typedef struct
128e01460c0Sagc {
129e01460c0Sagc 	const uint8_t *name;				/* the key name */
130e01460c0Sagc 	val_kind_t val;				/* the value type */
131e01460c0Sagc 	uint32_t defval;			/* default value */
132e01460c0Sagc } key_entry_t;
133e01460c0Sagc 
134e01460c0Sagc STATIC key_entry_t entries[] = {
135e01460c0Sagc 	{"AuthMethod", T_AUTH, 0},
1364ccc6176Smlelstv 	{"CHAP_A", T_NUM, ISCSI_CHAP_MD5},
137e01460c0Sagc 	{"CHAP_C", T_BIGNUM, 0},
138e01460c0Sagc 	{"CHAP_I", T_NUM, 0},
139e01460c0Sagc 	{"CHAP_N", T_STRING, 0},
140e01460c0Sagc 	{"CHAP_R", T_BIGNUM, 0},
141e01460c0Sagc 	{"DataDigest", T_DIGEST, 0},
142e01460c0Sagc 	{"DataPDUInOrder", T_YESNO, 1},
143e01460c0Sagc 	{"DataSequenceInOrder", T_YESNO, 1},
144e01460c0Sagc 	{"DefaultTime2Retain", T_NUM, 20},
145e01460c0Sagc 	{"DefaultTime2Wait", T_NUM, 2},
146e01460c0Sagc 	{"ErrorRecoveryLevel", T_NUM, 0},
147e01460c0Sagc 	{"FirstBurstLength", T_NUM, 64 * 1024},
148e01460c0Sagc 	{"HeaderDigest", T_DIGEST, 0},
149e01460c0Sagc 	{"IFMarker", T_YESNO, 0},
150e01460c0Sagc 	{"IFMarkInt", T_RANGE, 2048},
151e01460c0Sagc 	{"ImmediateData", T_YESNO, 1},
152e01460c0Sagc 	{"InitialR2T", T_YESNO, 1},
153e01460c0Sagc 	{"InitiatorAlias", T_STRING, 0},
154e01460c0Sagc 	{"InitiatorName", T_STRING, 0},
155e01460c0Sagc 	{"MaxBurstLength", T_NUM, 256 * 1024},
156e01460c0Sagc 	{"MaxConnections", T_NUM, 1},
157e01460c0Sagc 	{"MaxOutstandingR2T", T_NUM, 1},
158e01460c0Sagc 	{"MaxRecvDataSegmentLength", T_NUM, 8192},
159e01460c0Sagc 	{"OFMarker", T_YESNO, 0},
160e01460c0Sagc 	{"OFMarkInt", T_RANGE, 2048},
161e01460c0Sagc 	{"SendTargets", T_SENDT, 0},
162e01460c0Sagc 	{"SessionType", T_SESS, 0},
163e01460c0Sagc 	{"TargetAddress", T_STRING, 0},
164e01460c0Sagc 	{"TargetAlias", T_STRING, 0},
165e01460c0Sagc 	{"TargetName", T_STRING, 0},
166e01460c0Sagc 	{"TargetPortalGroupTag", T_NUM, 0},
167e01460c0Sagc 	{NULL, T_STRING, 0}
168e01460c0Sagc };
169e01460c0Sagc 
170e01460c0Sagc /* a negotiation parameter: key and values (there may be more than 1 for lists) */
171e01460c0Sagc typedef struct
172e01460c0Sagc {
173e01460c0Sagc 	text_key_t key;		/* the key */
174e01460c0Sagc 	int list_num;		/* number of elements in list, doubles as */
175e01460c0Sagc 				/* data size for large numeric values */
1764ccc6176Smlelstv 	bool hex_bignums;	/* whether to encode in hex or base64 */
177e01460c0Sagc 	union
178e01460c0Sagc 	{
179e01460c0Sagc 		uint32_t nval[MAX_LIST];/* numeric or enumeration values */
180e01460c0Sagc 		uint8_t *sval;		/* string or data pointer */
181e01460c0Sagc 	} val;
182e01460c0Sagc } negotiation_parameter_t;
183e01460c0Sagc 
184e01460c0Sagc 
185e01460c0Sagc /* Negotiation state flags */
186e01460c0Sagc #define NS_SENT      0x01		/* key was sent to target */
187e01460c0Sagc #define NS_RECEIVED  0x02		/* key was received from target */
188e01460c0Sagc 
189e01460c0Sagc typedef struct
190e01460c0Sagc {
191e01460c0Sagc 	negotiation_parameter_t pars[MAX_NEG];	/* the parameters to send */
192e01460c0Sagc 	negotiation_parameter_t *cpar;			/* the last parameter set */
193e01460c0Sagc 	uint16_t num_pars;						/* number of parameters to send */
194e01460c0Sagc 	auth_state_t auth_state;				/* authentication state */
195e01460c0Sagc 	iscsi_auth_types_t auth_alg;			/* authentication algorithm */
196e01460c0Sagc 	uint8_t kflags[MAX_KEY + 2];			/* negotiation flags for each key */
197e01460c0Sagc 	uint8_t password[MAX_STRING + 1];		/* authentication secret */
198e01460c0Sagc 	uint8_t target_password[MAX_STRING + 1];	/* target authentication secret */
199e01460c0Sagc 	uint8_t user_name[MAX_STRING + 1];		/* authentication user ID */
200e01460c0Sagc 	uint8_t temp_buf[MAX_STRING + 1];		/* scratch buffer */
201e01460c0Sagc 
202e01460c0Sagc 	bool HeaderDigest;
203e01460c0Sagc 	bool DataDigest;
204e01460c0Sagc 	bool InitialR2T;
205e01460c0Sagc 	bool ImmediateData;
206e01460c0Sagc 	uint32_t ErrorRecoveryLevel;
207e01460c0Sagc 	uint32_t MaxRecvDataSegmentLength;
208e01460c0Sagc 	uint32_t MaxConnections;
209e01460c0Sagc 	uint32_t DefaultTime2Wait;
210e01460c0Sagc 	uint32_t DefaultTime2Retain;
211e01460c0Sagc 	uint32_t MaxBurstLength;
212e01460c0Sagc 	uint32_t FirstBurstLength;
213e01460c0Sagc 	uint32_t MaxOutstandingR2T;
214e01460c0Sagc 
215e01460c0Sagc } negotiation_state_t;
216e01460c0Sagc 
217e01460c0Sagc 
218e01460c0Sagc #define TX(state, key) (state->kflags [key] & NS_SENT)
219e01460c0Sagc #define RX(state, key) (state->kflags [key] & NS_RECEIVED)
220e01460c0Sagc 
221e01460c0Sagc /*****************************************************************************/
222e01460c0Sagc 
223e01460c0Sagc STATIC void
chap_md5_response(uint8_t * buffer,uint8_t identifier,uint8_t * secret,uint8_t * challenge,int challenge_size)224e01460c0Sagc chap_md5_response(uint8_t *buffer, uint8_t identifier, uint8_t *secret,
225e01460c0Sagc 				  uint8_t *challenge, int challenge_size)
226e01460c0Sagc {
227e01460c0Sagc 	MD5_CTX md5;
228e01460c0Sagc 
229e01460c0Sagc 	MD5Init(&md5);
230e01460c0Sagc 	MD5Update(&md5, &identifier, 1);
231e01460c0Sagc 	MD5Update(&md5, secret, strlen(secret));
232e01460c0Sagc 	MD5Update(&md5, challenge, challenge_size);
233e01460c0Sagc 	MD5Final(buffer, &md5);
234e01460c0Sagc }
235e01460c0Sagc 
236e01460c0Sagc /*****************************************************************************/
237e01460c0Sagc 
238e01460c0Sagc /*
239e01460c0Sagc  * hexdig:
240e01460c0Sagc  *    Return value of hex digit.
241e01460c0Sagc  *    Note: a null character is acceptable, and returns 0.
242e01460c0Sagc  *
243e01460c0Sagc  *    Parameter:
244e01460c0Sagc  *          c     The character
245e01460c0Sagc  *
246e01460c0Sagc  *    Returns:    The value, -1 on error.
247e01460c0Sagc  */
248e01460c0Sagc 
249e01460c0Sagc static __inline int
hexdig(uint8_t c)250e01460c0Sagc hexdig(uint8_t c)
251e01460c0Sagc {
252e01460c0Sagc 
253e01460c0Sagc 	if (!c) {
254e01460c0Sagc 		return 0;
255e01460c0Sagc 	}
256e01460c0Sagc 	if (isdigit(c)) {
257e01460c0Sagc 		return c - '0';
258e01460c0Sagc 	}
259e01460c0Sagc 	c = toupper(c);
260e01460c0Sagc 	if (c >= 'A' && c <= 'F') {
261e01460c0Sagc 		return c - 'A' + 10;
262e01460c0Sagc 	}
263e01460c0Sagc 	return -1;
264e01460c0Sagc }
265e01460c0Sagc 
266e01460c0Sagc /*
267e01460c0Sagc  * skiptozero:
268e01460c0Sagc  *    Skip to next zero character in buffer.
269e01460c0Sagc  *
270e01460c0Sagc  *    Parameter:
271e01460c0Sagc  *          buf      The buffer pointer
272e01460c0Sagc  *
273e01460c0Sagc  *    Returns:    The pointer to the character after the zero character.
274e01460c0Sagc  */
275e01460c0Sagc 
276e01460c0Sagc static __inline uint8_t *
skiptozero(uint8_t * buf)277e01460c0Sagc skiptozero(uint8_t *buf)
278e01460c0Sagc {
279e01460c0Sagc 
280e01460c0Sagc 	while (*buf) {
281e01460c0Sagc 		buf++;
282e01460c0Sagc 	}
283e01460c0Sagc 	return buf + 1;
284e01460c0Sagc }
285e01460c0Sagc 
286e01460c0Sagc 
287e01460c0Sagc /*
288e01460c0Sagc  * get_bignumval:
289e01460c0Sagc  *    Get a large numeric value.
290e01460c0Sagc  *    NOTE: Overwrites source string.
291e01460c0Sagc  *
292e01460c0Sagc  *    Parameter:
293e01460c0Sagc  *          buf      The buffer pointer
294e01460c0Sagc  *          par      The parameter
295e01460c0Sagc  *
296e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
297e01460c0Sagc  */
298e01460c0Sagc 
299e01460c0Sagc STATIC uint8_t *
get_bignumval(uint8_t * buf,negotiation_parameter_t * par)300e01460c0Sagc get_bignumval(uint8_t *buf, negotiation_parameter_t *par)
301e01460c0Sagc {
302e01460c0Sagc 	int val;
303e01460c0Sagc 	char c;
304e01460c0Sagc 	uint8_t *dp = buf;
305e01460c0Sagc 
306e01460c0Sagc 	par->val.sval = buf;
307e01460c0Sagc 
308e01460c0Sagc 	if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
309e01460c0Sagc 		buf += 2;
310e01460c0Sagc 		while ((c = *buf) != 0x0) {
311e01460c0Sagc 			buf++;
312e01460c0Sagc 			val = (hexdig(c) << 4) | hexdig(*buf);
313e01460c0Sagc 			if (val < 0) {
314e01460c0Sagc 				return NULL;
315e01460c0Sagc 			}
316e01460c0Sagc 			*dp++ = (uint8_t) val;
317e01460c0Sagc 			if (*buf) {
318e01460c0Sagc 				buf++;
319e01460c0Sagc 			}
320e01460c0Sagc 		}
321e01460c0Sagc 		buf++;
322e01460c0Sagc 		par->list_num = dp - par->val.sval;
3234ccc6176Smlelstv 		par->hex_bignums = true;
324e01460c0Sagc 	} else if (buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B')) {
325e01460c0Sagc 		buf = base64_decode(&buf[2], par->val.sval, &par->list_num);
326e01460c0Sagc 	} else {
327e01460c0Sagc 		DEBOUT(("Ill-formatted large number <%s>\n", buf));
328e01460c0Sagc 		return NULL;
329e01460c0Sagc 	}
330e01460c0Sagc 
331e01460c0Sagc 	return buf;
332e01460c0Sagc }
333e01460c0Sagc 
334e01460c0Sagc 
335e01460c0Sagc /*
336e01460c0Sagc  * get_numval:
337e01460c0Sagc  *    Get a numeric value.
338e01460c0Sagc  *
339e01460c0Sagc  *    Parameter:
340e01460c0Sagc  *          buf      The buffer pointer
341e01460c0Sagc  *          pval     The pointer to the result.
3424ccc6176Smlelstv  *          sep      Separator to next value.
343e01460c0Sagc  *
344e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
345e01460c0Sagc  */
346e01460c0Sagc 
347e01460c0Sagc STATIC uint8_t *
get_numval(uint8_t * buf,uint32_t * pval,const uint8_t sep)3484ccc6176Smlelstv get_numval(uint8_t *buf, uint32_t *pval, const uint8_t sep)
349e01460c0Sagc {
350e01460c0Sagc 	uint32_t val = 0;
351e01460c0Sagc 	char c;
352e01460c0Sagc 
353e01460c0Sagc 	if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
354e01460c0Sagc 		buf += 2;
355e01460c0Sagc 		while (*buf && *buf != '~') {
356e01460c0Sagc 			int n;
357e01460c0Sagc 
358e01460c0Sagc 			if ((n = hexdig(*buf++)) < 0)
359e01460c0Sagc 				return NULL;
360e01460c0Sagc 			val = (val << 4) | n;
361e01460c0Sagc 		}
362e01460c0Sagc 	} else
363e01460c0Sagc 		while (*buf && *buf != '~') {
364e01460c0Sagc 			c = *buf++;
365e01460c0Sagc 			if (!isdigit(c))
366e01460c0Sagc 				return NULL;
367e01460c0Sagc 			val = val * 10 + (c - '0');
368e01460c0Sagc 		}
369e01460c0Sagc 
370e01460c0Sagc 	*pval = val;
371e01460c0Sagc 
372e01460c0Sagc 	return buf + 1;
373e01460c0Sagc }
374e01460c0Sagc 
375e01460c0Sagc 
376e01460c0Sagc /*
377e01460c0Sagc  * get_range:
378e01460c0Sagc  *    Get a numeric range.
379e01460c0Sagc  *
380e01460c0Sagc  *    Parameter:
381e01460c0Sagc  *          buf      The buffer pointer
382e01460c0Sagc  *          pval1    The pointer to the first result.
383e01460c0Sagc  *          pval2    The pointer to the second result.
384e01460c0Sagc  *
385e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
386e01460c0Sagc  */
387e01460c0Sagc 
388e01460c0Sagc STATIC uint8_t *
get_range(uint8_t * buf,uint32_t * pval1,uint32_t * pval2)389e01460c0Sagc get_range(uint8_t *buf, uint32_t *pval1, uint32_t *pval2)
390e01460c0Sagc {
391e01460c0Sagc 
3924ccc6176Smlelstv 	if ((buf = get_numval(buf, pval1, '~')) == NULL)
393e01460c0Sagc 		return NULL;
394e01460c0Sagc 	if (!*buf)
395e01460c0Sagc 		return NULL;
3964ccc6176Smlelstv 	if ((buf = get_numval(buf, pval2, '~')) == NULL)
397e01460c0Sagc 		return NULL;
398e01460c0Sagc 	return buf;
399e01460c0Sagc }
400e01460c0Sagc 
401e01460c0Sagc 
402e01460c0Sagc /*
403e01460c0Sagc  * get_ynval:
404e01460c0Sagc  *    Get a yes/no selection.
405e01460c0Sagc  *
406e01460c0Sagc  *    Parameter:
407e01460c0Sagc  *          buf      The buffer pointer
408e01460c0Sagc  *          pval     The pointer to the result.
409e01460c0Sagc  *
410e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
411e01460c0Sagc  */
412e01460c0Sagc 
413e01460c0Sagc STATIC uint8_t *
get_ynval(uint8_t * buf,uint32_t * pval)414e01460c0Sagc get_ynval(uint8_t *buf, uint32_t *pval)
415e01460c0Sagc {
416e01460c0Sagc 
417e01460c0Sagc 	if (strcmp(buf, "Yes") == 0)
418e01460c0Sagc 		*pval = 1;
419e01460c0Sagc 	else if (strcmp(buf, "No") == 0)
420e01460c0Sagc 		*pval = 0;
421e01460c0Sagc 	else
422e01460c0Sagc 		return NULL;
423e01460c0Sagc 
424e01460c0Sagc 	return skiptozero(buf);
425e01460c0Sagc }
426e01460c0Sagc 
427e01460c0Sagc 
428e01460c0Sagc /*
429e01460c0Sagc  * get_digestval:
430e01460c0Sagc  *    Get a digest selection.
431e01460c0Sagc  *
432e01460c0Sagc  *    Parameter:
433e01460c0Sagc  *          buf      The buffer pointer
434e01460c0Sagc  *          pval     The pointer to the result.
435e01460c0Sagc  *
436e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
437e01460c0Sagc  */
438e01460c0Sagc 
439e01460c0Sagc STATIC uint8_t *
get_digestval(uint8_t * buf,uint32_t * pval)440e01460c0Sagc get_digestval(uint8_t *buf, uint32_t *pval)
441e01460c0Sagc {
442e01460c0Sagc 
443e01460c0Sagc 	if (strcmp(buf, "CRC32C") == 0)
444e01460c0Sagc 		*pval = 1;
445e01460c0Sagc 	else if (strcmp(buf, "None") == 0)
446e01460c0Sagc 		*pval = 0;
447e01460c0Sagc 	else
448e01460c0Sagc 		return NULL;
449e01460c0Sagc 
450e01460c0Sagc 	return skiptozero(buf);
451e01460c0Sagc }
452e01460c0Sagc 
453e01460c0Sagc 
454e01460c0Sagc /*
455e01460c0Sagc  * get_authval:
456e01460c0Sagc  *    Get an authentication method.
457e01460c0Sagc  *
458e01460c0Sagc  *    Parameter:
459e01460c0Sagc  *          buf      The buffer pointer
460e01460c0Sagc  *          pval     The pointer to the result.
461e01460c0Sagc  *
462e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
463e01460c0Sagc  */
464e01460c0Sagc 
465e01460c0Sagc STATIC uint8_t *
get_authval(uint8_t * buf,uint32_t * pval)466e01460c0Sagc get_authval(uint8_t *buf, uint32_t *pval)
467e01460c0Sagc {
468e01460c0Sagc 
469e01460c0Sagc 	if (strcmp(buf, "None") == 0)
470e01460c0Sagc 		*pval = ISCSI_AUTH_None;
471e01460c0Sagc 	else if (strcmp(buf, "CHAP") == 0)
472e01460c0Sagc 		*pval = ISCSI_AUTH_CHAP;
473e01460c0Sagc 	else if (strcmp(buf, "KRB5") == 0)
474e01460c0Sagc 		*pval = ISCSI_AUTH_KRB5;
475e01460c0Sagc 	else if (strcmp(buf, "SRP") == 0)
476e01460c0Sagc 		*pval = ISCSI_AUTH_SRP;
477e01460c0Sagc 	else
478e01460c0Sagc 		return NULL;
479e01460c0Sagc 
480e01460c0Sagc 	return skiptozero(buf);
481e01460c0Sagc }
482e01460c0Sagc 
483e01460c0Sagc 
484e01460c0Sagc /*
485e01460c0Sagc  * get_strval:
486e01460c0Sagc  *    Get a string value (returns pointer to original buffer, not a copy).
487e01460c0Sagc  *
488e01460c0Sagc  *    Parameter:
489e01460c0Sagc  *          buf      The buffer pointer
490e01460c0Sagc  *          pval     The pointer to the result pointer.
491e01460c0Sagc  *
492e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
493e01460c0Sagc  */
494e01460c0Sagc 
495e01460c0Sagc STATIC uint8_t *
get_strval(uint8_t * buf,uint8_t ** pval)496e01460c0Sagc get_strval(uint8_t *buf, uint8_t **pval)
497e01460c0Sagc {
498e01460c0Sagc 
499e01460c0Sagc 	if (strlen(buf) > MAX_STRING)
500e01460c0Sagc 		return NULL;
501e01460c0Sagc 
502e01460c0Sagc 	*pval = buf;
503e01460c0Sagc 
504e01460c0Sagc 	return skiptozero(buf);
505e01460c0Sagc }
506e01460c0Sagc 
507e01460c0Sagc 
508e01460c0Sagc /*
509e01460c0Sagc  * get_parameter:
510e01460c0Sagc  *    Analyze a key=value string.
511e01460c0Sagc  *    NOTE: The string is modified in the process.
512e01460c0Sagc  *
513e01460c0Sagc  *    Parameter:
514e01460c0Sagc  *          buf      The buffer pointer
515e01460c0Sagc  *          par      The parameter descriptor to be filled in
516e01460c0Sagc  *
517e01460c0Sagc  *    Returns:    The pointer to the next parameter, NULL on error.
518e01460c0Sagc  */
519e01460c0Sagc 
520e01460c0Sagc STATIC uint8_t *
get_parameter(uint8_t * buf,negotiation_parameter_t * par)521e01460c0Sagc get_parameter(uint8_t *buf, negotiation_parameter_t *par)
522e01460c0Sagc {
523e01460c0Sagc 	uint8_t *bp = buf;
524e01460c0Sagc 	int i;
525e01460c0Sagc 
526e01460c0Sagc 	while (*bp && *bp != '=') {
527e01460c0Sagc 		bp++;
528e01460c0Sagc 	}
529e01460c0Sagc 	if (!*bp) {
530e01460c0Sagc 		DEBOUT(("get_parameter: Premature end of parameter\n"));
531e01460c0Sagc 		return NULL;
532e01460c0Sagc 	}
533e01460c0Sagc 
534e01460c0Sagc 	*bp++ = 0;
535e01460c0Sagc 
536e01460c0Sagc 	for (i = 0; i <= MAX_KEY; i++)
537e01460c0Sagc 		if (!strcmp(buf, entries[i].name))
538e01460c0Sagc 			break;
539e01460c0Sagc 
540e01460c0Sagc 	par->key = i;
541e01460c0Sagc 	par->list_num = 1;
5424ccc6176Smlelstv 	par->hex_bignums = false; /* set by get_bignumval */
543e01460c0Sagc 
544e01460c0Sagc 	if (i > MAX_KEY) {
545e01460c0Sagc 		DEBOUT(("get_parameter: unrecognized key <%s>\n", buf));
546e01460c0Sagc 		if (strlen(buf) > MAX_STRING) {
547e01460c0Sagc 			DEBOUT(("get_parameter: key name > MAX_STRING\n"));
548e01460c0Sagc 			return NULL;
549e01460c0Sagc 		}
550e01460c0Sagc 		par->val.sval = buf;
551e01460c0Sagc 		return skiptozero(bp);
552e01460c0Sagc 	}
553e01460c0Sagc 
554da501d22Smlelstv 	DEB(10, ("get_par: key <%s>=%d, val=%d, ret %p\n",
555da501d22Smlelstv 			buf, i, entries[i].val, bp));
556da501d22Smlelstv 	DEB(10, ("get_par: value '%s'\n",bp));
557da501d22Smlelstv 
558e01460c0Sagc 	switch (entries[i].val) {
559e01460c0Sagc 	case T_NUM:
5604ccc6176Smlelstv 		bp = get_numval(bp, &par->val.nval[0], '\0');
561e01460c0Sagc 		break;
562e01460c0Sagc 
563e01460c0Sagc 	case T_BIGNUM:
564e01460c0Sagc 		bp = get_bignumval(bp, par);
565e01460c0Sagc 		break;
566e01460c0Sagc 
567e01460c0Sagc 	case T_STRING:
568e01460c0Sagc 		bp = get_strval(bp, &par->val.sval);
569e01460c0Sagc 		break;
570e01460c0Sagc 
571e01460c0Sagc 	case T_YESNO:
572e01460c0Sagc 		bp = get_ynval(bp, &par->val.nval[0]);
573e01460c0Sagc 		break;
574e01460c0Sagc 
575e01460c0Sagc 	case T_AUTH:
576e01460c0Sagc 		bp = get_authval(bp, &par->val.nval[0]);
577e01460c0Sagc 		break;
578e01460c0Sagc 
579e01460c0Sagc 	case T_DIGEST:
580e01460c0Sagc 		bp = get_digestval(bp, &par->val.nval[0]);
581e01460c0Sagc 		break;
582e01460c0Sagc 
583e01460c0Sagc 	case T_RANGE:
584e01460c0Sagc 		bp = get_range(bp, &par->val.nval[0], &par->val.nval[1]);
585e01460c0Sagc 		break;
586e01460c0Sagc 
587e01460c0Sagc 	default:
588e01460c0Sagc 		/* Target sending any other types is wrong */
589e01460c0Sagc 		bp = NULL;
590e01460c0Sagc 		break;
591e01460c0Sagc 	}
592e01460c0Sagc 	return bp;
593e01460c0Sagc }
594e01460c0Sagc 
595e01460c0Sagc /*****************************************************************************/
596e01460c0Sagc 
597e01460c0Sagc /*
598e01460c0Sagc  * my_strcpy:
599e01460c0Sagc  *    Replacement for strcpy that returns the end of the result string
600e01460c0Sagc  *
601e01460c0Sagc  *    Parameter:
602e01460c0Sagc  *          dest     The destination buffer pointer
603e01460c0Sagc  *          src      The source string
604e01460c0Sagc  *
605e01460c0Sagc  *    Returns:    A pointer to the terminating zero of the result.
606e01460c0Sagc  */
607e01460c0Sagc 
608e01460c0Sagc static __inline unsigned
my_strcpy(uint8_t * dest,const uint8_t * src)609e01460c0Sagc my_strcpy(uint8_t *dest, const uint8_t *src)
610e01460c0Sagc {
611e01460c0Sagc 	unsigned	cc;
612e01460c0Sagc 
613e01460c0Sagc 	for (cc = 0 ; (*dest = *src) != 0x0 ; cc++) {
614e01460c0Sagc 		dest++;
615e01460c0Sagc 		src++;
616e01460c0Sagc 	}
617e01460c0Sagc 	return cc;
618e01460c0Sagc }
619e01460c0Sagc 
620da501d22Smlelstv /*
621da501d22Smlelstv  * put_bignumval:
622da501d22Smlelstv  *    Write a large numeric value.
623da501d22Smlelstv  *    NOTE: Overwrites source string.
624da501d22Smlelstv  *
625da501d22Smlelstv  *    Parameter:
626da501d22Smlelstv  *          buf      The buffer pointer
627da501d22Smlelstv  *          par      The parameter
628da501d22Smlelstv  *
629da501d22Smlelstv  *    Returns:    The pointer to the next parameter, NULL on error.
630da501d22Smlelstv  */
631da501d22Smlelstv 
632da501d22Smlelstv STATIC unsigned
put_bignumval(negotiation_parameter_t * par,uint8_t * buf)633da501d22Smlelstv put_bignumval(negotiation_parameter_t *par, uint8_t *buf)
634da501d22Smlelstv {
635996d5208Smlelstv 	int k, c;
636996d5208Smlelstv 
637f1a7fa8cSmlelstv 	if (par->hex_bignums) {
638996d5208Smlelstv 		my_strcpy(buf, "0x");
639996d5208Smlelstv 		for (k=0; k<par->list_num; ++k) {
640996d5208Smlelstv 			c = par->val.sval[k] >> 4;
641996d5208Smlelstv 			buf[2+2*k] = c < 10 ? '0' + c : 'a' + (c-10);
642996d5208Smlelstv 			c = par->val.sval[k] & 0xf;
643996d5208Smlelstv 			buf[2+2*k+1] = c < 10 ? '0' + c : 'a' + (c-10);
644996d5208Smlelstv 		}
645996d5208Smlelstv 		buf[2+2*k] = '\0';
646996d5208Smlelstv 
647996d5208Smlelstv 		return 2+2*par->list_num;
648f1a7fa8cSmlelstv 	}
649da501d22Smlelstv 	return base64_encode(par->val.sval, par->list_num, buf);
650da501d22Smlelstv }
651e01460c0Sagc 
652e01460c0Sagc /*
653e01460c0Sagc  * put_parameter:
654e01460c0Sagc  *    Create a key=value string.
655e01460c0Sagc  *
656e01460c0Sagc  *    Parameter:
657e01460c0Sagc  *          buf      The buffer pointer
658e01460c0Sagc  *          par      The parameter descriptor
659e01460c0Sagc  *
660e01460c0Sagc  *    Returns:    The pointer to the next free buffer space, NULL on error.
661e01460c0Sagc  */
662e01460c0Sagc 
663e01460c0Sagc STATIC unsigned
put_parameter(uint8_t * buf,unsigned len,negotiation_parameter_t * par)664e01460c0Sagc put_parameter(uint8_t *buf, unsigned len, negotiation_parameter_t *par)
665e01460c0Sagc {
666e01460c0Sagc 	int i;
667da501d22Smlelstv 	unsigned	cc, cl;
668e01460c0Sagc 	const uint8_t *sp;
669e01460c0Sagc 
670da501d22Smlelstv 	DEB(10, ("put_par: key <%s>=%d, val=%d\n",
671da501d22Smlelstv 		entries[par->key].name, par->key, entries[par->key].val));
672da501d22Smlelstv 
673e01460c0Sagc 	if (par->key > MAX_KEY) {
674e01460c0Sagc 		return snprintf(buf, len, "%s=NotUnderstood", par->val.sval);
675e01460c0Sagc 	}
676e01460c0Sagc 
677e01460c0Sagc 	cc = snprintf(buf, len, "%s=", entries[par->key].name);
678fb640ba0Schristos 	if (cc >= len)
679fb640ba0Schristos 		return len;
680e01460c0Sagc 
681e01460c0Sagc 	for (i = 0; i < par->list_num; i++) {
682e01460c0Sagc 		switch (entries[par->key].val) {
683e01460c0Sagc 		case T_NUM:
684da501d22Smlelstv 			cl = snprintf(&buf[cc], len - cc, "%d",
685da501d22Smlelstv 			               par->val.nval[i]);
686e01460c0Sagc 			break;
687e01460c0Sagc 
688e01460c0Sagc 		case T_BIGNUM:
689da501d22Smlelstv 			cl = put_bignumval(par, &buf[cc]);
690e01460c0Sagc 			i = par->list_num;
691e01460c0Sagc 			break;
692e01460c0Sagc 
693e01460c0Sagc 		case T_STRING:
694da501d22Smlelstv 			cl =  my_strcpy(&buf[cc], par->val.sval);
695e01460c0Sagc 			break;
696e01460c0Sagc 
697e01460c0Sagc 		case T_YESNO:
698da501d22Smlelstv 			cl = my_strcpy(&buf[cc],
699e01460c0Sagc 				(par->val.nval[i]) ? "Yes" : "No");
700e01460c0Sagc 			break;
701e01460c0Sagc 
702e01460c0Sagc 		case T_AUTH:
703e01460c0Sagc 			switch (par->val.nval[i]) {
704e01460c0Sagc 			case ISCSI_AUTH_CHAP:
705e01460c0Sagc 				sp = "CHAP";
706e01460c0Sagc 				break;
707e01460c0Sagc 			case ISCSI_AUTH_KRB5:
708e01460c0Sagc 				sp = "KRB5";
709e01460c0Sagc 				break;
710e01460c0Sagc 			case ISCSI_AUTH_SRP:
711e01460c0Sagc 				sp = "SRP";
712e01460c0Sagc 				break;
713e01460c0Sagc 			default:
714e01460c0Sagc 				sp = "None";
715e01460c0Sagc 				break;
716e01460c0Sagc 			}
717da501d22Smlelstv 			cl = my_strcpy(&buf[cc], sp);
718e01460c0Sagc 			break;
719e01460c0Sagc 
720e01460c0Sagc 		case T_DIGEST:
721da501d22Smlelstv 			cl = my_strcpy(&buf[cc],
722da501d22Smlelstv 				(par->val.nval[i]) ? "CRC32C" : "None");
723e01460c0Sagc 			break;
724e01460c0Sagc 
725e01460c0Sagc 		case T_RANGE:
726e01460c0Sagc 			if ((i + 1) >= par->list_num) {
727da501d22Smlelstv 				cl = my_strcpy(&buf[cc], "Reject");
728e01460c0Sagc 			} else {
729da501d22Smlelstv 				cl = snprintf(&buf[cc], len - cc,
730e01460c0Sagc 						"%d~%d", par->val.nval[i],
731e01460c0Sagc 						par->val.nval[i + 1]);
732e01460c0Sagc 				i++;
733e01460c0Sagc 			}
734e01460c0Sagc 			break;
735e01460c0Sagc 
736e01460c0Sagc 		case T_SENDT:
737da501d22Smlelstv 			cl = my_strcpy(&buf[cc], par->val.sval);
738e01460c0Sagc 			break;
739e01460c0Sagc 
740e01460c0Sagc 		case T_SESS:
741da501d22Smlelstv 			cl = my_strcpy(&buf[cc],
742e01460c0Sagc 				(par->val.nval[i]) ? "Normal" : "Discovery");
743e01460c0Sagc 			break;
744e01460c0Sagc 
745e01460c0Sagc 		default:
746da501d22Smlelstv 			cl = 0;
747*cb7270a4Sandvar 			/* We shouldn't be here... */
748e01460c0Sagc 			DEBOUT(("Invalid type %d in put_parameter!\n",
749e01460c0Sagc 					entries[par->key].val));
750e01460c0Sagc 			break;
751e01460c0Sagc 		}
752da501d22Smlelstv 
753da501d22Smlelstv 		DEB(10, ("put_par: value '%s'\n",&buf[cc]));
754da501d22Smlelstv 
755da501d22Smlelstv 		cc += cl;
756fb640ba0Schristos 		if (cc >= len)
757fb640ba0Schristos 			return len;
758e01460c0Sagc 		if ((i + 1) < par->list_num) {
759fb640ba0Schristos 			if (cc >= len)
760fb640ba0Schristos 				return len;
761e01460c0Sagc 			buf[cc++] = ',';
762e01460c0Sagc 		}
763e01460c0Sagc 	}
764e01460c0Sagc 
765fb640ba0Schristos 	if (cc >= len)
766fb640ba0Schristos 		return len;
767e01460c0Sagc 	buf[cc] = 0x0;				/* make sure it's terminated */
768e01460c0Sagc 	return cc + 1;				/* return next place in list */
769e01460c0Sagc }
770e01460c0Sagc 
771e01460c0Sagc 
772e01460c0Sagc /*
773e01460c0Sagc  * put_par_block:
774e01460c0Sagc  *    Fill a parameter block
775e01460c0Sagc  *
776e01460c0Sagc  *    Parameter:
777e01460c0Sagc  *          buf      The buffer pointer
778e01460c0Sagc  *          pars     The parameter descriptor array
779e01460c0Sagc  *          n        The number of elements
780e01460c0Sagc  *
781e01460c0Sagc  *    Returns:    result from put_parameter (ptr to buffer, NULL on error)
782e01460c0Sagc  */
783e01460c0Sagc 
784e01460c0Sagc static __inline unsigned
put_par_block(uint8_t * buf,unsigned len,negotiation_parameter_t * pars,int n)785e01460c0Sagc put_par_block(uint8_t *buf, unsigned len, negotiation_parameter_t *pars, int n)
786e01460c0Sagc {
787e01460c0Sagc 	unsigned	cc;
788e01460c0Sagc 	int i;
789e01460c0Sagc 
790e01460c0Sagc 	for (cc = 0, i = 0; i < n; i++) {
791e01460c0Sagc 		cc += put_parameter(&buf[cc], len - cc, pars++);
792e01460c0Sagc 		if (cc >= len) {
793e01460c0Sagc 			break;
794e01460c0Sagc 		}
795e01460c0Sagc 	}
796e01460c0Sagc 	return cc;
797e01460c0Sagc }
798e01460c0Sagc 
799e01460c0Sagc /*
800e01460c0Sagc  * parameter_size:
801e01460c0Sagc  *    Determine the size of a key=value string.
802e01460c0Sagc  *
803e01460c0Sagc  *    Parameter:
804e01460c0Sagc  *          par      The parameter descriptor
805e01460c0Sagc  *
806e01460c0Sagc  *    Returns:    The size of the resulting string.
807e01460c0Sagc  */
808e01460c0Sagc 
809e01460c0Sagc STATIC int
parameter_size(negotiation_parameter_t * par)810e01460c0Sagc parameter_size(negotiation_parameter_t *par)
811e01460c0Sagc {
812e01460c0Sagc 	int i, size;
813e01460c0Sagc 	char buf[24];	/* max. 2 10-digit numbers + sep. */
814e01460c0Sagc 
815e01460c0Sagc 	if (par->key > MAX_KEY) {
816e01460c0Sagc 		return strlen(par->val.sval) + 15;
817e01460c0Sagc 	}
818e01460c0Sagc 	/* count '=' and terminal zero */
819e01460c0Sagc 	size = strlen(entries[par->key].name) + 2;
820e01460c0Sagc 
821e01460c0Sagc 	for (i = 0; i < par->list_num; i++) {
822e01460c0Sagc 		switch (entries[par->key].val) {
823e01460c0Sagc 		case T_NUM:
824e01460c0Sagc 			size += snprintf(buf, sizeof(buf), "%d",
825e01460c0Sagc 					par->val.nval[i]);
826e01460c0Sagc 			break;
827e01460c0Sagc 
828e01460c0Sagc 		case T_BIGNUM:
829e01460c0Sagc 			/* list_num holds value size */
830f1a7fa8cSmlelstv 			if (par->hex_bignums)
831996d5208Smlelstv 				size += 2 + 2*par->list_num;
832f1a7fa8cSmlelstv 			else
833e01460c0Sagc 				size += base64_enclen(par->list_num);
834e01460c0Sagc 			i = par->list_num;
835e01460c0Sagc 			break;
836e01460c0Sagc 
837e01460c0Sagc 		case T_STRING:
838e01460c0Sagc 		case T_SENDT:
839e01460c0Sagc 			size += strlen(par->val.sval);
840e01460c0Sagc 			break;
841e01460c0Sagc 
842e01460c0Sagc 		case T_YESNO:
843e01460c0Sagc 			size += (par->val.nval[i]) ? 3 : 2;
844e01460c0Sagc 			break;
845e01460c0Sagc 
846e01460c0Sagc 		case T_AUTH:
847e01460c0Sagc 			size += (par->val.nval[i] == ISCSI_AUTH_SRP) ? 3 : 4;
848e01460c0Sagc 			break;
849e01460c0Sagc 
850e01460c0Sagc 		case T_DIGEST:
851e01460c0Sagc 			size += (par->val.nval[i]) ? 6 : 4;
852e01460c0Sagc 			break;
853e01460c0Sagc 
854e01460c0Sagc 		case T_RANGE:
855996d5208Smlelstv 			if (i+1 < par->list_num) {
856e01460c0Sagc 				size += snprintf(buf, sizeof(buf), "%d~%d",
857e01460c0Sagc 					par->val.nval[i],
858e01460c0Sagc 					par->val.nval[i + 1]);
859e01460c0Sagc 				i++;
860996d5208Smlelstv 			} else
861996d5208Smlelstv 				DEBOUT(("Incomplete range parameter\n"));
862e01460c0Sagc 			break;
863e01460c0Sagc 
864e01460c0Sagc 		case T_SESS:
865e01460c0Sagc 			size += (par->val.nval[i]) ? 6 : 9;
866e01460c0Sagc 			break;
867e01460c0Sagc 
868e01460c0Sagc 		default:
869*cb7270a4Sandvar 			/* We shouldn't be here... */
870e01460c0Sagc 			DEBOUT(("Invalid type %d in parameter_size!\n",
871e01460c0Sagc 					entries[par->key].val));
872e01460c0Sagc 			break;
873e01460c0Sagc 		}
874e01460c0Sagc 		if ((i + 1) < par->list_num) {
875e01460c0Sagc 			size++;
876e01460c0Sagc 		}
877e01460c0Sagc 	}
878e01460c0Sagc 
879e01460c0Sagc 	return size;
880e01460c0Sagc }
881e01460c0Sagc 
882e01460c0Sagc 
883e01460c0Sagc /*
884e01460c0Sagc  * total_size:
885e01460c0Sagc  *    Determine the size of a negotiation data block
886e01460c0Sagc  *
887e01460c0Sagc  *    Parameter:
888e01460c0Sagc  *          pars     The parameter descriptor array
889e01460c0Sagc  *          n        The number of elements
890e01460c0Sagc  *
891e01460c0Sagc  *    Returns:    The size of the block
892e01460c0Sagc  */
893e01460c0Sagc 
894e01460c0Sagc static __inline int
total_size(negotiation_parameter_t * pars,int n)895e01460c0Sagc total_size(negotiation_parameter_t *pars, int n)
896e01460c0Sagc {
897e01460c0Sagc 	int i, size;
898e01460c0Sagc 
899e01460c0Sagc 	for (i = 0, size = 0; i < n; i++) {
900e01460c0Sagc 		size += parameter_size(pars++);
901e01460c0Sagc 	}
902e01460c0Sagc 	return size;
903e01460c0Sagc }
904e01460c0Sagc 
905e01460c0Sagc /*****************************************************************************/
906e01460c0Sagc 
907e01460c0Sagc 
908e01460c0Sagc /*
909e01460c0Sagc  * complete_pars:
910e01460c0Sagc  *    Allocate space for text parameters, translate parameter values into
911e01460c0Sagc  *    text.
912e01460c0Sagc  *
913e01460c0Sagc  *    Parameter:
914e01460c0Sagc  *          state    Negotiation state
915e01460c0Sagc  *          pdu      The transmit PDU
916e01460c0Sagc  *
917e01460c0Sagc  *    Returns:    0     On success
918e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
919e01460c0Sagc  */
920e01460c0Sagc 
921e01460c0Sagc STATIC int
complete_pars(negotiation_state_t * state,pdu_t * pdu)922e01460c0Sagc complete_pars(negotiation_state_t *state, pdu_t *pdu)
923e01460c0Sagc {
924e01460c0Sagc 	int len;
925e01460c0Sagc 	uint8_t *bp;
926e01460c0Sagc 
927e01460c0Sagc 	len = total_size(state->pars, state->num_pars);
928e01460c0Sagc 
929e01460c0Sagc 	DEB(10, ("complete_pars: n=%d, len=%d\n", state->num_pars, len));
930e01460c0Sagc 
9314ccc6176Smlelstv 	if (len == 0) {
9324ccc6176Smlelstv 		pdu->pdu_temp_data = NULL;
9334ccc6176Smlelstv 		pdu->pdu_temp_data_len = 0;
9344ccc6176Smlelstv 		return 0;
9354ccc6176Smlelstv 	}
9364ccc6176Smlelstv 
937e01460c0Sagc 	if ((bp = malloc(len, M_TEMP, M_WAITOK)) == NULL) {
938e01460c0Sagc 		DEBOUT(("*** Out of memory in complete_pars\n"));
939e01460c0Sagc 		return ISCSI_STATUS_NO_RESOURCES;
940e01460c0Sagc 	}
9418ab41cb9Schristos 	pdu->pdu_temp_data = bp;
942e01460c0Sagc 
9438ab41cb9Schristos 	if (put_par_block(pdu->pdu_temp_data, len, state->pars,
944e01460c0Sagc 			state->num_pars) == 0) {
945e01460c0Sagc 		DEBOUT(("Bad parameter in complete_pars\n"));
946e01460c0Sagc 		return ISCSI_STATUS_PARAMETER_INVALID;
947e01460c0Sagc 	}
948e01460c0Sagc 
9498ab41cb9Schristos 	pdu->pdu_temp_data_len = len;
950e01460c0Sagc 	return 0;
951e01460c0Sagc }
952e01460c0Sagc 
953e01460c0Sagc 
954e01460c0Sagc /*
955e01460c0Sagc  * set_key_n:
956e01460c0Sagc  *    Initialize a key and its numeric value.
957e01460c0Sagc  *
958e01460c0Sagc  *    Parameter:
959e01460c0Sagc  *          state    Negotiation state
960e01460c0Sagc  *          key      The key
961e01460c0Sagc  *          val      The value
962e01460c0Sagc  */
963e01460c0Sagc 
964e01460c0Sagc STATIC negotiation_parameter_t *
set_key_n(negotiation_state_t * state,text_key_t key,uint32_t val)965e01460c0Sagc set_key_n(negotiation_state_t *state, text_key_t key, uint32_t val)
966e01460c0Sagc {
967e01460c0Sagc 	negotiation_parameter_t *par;
968e01460c0Sagc 
969e01460c0Sagc 	if (state->num_pars >= MAX_NEG) {
970e01460c0Sagc 		DEBOUT(("set_key_n: num_pars (%d) >= MAX_NEG (%d)\n",
971e01460c0Sagc 				state->num_pars, MAX_NEG));
972e01460c0Sagc 		return NULL;
973e01460c0Sagc 	}
974e01460c0Sagc 	par = &state->pars[state->num_pars];
975e01460c0Sagc 	par->key = key;
976e01460c0Sagc 	par->list_num = 1;
977e01460c0Sagc 	par->val.nval[0] = val;
978e01460c0Sagc 	state->num_pars++;
979e01460c0Sagc 	state->kflags[key] |= NS_SENT;
980e01460c0Sagc 
981e01460c0Sagc 	return par;
982e01460c0Sagc }
983e01460c0Sagc 
984e01460c0Sagc /*
985e01460c0Sagc  * set_key_s:
986e01460c0Sagc  *    Initialize a key and its string value.
987e01460c0Sagc  *
988e01460c0Sagc  *    Parameter:
989e01460c0Sagc  *          state    Negotiation state
990e01460c0Sagc  *          key      The key
991e01460c0Sagc  *          val      The value
992e01460c0Sagc  */
993e01460c0Sagc 
994e01460c0Sagc STATIC negotiation_parameter_t *
set_key_s(negotiation_state_t * state,text_key_t key,uint8_t * val)995e01460c0Sagc set_key_s(negotiation_state_t *state, text_key_t key, uint8_t *val)
996e01460c0Sagc {
997e01460c0Sagc 	negotiation_parameter_t *par;
998e01460c0Sagc 
999e01460c0Sagc 	if (state->num_pars >= MAX_NEG) {
1000e01460c0Sagc 		DEBOUT(("set_key_s: num_pars (%d) >= MAX_NEG (%d)\n",
1001e01460c0Sagc 				state->num_pars, MAX_NEG));
1002e01460c0Sagc 		return NULL;
1003e01460c0Sagc 	}
1004e01460c0Sagc 	par = &state->pars[state->num_pars];
1005e01460c0Sagc 	par->key = key;
1006e01460c0Sagc 	par->list_num = 1;
1007e01460c0Sagc 	par->val.sval = val;
1008f1a7fa8cSmlelstv 	par->hex_bignums = iscsi_hex_bignums;
1009e01460c0Sagc 	state->num_pars++;
1010e01460c0Sagc 	state->kflags[key] |= NS_SENT;
1011e01460c0Sagc 
1012e01460c0Sagc 	return par;
1013e01460c0Sagc }
1014e01460c0Sagc 
1015e01460c0Sagc 
1016e01460c0Sagc /*****************************************************************************/
1017e01460c0Sagc 
1018e01460c0Sagc /*
1019e01460c0Sagc  * eval_parameter:
1020e01460c0Sagc  *    Evaluate a received negotiation value.
1021e01460c0Sagc  *
1022e01460c0Sagc  *    Parameter:
1023e01460c0Sagc  *          conn     The connection
1024e01460c0Sagc  *          state    The negotiation state
1025e01460c0Sagc  *          par      The parameter
1026e01460c0Sagc  *
1027e01460c0Sagc  *    Returns:    0 on success, else an ISCSI status value.
1028e01460c0Sagc  */
1029e01460c0Sagc 
1030e01460c0Sagc STATIC int
eval_parameter(connection_t * conn,negotiation_state_t * state,negotiation_parameter_t * par)1031e01460c0Sagc eval_parameter(connection_t *conn, negotiation_state_t *state,
1032e01460c0Sagc 			   negotiation_parameter_t *par)
1033e01460c0Sagc {
1034e01460c0Sagc 	uint32_t n = par->val.nval[0];
1035e01460c0Sagc 	size_t sz;
1036e01460c0Sagc 	text_key_t key = par->key;
1037e01460c0Sagc 	bool sent = (state->kflags[key] & NS_SENT) != 0;
1038e01460c0Sagc 
1039e01460c0Sagc 	state->kflags[key] |= NS_RECEIVED;
1040e01460c0Sagc 
1041e01460c0Sagc 	switch (key) {
1042e01460c0Sagc 		/*
1043e01460c0Sagc 		 *  keys connected to security negotiation
1044e01460c0Sagc 		 */
1045e01460c0Sagc 	case K_AuthMethod:
1046e01460c0Sagc 		if (n) {
1047e01460c0Sagc 			DEBOUT(("eval_par: AuthMethod nonzero (%d)\n", n));
1048e01460c0Sagc 			return ISCSI_STATUS_NEGOTIATION_ERROR;
1049e01460c0Sagc 		}
1050e01460c0Sagc 		break;
1051e01460c0Sagc 
1052e01460c0Sagc 	case K_Auth_CHAP_Algorithm:
1053e01460c0Sagc 	case K_Auth_CHAP_Challenge:
1054e01460c0Sagc 	case K_Auth_CHAP_Identifier:
1055e01460c0Sagc 	case K_Auth_CHAP_Name:
1056e01460c0Sagc 	case K_Auth_CHAP_Response:
1057e01460c0Sagc 		DEBOUT(("eval_par: Authorization Key in Operational Phase\n"));
1058e01460c0Sagc 		return ISCSI_STATUS_NEGOTIATION_ERROR;
1059e01460c0Sagc 
1060e01460c0Sagc 		/*
1061e01460c0Sagc 		 * keys we always send
1062e01460c0Sagc 		 */
1063e01460c0Sagc 	case K_DataDigest:
1064e01460c0Sagc 		state->DataDigest = n;
1065e01460c0Sagc 		if (!sent)
1066e01460c0Sagc 			set_key_n(state, key, n);
1067e01460c0Sagc 		break;
1068e01460c0Sagc 
1069e01460c0Sagc 	case K_HeaderDigest:
1070e01460c0Sagc 		state->HeaderDigest = n;
1071e01460c0Sagc 		if (!sent)
1072e01460c0Sagc 			set_key_n(state, key, n);
1073e01460c0Sagc 		break;
1074e01460c0Sagc 
1075e01460c0Sagc 	case K_ErrorRecoveryLevel:
1076e01460c0Sagc 		state->ErrorRecoveryLevel = n;
1077e01460c0Sagc 		if (!sent)
1078e01460c0Sagc 			set_key_n(state, key, n);
1079e01460c0Sagc 		break;
1080e01460c0Sagc 
1081e01460c0Sagc 	case K_ImmediateData:
1082e01460c0Sagc 		state->ImmediateData = n;
1083e01460c0Sagc 		if (!sent)
1084e01460c0Sagc 			set_key_n(state, key, n);
1085e01460c0Sagc 		break;
1086e01460c0Sagc 
1087e01460c0Sagc 	case K_InitialR2T:
1088e01460c0Sagc 		state->InitialR2T = n;
1089e01460c0Sagc 		if (!sent)
1090e01460c0Sagc 			set_key_n(state, key, n);
1091e01460c0Sagc 		break;
1092e01460c0Sagc 
1093e01460c0Sagc 	case K_MaxRecvDataSegmentLength:
1094e01460c0Sagc 		state->MaxRecvDataSegmentLength = n;
1095e01460c0Sagc 		/* this is basically declarative, not negotiated */
1096e01460c0Sagc 		/* (each side has its own value) */
1097e01460c0Sagc 		break;
1098e01460c0Sagc 
1099e01460c0Sagc 		/*
1100e01460c0Sagc 		 * keys we don't always send, so we may have to reflect the value
1101e01460c0Sagc 		 */
1102e01460c0Sagc 	case K_DefaultTime2Retain:
1103e01460c0Sagc 		state->DefaultTime2Retain = n = min(state->DefaultTime2Retain, n);
1104e01460c0Sagc 		if (!sent)
1105e01460c0Sagc 			set_key_n(state, key, n);
1106e01460c0Sagc 		break;
1107e01460c0Sagc 
1108e01460c0Sagc 	case K_DefaultTime2Wait:
1109e01460c0Sagc 		state->DefaultTime2Wait = n = min(state->DefaultTime2Wait, n);
1110e01460c0Sagc 		if (!sent)
1111e01460c0Sagc 			set_key_n(state, key, n);
1112e01460c0Sagc 		break;
1113e01460c0Sagc 
1114e01460c0Sagc 	case K_MaxConnections:
1115e01460c0Sagc 		if (state->MaxConnections)
1116e01460c0Sagc 			state->MaxConnections = n = min(state->MaxConnections, n);
1117e01460c0Sagc 		else
1118e01460c0Sagc 			state->MaxConnections = n;
1119e01460c0Sagc 
1120e01460c0Sagc 		if (!sent)
1121e01460c0Sagc 			set_key_n(state, key, n);
1122e01460c0Sagc 		break;
1123e01460c0Sagc 
1124e01460c0Sagc 	case K_MaxOutstandingR2T:
1125e01460c0Sagc 		state->MaxOutstandingR2T = n;
1126e01460c0Sagc 		if (!sent)
1127e01460c0Sagc 			set_key_n(state, key, n);
1128e01460c0Sagc 		break;
1129e01460c0Sagc 
1130e01460c0Sagc 	case K_FirstBurstLength:
1131e01460c0Sagc 		state->FirstBurstLength = n;
1132e01460c0Sagc 		if (!sent)
1133e01460c0Sagc 			set_key_n(state, key, n);
1134e01460c0Sagc 		break;
1135e01460c0Sagc 
1136e01460c0Sagc 	case K_MaxBurstLength:
1137e01460c0Sagc 		state->MaxBurstLength = n;
1138e01460c0Sagc 		if (!sent)
1139e01460c0Sagc 			set_key_n(state, key, n);
1140e01460c0Sagc 		break;
1141e01460c0Sagc 
1142e01460c0Sagc 	case K_IFMarker:
1143e01460c0Sagc 	case K_OFMarker:
1144e01460c0Sagc 		/* not (yet) supported */
1145e01460c0Sagc 		if (!sent)
1146e01460c0Sagc 			set_key_n(state, key, 0);
1147e01460c0Sagc 		break;
1148e01460c0Sagc 
1149e01460c0Sagc 	case K_IFMarkInt:
1150e01460c0Sagc 	case K_OFMarkInt:
1151e01460c0Sagc 		/* it's a range, and list_num will be 1, so this will reply "Reject" */
1152e01460c0Sagc 		if (!sent)
1153e01460c0Sagc 			set_key_n(state, key, 0);
1154e01460c0Sagc 		break;
1155e01460c0Sagc 
1156e01460c0Sagc 	case K_DataPDUInOrder:
1157e01460c0Sagc 	case K_DataSequenceInOrder:
1158e01460c0Sagc 		/* values are don't care */
1159e01460c0Sagc 		if (!sent)
1160e01460c0Sagc 			set_key_n(state, key, n);
1161e01460c0Sagc 		break;
1162e01460c0Sagc 
1163e01460c0Sagc 	case K_NotUnderstood:
1164e01460c0Sagc 		/* return "NotUnderstood" */
1165e01460c0Sagc 		set_key_s(state, key, par->val.sval);
1166e01460c0Sagc 		break;
1167e01460c0Sagc 
1168e01460c0Sagc 		/*
1169e01460c0Sagc 		 * Declarative keys (no response required)
1170e01460c0Sagc 		 */
1171e01460c0Sagc 	case K_TargetAddress:
1172e01460c0Sagc 		/* ignore for now... */
1173e01460c0Sagc 		break;
1174e01460c0Sagc 
1175e01460c0Sagc 	case K_TargetAlias:
11768ab41cb9Schristos 		if (conn->c_login_par->is_present.TargetAlias) {
11778ab41cb9Schristos 			copyoutstr(par->val.sval, conn->c_login_par->TargetAlias,
1178e01460c0Sagc 				ISCSI_STRING_LENGTH - 1, &sz);
1179e01460c0Sagc 			/* do anything with return code?? */
1180e01460c0Sagc 		}
1181e01460c0Sagc 		break;
1182e01460c0Sagc 
1183e01460c0Sagc 	case K_TargetPortalGroupTag:
1184e01460c0Sagc 		/* ignore for now... */
1185e01460c0Sagc 		break;
1186e01460c0Sagc 
1187e01460c0Sagc 	default:
1188e01460c0Sagc 		DEBOUT(("eval_par: Invalid parameter type %d\n", par->key));
1189e01460c0Sagc 		return ISCSI_STATUS_NEGOTIATION_ERROR;
1190e01460c0Sagc 	}
1191e01460c0Sagc 	return 0;
1192e01460c0Sagc }
1193e01460c0Sagc 
1194e01460c0Sagc /*****************************************************************************/
1195e01460c0Sagc 
1196e01460c0Sagc 
1197e01460c0Sagc /*
1198e01460c0Sagc  * init_session_parameters:
1199e01460c0Sagc  *    Initialize session-related negotiation parameters from existing session
1200e01460c0Sagc  *
1201e01460c0Sagc  *    Parameter:
1202e01460c0Sagc  *          sess     The session
1203e01460c0Sagc  *          state    The negotiation state
1204e01460c0Sagc  */
1205e01460c0Sagc 
1206e01460c0Sagc STATIC void
init_session_parameters(session_t * sess,negotiation_state_t * state)1207e01460c0Sagc init_session_parameters(session_t *sess, negotiation_state_t *state)
1208e01460c0Sagc {
1209e01460c0Sagc 
12108ab41cb9Schristos 	state->ErrorRecoveryLevel = sess->s_ErrorRecoveryLevel;
12118ab41cb9Schristos 	state->InitialR2T = sess->s_InitialR2T;
12128ab41cb9Schristos 	state->ImmediateData = sess->s_ImmediateData;
12138ab41cb9Schristos 	state->MaxConnections = sess->s_MaxConnections;
12148ab41cb9Schristos 	state->DefaultTime2Wait = sess->s_DefaultTime2Wait;
12158ab41cb9Schristos 	state->DefaultTime2Retain = sess->s_DefaultTime2Retain;
12168ab41cb9Schristos 	state->MaxBurstLength = sess->s_MaxBurstLength;
12178ab41cb9Schristos 	state->FirstBurstLength = sess->s_FirstBurstLength;
12188ab41cb9Schristos 	state->MaxOutstandingR2T = sess->s_MaxOutstandingR2T;
1219e01460c0Sagc }
1220e01460c0Sagc 
1221e01460c0Sagc 
1222e01460c0Sagc 
1223e01460c0Sagc /*
1224e01460c0Sagc  * assemble_login_parameters:
1225e01460c0Sagc  *    Assemble the initial login negotiation parameters.
1226e01460c0Sagc  *
1227e01460c0Sagc  *    Parameter:
1228e01460c0Sagc  *          conn     The connection
1229e01460c0Sagc  *          ccb      The CCB for the login exchange
1230e01460c0Sagc  *          pdu      The PDU to use for sending
1231e01460c0Sagc  *
1232e01460c0Sagc  *    Returns:    < 0   if more security negotiation is required
1233e01460c0Sagc  *                0     if this is the last security negotiation block
1234e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
1235e01460c0Sagc  */
1236e01460c0Sagc 
1237e01460c0Sagc int
assemble_login_parameters(connection_t * conn,ccb_t * ccb,pdu_t * pdu)1238e01460c0Sagc assemble_login_parameters(connection_t *conn, ccb_t *ccb, pdu_t *pdu)
1239e01460c0Sagc {
12408ab41cb9Schristos 	iscsi_login_parameters_t *par = conn->c_login_par;
1241e01460c0Sagc 	size_t sz;
1242e01460c0Sagc 	int rc, i, next;
1243e01460c0Sagc 	negotiation_state_t *state;
1244e01460c0Sagc 	negotiation_parameter_t *cpar;
1245e01460c0Sagc 
1246e01460c0Sagc 	state = malloc(sizeof(*state), M_TEMP, M_WAITOK | M_ZERO);
1247e01460c0Sagc 	if (state == NULL) {
1248e01460c0Sagc 		DEBOUT(("*** Out of memory in assemble_login_params\n"));
1249e01460c0Sagc 		return ISCSI_STATUS_NO_RESOURCES;
1250e01460c0Sagc 	}
12518ab41cb9Schristos 	ccb->ccb_temp_data = state;
1252e01460c0Sagc 
1253a22a9581Smlelstv 	if (!iscsi_InitiatorName[0]) {
1254e01460c0Sagc 		DEBOUT(("No InitiatorName\n"));
1255e01460c0Sagc 		return ISCSI_STATUS_PARAMETER_MISSING;
1256e01460c0Sagc 	}
1257a22a9581Smlelstv 	set_key_s(state, K_InitiatorName, iscsi_InitiatorName);
1258e01460c0Sagc 
1259a22a9581Smlelstv 	if (iscsi_InitiatorAlias[0])
1260a22a9581Smlelstv 		set_key_s(state, K_InitiatorAlias, iscsi_InitiatorAlias);
1261e01460c0Sagc 
12628ab41cb9Schristos 	conn->c_Our_MaxRecvDataSegmentLength =
1263e01460c0Sagc 		(par->is_present.MaxRecvDataSegmentLength)
1264e01460c0Sagc 		? par->MaxRecvDataSegmentLength : DEFAULT_MaxRecvDataSegmentLength;
1265e01460c0Sagc 
1266e01460c0Sagc 	/* setup some values for authentication */
1267e01460c0Sagc 	if (par->is_present.password)
1268e01460c0Sagc 		copyinstr(par->password, state->password, MAX_STRING, &sz);
1269e01460c0Sagc 	if (par->is_present.target_password)
1270e01460c0Sagc 		copyinstr(par->target_password, state->target_password,
1271e01460c0Sagc 			MAX_STRING, &sz);
1272e01460c0Sagc 	if (par->is_present.user_name)
1273e01460c0Sagc 		copyinstr(par->user_name, state->user_name, MAX_STRING, &sz);
1274e01460c0Sagc 	else
1275a22a9581Smlelstv 		strlcpy(state->user_name, iscsi_InitiatorName,
1276e01460c0Sagc 			sizeof(state->user_name));
1277e01460c0Sagc 
1278e01460c0Sagc 	next = TRUE;
1279e01460c0Sagc 
1280e01460c0Sagc 	set_key_n(state, K_SessionType,
1281e01460c0Sagc 			  par->login_type > ISCSI_LOGINTYPE_DISCOVERY);
1282e01460c0Sagc 
1283e01460c0Sagc 	cpar = set_key_n(state, K_AuthMethod, ISCSI_AUTH_None);
1284e01460c0Sagc 
1285e01460c0Sagc 	if (cpar != NULL && par->is_present.auth_info &&
1286e01460c0Sagc 		par->auth_info.auth_number > 0) {
1287e01460c0Sagc 		if (par->auth_info.auth_number > ISCSI_AUTH_OPTIONS) {
1288e01460c0Sagc 			DEBOUT(("Auth number too big in asm_login\n"));
1289e01460c0Sagc 			return ISCSI_STATUS_PARAMETER_INVALID;
1290e01460c0Sagc 		}
1291e01460c0Sagc 		cpar->list_num = par->auth_info.auth_number;
1292e01460c0Sagc 		for (i = 0; i < cpar->list_num; i++) {
1293e01460c0Sagc 			cpar->val.nval[i] = par->auth_info.auth_type[i];
1294e01460c0Sagc 			if (par->auth_info.auth_type[i])
1295e01460c0Sagc 				next = FALSE;
1296e01460c0Sagc 		}
1297e01460c0Sagc 	}
1298e01460c0Sagc 
1299e01460c0Sagc 	if (par->is_present.TargetName)
1300e01460c0Sagc 		copyinstr(par->TargetName, state->temp_buf, ISCSI_STRING_LENGTH - 1,
1301e01460c0Sagc 				  &sz);
1302e01460c0Sagc 	else {
1303e01460c0Sagc 		state->temp_buf[0] = 0;
1304e01460c0Sagc 		sz = 0;
1305e01460c0Sagc 	}
1306e01460c0Sagc 
1307e01460c0Sagc 	if ((!sz || !state->temp_buf[0]) &&
1308e01460c0Sagc 		par->login_type != ISCSI_LOGINTYPE_DISCOVERY) {
1309e01460c0Sagc 		DEBOUT(("No TargetName\n"));
1310e01460c0Sagc 		return ISCSI_STATUS_PARAMETER_MISSING;
1311e01460c0Sagc 	}
1312e01460c0Sagc 
1313e01460c0Sagc 	if (state->temp_buf[0]) {
1314e01460c0Sagc 		set_key_s(state, K_TargetName, state->temp_buf);
1315e01460c0Sagc 	}
1316e01460c0Sagc 
1317e01460c0Sagc 	if ((rc = complete_pars(state, pdu)) != 0)
1318e01460c0Sagc 		return rc;
1319e01460c0Sagc 
1320e01460c0Sagc 	return (next) ? 0 : -1;
1321e01460c0Sagc }
1322e01460c0Sagc 
1323e01460c0Sagc /*
1324e01460c0Sagc  * assemble_security_parameters:
1325e01460c0Sagc  *    Assemble the security negotiation parameters.
1326e01460c0Sagc  *
1327e01460c0Sagc  *    Parameter:
1328e01460c0Sagc  *          conn     The connection
1329e01460c0Sagc  *          rx_pdu   The received login response PDU
1330e01460c0Sagc  *          tx_pdu   The transmit PDU
1331e01460c0Sagc  *
1332e01460c0Sagc  *    Returns:    < 0   if more security negotiation is required
1333e01460c0Sagc  *                0     if this is the last security negotiation block
1334e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
1335e01460c0Sagc  */
1336e01460c0Sagc 
1337e01460c0Sagc int
assemble_security_parameters(connection_t * conn,ccb_t * ccb,pdu_t * rx_pdu,pdu_t * tx_pdu)1338e01460c0Sagc assemble_security_parameters(connection_t *conn, ccb_t *ccb, pdu_t *rx_pdu,
1339e01460c0Sagc 							 pdu_t *tx_pdu)
1340e01460c0Sagc {
13418ab41cb9Schristos 	negotiation_state_t *state = (negotiation_state_t *) ccb->ccb_temp_data;
13428ab41cb9Schristos 	iscsi_login_parameters_t *par = conn->c_login_par;
1343e01460c0Sagc 	negotiation_parameter_t rxp, *cpar;
1344e01460c0Sagc 	uint8_t *rxpars;
1345e01460c0Sagc 	int rc, next;
1346e01460c0Sagc 	uint8_t identifier = 0;
1347e01460c0Sagc 	uint8_t *challenge = NULL;
1348e01460c0Sagc 	int challenge_size = 0;
1349e01460c0Sagc 	uint8_t *response = NULL;
1350e01460c0Sagc 	int response_size = 0;
13514ccc6176Smlelstv 	bool challenge_hex = iscsi_hex_bignums;
1352e01460c0Sagc 
1353e01460c0Sagc 	state->num_pars = 0;
1354e01460c0Sagc 	next = 0;
1355e01460c0Sagc 
13568ab41cb9Schristos 	rxpars = (uint8_t *) rx_pdu->pdu_temp_data;
1357e01460c0Sagc 	if (rxpars == NULL) {
1358e01460c0Sagc 		DEBOUT(("No received parameters!\n"));
1359e01460c0Sagc 		return ISCSI_STATUS_NEGOTIATION_ERROR;
1360e01460c0Sagc 	}
1361e01460c0Sagc 	/* Note: There are always at least 2 extra bytes past temp_data_len */
13628ab41cb9Schristos 	rxpars[rx_pdu->pdu_temp_data_len] = '\0';
13638ab41cb9Schristos 	rxpars[rx_pdu->pdu_temp_data_len + 1] = '\0';
1364e01460c0Sagc 
1365e01460c0Sagc 	while (*rxpars) {
1366e01460c0Sagc 		if ((rxpars = get_parameter(rxpars, &rxp)) == NULL) {
1367e01460c0Sagc 			DEBOUT(("get_parameter returned error\n"));
1368e01460c0Sagc 			return ISCSI_STATUS_NEGOTIATION_ERROR;
1369e01460c0Sagc 		}
1370e01460c0Sagc 
1371e01460c0Sagc 		state->kflags[rxp.key] |= NS_RECEIVED;
1372e01460c0Sagc 
1373e01460c0Sagc 		switch (rxp.key) {
1374e01460c0Sagc 		case K_AuthMethod:
1375e01460c0Sagc 			if (state->auth_state != AUTH_INITIAL) {
1376e01460c0Sagc 				DEBOUT(("AuthMethod received, auth_state = %d\n",
1377e01460c0Sagc 						state->auth_state));
1378e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1379e01460c0Sagc 			}
1380e01460c0Sagc 
1381e01460c0Sagc 			/* Note: if the selection is None, we shouldn't be here,
1382e01460c0Sagc 			 * the target should have transited the state to op-neg.
1383e01460c0Sagc 			 */
1384e01460c0Sagc 			if (rxp.val.nval[0] != ISCSI_AUTH_CHAP) {
1385e01460c0Sagc 				DEBOUT(("AuthMethod isn't CHAP (%d)\n", rxp.val.nval[0]));
1386e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1387e01460c0Sagc 			}
1388e01460c0Sagc 
1389e01460c0Sagc 			state->auth_state = AUTH_METHOD_SELECTED;
1390e01460c0Sagc 			state->auth_alg = rxp.val.nval[0];
1391e01460c0Sagc 			break;
1392e01460c0Sagc 
1393e01460c0Sagc 		case K_Auth_CHAP_Algorithm:
1394e01460c0Sagc 			if (state->auth_state != AUTH_CHAP_ALG_SENT ||
13954ccc6176Smlelstv 			    rxp.val.nval[0] != ISCSI_CHAP_MD5) {
1396e01460c0Sagc 				DEBOUT(("Bad algorithm, auth_state = %d, alg %d\n",
1397e01460c0Sagc 						state->auth_state, rxp.val.nval[0]));
1398e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1399e01460c0Sagc 			}
1400e01460c0Sagc 			break;
1401e01460c0Sagc 
1402e01460c0Sagc 		case K_Auth_CHAP_Challenge:
1403e01460c0Sagc 			if (state->auth_state != AUTH_CHAP_ALG_SENT || !rxp.list_num) {
1404e01460c0Sagc 				DEBOUT(("Bad Challenge, auth_state = %d, len %d\n",
1405e01460c0Sagc 						state->auth_state, rxp.list_num));
1406e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1407e01460c0Sagc 			}
1408e01460c0Sagc 			challenge = rxp.val.sval;
1409e01460c0Sagc 			challenge_size = rxp.list_num;
14104ccc6176Smlelstv 			/* respond in the same format as the challenge */
14114ccc6176Smlelstv 			challenge_hex = rxp.hex_bignums;
1412e01460c0Sagc 			break;
1413e01460c0Sagc 
1414e01460c0Sagc 		case K_Auth_CHAP_Identifier:
1415e01460c0Sagc 			if (state->auth_state != AUTH_CHAP_ALG_SENT) {
1416e01460c0Sagc 				DEBOUT(("Bad ID, auth_state = %d, id %d\n",
1417e01460c0Sagc 						state->auth_state, rxp.val.nval[0]));
1418e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1419e01460c0Sagc 			}
1420e01460c0Sagc 			identifier = (uint8_t) rxp.val.nval[0];
1421e01460c0Sagc 			break;
1422e01460c0Sagc 
1423e01460c0Sagc 		case K_Auth_CHAP_Name:
1424e01460c0Sagc 			if (state->auth_state != AUTH_CHAP_RSP_SENT) {
1425e01460c0Sagc 				DEBOUT(("Bad Name, auth_state = %d, name <%s>\n",
1426e01460c0Sagc 						state->auth_state, rxp.val.sval));
1427e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1428e01460c0Sagc 			}
1429e01460c0Sagc 			/* what do we do with the name?? */
1430e01460c0Sagc 			break;
1431e01460c0Sagc 
1432e01460c0Sagc 		case K_Auth_CHAP_Response:
1433e01460c0Sagc 			if (state->auth_state != AUTH_CHAP_RSP_SENT) {
1434e01460c0Sagc 				DEBOUT(("Bad Response, auth_state = %d, size %d\n",
1435e01460c0Sagc 						state->auth_state, rxp.list_num));
1436e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1437e01460c0Sagc 			}
1438e01460c0Sagc 			response = rxp.val.sval;
1439e01460c0Sagc 			response_size = rxp.list_num;
14404ccc6176Smlelstv 			if (response_size != CHAP_MD5_SIZE) {
14414ccc6176Smlelstv 				DEBOUT(("CHAP Response, bad size %d\n",
14424ccc6176Smlelstv 						response_size));
1443e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
14444ccc6176Smlelstv 			}
1445e01460c0Sagc 			break;
1446e01460c0Sagc 
1447e01460c0Sagc 		default:
1448e01460c0Sagc 			rc = eval_parameter(conn, state, &rxp);
1449e01460c0Sagc 			if (rc)
1450e01460c0Sagc 				return rc;
1451e01460c0Sagc 			break;
1452e01460c0Sagc 		}
1453e01460c0Sagc 	}
1454e01460c0Sagc 
1455e01460c0Sagc 	switch (state->auth_state) {
1456e01460c0Sagc 	case AUTH_INITIAL:
1457e01460c0Sagc 		DEBOUT(("Didn't receive Method\n"));
1458e01460c0Sagc 		return ISCSI_STATUS_NEGOTIATION_ERROR;
1459e01460c0Sagc 
1460e01460c0Sagc 	case AUTH_METHOD_SELECTED:
14614ccc6176Smlelstv 		set_key_n(state, K_Auth_CHAP_Algorithm, ISCSI_CHAP_MD5);
1462e01460c0Sagc 		state->auth_state = AUTH_CHAP_ALG_SENT;
1463e01460c0Sagc 		next = -1;
1464e01460c0Sagc 		break;
1465e01460c0Sagc 
1466e01460c0Sagc 	case AUTH_CHAP_ALG_SENT:
1467e01460c0Sagc 		if (!RX(state, K_Auth_CHAP_Algorithm) ||
1468e01460c0Sagc 			!RX(state, K_Auth_CHAP_Identifier) ||
1469e01460c0Sagc 			!RX(state, K_Auth_CHAP_Challenge)) {
1470e01460c0Sagc 			DEBOUT(("Didn't receive all parameters\n"));
1471e01460c0Sagc 			return ISCSI_STATUS_NEGOTIATION_ERROR;
1472e01460c0Sagc 		}
1473e01460c0Sagc 
1474e01460c0Sagc 		set_key_s(state, K_Auth_CHAP_Name, state->user_name);
1475e01460c0Sagc 
14764ccc6176Smlelstv 		chap_md5_response(state->temp_buf, identifier,
14774ccc6176Smlelstv 		    state->password, challenge, challenge_size);
1478e01460c0Sagc 
1479e01460c0Sagc 		cpar = set_key_s(state, K_Auth_CHAP_Response, state->temp_buf);
14804ccc6176Smlelstv 		if (cpar != NULL) {
1481e01460c0Sagc 			cpar->list_num = CHAP_MD5_SIZE;
14824ccc6176Smlelstv 			/* respond in same format as challenge */
14834ccc6176Smlelstv 			cpar->hex_bignums = challenge_hex;
14844ccc6176Smlelstv 		}
1485e01460c0Sagc 
1486e01460c0Sagc 		if (par->auth_info.mutual_auth) {
1487e01460c0Sagc 			if (!state->target_password[0]) {
1488e01460c0Sagc 				DEBOUT(("No target password with mutual authentication!\n"));
1489e01460c0Sagc 				return ISCSI_STATUS_PARAMETER_MISSING;
1490e01460c0Sagc 			}
1491e01460c0Sagc 
149238f95ba1Stls 			cprng_strong(kern_cprng,
149338f95ba1Stls 				     &state->temp_buf[CHAP_MD5_SIZE],
14946e1dd068Stls 				     CHAP_CHALLENGE_LEN + 1, 0);
1495e01460c0Sagc 			set_key_n(state, K_Auth_CHAP_Identifier,
1496e01460c0Sagc 					  state->temp_buf[CHAP_MD5_SIZE]);
1497e01460c0Sagc 			cpar = set_key_s(state, K_Auth_CHAP_Challenge,
1498e01460c0Sagc 							 &state->temp_buf[CHAP_MD5_SIZE + 1]);
14994ccc6176Smlelstv 			if (cpar != NULL) {
1500e01460c0Sagc 				cpar->list_num = CHAP_CHALLENGE_LEN;
15014ccc6176Smlelstv 				/* use same format as target challenge */
15024ccc6176Smlelstv 				cpar->hex_bignums = challenge_hex;
15034ccc6176Smlelstv 			}
15044ccc6176Smlelstv 
15054ccc6176Smlelstv 			/* transitional state */
15064ccc6176Smlelstv 			conn->c_state = ST_SEC_FIN;
1507e01460c0Sagc 		}
1508e01460c0Sagc 		state->auth_state = AUTH_CHAP_RSP_SENT;
1509e01460c0Sagc 		break;
1510e01460c0Sagc 
1511e01460c0Sagc 	case AUTH_CHAP_RSP_SENT:
1512e01460c0Sagc 		/* we can only be here for mutual authentication */
1513e01460c0Sagc 		if (!par->auth_info.mutual_auth || response == NULL) {
1514e01460c0Sagc 			DEBOUT(("Mutual authentication not requested\n"));
1515e01460c0Sagc 			return ISCSI_STATUS_NEGOTIATION_ERROR;
1516e01460c0Sagc 		}
1517e01460c0Sagc 
1518e01460c0Sagc 		chap_md5_response(state->temp_buf,
1519e01460c0Sagc 			state->temp_buf[CHAP_MD5_SIZE],
15204ccc6176Smlelstv 			state->target_password,
1521e01460c0Sagc 			&state->temp_buf[CHAP_MD5_SIZE + 1],
1522e01460c0Sagc 			CHAP_CHALLENGE_LEN);
1523e01460c0Sagc 
15244ccc6176Smlelstv 		if (response_size > sizeof(state->temp_buf) ||
15254ccc6176Smlelstv 		    memcmp(state->temp_buf, response, response_size)) {
1526e01460c0Sagc 			DEBOUT(("Mutual authentication mismatch\n"));
1527e01460c0Sagc 			return ISCSI_STATUS_AUTHENTICATION_FAILED;
1528e01460c0Sagc 		}
1529e01460c0Sagc 		break;
1530e01460c0Sagc 
1531e01460c0Sagc 	default:
1532e01460c0Sagc 		break;
1533e01460c0Sagc 	}
1534e01460c0Sagc 
1535e01460c0Sagc 	complete_pars(state, tx_pdu);
1536e01460c0Sagc 
1537e01460c0Sagc 	return next;
1538e01460c0Sagc }
1539e01460c0Sagc 
1540e01460c0Sagc 
1541e01460c0Sagc /*
1542e01460c0Sagc  * set_first_opnegs:
1543e01460c0Sagc  *    Set the operational negotiation parameters we want to negotiate in
1544e01460c0Sagc  *    the first login request in op_neg phase.
1545e01460c0Sagc  *
1546e01460c0Sagc  *    Parameter:
1547e01460c0Sagc  *          conn     The connection
1548e01460c0Sagc  *          state    Negotiation state
1549e01460c0Sagc  */
1550e01460c0Sagc 
1551e01460c0Sagc STATIC void
set_first_opnegs(connection_t * conn,negotiation_state_t * state)1552e01460c0Sagc set_first_opnegs(connection_t *conn, negotiation_state_t *state)
1553e01460c0Sagc {
15548ab41cb9Schristos 	iscsi_login_parameters_t *lpar = conn->c_login_par;
1555e01460c0Sagc 	negotiation_parameter_t *cpar;
1556e01460c0Sagc 
1557e01460c0Sagc 	/* Digests - suggest None,CRC32C unless the user forces a value */
1558e01460c0Sagc 	cpar = set_key_n(state, K_HeaderDigest,
1559e01460c0Sagc 	    (lpar->is_present.HeaderDigest) ? lpar->HeaderDigest : 0);
1560e01460c0Sagc 	if (cpar != NULL && !lpar->is_present.HeaderDigest) {
1561e01460c0Sagc 		cpar->list_num = 2;
1562e01460c0Sagc 		cpar->val.nval[1] = 1;
1563e01460c0Sagc 	}
1564e01460c0Sagc 
1565e01460c0Sagc 	cpar = set_key_n(state, K_DataDigest, (lpar->is_present.DataDigest)
1566e01460c0Sagc 		? lpar->DataDigest : 0);
1567e01460c0Sagc 	if (cpar != NULL && !lpar->is_present.DataDigest) {
1568e01460c0Sagc 		cpar->list_num = 2;
1569e01460c0Sagc 		cpar->val.nval[1] = 1;
1570e01460c0Sagc 	}
1571e01460c0Sagc 
1572e01460c0Sagc 	set_key_n(state, K_MaxRecvDataSegmentLength,
15738ab41cb9Schristos 		conn->c_Our_MaxRecvDataSegmentLength);
1574e01460c0Sagc 	/* This is direction-specific, we may have a different default */
1575e01460c0Sagc 	state->MaxRecvDataSegmentLength =
1576e01460c0Sagc 		entries[K_MaxRecvDataSegmentLength].defval;
1577e01460c0Sagc 
1578e01460c0Sagc 	/* First connection only */
15798ab41cb9Schristos 	if (!conn->c_session->s_TSIH) {
1580e01460c0Sagc 		state->ErrorRecoveryLevel =
15814ccc6176Smlelstv 		    (lpar->is_present.ErrorRecoveryLevel) ?
15824ccc6176Smlelstv 		    lpar->ErrorRecoveryLevel : 2;
1583e01460c0Sagc 		/*
15844ccc6176Smlelstv 		 * Negotiate InitialR2T to FALSE and ImmediateData to
15854ccc6176Smlelstv 		 * TRUE, should be slightly more efficient than the
15864ccc6176Smlelstv 		 * default InitialR2T=TRUE.
1587e01460c0Sagc 		 */
1588e01460c0Sagc 		state->InitialR2T = FALSE;
1589e01460c0Sagc 		state->ImmediateData = TRUE;
1590e01460c0Sagc 
15914ccc6176Smlelstv 		/* We don't really care about this, so don't negotiate
15924ccc6176Smlelstv 		 * by default
15934ccc6176Smlelstv 		 */
1594e01460c0Sagc 		state->MaxBurstLength = entries[K_MaxBurstLength].defval;
1595e01460c0Sagc 		state->FirstBurstLength = entries[K_FirstBurstLength].defval;
1596e01460c0Sagc 		state->MaxOutstandingR2T = entries[K_MaxOutstandingR2T].defval;
1597e01460c0Sagc 
1598e01460c0Sagc 		set_key_n(state, K_ErrorRecoveryLevel, state->ErrorRecoveryLevel);
1599e01460c0Sagc 		set_key_n(state, K_InitialR2T, state->InitialR2T);
1600e01460c0Sagc 		set_key_n(state, K_ImmediateData, state->ImmediateData);
1601e01460c0Sagc 
1602e01460c0Sagc 		if (lpar->is_present.MaxConnections) {
1603e01460c0Sagc 			state->MaxConnections = lpar->MaxConnections;
1604e01460c0Sagc 			set_key_n(state, K_MaxConnections, lpar->MaxConnections);
1605e01460c0Sagc 		}
1606e01460c0Sagc 
1607e01460c0Sagc 		if (lpar->is_present.DefaultTime2Wait)
1608e01460c0Sagc 			set_key_n(state, K_DefaultTime2Wait, lpar->DefaultTime2Wait);
1609e01460c0Sagc 		else
1610e01460c0Sagc 			state->DefaultTime2Wait = entries[K_DefaultTime2Wait].defval;
1611e01460c0Sagc 
1612e01460c0Sagc 		if (lpar->is_present.DefaultTime2Retain)
1613e01460c0Sagc 			set_key_n(state, K_DefaultTime2Retain, lpar->DefaultTime2Retain);
1614e01460c0Sagc 		else
1615e01460c0Sagc 			state->DefaultTime2Retain = entries[K_DefaultTime2Retain].defval;
1616e01460c0Sagc 	} else
16178ab41cb9Schristos 		init_session_parameters(conn->c_session, state);
1618e01460c0Sagc 
1619e01460c0Sagc 	DEBC(conn, 10, ("SetFirstOpnegs: recover=%d, MRDSL=%d\n",
16208ab41cb9Schristos 		conn->c_recover, state->MaxRecvDataSegmentLength));
1621e01460c0Sagc }
1622e01460c0Sagc 
1623e01460c0Sagc 
1624e01460c0Sagc /*
1625e01460c0Sagc  * assemble_negotiation_parameters:
1626e01460c0Sagc  *    Assemble any negotiation parameters requested by the other side.
1627e01460c0Sagc  *
1628e01460c0Sagc  *    Parameter:
1629e01460c0Sagc  *          conn     The connection
1630e01460c0Sagc  *          ccb      The login ccb
1631e01460c0Sagc  *          rx_pdu   The received login response PDU
1632e01460c0Sagc  *          tx_pdu   The transmit PDU
1633e01460c0Sagc  *
1634e01460c0Sagc  *    Returns:    0     On success
1635e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
1636e01460c0Sagc  */
1637e01460c0Sagc 
1638e01460c0Sagc int
assemble_negotiation_parameters(connection_t * conn,ccb_t * ccb,pdu_t * rx_pdu,pdu_t * tx_pdu)1639e01460c0Sagc assemble_negotiation_parameters(connection_t *conn, ccb_t *ccb, pdu_t *rx_pdu,
1640e01460c0Sagc 							    pdu_t *tx_pdu)
1641e01460c0Sagc {
16428ab41cb9Schristos 	negotiation_state_t *state = (negotiation_state_t *) ccb->ccb_temp_data;
1643e01460c0Sagc 	negotiation_parameter_t rxp;
1644e01460c0Sagc 	uint8_t *rxpars;
1645e01460c0Sagc 	int rc;
1646e01460c0Sagc 
1647e01460c0Sagc 	state->num_pars = 0;
1648e01460c0Sagc 
1649e01460c0Sagc 	DEBC(conn, 10, ("AsmNegParams: connState=%d, MRDSL=%d\n",
16508ab41cb9Schristos 		conn->c_state, state->MaxRecvDataSegmentLength));
1651e01460c0Sagc 
16524ccc6176Smlelstv 	if (conn->c_state == ST_SEC_NEG || conn->c_state == ST_SEC_FIN) {
16538ab41cb9Schristos 		conn->c_state = ST_OP_NEG;
1654e01460c0Sagc 		set_first_opnegs(conn, state);
1655e01460c0Sagc 	}
1656e01460c0Sagc 
16578ab41cb9Schristos 	rxpars = (uint8_t *) rx_pdu->pdu_temp_data;
1658e01460c0Sagc 	if (rxpars != NULL) {
1659e01460c0Sagc 		/* Note: There are always at least 2 extra bytes past temp_data_len */
16608ab41cb9Schristos 		rxpars[rx_pdu->pdu_temp_data_len] = '\0';
16618ab41cb9Schristos 		rxpars[rx_pdu->pdu_temp_data_len + 1] = '\0';
1662e01460c0Sagc 
1663e01460c0Sagc 		while (*rxpars) {
1664e01460c0Sagc 			if ((rxpars = get_parameter(rxpars, &rxp)) == NULL)
1665e01460c0Sagc 				return ISCSI_STATUS_NEGOTIATION_ERROR;
1666e01460c0Sagc 
1667e01460c0Sagc 			rc = eval_parameter(conn, state, &rxp);
1668e01460c0Sagc 			if (rc)
1669e01460c0Sagc 				return rc;
1670e01460c0Sagc 		}
1671e01460c0Sagc 	}
1672e01460c0Sagc 
1673e01460c0Sagc 	if (tx_pdu == NULL)
1674e01460c0Sagc 		return 0;
1675e01460c0Sagc 
1676e01460c0Sagc 	complete_pars(state, tx_pdu);
1677e01460c0Sagc 
1678e01460c0Sagc 	return 0;
1679e01460c0Sagc }
1680e01460c0Sagc 
1681e01460c0Sagc /*
1682e01460c0Sagc  * init_text_parameters:
1683e01460c0Sagc  *    Initialize text negotiation.
1684e01460c0Sagc  *
1685e01460c0Sagc  *    Parameter:
1686e01460c0Sagc  *          conn     The connection
1687e01460c0Sagc  *          tx_pdu   The transmit PDU
1688e01460c0Sagc  *
1689e01460c0Sagc  *    Returns:    0     On success
1690e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
1691e01460c0Sagc  */
1692e01460c0Sagc 
1693e01460c0Sagc int
init_text_parameters(connection_t * conn,ccb_t * ccb)1694e01460c0Sagc init_text_parameters(connection_t *conn, ccb_t *ccb)
1695e01460c0Sagc {
1696e01460c0Sagc 	negotiation_state_t *state;
1697e01460c0Sagc 
1698e01460c0Sagc 	state = malloc(sizeof(*state), M_TEMP, M_WAITOK | M_ZERO);
1699e01460c0Sagc 	if (state == NULL) {
1700e01460c0Sagc 		DEBOUT(("*** Out of memory in init_text_params\n"));
1701e01460c0Sagc 		return ISCSI_STATUS_NO_RESOURCES;
1702e01460c0Sagc 	}
17038ab41cb9Schristos 	ccb->ccb_temp_data = state;
1704e01460c0Sagc 
17058ab41cb9Schristos 	state->HeaderDigest = conn->c_HeaderDigest;
17068ab41cb9Schristos 	state->DataDigest = conn->c_DataDigest;
17078ab41cb9Schristos 	state->MaxRecvDataSegmentLength = conn->c_MaxRecvDataSegmentLength;
17088ab41cb9Schristos 	init_session_parameters(conn->c_session, state);
1709e01460c0Sagc 
1710e01460c0Sagc 	return 0;
1711e01460c0Sagc }
1712e01460c0Sagc 
1713e01460c0Sagc 
1714e01460c0Sagc /*
1715e01460c0Sagc  * assemble_send_targets:
1716e01460c0Sagc  *    Assemble send targets request
1717e01460c0Sagc  *
1718e01460c0Sagc  *    Parameter:
1719e01460c0Sagc  *          pdu      The transmit PDU
1720e01460c0Sagc  *          val      The SendTargets key value
1721e01460c0Sagc  *
1722e01460c0Sagc  *    Returns:    0     On success
1723e01460c0Sagc  *                > 0   (an ISCSI error code) if an error occurred.
1724e01460c0Sagc  */
1725e01460c0Sagc 
1726e01460c0Sagc int
assemble_send_targets(pdu_t * pdu,uint8_t * val)1727e01460c0Sagc assemble_send_targets(pdu_t *pdu, uint8_t *val)
1728e01460c0Sagc {
1729e01460c0Sagc 	negotiation_parameter_t par;
1730e01460c0Sagc 	uint8_t *buf;
1731e01460c0Sagc 	int len;
1732e01460c0Sagc 
1733e01460c0Sagc 	par.key = K_SendTargets;
1734e01460c0Sagc 	par.list_num = 1;
1735e01460c0Sagc 	par.val.sval = val;
17364ccc6176Smlelstv 	par.hex_bignums = false;
1737e01460c0Sagc 
1738e01460c0Sagc 	len = parameter_size(&par);
1739e01460c0Sagc 
1740e01460c0Sagc 	if ((buf = malloc(len, M_TEMP, M_WAITOK)) == NULL) {
1741e01460c0Sagc 		DEBOUT(("*** Out of memory in assemble_send_targets\n"));
1742e01460c0Sagc 		return ISCSI_STATUS_NO_RESOURCES;
1743e01460c0Sagc 	}
17448ab41cb9Schristos 	pdu->pdu_temp_data = buf;
17458ab41cb9Schristos 	pdu->pdu_temp_data_len = len;
1746e01460c0Sagc 
17474ccc6176Smlelstv 	if (put_parameter(buf, len, &par) == 0) {
17484ccc6176Smlelstv 		DEBOUT(("trying to put zero sized buffer\n"));
1749e01460c0Sagc 		return ISCSI_STATUS_PARAMETER_INVALID;
17504ccc6176Smlelstv 	}
1751e01460c0Sagc 
1752e01460c0Sagc 	return 0;
1753e01460c0Sagc }
1754e01460c0Sagc 
1755e01460c0Sagc 
1756e01460c0Sagc /*
1757e01460c0Sagc  * set_negotiated_parameters:
1758e01460c0Sagc  *    Copy the negotiated parameters into the connection and session structure.
1759e01460c0Sagc  *
1760e01460c0Sagc  *    Parameter:
1761e01460c0Sagc  *          ccb      The ccb containing the state information
1762e01460c0Sagc  */
1763e01460c0Sagc 
1764e01460c0Sagc void
set_negotiated_parameters(ccb_t * ccb)1765e01460c0Sagc set_negotiated_parameters(ccb_t *ccb)
1766e01460c0Sagc {
17678ab41cb9Schristos 	negotiation_state_t *state = (negotiation_state_t *) ccb->ccb_temp_data;
17688ab41cb9Schristos 	connection_t *conn = ccb->ccb_connection;
17698ab41cb9Schristos 	session_t *sess = ccb->ccb_session;
1770e01460c0Sagc 
17718ab41cb9Schristos 	conn->c_HeaderDigest = state->HeaderDigest;
17728ab41cb9Schristos 	conn->c_DataDigest = state->DataDigest;
17738ab41cb9Schristos 	sess->s_ErrorRecoveryLevel = state->ErrorRecoveryLevel;
17748ab41cb9Schristos 	sess->s_InitialR2T = state->InitialR2T;
17758ab41cb9Schristos 	sess->s_ImmediateData = state->ImmediateData;
17768ab41cb9Schristos 	conn->c_MaxRecvDataSegmentLength = state->MaxRecvDataSegmentLength;
17778ab41cb9Schristos 	sess->s_MaxConnections = state->MaxConnections;
17788ab41cb9Schristos 	sess->s_DefaultTime2Wait = conn->c_Time2Wait = state->DefaultTime2Wait;
17798ab41cb9Schristos 	sess->s_DefaultTime2Retain = conn->c_Time2Retain =
1780e01460c0Sagc 		state->DefaultTime2Retain;
1781e01460c0Sagc 
1782e01460c0Sagc 	/* set idle connection timeout to half the Time2Retain window so we */
1783e01460c0Sagc 	/* don't miss it, unless Time2Retain is ridiculously small. */
17848ab41cb9Schristos 	conn->c_idle_timeout_val = (conn->c_Time2Retain >= 10) ?
17858ab41cb9Schristos 		(conn->c_Time2Retain / 2) * hz : CONNECTION_IDLE_TIMEOUT;
1786e01460c0Sagc 
17878ab41cb9Schristos 	sess->s_MaxBurstLength = state->MaxBurstLength;
17888ab41cb9Schristos 	sess->s_FirstBurstLength = state->FirstBurstLength;
17898ab41cb9Schristos 	sess->s_MaxOutstandingR2T = state->MaxOutstandingR2T;
1790e01460c0Sagc 
1791e01460c0Sagc 	DEBC(conn, 10,("SetNegPar: MRDSL=%d, MBL=%d, FBL=%d, IR2T=%d, ImD=%d\n",
1792e01460c0Sagc 		state->MaxRecvDataSegmentLength, state->MaxBurstLength,
1793e01460c0Sagc 		state->FirstBurstLength, state->InitialR2T,
1794e01460c0Sagc 		state->ImmediateData));
1795e01460c0Sagc 
17968ab41cb9Schristos 	conn->c_max_transfer = min(sess->s_MaxBurstLength, conn->c_MaxRecvDataSegmentLength);
1797e01460c0Sagc 
17988ab41cb9Schristos 	conn->c_max_firstimmed = (!sess->s_ImmediateData) ? 0 :
17998ab41cb9Schristos 				min(sess->s_FirstBurstLength, conn->c_max_transfer);
1800e01460c0Sagc 
18018ab41cb9Schristos 	conn->c_max_firstdata = (sess->s_InitialR2T || sess->s_FirstBurstLength < conn->c_max_firstimmed) ? 0 :
18028ab41cb9Schristos 				min(sess->s_FirstBurstLength - conn->c_max_firstimmed, conn->c_max_transfer);
1803d1c48dffSmlelstv 
1804e01460c0Sagc }
1805