📄 text_param.c
字号:
if (dummy) { /* restore the comma and goto the next value */ *dummy++ = ','; } value = dummy; } while (value); out: TRACE(TRACE_ENTER_LEAVE, "Leave check_type_correctness\n"); return;}/* * Checks the correctness of the passed string, checks whether it * conforms to the <key>=<value> format * extracts the value from the input string and returns it as an * output parameter. * Returns pointer to parameter in p_param_tbl if ok, else NULL * (but on non-NULL p->neg_info can have flag set on fatal error) */static struct parameter_type * __attribute__ ((no_instrument_function))check_correctness(char *keytext, char **p_value, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], __u32 who_called, __u32 when_called, __u32 flags, int *int_value, struct unknown_key **unknown_key_list){ char *value; struct parameter_type *p = NULL; struct unknown_key *uptr; __u32 count; TRACE(TRACE_ENTER_LEAVE, "Enter check_correctness\n"); TRACE(TRACE_ISCSI, "Got key: %s\n", keytext); if ((value = strchr(keytext, '=')) == NULL) { /* could not find '=', don't accept this */ TRACE_ERROR("key \"%s\" not followed by '='\n", keytext); goto out; } /* terminate the key name string and point at the value string */ *value++ = '\0'; /* Check for length of the key name. */ /* Draft 20, Section 5.1 Text Format * "A standard-lable (key-name) MUST begin with a capital letter and * must not exceed 63 characters." */ if (strlen(keytext) > MAX_KEY_NAME_LENGTH) { if (TRACE_TEST(TRACE_ISCSI)) { TRACE_WARNING("length of key name \"%s\" exceeds %d\n", keytext, MAX_KEY_NAME_LENGTH); } } /* Draft 20, Section 10.12.10 Login Parametersr * "All keys in Chapter 12, except for the X extension formats, * MUST be supported by iSCSI initiators and targets. * Keys in Chapter 11 only * need to be supported when the function to which they * refer is mandatory * to implement." */ if (!(p = find_parameter(keytext, p_param_tbl))) { /* key not found in our table, look for value = "Reject" or "Irrelevant" or "NotUnderstood" */ if (!strcmp(value, key_table->reject) || !strcmp(value, key_table->irrelevant) || !strcmp(value, key_table->notunderstood)) { /* These values always fatal as a value for offer of unknown key */ TRACE_ERROR("unknown key with illegal value: %s=%s\n", keytext, value); } else { /* value not bad, but have we seen this unknown key before? */ for (count = 0, uptr = *unknown_key_list; uptr != NULL; count++, uptr = uptr->next) { if (!strcmp(keytext, uptr->keyname)) { /* yes, this unknown key is being negotiated twice */ TRACE_ERROR ("unknown key \"%s\" received twice\n", keytext); goto out; } } /* never saw this key before, should we save it for later checks? */ /* chap support = CHONG */ if (!is_securitykey(keytext)) { if (TRACE_TEST(TRACE_ISCSI)) { TRACE_WARNING("unknown key \"%s\"\n", keytext); } } if (count >= MAX_UNKNOWN_KEYS) { /* no, we have seen too many unknown keys, bail out */ TRACE_ERROR ("%u unknown keys received, too many!\n", count); goto out; } else if ((uptr = my_kmalloc(sizeof (struct unknown_key), "Unknown key")) == NULL) { goto out; } /* chap and srp support - CHONG */ else if ((uptr->keyname = my_kmalloc(strlen(keytext) + 1, "Key Name")) == NULL) { my_kfree((void **) &uptr, "Unknown key"); goto out; } else if ((uptr->keyvalue = my_kmalloc(strlen(value) + 1, "Key Value")) == NULL) { my_kfree((void **) &uptr->keyname, "Key Name"); my_kfree((void **) &uptr, "Unknown key"); goto out; } else { strcpy(uptr->keyname, keytext); strcpy(uptr->keyvalue, value); uptr->processed = 0; uptr->next = *unknown_key_list; *unknown_key_list = uptr; if ((flags & USE_REFLECT_XKEYS) && (strncmp(keytext, "X-", 2) == 0 || strncmp(keytext, "X#", 2) == 0)) /* this is an X key and user wants its * value reflected back to sender */ *p_value = value; else /* pass back Notunderstood value for * unknown key */ *p_value = key_table->notunderstood; } } goto out; } if ((who_called == INITIATOR && !IS_USE_BY_TARGET(p->type)) || (who_called == TARGET && !IS_USE_BY_INITIATOR(p->type))) { TRACE_ERROR("key \"%s\" cannot be sent to %s\n", keytext, who_called == INITIATOR ? "initiator" : "target"); p->neg_info |= KEY_BAD; goto out; } if (IS_KEY_GOT_FROM_OTHER_SIDE(p->neg_info)) { /* attempting to negotiate this key twice */ /* Draft 20, Section 5.3 Login Phase * "Neither the initiator nor the target should attempt to * declare or negotiate a parameter more than once * during login except for responses to specific keys * that explicitly allow repeated key declarations * (e.e., TargetAddress). An attempt to renegotiate/ * redeclare parameters not specifically allowed MUST * be detected by the initiator and target. If such an * attempt is detected by the target, the target MUST * respond with Login reject (initiator error); * if detected by the initiator, the initiator MUST drop the * connection." */ TRACE_ERROR("key \"%s\" received twice\n", p->parameter_name); p->neg_info |= KEY_BAD; goto out; } if (!IS_KEY_SENT_TO_OTHER_SIDE(p->neg_info)) { /* this is new offer from other side, not reply to one of our offers */ if (!(p->type & when_called)) { /* wrong time to be negotiating this parameter */ TRACE_ERROR("key \"%s\" cannot be negotiated now\n", keytext); p->neg_info |= KEY_BAD; goto out; } } check_type_correctness(p, value, who_called, int_value); /* Return the value pointer on success */ *p_value = value; out: TRACE(TRACE_ENTER_LEAVE, "Leave check_correctness, p %p\n", p); return p;}char * __attribute__ ((no_instrument_function))strdup(char *str){ int n = strlen(str) + 1; char *s = kmalloc(n, GFP_KERNEL); if (!s) return NULL; return strcpy(s, str);}void __attribute__ ((no_instrument_function))strreplace(char **str, char *new_str){ if (*str != NULL) kfree(*str); *str = strdup(new_str);}/* Copy src parameter table to dst, duplicating any strings */voidparam_tbl_cpy(struct parameter_type dst[MAX_CONFIG_PARAMS], struct parameter_type src[MAX_CONFIG_PARAMS]){ struct parameter_type *dptr; int i; TRACE(TRACE_ENTER_LEAVE, "Enter param_tbl_cpy, dst %p, src %p, size %d\n", dst, src, sizeof (struct parameter_type) * MAX_CONFIG_PARAMS); /* copy everything in the src table to the dst table "as is" */ memcpy(dst, src, sizeof (struct parameter_type) * MAX_CONFIG_PARAMS); /* now go back and "dup" all the strings */ for (i = 0, dptr = dst; i < MAX_CONFIG_PARAMS; i++, dptr++) { if (dptr->parameter_name) { dptr->parameter_name = strdup(dptr->parameter_name); } if (dptr->str_value) { dptr->str_value = strdup(dptr->str_value); } if (dptr->value_list) { dptr->value_list = strdup(dptr->value_list); } } TRACE(TRACE_ENTER_LEAVE, "Leave param_tbl_cpy\n");}/* Copy initial parameter table to dst, duplicating any strings */voidparam_tbl_init(struct parameter_type dst[MAX_CONFIG_PARAMS]){ param_tbl_cpy(dst, config_params);}/* Free any strings referenced in dst parameter table */voidparam_tbl_uncpy(struct parameter_type dst[MAX_CONFIG_PARAMS]){ struct parameter_type *dptr; int i; TRACE(TRACE_ENTER_LEAVE, "Enter param_tbl_uncpy, dst %p, size %d\n", dst, sizeof (struct parameter_type) * MAX_CONFIG_PARAMS); /* go thru and free all the strings that were "duped" during copy */ for (i = 0, dptr = dst; i < MAX_CONFIG_PARAMS; i++, dptr++) { if (dptr->parameter_name) { kfree(dptr->parameter_name); } if (dptr->str_value) { kfree(dptr->str_value); } if (dptr->value_list) { kfree(dptr->value_list); } } TRACE(TRACE_ENTER_LEAVE, "Leave param_tbl_uncpy\n");}voidconfigure_parameter(int param_neg_info, char *ptr_to_keytext, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS]){ struct parameter_type *param = NULL; char *value_list = NULL; char *endptr; int int_value; TRACE(TRACE_ENTER_LEAVE, "Enter configure_parameter\n"); /* Get the value string */ value_list = strchr(ptr_to_keytext, '='); if (value_list) *value_list++ = '\0'; /* terminate the key text string */ if ((param = find_parameter(ptr_to_keytext, p_param_tbl)) != NULL) { if (value_list) { if (IS_NUMBER(param->type)) { /* parameter is a number, set only the * int_value field, don't set value_list * or str_value fields */ int_value = simple_strtoul(value_list, &endptr, 0); if (strspn(endptr, WHITE_SPACE) != strlen(endptr)) { TRACE_ERROR("illegal number \"%s\"\n", value_list); goto out; } else { param->int_value = int_value; } } else { /* parameter is a string, enumerated, boolean * or range, * set both the value_list and str_value fields, * do not set int_value field */ if (IS_NUMBER_RANGE(param->type)) { /* this is a range, check both numbers and their order */ if (check_range(value_list, -1) < 0) goto out; } strreplace(¶m->value_list, value_list); endptr = strchr(value_list, ','); if (endptr) { /* value_list really a list,i * use 1st on list as * current value */ *endptr = '\0'; strreplace(¶m->str_value, value_list); *endptr = ','; /* repair the damage */ } else { /* value_list only single value, make it current val too */ strreplace(¶m->str_value, value_list); } } } /* set the negotiation info only if no error */ param->neg_info = param_neg_info; } out: TRACE(TRACE_ENTER_LEAVE, "Leave configure_parameter\n");}/* Draft 20, Section 5.2 Text Mode Negotiation * "Some parameters may be subject to integrity rules (e.g., parameter-x * must not exceed parameter-y or parameter-u not 1 implies parameter-v * be Yes). Whenever required, integrity rules are specified with the * keys. Checking for compliance with the integrity rule must only be * performed after all the parameters are available (the existent and the * newly negotiated). An iSCSI target MUST perform integrity checking * before the new parameters take effect. An initiator MAY perform * integrity checking." */voidcheck_integrity_rules(struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], __u16 secondary_connection){ struct parameter_type *p, *p2; TRACE(TRACE_ENTER_LEAVE, "Enter check_integrity_rules\n"); /* Draft 20, Section A.3.2 OFMarkInt, IFMarkInt * "Reject is resetting the marker function in the specified * direction (Output or Input) to No." */ if ((p = find_flag_parameter(OFMARKINT_FLAG, p_param_tbl)) != NULL) { if (p->neg_info & KEY_REJECT) { /* got OFMarkInt=Reject, so set OFMarker=No */ TRACE(TRACE_DEBUG, "Checking %s=%d\n", p->parameter_name, p->int_value); if ((p = find_flag_parameter(OFMARKER_FLAG, p_param_tbl)) != NULL) { TRACE(TRACE_DEBUG, "Have %s=%s\n", p->parameter_name, p->str_value); if (!strcmp(p->str_value, key_table->yes)) { /* have OFMarker=Yes, change value to No */ strreplace(&p->str_value, key_table->no); TRACE(TRACE_ISCSI, "Reset %s to %s\n", p->parameter_name, p->str_value); } } } } if ((p = find_flag_parameter(IFMARKINT_FLAG, p_param_tbl)) != NULL) { if (p->neg_info & KEY_REJECT) { /* got IFMarkInt=Reject, so set IFMarker=No */ TRACE(TRACE_DEBUG, "Checking %s=%d\n", p->parameter_name, p->int_value); if ((p = find_flag_parameter(IFMARKER_FLAG, p_param_tbl)) != NULL) { TRACE(TRACE_DEBUG, "Have %s=%s\n", p->parameter_name, p->str_value); if (!strcmp(p->str_value, key_table->yes)) { /* have IFMarker=Yes, change value to No */ strreplace(&p->str_value, key_table->no); TRACE(TRACE_ISCSI, "Reset %s to %s\n", p->parameter_name, p->str_value); } } } } /* the following checks are done only on first connection in * a session */ if (!secondary_connection) { /* Draft 20, Section 12.14 FirstBurstLength * "FirstBurstLength MUST NOT exceed MaxBurstLength." */ if ((p = find_flag_parameter(FIRSTBURSTLENGTH_FLAG, p_param_tbl)) != NULL) { if ((p2 = find_flag_parameter(MAXBURSTLENGTH_FLAG, p_param_tbl)) != NULL) { if (p->int_value > p2->int_value) { if (TRACE_TEST(TRACE_ISCSI)) { TRACE_WARNING("FirstBurstLength %u" " exceeds MaxBurstLength %u\n", p->int_value, p2->int_value); } /* fix FirstBurstLength */ p->int_value = p2->int_value; } } } /* Draft 20, Section 12.21 SessionType * "The discovery session implies MaxConnections = 1 * and overrides both * the default and an explicit setting." */ if ((p = find_flag_parameter(SESSIONTYPE_FLAG, p_param_tbl)) != NULL) { if (!strcmp(p->str_value, key_table->discovery) && (p2 = find_flag_parameter(MAXCONNECTIONS_FLAG, p_param_tbl)) != NULL) { if (p2->int_value != 1) { /* do not have MaxConnections=1, change value to 1 */ p2->int_value = 1; TRACE(TRACE_ISCSI, "Reset %s to %u\n", p2->parameter_name, p2->int_value); } } } /* Draft 20, Section 12.19 DataSequenceInOrder * "If DataSequenceInOrder is set to Yes, a target may * retry at most the last R2T, and an initiator may
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -