1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /******************************************************************************* |
3 | * This file contains main functions related to iSCSI Parameter negotiation. |
4 | * |
5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * |
7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
8 | * |
9 | ******************************************************************************/ |
10 | |
11 | #include <linux/slab.h> |
12 | #include <linux/uio.h> /* struct kvec */ |
13 | #include <target/iscsi/iscsi_target_core.h> |
14 | #include "iscsi_target_util.h" |
15 | #include "iscsi_target_parameters.h" |
16 | |
17 | int iscsi_login_rx_data( |
18 | struct iscsit_conn *conn, |
19 | char *buf, |
20 | int length) |
21 | { |
22 | int rx_got; |
23 | struct kvec iov; |
24 | |
25 | memset(&iov, 0, sizeof(struct kvec)); |
26 | iov.iov_len = length; |
27 | iov.iov_base = buf; |
28 | |
29 | rx_got = rx_data(conn, &iov, 1, length); |
30 | if (rx_got != length) { |
31 | pr_err("rx_data returned %d, expecting %d.\n" , |
32 | rx_got, length); |
33 | return -1; |
34 | } |
35 | |
36 | return 0 ; |
37 | } |
38 | |
39 | int iscsi_login_tx_data( |
40 | struct iscsit_conn *conn, |
41 | char *pdu_buf, |
42 | char *text_buf, |
43 | int text_length) |
44 | { |
45 | int length, tx_sent, iov_cnt = 1; |
46 | struct kvec iov[2]; |
47 | |
48 | length = (ISCSI_HDR_LEN + text_length); |
49 | |
50 | memset(&iov[0], 0, 2 * sizeof(struct kvec)); |
51 | iov[0].iov_len = ISCSI_HDR_LEN; |
52 | iov[0].iov_base = pdu_buf; |
53 | |
54 | if (text_buf && text_length) { |
55 | iov[1].iov_len = text_length; |
56 | iov[1].iov_base = text_buf; |
57 | iov_cnt++; |
58 | } |
59 | |
60 | tx_sent = tx_data(conn, &iov[0], iov_cnt, length); |
61 | if (tx_sent != length) { |
62 | pr_err("tx_data returned %d, expecting %d.\n" , |
63 | tx_sent, length); |
64 | return -1; |
65 | } |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | void iscsi_dump_conn_ops(struct iscsi_conn_ops *conn_ops) |
71 | { |
72 | pr_debug("HeaderDigest: %s\n" , (conn_ops->HeaderDigest) ? |
73 | "CRC32C" : "None" ); |
74 | pr_debug("DataDigest: %s\n" , (conn_ops->DataDigest) ? |
75 | "CRC32C" : "None" ); |
76 | pr_debug("MaxRecvDataSegmentLength: %u\n" , |
77 | conn_ops->MaxRecvDataSegmentLength); |
78 | } |
79 | |
80 | void iscsi_dump_sess_ops(struct iscsi_sess_ops *sess_ops) |
81 | { |
82 | pr_debug("InitiatorName: %s\n" , sess_ops->InitiatorName); |
83 | pr_debug("InitiatorAlias: %s\n" , sess_ops->InitiatorAlias); |
84 | pr_debug("TargetName: %s\n" , sess_ops->TargetName); |
85 | pr_debug("TargetAlias: %s\n" , sess_ops->TargetAlias); |
86 | pr_debug("TargetPortalGroupTag: %hu\n" , |
87 | sess_ops->TargetPortalGroupTag); |
88 | pr_debug("MaxConnections: %hu\n" , sess_ops->MaxConnections); |
89 | pr_debug("InitialR2T: %s\n" , |
90 | (sess_ops->InitialR2T) ? "Yes" : "No" ); |
91 | pr_debug("ImmediateData: %s\n" , (sess_ops->ImmediateData) ? |
92 | "Yes" : "No" ); |
93 | pr_debug("MaxBurstLength: %u\n" , sess_ops->MaxBurstLength); |
94 | pr_debug("FirstBurstLength: %u\n" , sess_ops->FirstBurstLength); |
95 | pr_debug("DefaultTime2Wait: %hu\n" , sess_ops->DefaultTime2Wait); |
96 | pr_debug("DefaultTime2Retain: %hu\n" , |
97 | sess_ops->DefaultTime2Retain); |
98 | pr_debug("MaxOutstandingR2T: %hu\n" , |
99 | sess_ops->MaxOutstandingR2T); |
100 | pr_debug("DataPDUInOrder: %s\n" , |
101 | (sess_ops->DataPDUInOrder) ? "Yes" : "No" ); |
102 | pr_debug("DataSequenceInOrder: %s\n" , |
103 | (sess_ops->DataSequenceInOrder) ? "Yes" : "No" ); |
104 | pr_debug("ErrorRecoveryLevel: %hu\n" , |
105 | sess_ops->ErrorRecoveryLevel); |
106 | pr_debug("SessionType: %s\n" , (sess_ops->SessionType) ? |
107 | "Discovery" : "Normal" ); |
108 | } |
109 | |
110 | void iscsi_print_params(struct iscsi_param_list *param_list) |
111 | { |
112 | struct iscsi_param *param; |
113 | |
114 | list_for_each_entry(param, ¶m_list->param_list, p_list) |
115 | pr_debug("%s: %s\n" , param->name, param->value); |
116 | } |
117 | |
118 | static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *param_list, |
119 | char *name, char *value, u8 phase, u8 scope, u8 sender, |
120 | u16 type_range, u8 use) |
121 | { |
122 | struct iscsi_param *param = NULL; |
123 | |
124 | param = kzalloc(size: sizeof(struct iscsi_param), GFP_KERNEL); |
125 | if (!param) { |
126 | pr_err("Unable to allocate memory for parameter.\n" ); |
127 | goto out; |
128 | } |
129 | INIT_LIST_HEAD(list: ¶m->p_list); |
130 | |
131 | param->name = kstrdup(s: name, GFP_KERNEL); |
132 | if (!param->name) { |
133 | pr_err("Unable to allocate memory for parameter name.\n" ); |
134 | goto out; |
135 | } |
136 | |
137 | param->value = kstrdup(s: value, GFP_KERNEL); |
138 | if (!param->value) { |
139 | pr_err("Unable to allocate memory for parameter value.\n" ); |
140 | goto out; |
141 | } |
142 | |
143 | param->phase = phase; |
144 | param->scope = scope; |
145 | param->sender = sender; |
146 | param->use = use; |
147 | param->type_range = type_range; |
148 | |
149 | switch (param->type_range) { |
150 | case TYPERANGE_BOOL_AND: |
151 | param->type = TYPE_BOOL_AND; |
152 | break; |
153 | case TYPERANGE_BOOL_OR: |
154 | param->type = TYPE_BOOL_OR; |
155 | break; |
156 | case TYPERANGE_0_TO_2: |
157 | case TYPERANGE_0_TO_3600: |
158 | case TYPERANGE_0_TO_32767: |
159 | case TYPERANGE_0_TO_65535: |
160 | case TYPERANGE_1_TO_65535: |
161 | case TYPERANGE_2_TO_3600: |
162 | case TYPERANGE_512_TO_16777215: |
163 | param->type = TYPE_NUMBER; |
164 | break; |
165 | case TYPERANGE_AUTH: |
166 | case TYPERANGE_DIGEST: |
167 | param->type = TYPE_VALUE_LIST | TYPE_STRING; |
168 | break; |
169 | case TYPERANGE_ISCSINAME: |
170 | case TYPERANGE_SESSIONTYPE: |
171 | case TYPERANGE_TARGETADDRESS: |
172 | case TYPERANGE_UTF8: |
173 | param->type = TYPE_STRING; |
174 | break; |
175 | default: |
176 | pr_err("Unknown type_range 0x%02x\n" , |
177 | param->type_range); |
178 | goto out; |
179 | } |
180 | list_add_tail(new: ¶m->p_list, head: ¶m_list->param_list); |
181 | |
182 | return param; |
183 | out: |
184 | if (param) { |
185 | kfree(objp: param->value); |
186 | kfree(objp: param->name); |
187 | kfree(objp: param); |
188 | } |
189 | |
190 | return NULL; |
191 | } |
192 | |
193 | /* #warning Add extension keys */ |
194 | int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) |
195 | { |
196 | struct iscsi_param *param = NULL; |
197 | struct iscsi_param_list *pl; |
198 | |
199 | pl = kzalloc(size: sizeof(struct iscsi_param_list), GFP_KERNEL); |
200 | if (!pl) { |
201 | pr_err("Unable to allocate memory for" |
202 | " struct iscsi_param_list.\n" ); |
203 | return -ENOMEM; |
204 | } |
205 | INIT_LIST_HEAD(list: &pl->param_list); |
206 | INIT_LIST_HEAD(list: &pl->extra_response_list); |
207 | |
208 | /* |
209 | * The format for setting the initial parameter definitions are: |
210 | * |
211 | * Parameter name: |
212 | * Initial value: |
213 | * Allowable phase: |
214 | * Scope: |
215 | * Allowable senders: |
216 | * Typerange: |
217 | * Use: |
218 | */ |
219 | param = iscsi_set_default_param(param_list: pl, AUTHMETHOD, INITIAL_AUTHMETHOD, |
220 | PHASE_SECURITY, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
221 | TYPERANGE_AUTH, USE_INITIAL_ONLY); |
222 | if (!param) |
223 | goto out; |
224 | |
225 | param = iscsi_set_default_param(param_list: pl, HEADERDIGEST, INITIAL_HEADERDIGEST, |
226 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
227 | TYPERANGE_DIGEST, USE_INITIAL_ONLY); |
228 | if (!param) |
229 | goto out; |
230 | |
231 | param = iscsi_set_default_param(param_list: pl, DATADIGEST, INITIAL_DATADIGEST, |
232 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
233 | TYPERANGE_DIGEST, USE_INITIAL_ONLY); |
234 | if (!param) |
235 | goto out; |
236 | |
237 | param = iscsi_set_default_param(param_list: pl, MAXCONNECTIONS, |
238 | INITIAL_MAXCONNECTIONS, PHASE_OPERATIONAL, |
239 | SCOPE_SESSION_WIDE, SENDER_BOTH, |
240 | TYPERANGE_1_TO_65535, USE_LEADING_ONLY); |
241 | if (!param) |
242 | goto out; |
243 | |
244 | param = iscsi_set_default_param(param_list: pl, SENDTARGETS, INITIAL_SENDTARGETS, |
245 | PHASE_FFP0, SCOPE_SESSION_WIDE, SENDER_INITIATOR, |
246 | TYPERANGE_UTF8, use: 0); |
247 | if (!param) |
248 | goto out; |
249 | |
250 | param = iscsi_set_default_param(param_list: pl, TARGETNAME, INITIAL_TARGETNAME, |
251 | PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_BOTH, |
252 | TYPERANGE_ISCSINAME, USE_ALL); |
253 | if (!param) |
254 | goto out; |
255 | |
256 | param = iscsi_set_default_param(param_list: pl, INITIATORNAME, |
257 | INITIAL_INITIATORNAME, PHASE_DECLARATIVE, |
258 | SCOPE_SESSION_WIDE, SENDER_INITIATOR, |
259 | TYPERANGE_ISCSINAME, USE_INITIAL_ONLY); |
260 | if (!param) |
261 | goto out; |
262 | |
263 | param = iscsi_set_default_param(param_list: pl, TARGETALIAS, INITIAL_TARGETALIAS, |
264 | PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET, |
265 | TYPERANGE_UTF8, USE_ALL); |
266 | if (!param) |
267 | goto out; |
268 | |
269 | param = iscsi_set_default_param(param_list: pl, INITIATORALIAS, |
270 | INITIAL_INITIATORALIAS, PHASE_DECLARATIVE, |
271 | SCOPE_SESSION_WIDE, SENDER_INITIATOR, TYPERANGE_UTF8, |
272 | USE_ALL); |
273 | if (!param) |
274 | goto out; |
275 | |
276 | param = iscsi_set_default_param(param_list: pl, TARGETADDRESS, |
277 | INITIAL_TARGETADDRESS, PHASE_DECLARATIVE, |
278 | SCOPE_SESSION_WIDE, SENDER_TARGET, |
279 | TYPERANGE_TARGETADDRESS, USE_ALL); |
280 | if (!param) |
281 | goto out; |
282 | |
283 | param = iscsi_set_default_param(param_list: pl, TARGETPORTALGROUPTAG, |
284 | INITIAL_TARGETPORTALGROUPTAG, |
285 | PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET, |
286 | TYPERANGE_0_TO_65535, USE_INITIAL_ONLY); |
287 | if (!param) |
288 | goto out; |
289 | |
290 | param = iscsi_set_default_param(param_list: pl, INITIALR2T, INITIAL_INITIALR2T, |
291 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
292 | TYPERANGE_BOOL_OR, USE_LEADING_ONLY); |
293 | if (!param) |
294 | goto out; |
295 | |
296 | param = iscsi_set_default_param(param_list: pl, IMMEDIATEDATA, |
297 | INITIAL_IMMEDIATEDATA, PHASE_OPERATIONAL, |
298 | SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_AND, |
299 | USE_LEADING_ONLY); |
300 | if (!param) |
301 | goto out; |
302 | |
303 | param = iscsi_set_default_param(param_list: pl, MAXXMITDATASEGMENTLENGTH, |
304 | INITIAL_MAXXMITDATASEGMENTLENGTH, |
305 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
306 | TYPERANGE_512_TO_16777215, USE_ALL); |
307 | if (!param) |
308 | goto out; |
309 | |
310 | param = iscsi_set_default_param(param_list: pl, MAXRECVDATASEGMENTLENGTH, |
311 | INITIAL_MAXRECVDATASEGMENTLENGTH, |
312 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
313 | TYPERANGE_512_TO_16777215, USE_ALL); |
314 | if (!param) |
315 | goto out; |
316 | |
317 | param = iscsi_set_default_param(param_list: pl, MAXBURSTLENGTH, |
318 | INITIAL_MAXBURSTLENGTH, PHASE_OPERATIONAL, |
319 | SCOPE_SESSION_WIDE, SENDER_BOTH, |
320 | TYPERANGE_512_TO_16777215, USE_LEADING_ONLY); |
321 | if (!param) |
322 | goto out; |
323 | |
324 | param = iscsi_set_default_param(param_list: pl, FIRSTBURSTLENGTH, |
325 | INITIAL_FIRSTBURSTLENGTH, |
326 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
327 | TYPERANGE_512_TO_16777215, USE_LEADING_ONLY); |
328 | if (!param) |
329 | goto out; |
330 | |
331 | param = iscsi_set_default_param(param_list: pl, DEFAULTTIME2WAIT, |
332 | INITIAL_DEFAULTTIME2WAIT, |
333 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
334 | TYPERANGE_0_TO_3600, USE_LEADING_ONLY); |
335 | if (!param) |
336 | goto out; |
337 | |
338 | param = iscsi_set_default_param(param_list: pl, DEFAULTTIME2RETAIN, |
339 | INITIAL_DEFAULTTIME2RETAIN, |
340 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
341 | TYPERANGE_0_TO_3600, USE_LEADING_ONLY); |
342 | if (!param) |
343 | goto out; |
344 | |
345 | param = iscsi_set_default_param(param_list: pl, MAXOUTSTANDINGR2T, |
346 | INITIAL_MAXOUTSTANDINGR2T, |
347 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
348 | TYPERANGE_1_TO_65535, USE_LEADING_ONLY); |
349 | if (!param) |
350 | goto out; |
351 | |
352 | param = iscsi_set_default_param(param_list: pl, DATAPDUINORDER, |
353 | INITIAL_DATAPDUINORDER, PHASE_OPERATIONAL, |
354 | SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_OR, |
355 | USE_LEADING_ONLY); |
356 | if (!param) |
357 | goto out; |
358 | |
359 | param = iscsi_set_default_param(param_list: pl, DATASEQUENCEINORDER, |
360 | INITIAL_DATASEQUENCEINORDER, |
361 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
362 | TYPERANGE_BOOL_OR, USE_LEADING_ONLY); |
363 | if (!param) |
364 | goto out; |
365 | |
366 | param = iscsi_set_default_param(param_list: pl, ERRORRECOVERYLEVEL, |
367 | INITIAL_ERRORRECOVERYLEVEL, |
368 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
369 | TYPERANGE_0_TO_2, USE_LEADING_ONLY); |
370 | if (!param) |
371 | goto out; |
372 | |
373 | param = iscsi_set_default_param(param_list: pl, SESSIONTYPE, INITIAL_SESSIONTYPE, |
374 | PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_INITIATOR, |
375 | TYPERANGE_SESSIONTYPE, USE_LEADING_ONLY); |
376 | if (!param) |
377 | goto out; |
378 | |
379 | param = iscsi_set_default_param(param_list: pl, IFMARKER, INITIAL_IFMARKER, |
380 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
381 | TYPERANGE_BOOL_AND, USE_INITIAL_ONLY); |
382 | if (!param) |
383 | goto out; |
384 | |
385 | param = iscsi_set_default_param(param_list: pl, OFMARKER, INITIAL_OFMARKER, |
386 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
387 | TYPERANGE_BOOL_AND, USE_INITIAL_ONLY); |
388 | if (!param) |
389 | goto out; |
390 | |
391 | param = iscsi_set_default_param(param_list: pl, IFMARKINT, INITIAL_IFMARKINT, |
392 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
393 | TYPERANGE_UTF8, USE_INITIAL_ONLY); |
394 | if (!param) |
395 | goto out; |
396 | |
397 | param = iscsi_set_default_param(param_list: pl, OFMARKINT, INITIAL_OFMARKINT, |
398 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
399 | TYPERANGE_UTF8, USE_INITIAL_ONLY); |
400 | if (!param) |
401 | goto out; |
402 | |
403 | /* |
404 | * Extra parameters for ISER from RFC-5046 |
405 | */ |
406 | param = iscsi_set_default_param(param_list: pl, RDMAEXTENSIONS, INITIAL_RDMAEXTENSIONS, |
407 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, |
408 | TYPERANGE_BOOL_AND, USE_LEADING_ONLY); |
409 | if (!param) |
410 | goto out; |
411 | |
412 | param = iscsi_set_default_param(param_list: pl, INITIATORRECVDATASEGMENTLENGTH, |
413 | INITIAL_INITIATORRECVDATASEGMENTLENGTH, |
414 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
415 | TYPERANGE_512_TO_16777215, USE_ALL); |
416 | if (!param) |
417 | goto out; |
418 | |
419 | param = iscsi_set_default_param(param_list: pl, TARGETRECVDATASEGMENTLENGTH, |
420 | INITIAL_TARGETRECVDATASEGMENTLENGTH, |
421 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, |
422 | TYPERANGE_512_TO_16777215, USE_ALL); |
423 | if (!param) |
424 | goto out; |
425 | |
426 | *param_list_ptr = pl; |
427 | return 0; |
428 | out: |
429 | iscsi_release_param_list(pl); |
430 | return -1; |
431 | } |
432 | |
433 | int iscsi_set_keys_to_negotiate( |
434 | struct iscsi_param_list *param_list, |
435 | bool iser) |
436 | { |
437 | struct iscsi_param *param; |
438 | |
439 | param_list->iser = iser; |
440 | |
441 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
442 | param->state = 0; |
443 | if (!strcmp(param->name, AUTHMETHOD)) { |
444 | SET_PSTATE_NEGOTIATE(param); |
445 | } else if (!strcmp(param->name, HEADERDIGEST)) { |
446 | if (!iser) |
447 | SET_PSTATE_NEGOTIATE(param); |
448 | } else if (!strcmp(param->name, DATADIGEST)) { |
449 | if (!iser) |
450 | SET_PSTATE_NEGOTIATE(param); |
451 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { |
452 | SET_PSTATE_NEGOTIATE(param); |
453 | } else if (!strcmp(param->name, TARGETNAME)) { |
454 | continue; |
455 | } else if (!strcmp(param->name, INITIATORNAME)) { |
456 | continue; |
457 | } else if (!strcmp(param->name, TARGETALIAS)) { |
458 | if (param->value) |
459 | SET_PSTATE_NEGOTIATE(param); |
460 | } else if (!strcmp(param->name, INITIATORALIAS)) { |
461 | continue; |
462 | } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) { |
463 | SET_PSTATE_NEGOTIATE(param); |
464 | } else if (!strcmp(param->name, INITIALR2T)) { |
465 | SET_PSTATE_NEGOTIATE(param); |
466 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { |
467 | SET_PSTATE_NEGOTIATE(param); |
468 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
469 | if (!iser) |
470 | SET_PSTATE_NEGOTIATE(param); |
471 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
472 | continue; |
473 | } else if (!strcmp(param->name, MAXBURSTLENGTH)) { |
474 | SET_PSTATE_NEGOTIATE(param); |
475 | } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) { |
476 | SET_PSTATE_NEGOTIATE(param); |
477 | } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { |
478 | SET_PSTATE_NEGOTIATE(param); |
479 | } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) { |
480 | SET_PSTATE_NEGOTIATE(param); |
481 | } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) { |
482 | SET_PSTATE_NEGOTIATE(param); |
483 | } else if (!strcmp(param->name, DATAPDUINORDER)) { |
484 | SET_PSTATE_NEGOTIATE(param); |
485 | } else if (!strcmp(param->name, DATASEQUENCEINORDER)) { |
486 | SET_PSTATE_NEGOTIATE(param); |
487 | } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) { |
488 | SET_PSTATE_NEGOTIATE(param); |
489 | } else if (!strcmp(param->name, SESSIONTYPE)) { |
490 | SET_PSTATE_NEGOTIATE(param); |
491 | } else if (!strcmp(param->name, IFMARKER)) { |
492 | SET_PSTATE_REJECT(param); |
493 | } else if (!strcmp(param->name, OFMARKER)) { |
494 | SET_PSTATE_REJECT(param); |
495 | } else if (!strcmp(param->name, IFMARKINT)) { |
496 | SET_PSTATE_REJECT(param); |
497 | } else if (!strcmp(param->name, OFMARKINT)) { |
498 | SET_PSTATE_REJECT(param); |
499 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { |
500 | if (iser) |
501 | SET_PSTATE_NEGOTIATE(param); |
502 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { |
503 | if (iser) |
504 | SET_PSTATE_NEGOTIATE(param); |
505 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { |
506 | if (iser) |
507 | SET_PSTATE_NEGOTIATE(param); |
508 | } |
509 | } |
510 | |
511 | return 0; |
512 | } |
513 | |
514 | int iscsi_set_keys_irrelevant_for_discovery( |
515 | struct iscsi_param_list *param_list) |
516 | { |
517 | struct iscsi_param *param; |
518 | |
519 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
520 | if (!strcmp(param->name, MAXCONNECTIONS)) |
521 | param->state &= ~PSTATE_NEGOTIATE; |
522 | else if (!strcmp(param->name, INITIALR2T)) |
523 | param->state &= ~PSTATE_NEGOTIATE; |
524 | else if (!strcmp(param->name, IMMEDIATEDATA)) |
525 | param->state &= ~PSTATE_NEGOTIATE; |
526 | else if (!strcmp(param->name, MAXBURSTLENGTH)) |
527 | param->state &= ~PSTATE_NEGOTIATE; |
528 | else if (!strcmp(param->name, FIRSTBURSTLENGTH)) |
529 | param->state &= ~PSTATE_NEGOTIATE; |
530 | else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) |
531 | param->state &= ~PSTATE_NEGOTIATE; |
532 | else if (!strcmp(param->name, DATAPDUINORDER)) |
533 | param->state &= ~PSTATE_NEGOTIATE; |
534 | else if (!strcmp(param->name, DATASEQUENCEINORDER)) |
535 | param->state &= ~PSTATE_NEGOTIATE; |
536 | else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) |
537 | param->state &= ~PSTATE_NEGOTIATE; |
538 | else if (!strcmp(param->name, DEFAULTTIME2WAIT)) |
539 | param->state &= ~PSTATE_NEGOTIATE; |
540 | else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) |
541 | param->state &= ~PSTATE_NEGOTIATE; |
542 | else if (!strcmp(param->name, IFMARKER)) |
543 | param->state &= ~PSTATE_NEGOTIATE; |
544 | else if (!strcmp(param->name, OFMARKER)) |
545 | param->state &= ~PSTATE_NEGOTIATE; |
546 | else if (!strcmp(param->name, IFMARKINT)) |
547 | param->state &= ~PSTATE_NEGOTIATE; |
548 | else if (!strcmp(param->name, OFMARKINT)) |
549 | param->state &= ~PSTATE_NEGOTIATE; |
550 | else if (!strcmp(param->name, RDMAEXTENSIONS)) |
551 | param->state &= ~PSTATE_NEGOTIATE; |
552 | else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) |
553 | param->state &= ~PSTATE_NEGOTIATE; |
554 | else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) |
555 | param->state &= ~PSTATE_NEGOTIATE; |
556 | } |
557 | |
558 | return 0; |
559 | } |
560 | |
561 | int iscsi_copy_param_list( |
562 | struct iscsi_param_list **dst_param_list, |
563 | struct iscsi_param_list *src_param_list, |
564 | int leading) |
565 | { |
566 | struct iscsi_param *param = NULL; |
567 | struct iscsi_param *new_param = NULL; |
568 | struct iscsi_param_list *param_list = NULL; |
569 | |
570 | param_list = kzalloc(size: sizeof(struct iscsi_param_list), GFP_KERNEL); |
571 | if (!param_list) { |
572 | pr_err("Unable to allocate memory for struct iscsi_param_list.\n" ); |
573 | return -ENOMEM; |
574 | } |
575 | INIT_LIST_HEAD(list: ¶m_list->param_list); |
576 | INIT_LIST_HEAD(list: ¶m_list->extra_response_list); |
577 | |
578 | list_for_each_entry(param, &src_param_list->param_list, p_list) { |
579 | if (!leading && (param->scope & SCOPE_SESSION_WIDE)) { |
580 | if ((strcmp(param->name, "TargetName" ) != 0) && |
581 | (strcmp(param->name, "InitiatorName" ) != 0) && |
582 | (strcmp(param->name, "TargetPortalGroupTag" ) != 0)) |
583 | continue; |
584 | } |
585 | |
586 | new_param = kzalloc(size: sizeof(struct iscsi_param), GFP_KERNEL); |
587 | if (!new_param) { |
588 | pr_err("Unable to allocate memory for struct iscsi_param.\n" ); |
589 | goto err_out; |
590 | } |
591 | |
592 | new_param->name = kstrdup(s: param->name, GFP_KERNEL); |
593 | new_param->value = kstrdup(s: param->value, GFP_KERNEL); |
594 | if (!new_param->value || !new_param->name) { |
595 | kfree(objp: new_param->value); |
596 | kfree(objp: new_param->name); |
597 | kfree(objp: new_param); |
598 | pr_err("Unable to allocate memory for parameter name/value.\n" ); |
599 | goto err_out; |
600 | } |
601 | |
602 | new_param->set_param = param->set_param; |
603 | new_param->phase = param->phase; |
604 | new_param->scope = param->scope; |
605 | new_param->sender = param->sender; |
606 | new_param->type = param->type; |
607 | new_param->use = param->use; |
608 | new_param->type_range = param->type_range; |
609 | |
610 | list_add_tail(new: &new_param->p_list, head: ¶m_list->param_list); |
611 | } |
612 | |
613 | if (!list_empty(head: ¶m_list->param_list)) { |
614 | *dst_param_list = param_list; |
615 | } else { |
616 | pr_err("No parameters allocated.\n" ); |
617 | goto err_out; |
618 | } |
619 | |
620 | return 0; |
621 | |
622 | err_out: |
623 | iscsi_release_param_list(param_list); |
624 | return -ENOMEM; |
625 | } |
626 | |
627 | static void (struct iscsi_param_list *param_list) |
628 | { |
629 | struct iscsi_extra_response *er, *er_tmp; |
630 | |
631 | list_for_each_entry_safe(er, er_tmp, ¶m_list->extra_response_list, |
632 | er_list) { |
633 | list_del(entry: &er->er_list); |
634 | kfree(objp: er); |
635 | } |
636 | } |
637 | |
638 | void iscsi_release_param_list(struct iscsi_param_list *param_list) |
639 | { |
640 | struct iscsi_param *param, *param_tmp; |
641 | |
642 | list_for_each_entry_safe(param, param_tmp, ¶m_list->param_list, |
643 | p_list) { |
644 | list_del(entry: ¶m->p_list); |
645 | |
646 | kfree(objp: param->name); |
647 | kfree(objp: param->value); |
648 | kfree(objp: param); |
649 | } |
650 | |
651 | iscsi_release_extra_responses(param_list); |
652 | |
653 | kfree(objp: param_list); |
654 | } |
655 | |
656 | struct iscsi_param *iscsi_find_param_from_key( |
657 | char *key, |
658 | struct iscsi_param_list *param_list) |
659 | { |
660 | struct iscsi_param *param; |
661 | |
662 | if (!key || !param_list) { |
663 | pr_err("Key or parameter list pointer is NULL.\n" ); |
664 | return NULL; |
665 | } |
666 | |
667 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
668 | if (!strcmp(key, param->name)) |
669 | return param; |
670 | } |
671 | |
672 | pr_err("Unable to locate key \"%s\".\n" , key); |
673 | return NULL; |
674 | } |
675 | EXPORT_SYMBOL(iscsi_find_param_from_key); |
676 | |
677 | int (char *textbuf, char **key, char **value) |
678 | { |
679 | *value = strchr(textbuf, '='); |
680 | if (!*value) { |
681 | pr_err("Unable to locate \"=\" separator for key," |
682 | " ignoring request.\n" ); |
683 | return -1; |
684 | } |
685 | |
686 | *key = textbuf; |
687 | **value = '\0'; |
688 | *value = *value + 1; |
689 | |
690 | return 0; |
691 | } |
692 | |
693 | int iscsi_update_param_value(struct iscsi_param *param, char *value) |
694 | { |
695 | kfree(objp: param->value); |
696 | |
697 | param->value = kstrdup(s: value, GFP_KERNEL); |
698 | if (!param->value) { |
699 | pr_err("Unable to allocate memory for value.\n" ); |
700 | return -ENOMEM; |
701 | } |
702 | |
703 | pr_debug("iSCSI Parameter updated to %s=%s\n" , |
704 | param->name, param->value); |
705 | return 0; |
706 | } |
707 | |
708 | static int iscsi_add_notunderstood_response( |
709 | char *key, |
710 | char *value, |
711 | struct iscsi_param_list *param_list) |
712 | { |
713 | struct iscsi_extra_response *; |
714 | |
715 | if (strlen(value) > VALUE_MAXLEN) { |
716 | pr_err("Value for notunderstood key \"%s\" exceeds %d," |
717 | " protocol error.\n" , key, VALUE_MAXLEN); |
718 | return -1; |
719 | } |
720 | |
721 | extra_response = kzalloc(size: sizeof(struct iscsi_extra_response), GFP_KERNEL); |
722 | if (!extra_response) { |
723 | pr_err("Unable to allocate memory for" |
724 | " struct iscsi_extra_response.\n" ); |
725 | return -ENOMEM; |
726 | } |
727 | INIT_LIST_HEAD(list: &extra_response->er_list); |
728 | |
729 | strscpy(p: extra_response->key, q: key, size: sizeof(extra_response->key)); |
730 | strscpy(p: extra_response->value, NOTUNDERSTOOD, |
731 | size: sizeof(extra_response->value)); |
732 | |
733 | list_add_tail(new: &extra_response->er_list, |
734 | head: ¶m_list->extra_response_list); |
735 | return 0; |
736 | } |
737 | |
738 | static int iscsi_check_for_auth_key(char *key) |
739 | { |
740 | /* |
741 | * RFC 1994 |
742 | */ |
743 | if (!strcmp(key, "CHAP_A" ) || !strcmp(key, "CHAP_I" ) || |
744 | !strcmp(key, "CHAP_C" ) || !strcmp(key, "CHAP_N" ) || |
745 | !strcmp(key, "CHAP_R" )) |
746 | return 1; |
747 | |
748 | /* |
749 | * RFC 2945 |
750 | */ |
751 | if (!strcmp(key, "SRP_U" ) || !strcmp(key, "SRP_N" ) || |
752 | !strcmp(key, "SRP_g" ) || !strcmp(key, "SRP_s" ) || |
753 | !strcmp(key, "SRP_A" ) || !strcmp(key, "SRP_B" ) || |
754 | !strcmp(key, "SRP_M" ) || !strcmp(key, "SRP_HM" )) |
755 | return 1; |
756 | |
757 | return 0; |
758 | } |
759 | |
760 | static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param, |
761 | bool keys_workaround) |
762 | { |
763 | if (IS_TYPE_BOOL_AND(param)) { |
764 | if (!strcmp(param->value, NO)) |
765 | SET_PSTATE_REPLY_OPTIONAL(param); |
766 | } else if (IS_TYPE_BOOL_OR(param)) { |
767 | if (!strcmp(param->value, YES)) |
768 | SET_PSTATE_REPLY_OPTIONAL(param); |
769 | |
770 | if (keys_workaround) { |
771 | /* |
772 | * Required for gPXE iSCSI boot client |
773 | */ |
774 | if (!strcmp(param->name, IMMEDIATEDATA)) |
775 | SET_PSTATE_REPLY_OPTIONAL(param); |
776 | } |
777 | } else if (IS_TYPE_NUMBER(param)) { |
778 | if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) |
779 | SET_PSTATE_REPLY_OPTIONAL(param); |
780 | |
781 | if (keys_workaround) { |
782 | /* |
783 | * Required for Mellanox Flexboot PXE boot ROM |
784 | */ |
785 | if (!strcmp(param->name, FIRSTBURSTLENGTH)) |
786 | SET_PSTATE_REPLY_OPTIONAL(param); |
787 | |
788 | /* |
789 | * Required for gPXE iSCSI boot client |
790 | */ |
791 | if (!strcmp(param->name, MAXCONNECTIONS)) |
792 | SET_PSTATE_REPLY_OPTIONAL(param); |
793 | } |
794 | } else if (IS_PHASE_DECLARATIVE(param)) |
795 | SET_PSTATE_REPLY_OPTIONAL(param); |
796 | } |
797 | |
798 | static int iscsi_check_boolean_value(struct iscsi_param *param, char *value) |
799 | { |
800 | if (strcmp(value, YES) && strcmp(value, NO)) { |
801 | pr_err("Illegal value for \"%s\", must be either" |
802 | " \"%s\" or \"%s\".\n" , param->name, YES, NO); |
803 | return -1; |
804 | } |
805 | |
806 | return 0; |
807 | } |
808 | |
809 | static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_ptr) |
810 | { |
811 | char *tmpptr; |
812 | int value = 0; |
813 | |
814 | value = simple_strtoul(value_ptr, &tmpptr, 0); |
815 | |
816 | if (IS_TYPERANGE_0_TO_2(param)) { |
817 | if ((value < 0) || (value > 2)) { |
818 | pr_err("Illegal value for \"%s\", must be" |
819 | " between 0 and 2.\n" , param->name); |
820 | return -1; |
821 | } |
822 | return 0; |
823 | } |
824 | if (IS_TYPERANGE_0_TO_3600(param)) { |
825 | if ((value < 0) || (value > 3600)) { |
826 | pr_err("Illegal value for \"%s\", must be" |
827 | " between 0 and 3600.\n" , param->name); |
828 | return -1; |
829 | } |
830 | return 0; |
831 | } |
832 | if (IS_TYPERANGE_0_TO_32767(param)) { |
833 | if ((value < 0) || (value > 32767)) { |
834 | pr_err("Illegal value for \"%s\", must be" |
835 | " between 0 and 32767.\n" , param->name); |
836 | return -1; |
837 | } |
838 | return 0; |
839 | } |
840 | if (IS_TYPERANGE_0_TO_65535(param)) { |
841 | if ((value < 0) || (value > 65535)) { |
842 | pr_err("Illegal value for \"%s\", must be" |
843 | " between 0 and 65535.\n" , param->name); |
844 | return -1; |
845 | } |
846 | return 0; |
847 | } |
848 | if (IS_TYPERANGE_1_TO_65535(param)) { |
849 | if ((value < 1) || (value > 65535)) { |
850 | pr_err("Illegal value for \"%s\", must be" |
851 | " between 1 and 65535.\n" , param->name); |
852 | return -1; |
853 | } |
854 | return 0; |
855 | } |
856 | if (IS_TYPERANGE_2_TO_3600(param)) { |
857 | if ((value < 2) || (value > 3600)) { |
858 | pr_err("Illegal value for \"%s\", must be" |
859 | " between 2 and 3600.\n" , param->name); |
860 | return -1; |
861 | } |
862 | return 0; |
863 | } |
864 | if (IS_TYPERANGE_512_TO_16777215(param)) { |
865 | if ((value < 512) || (value > 16777215)) { |
866 | pr_err("Illegal value for \"%s\", must be" |
867 | " between 512 and 16777215.\n" , param->name); |
868 | return -1; |
869 | } |
870 | return 0; |
871 | } |
872 | |
873 | return 0; |
874 | } |
875 | |
876 | static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *value) |
877 | { |
878 | if (IS_PSTATE_PROPOSER(param)) |
879 | return 0; |
880 | |
881 | if (IS_TYPERANGE_AUTH_PARAM(param)) { |
882 | if (strcmp(value, KRB5) && strcmp(value, SPKM1) && |
883 | strcmp(value, SPKM2) && strcmp(value, SRP) && |
884 | strcmp(value, CHAP) && strcmp(value, NONE)) { |
885 | pr_err("Illegal value for \"%s\", must be" |
886 | " \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"" |
887 | " or \"%s\".\n" , param->name, KRB5, |
888 | SPKM1, SPKM2, SRP, CHAP, NONE); |
889 | return -1; |
890 | } |
891 | } |
892 | if (IS_TYPERANGE_DIGEST_PARAM(param)) { |
893 | if (strcmp(value, CRC32C) && strcmp(value, NONE)) { |
894 | pr_err("Illegal value for \"%s\", must be" |
895 | " \"%s\" or \"%s\".\n" , param->name, |
896 | CRC32C, NONE); |
897 | return -1; |
898 | } |
899 | } |
900 | if (IS_TYPERANGE_SESSIONTYPE(param)) { |
901 | if (strcmp(value, DISCOVERY) && strcmp(value, NORMAL)) { |
902 | pr_err("Illegal value for \"%s\", must be" |
903 | " \"%s\" or \"%s\".\n" , param->name, |
904 | DISCOVERY, NORMAL); |
905 | return -1; |
906 | } |
907 | } |
908 | |
909 | return 0; |
910 | } |
911 | |
912 | static char *iscsi_check_valuelist_for_support( |
913 | struct iscsi_param *param, |
914 | char *value) |
915 | { |
916 | char *tmp1 = NULL, *tmp2 = NULL; |
917 | char *acceptor_values = NULL, *proposer_values = NULL; |
918 | |
919 | acceptor_values = param->value; |
920 | proposer_values = value; |
921 | |
922 | do { |
923 | if (!proposer_values) |
924 | return NULL; |
925 | tmp1 = strchr(proposer_values, ','); |
926 | if (tmp1) |
927 | *tmp1 = '\0'; |
928 | acceptor_values = param->value; |
929 | do { |
930 | if (!acceptor_values) { |
931 | if (tmp1) |
932 | *tmp1 = ','; |
933 | return NULL; |
934 | } |
935 | tmp2 = strchr(acceptor_values, ','); |
936 | if (tmp2) |
937 | *tmp2 = '\0'; |
938 | if (!strcmp(acceptor_values, proposer_values)) { |
939 | if (tmp2) |
940 | *tmp2 = ','; |
941 | goto out; |
942 | } |
943 | if (tmp2) |
944 | *tmp2++ = ','; |
945 | |
946 | acceptor_values = tmp2; |
947 | } while (acceptor_values); |
948 | if (tmp1) |
949 | *tmp1++ = ','; |
950 | proposer_values = tmp1; |
951 | } while (proposer_values); |
952 | |
953 | out: |
954 | return proposer_values; |
955 | } |
956 | |
957 | static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, |
958 | struct iscsit_conn *conn) |
959 | { |
960 | u8 acceptor_boolean_value = 0, proposer_boolean_value = 0; |
961 | char *negotiated_value = NULL; |
962 | |
963 | if (IS_PSTATE_ACCEPTOR(param)) { |
964 | pr_err("Received key \"%s\" twice, protocol error.\n" , |
965 | param->name); |
966 | return -1; |
967 | } |
968 | |
969 | if (IS_PSTATE_REJECT(param)) |
970 | return 0; |
971 | |
972 | if (IS_TYPE_BOOL_AND(param)) { |
973 | if (!strcmp(value, YES)) |
974 | proposer_boolean_value = 1; |
975 | if (!strcmp(param->value, YES)) |
976 | acceptor_boolean_value = 1; |
977 | if (acceptor_boolean_value && proposer_boolean_value) |
978 | do {} while (0); |
979 | else { |
980 | if (iscsi_update_param_value(param, NO) < 0) |
981 | return -1; |
982 | if (!proposer_boolean_value) |
983 | SET_PSTATE_REPLY_OPTIONAL(param); |
984 | } |
985 | } else if (IS_TYPE_BOOL_OR(param)) { |
986 | if (!strcmp(value, YES)) |
987 | proposer_boolean_value = 1; |
988 | if (!strcmp(param->value, YES)) |
989 | acceptor_boolean_value = 1; |
990 | if (acceptor_boolean_value || proposer_boolean_value) { |
991 | if (iscsi_update_param_value(param, YES) < 0) |
992 | return -1; |
993 | if (proposer_boolean_value) |
994 | SET_PSTATE_REPLY_OPTIONAL(param); |
995 | } |
996 | } else if (IS_TYPE_NUMBER(param)) { |
997 | char *tmpptr, buf[11]; |
998 | u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0); |
999 | u32 proposer_value = simple_strtoul(value, &tmpptr, 0); |
1000 | |
1001 | memset(buf, 0, sizeof(buf)); |
1002 | |
1003 | if (!strcmp(param->name, MAXCONNECTIONS) || |
1004 | !strcmp(param->name, MAXBURSTLENGTH) || |
1005 | !strcmp(param->name, FIRSTBURSTLENGTH) || |
1006 | !strcmp(param->name, MAXOUTSTANDINGR2T) || |
1007 | !strcmp(param->name, DEFAULTTIME2RETAIN) || |
1008 | !strcmp(param->name, ERRORRECOVERYLEVEL)) { |
1009 | if (proposer_value > acceptor_value) { |
1010 | sprintf(buf, fmt: "%u" , acceptor_value); |
1011 | if (iscsi_update_param_value(param, |
1012 | value: &buf[0]) < 0) |
1013 | return -1; |
1014 | } else { |
1015 | if (iscsi_update_param_value(param, value) < 0) |
1016 | return -1; |
1017 | } |
1018 | } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { |
1019 | if (acceptor_value > proposer_value) { |
1020 | sprintf(buf, fmt: "%u" , acceptor_value); |
1021 | if (iscsi_update_param_value(param, |
1022 | value: &buf[0]) < 0) |
1023 | return -1; |
1024 | } else { |
1025 | if (iscsi_update_param_value(param, value) < 0) |
1026 | return -1; |
1027 | } |
1028 | } else { |
1029 | if (iscsi_update_param_value(param, value) < 0) |
1030 | return -1; |
1031 | } |
1032 | |
1033 | if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
1034 | struct iscsi_param *param_mxdsl; |
1035 | unsigned long long tmp; |
1036 | int rc; |
1037 | |
1038 | rc = kstrtoull(s: param->value, base: 0, res: &tmp); |
1039 | if (rc < 0) |
1040 | return -1; |
1041 | |
1042 | conn->conn_ops->MaxRecvDataSegmentLength = tmp; |
1043 | pr_debug("Saving op->MaxRecvDataSegmentLength from" |
1044 | " original initiator received value: %u\n" , |
1045 | conn->conn_ops->MaxRecvDataSegmentLength); |
1046 | |
1047 | param_mxdsl = iscsi_find_param_from_key( |
1048 | MAXXMITDATASEGMENTLENGTH, |
1049 | conn->param_list); |
1050 | if (!param_mxdsl) |
1051 | return -1; |
1052 | |
1053 | rc = iscsi_update_param_value(param, |
1054 | value: param_mxdsl->value); |
1055 | if (rc < 0) |
1056 | return -1; |
1057 | |
1058 | pr_debug("Updated %s to target MXDSL value: %s\n" , |
1059 | param->name, param->value); |
1060 | } |
1061 | } else if (IS_TYPE_VALUE_LIST(param)) { |
1062 | negotiated_value = iscsi_check_valuelist_for_support( |
1063 | param, value); |
1064 | if (!negotiated_value) { |
1065 | pr_err("Proposer's value list \"%s\" contains" |
1066 | " no valid values from Acceptor's value list" |
1067 | " \"%s\".\n" , value, param->value); |
1068 | return -1; |
1069 | } |
1070 | if (iscsi_update_param_value(param, value: negotiated_value) < 0) |
1071 | return -1; |
1072 | } else if (IS_PHASE_DECLARATIVE(param)) { |
1073 | if (iscsi_update_param_value(param, value) < 0) |
1074 | return -1; |
1075 | SET_PSTATE_REPLY_OPTIONAL(param); |
1076 | } |
1077 | |
1078 | return 0; |
1079 | } |
1080 | |
1081 | static int iscsi_check_proposer_state(struct iscsi_param *param, char *value) |
1082 | { |
1083 | if (IS_PSTATE_RESPONSE_GOT(param)) { |
1084 | pr_err("Received key \"%s\" twice, protocol error.\n" , |
1085 | param->name); |
1086 | return -1; |
1087 | } |
1088 | |
1089 | if (IS_TYPE_VALUE_LIST(param)) { |
1090 | char *comma_ptr = NULL, *tmp_ptr = NULL; |
1091 | |
1092 | comma_ptr = strchr(value, ','); |
1093 | if (comma_ptr) { |
1094 | pr_err("Illegal \",\" in response for \"%s\".\n" , |
1095 | param->name); |
1096 | return -1; |
1097 | } |
1098 | |
1099 | tmp_ptr = iscsi_check_valuelist_for_support(param, value); |
1100 | if (!tmp_ptr) |
1101 | return -1; |
1102 | } |
1103 | |
1104 | if (iscsi_update_param_value(param, value) < 0) |
1105 | return -1; |
1106 | |
1107 | return 0; |
1108 | } |
1109 | |
1110 | static int iscsi_check_value(struct iscsi_param *param, char *value) |
1111 | { |
1112 | char *comma_ptr = NULL; |
1113 | |
1114 | if (!strcmp(value, REJECT)) { |
1115 | if (!strcmp(param->name, IFMARKINT) || |
1116 | !strcmp(param->name, OFMARKINT)) { |
1117 | /* |
1118 | * Reject is not fatal for [I,O]FMarkInt, and causes |
1119 | * [I,O]FMarker to be reset to No. (See iSCSI v20 A.3.2) |
1120 | */ |
1121 | SET_PSTATE_REJECT(param); |
1122 | return 0; |
1123 | } |
1124 | pr_err("Received %s=%s\n" , param->name, value); |
1125 | return -1; |
1126 | } |
1127 | if (!strcmp(value, IRRELEVANT)) { |
1128 | pr_debug("Received %s=%s\n" , param->name, value); |
1129 | SET_PSTATE_IRRELEVANT(param); |
1130 | return 0; |
1131 | } |
1132 | if (!strcmp(value, NOTUNDERSTOOD)) { |
1133 | if (!IS_PSTATE_PROPOSER(param)) { |
1134 | pr_err("Received illegal offer %s=%s\n" , |
1135 | param->name, value); |
1136 | return -1; |
1137 | } |
1138 | |
1139 | /* #warning FIXME: Add check for X-ExtensionKey here */ |
1140 | pr_err("Standard iSCSI key \"%s\" cannot be answered" |
1141 | " with \"%s\", protocol error.\n" , param->name, value); |
1142 | return -1; |
1143 | } |
1144 | |
1145 | do { |
1146 | comma_ptr = NULL; |
1147 | comma_ptr = strchr(value, ','); |
1148 | |
1149 | if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) { |
1150 | pr_err("Detected value separator \",\", but" |
1151 | " key \"%s\" does not allow a value list," |
1152 | " protocol error.\n" , param->name); |
1153 | return -1; |
1154 | } |
1155 | if (comma_ptr) |
1156 | *comma_ptr = '\0'; |
1157 | |
1158 | if (strlen(value) > VALUE_MAXLEN) { |
1159 | pr_err("Value for key \"%s\" exceeds %d," |
1160 | " protocol error.\n" , param->name, |
1161 | VALUE_MAXLEN); |
1162 | return -1; |
1163 | } |
1164 | |
1165 | if (IS_TYPE_BOOL_AND(param) || IS_TYPE_BOOL_OR(param)) { |
1166 | if (iscsi_check_boolean_value(param, value) < 0) |
1167 | return -1; |
1168 | } else if (IS_TYPE_NUMBER(param)) { |
1169 | if (iscsi_check_numerical_value(param, value_ptr: value) < 0) |
1170 | return -1; |
1171 | } else if (IS_TYPE_STRING(param) || IS_TYPE_VALUE_LIST(param)) { |
1172 | if (iscsi_check_string_or_list_value(param, value) < 0) |
1173 | return -1; |
1174 | } else { |
1175 | pr_err("Huh? 0x%02x\n" , param->type); |
1176 | return -1; |
1177 | } |
1178 | |
1179 | if (comma_ptr) |
1180 | *comma_ptr++ = ','; |
1181 | |
1182 | value = comma_ptr; |
1183 | } while (value); |
1184 | |
1185 | return 0; |
1186 | } |
1187 | |
1188 | static struct iscsi_param *__iscsi_check_key( |
1189 | char *key, |
1190 | int sender, |
1191 | struct iscsi_param_list *param_list) |
1192 | { |
1193 | struct iscsi_param *param; |
1194 | |
1195 | if (strlen(key) > KEY_MAXLEN) { |
1196 | pr_err("Length of key name \"%s\" exceeds %d.\n" , |
1197 | key, KEY_MAXLEN); |
1198 | return NULL; |
1199 | } |
1200 | |
1201 | param = iscsi_find_param_from_key(key, param_list); |
1202 | if (!param) |
1203 | return NULL; |
1204 | |
1205 | if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) { |
1206 | pr_err("Key \"%s\" may not be sent to %s," |
1207 | " protocol error.\n" , param->name, |
1208 | (sender & SENDER_RECEIVER) ? "target" : "initiator" ); |
1209 | return NULL; |
1210 | } |
1211 | |
1212 | if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) { |
1213 | pr_err("Key \"%s\" may not be sent to %s," |
1214 | " protocol error.\n" , param->name, |
1215 | (sender & SENDER_RECEIVER) ? "initiator" : "target" ); |
1216 | return NULL; |
1217 | } |
1218 | |
1219 | return param; |
1220 | } |
1221 | |
1222 | static struct iscsi_param *iscsi_check_key( |
1223 | char *key, |
1224 | int phase, |
1225 | int sender, |
1226 | struct iscsi_param_list *param_list) |
1227 | { |
1228 | struct iscsi_param *param; |
1229 | /* |
1230 | * Key name length must not exceed 63 bytes. (See iSCSI v20 5.1) |
1231 | */ |
1232 | if (strlen(key) > KEY_MAXLEN) { |
1233 | pr_err("Length of key name \"%s\" exceeds %d.\n" , |
1234 | key, KEY_MAXLEN); |
1235 | return NULL; |
1236 | } |
1237 | |
1238 | param = iscsi_find_param_from_key(key, param_list); |
1239 | if (!param) |
1240 | return NULL; |
1241 | |
1242 | if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) { |
1243 | pr_err("Key \"%s\" may not be sent to %s," |
1244 | " protocol error.\n" , param->name, |
1245 | (sender & SENDER_RECEIVER) ? "target" : "initiator" ); |
1246 | return NULL; |
1247 | } |
1248 | if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) { |
1249 | pr_err("Key \"%s\" may not be sent to %s," |
1250 | " protocol error.\n" , param->name, |
1251 | (sender & SENDER_RECEIVER) ? "initiator" : "target" ); |
1252 | return NULL; |
1253 | } |
1254 | |
1255 | if (IS_PSTATE_ACCEPTOR(param)) { |
1256 | pr_err("Key \"%s\" received twice, protocol error.\n" , |
1257 | key); |
1258 | return NULL; |
1259 | } |
1260 | |
1261 | if (!phase) |
1262 | return param; |
1263 | |
1264 | if (!(param->phase & phase)) { |
1265 | char *phase_name; |
1266 | |
1267 | switch (phase) { |
1268 | case PHASE_SECURITY: |
1269 | phase_name = "Security" ; |
1270 | break; |
1271 | case PHASE_OPERATIONAL: |
1272 | phase_name = "Operational" ; |
1273 | break; |
1274 | default: |
1275 | phase_name = "Unknown" ; |
1276 | } |
1277 | pr_err("Key \"%s\" may not be negotiated during %s phase.\n" , |
1278 | param->name, phase_name); |
1279 | return NULL; |
1280 | } |
1281 | |
1282 | return param; |
1283 | } |
1284 | |
1285 | static int iscsi_enforce_integrity_rules( |
1286 | u8 phase, |
1287 | struct iscsi_param_list *param_list) |
1288 | { |
1289 | char *tmpptr; |
1290 | u8 DataSequenceInOrder = 0; |
1291 | u8 ErrorRecoveryLevel = 0, SessionType = 0; |
1292 | u32 FirstBurstLength = 0, MaxBurstLength = 0; |
1293 | struct iscsi_param *param = NULL; |
1294 | |
1295 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1296 | if (!(param->phase & phase)) |
1297 | continue; |
1298 | if (!strcmp(param->name, SESSIONTYPE)) |
1299 | if (!strcmp(param->value, NORMAL)) |
1300 | SessionType = 1; |
1301 | if (!strcmp(param->name, ERRORRECOVERYLEVEL)) |
1302 | ErrorRecoveryLevel = simple_strtoul(param->value, |
1303 | &tmpptr, 0); |
1304 | if (!strcmp(param->name, DATASEQUENCEINORDER)) |
1305 | if (!strcmp(param->value, YES)) |
1306 | DataSequenceInOrder = 1; |
1307 | if (!strcmp(param->name, MAXBURSTLENGTH)) |
1308 | MaxBurstLength = simple_strtoul(param->value, |
1309 | &tmpptr, 0); |
1310 | } |
1311 | |
1312 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1313 | if (!(param->phase & phase)) |
1314 | continue; |
1315 | if (!SessionType && !IS_PSTATE_ACCEPTOR(param)) |
1316 | continue; |
1317 | if (!strcmp(param->name, MAXOUTSTANDINGR2T) && |
1318 | DataSequenceInOrder && (ErrorRecoveryLevel > 0)) { |
1319 | if (strcmp(param->value, "1" )) { |
1320 | if (iscsi_update_param_value(param, value: "1" ) < 0) |
1321 | return -1; |
1322 | pr_debug("Reset \"%s\" to \"%s\".\n" , |
1323 | param->name, param->value); |
1324 | } |
1325 | } |
1326 | if (!strcmp(param->name, MAXCONNECTIONS) && !SessionType) { |
1327 | if (strcmp(param->value, "1" )) { |
1328 | if (iscsi_update_param_value(param, value: "1" ) < 0) |
1329 | return -1; |
1330 | pr_debug("Reset \"%s\" to \"%s\".\n" , |
1331 | param->name, param->value); |
1332 | } |
1333 | } |
1334 | if (!strcmp(param->name, FIRSTBURSTLENGTH)) { |
1335 | FirstBurstLength = simple_strtoul(param->value, |
1336 | &tmpptr, 0); |
1337 | if (FirstBurstLength > MaxBurstLength) { |
1338 | char tmpbuf[11]; |
1339 | memset(tmpbuf, 0, sizeof(tmpbuf)); |
1340 | sprintf(buf: tmpbuf, fmt: "%u" , MaxBurstLength); |
1341 | if (iscsi_update_param_value(param, value: tmpbuf)) |
1342 | return -1; |
1343 | pr_debug("Reset \"%s\" to \"%s\".\n" , |
1344 | param->name, param->value); |
1345 | } |
1346 | } |
1347 | } |
1348 | |
1349 | return 0; |
1350 | } |
1351 | |
1352 | int iscsi_decode_text_input( |
1353 | u8 phase, |
1354 | u8 sender, |
1355 | char *textbuf, |
1356 | u32 length, |
1357 | struct iscsit_conn *conn) |
1358 | { |
1359 | struct iscsi_param_list *param_list = conn->param_list; |
1360 | char *tmpbuf, *start = NULL, *end = NULL; |
1361 | |
1362 | tmpbuf = kmemdup_nul(s: textbuf, len: length, GFP_KERNEL); |
1363 | if (!tmpbuf) { |
1364 | pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n" , length); |
1365 | return -ENOMEM; |
1366 | } |
1367 | |
1368 | start = tmpbuf; |
1369 | end = (start + length); |
1370 | |
1371 | while (start < end) { |
1372 | char *key, *value; |
1373 | struct iscsi_param *param; |
1374 | |
1375 | if (iscsi_extract_key_value(textbuf: start, key: &key, value: &value) < 0) |
1376 | goto free_buffer; |
1377 | |
1378 | pr_debug("Got key: %s=%s\n" , key, value); |
1379 | |
1380 | if (phase & PHASE_SECURITY) { |
1381 | if (iscsi_check_for_auth_key(key) > 0) { |
1382 | kfree(objp: tmpbuf); |
1383 | return 1; |
1384 | } |
1385 | } |
1386 | |
1387 | param = iscsi_check_key(key, phase, sender, param_list); |
1388 | if (!param) { |
1389 | if (iscsi_add_notunderstood_response(key, value, |
1390 | param_list) < 0) |
1391 | goto free_buffer; |
1392 | |
1393 | start += strlen(key) + strlen(value) + 2; |
1394 | continue; |
1395 | } |
1396 | if (iscsi_check_value(param, value) < 0) |
1397 | goto free_buffer; |
1398 | |
1399 | start += strlen(key) + strlen(value) + 2; |
1400 | |
1401 | if (IS_PSTATE_PROPOSER(param)) { |
1402 | if (iscsi_check_proposer_state(param, value) < 0) |
1403 | goto free_buffer; |
1404 | |
1405 | SET_PSTATE_RESPONSE_GOT(param); |
1406 | } else { |
1407 | if (iscsi_check_acceptor_state(param, value, conn) < 0) |
1408 | goto free_buffer; |
1409 | |
1410 | SET_PSTATE_ACCEPTOR(param); |
1411 | } |
1412 | } |
1413 | |
1414 | kfree(objp: tmpbuf); |
1415 | return 0; |
1416 | |
1417 | free_buffer: |
1418 | kfree(objp: tmpbuf); |
1419 | return -1; |
1420 | } |
1421 | |
1422 | int iscsi_encode_text_output( |
1423 | u8 phase, |
1424 | u8 sender, |
1425 | char *textbuf, |
1426 | u32 *length, |
1427 | struct iscsi_param_list *param_list, |
1428 | bool keys_workaround) |
1429 | { |
1430 | char *output_buf = NULL; |
1431 | struct iscsi_extra_response *er; |
1432 | struct iscsi_param *param; |
1433 | |
1434 | output_buf = textbuf + *length; |
1435 | |
1436 | if (iscsi_enforce_integrity_rules(phase, param_list) < 0) |
1437 | return -1; |
1438 | |
1439 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1440 | if (!(param->sender & sender)) |
1441 | continue; |
1442 | if (IS_PSTATE_ACCEPTOR(param) && |
1443 | !IS_PSTATE_RESPONSE_SENT(param) && |
1444 | !IS_PSTATE_REPLY_OPTIONAL(param) && |
1445 | (param->phase & phase)) { |
1446 | *length += sprintf(buf: output_buf, fmt: "%s=%s" , |
1447 | param->name, param->value); |
1448 | *length += 1; |
1449 | output_buf = textbuf + *length; |
1450 | SET_PSTATE_RESPONSE_SENT(param); |
1451 | pr_debug("Sending key: %s=%s\n" , |
1452 | param->name, param->value); |
1453 | continue; |
1454 | } |
1455 | if (IS_PSTATE_NEGOTIATE(param) && |
1456 | !IS_PSTATE_ACCEPTOR(param) && |
1457 | !IS_PSTATE_PROPOSER(param) && |
1458 | (param->phase & phase)) { |
1459 | *length += sprintf(buf: output_buf, fmt: "%s=%s" , |
1460 | param->name, param->value); |
1461 | *length += 1; |
1462 | output_buf = textbuf + *length; |
1463 | SET_PSTATE_PROPOSER(param); |
1464 | iscsi_check_proposer_for_optional_reply(param, |
1465 | keys_workaround); |
1466 | pr_debug("Sending key: %s=%s\n" , |
1467 | param->name, param->value); |
1468 | } |
1469 | } |
1470 | |
1471 | list_for_each_entry(er, ¶m_list->extra_response_list, er_list) { |
1472 | *length += sprintf(buf: output_buf, fmt: "%s=%s" , er->key, er->value); |
1473 | *length += 1; |
1474 | output_buf = textbuf + *length; |
1475 | pr_debug("Sending key: %s=%s\n" , er->key, er->value); |
1476 | } |
1477 | iscsi_release_extra_responses(param_list); |
1478 | |
1479 | return 0; |
1480 | } |
1481 | |
1482 | int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list) |
1483 | { |
1484 | int ret = 0; |
1485 | struct iscsi_param *param; |
1486 | |
1487 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1488 | if (IS_PSTATE_NEGOTIATE(param) && |
1489 | IS_PSTATE_PROPOSER(param) && |
1490 | !IS_PSTATE_RESPONSE_GOT(param) && |
1491 | !IS_PSTATE_REPLY_OPTIONAL(param) && |
1492 | !IS_PHASE_DECLARATIVE(param)) { |
1493 | pr_err("No response for proposed key \"%s\".\n" , |
1494 | param->name); |
1495 | ret = -1; |
1496 | } |
1497 | } |
1498 | |
1499 | return ret; |
1500 | } |
1501 | |
1502 | int iscsi_change_param_value( |
1503 | char *keyvalue, |
1504 | struct iscsi_param_list *param_list, |
1505 | int check_key) |
1506 | { |
1507 | char *key = NULL, *value = NULL; |
1508 | struct iscsi_param *param; |
1509 | int sender = 0; |
1510 | |
1511 | if (iscsi_extract_key_value(textbuf: keyvalue, key: &key, value: &value) < 0) |
1512 | return -1; |
1513 | |
1514 | if (!check_key) { |
1515 | param = __iscsi_check_key(key: keyvalue, sender, param_list); |
1516 | if (!param) |
1517 | return -1; |
1518 | } else { |
1519 | param = iscsi_check_key(key: keyvalue, phase: 0, sender, param_list); |
1520 | if (!param) |
1521 | return -1; |
1522 | |
1523 | param->set_param = 1; |
1524 | if (iscsi_check_value(param, value) < 0) { |
1525 | param->set_param = 0; |
1526 | return -1; |
1527 | } |
1528 | param->set_param = 0; |
1529 | } |
1530 | |
1531 | if (iscsi_update_param_value(param, value) < 0) |
1532 | return -1; |
1533 | |
1534 | return 0; |
1535 | } |
1536 | |
1537 | void iscsi_set_connection_parameters( |
1538 | struct iscsi_conn_ops *ops, |
1539 | struct iscsi_param_list *param_list) |
1540 | { |
1541 | char *tmpptr; |
1542 | struct iscsi_param *param; |
1543 | |
1544 | pr_debug("---------------------------------------------------" |
1545 | "---------------\n" ); |
1546 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1547 | /* |
1548 | * Special case to set MAXXMITDATASEGMENTLENGTH from the |
1549 | * target requested MaxRecvDataSegmentLength, even though |
1550 | * this key is not sent over the wire. |
1551 | */ |
1552 | if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
1553 | ops->MaxXmitDataSegmentLength = |
1554 | simple_strtoul(param->value, &tmpptr, 0); |
1555 | pr_debug("MaxXmitDataSegmentLength: %s\n" , |
1556 | param->value); |
1557 | } |
1558 | |
1559 | if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param)) |
1560 | continue; |
1561 | if (!strcmp(param->name, AUTHMETHOD)) { |
1562 | pr_debug("AuthMethod: %s\n" , |
1563 | param->value); |
1564 | } else if (!strcmp(param->name, HEADERDIGEST)) { |
1565 | ops->HeaderDigest = !strcmp(param->value, CRC32C); |
1566 | pr_debug("HeaderDigest: %s\n" , |
1567 | param->value); |
1568 | } else if (!strcmp(param->name, DATADIGEST)) { |
1569 | ops->DataDigest = !strcmp(param->value, CRC32C); |
1570 | pr_debug("DataDigest: %s\n" , |
1571 | param->value); |
1572 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
1573 | /* |
1574 | * At this point iscsi_check_acceptor_state() will have |
1575 | * set ops->MaxRecvDataSegmentLength from the original |
1576 | * initiator provided value. |
1577 | */ |
1578 | pr_debug("MaxRecvDataSegmentLength: %u\n" , |
1579 | ops->MaxRecvDataSegmentLength); |
1580 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { |
1581 | ops->InitiatorRecvDataSegmentLength = |
1582 | simple_strtoul(param->value, &tmpptr, 0); |
1583 | pr_debug("InitiatorRecvDataSegmentLength: %s\n" , |
1584 | param->value); |
1585 | ops->MaxRecvDataSegmentLength = |
1586 | ops->InitiatorRecvDataSegmentLength; |
1587 | pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n" ); |
1588 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { |
1589 | ops->TargetRecvDataSegmentLength = |
1590 | simple_strtoul(param->value, &tmpptr, 0); |
1591 | pr_debug("TargetRecvDataSegmentLength: %s\n" , |
1592 | param->value); |
1593 | ops->MaxXmitDataSegmentLength = |
1594 | ops->TargetRecvDataSegmentLength; |
1595 | pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n" ); |
1596 | } |
1597 | } |
1598 | pr_debug("----------------------------------------------------" |
1599 | "--------------\n" ); |
1600 | } |
1601 | |
1602 | void iscsi_set_session_parameters( |
1603 | struct iscsi_sess_ops *ops, |
1604 | struct iscsi_param_list *param_list, |
1605 | int leading) |
1606 | { |
1607 | char *tmpptr; |
1608 | struct iscsi_param *param; |
1609 | |
1610 | pr_debug("----------------------------------------------------" |
1611 | "--------------\n" ); |
1612 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
1613 | if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param)) |
1614 | continue; |
1615 | if (!strcmp(param->name, INITIATORNAME)) { |
1616 | if (!param->value) |
1617 | continue; |
1618 | if (leading) |
1619 | snprintf(buf: ops->InitiatorName, |
1620 | size: sizeof(ops->InitiatorName), |
1621 | fmt: "%s" , param->value); |
1622 | pr_debug("InitiatorName: %s\n" , |
1623 | param->value); |
1624 | } else if (!strcmp(param->name, INITIATORALIAS)) { |
1625 | if (!param->value) |
1626 | continue; |
1627 | snprintf(buf: ops->InitiatorAlias, |
1628 | size: sizeof(ops->InitiatorAlias), |
1629 | fmt: "%s" , param->value); |
1630 | pr_debug("InitiatorAlias: %s\n" , |
1631 | param->value); |
1632 | } else if (!strcmp(param->name, TARGETNAME)) { |
1633 | if (!param->value) |
1634 | continue; |
1635 | if (leading) |
1636 | snprintf(buf: ops->TargetName, |
1637 | size: sizeof(ops->TargetName), |
1638 | fmt: "%s" , param->value); |
1639 | pr_debug("TargetName: %s\n" , |
1640 | param->value); |
1641 | } else if (!strcmp(param->name, TARGETALIAS)) { |
1642 | if (!param->value) |
1643 | continue; |
1644 | snprintf(buf: ops->TargetAlias, size: sizeof(ops->TargetAlias), |
1645 | fmt: "%s" , param->value); |
1646 | pr_debug("TargetAlias: %s\n" , |
1647 | param->value); |
1648 | } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) { |
1649 | ops->TargetPortalGroupTag = |
1650 | simple_strtoul(param->value, &tmpptr, 0); |
1651 | pr_debug("TargetPortalGroupTag: %s\n" , |
1652 | param->value); |
1653 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { |
1654 | ops->MaxConnections = |
1655 | simple_strtoul(param->value, &tmpptr, 0); |
1656 | pr_debug("MaxConnections: %s\n" , |
1657 | param->value); |
1658 | } else if (!strcmp(param->name, INITIALR2T)) { |
1659 | ops->InitialR2T = !strcmp(param->value, YES); |
1660 | pr_debug("InitialR2T: %s\n" , |
1661 | param->value); |
1662 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { |
1663 | ops->ImmediateData = !strcmp(param->value, YES); |
1664 | pr_debug("ImmediateData: %s\n" , |
1665 | param->value); |
1666 | } else if (!strcmp(param->name, MAXBURSTLENGTH)) { |
1667 | ops->MaxBurstLength = |
1668 | simple_strtoul(param->value, &tmpptr, 0); |
1669 | pr_debug("MaxBurstLength: %s\n" , |
1670 | param->value); |
1671 | } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) { |
1672 | ops->FirstBurstLength = |
1673 | simple_strtoul(param->value, &tmpptr, 0); |
1674 | pr_debug("FirstBurstLength: %s\n" , |
1675 | param->value); |
1676 | } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { |
1677 | ops->DefaultTime2Wait = |
1678 | simple_strtoul(param->value, &tmpptr, 0); |
1679 | pr_debug("DefaultTime2Wait: %s\n" , |
1680 | param->value); |
1681 | } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) { |
1682 | ops->DefaultTime2Retain = |
1683 | simple_strtoul(param->value, &tmpptr, 0); |
1684 | pr_debug("DefaultTime2Retain: %s\n" , |
1685 | param->value); |
1686 | } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) { |
1687 | ops->MaxOutstandingR2T = |
1688 | simple_strtoul(param->value, &tmpptr, 0); |
1689 | pr_debug("MaxOutstandingR2T: %s\n" , |
1690 | param->value); |
1691 | } else if (!strcmp(param->name, DATAPDUINORDER)) { |
1692 | ops->DataPDUInOrder = !strcmp(param->value, YES); |
1693 | pr_debug("DataPDUInOrder: %s\n" , |
1694 | param->value); |
1695 | } else if (!strcmp(param->name, DATASEQUENCEINORDER)) { |
1696 | ops->DataSequenceInOrder = !strcmp(param->value, YES); |
1697 | pr_debug("DataSequenceInOrder: %s\n" , |
1698 | param->value); |
1699 | } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) { |
1700 | ops->ErrorRecoveryLevel = |
1701 | simple_strtoul(param->value, &tmpptr, 0); |
1702 | pr_debug("ErrorRecoveryLevel: %s\n" , |
1703 | param->value); |
1704 | } else if (!strcmp(param->name, SESSIONTYPE)) { |
1705 | ops->SessionType = !strcmp(param->value, DISCOVERY); |
1706 | pr_debug("SessionType: %s\n" , |
1707 | param->value); |
1708 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { |
1709 | ops->RDMAExtensions = !strcmp(param->value, YES); |
1710 | pr_debug("RDMAExtensions: %s\n" , |
1711 | param->value); |
1712 | } |
1713 | } |
1714 | pr_debug("----------------------------------------------------" |
1715 | "--------------\n" ); |
1716 | |
1717 | } |
1718 | |