int main(int argc, char *argv[]){ char conf_file[128]; int status = 0; int wpid = 0; if(argc <= 1){ strcpy(conf_file, "targets.txt"); }else{ printf("%s, %s\n", argv[0], argv[1]); strcpy(conf_file, argv[1]); } add_targets(conf_file); attach(); while(1) sleep(1); return 0; }
/* * []---- * | parse_text -- receive text information from initiator and parse * | * | Read in the current data based on the amount which the login PDU says * | should be available. Add it to the end of previous data if it exists. * | Previous data would be from a PDU which had the 'C' bit set and was * | stored in the connection. * | * | Once values for parameter name has been selected store outgoing string * | in text message for response. * | * | If errcode is non-NULL the appropriate login error code will be * | stored. * []---- */ Boolean_t parse_text(iscsi_conn_t *c, int dlen, char **text, int *text_length, int *errcode) { char *p = NULL; char *n; char *cur_pair; char param_rsp[32]; int plen; /* pair length */ Boolean_t rval = True; char *target_name = NULL; char *initiator_name = NULL; char param_buf[16]; if ((p = (char *)malloc(dlen)) == NULL) return (False); /* * Read in data to buffer. */ if (read(c->c_fd, p, dlen) != dlen) { free(p); return (False); } queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x Available text size %d\n", c->c_num, dlen); /* * Read in and toss any pad data */ if (dlen % ISCSI_PAD_WORD_LEN) { char junk[ISCSI_PAD_WORD_LEN]; int pad_len = ISCSI_PAD_WORD_LEN - (dlen % ISCSI_PAD_WORD_LEN); if (read(c->c_fd, junk, pad_len) != pad_len) { free(p); return (False); } } if (c->c_text_area != NULL) { if ((n = (char *)realloc(c->c_text_area, c->c_text_len + dlen)) == NULL) { free(p); return (False); } bcopy(p, n + c->c_text_len, dlen); /* * No longer need the space allocated to 'p' since it * will point to the aggregated area of all data. */ free(p); /* * Point 'p' to this new area for parsing and save the * combined length in dlen. */ p = n; dlen += c->c_text_len; /* * Clear the indication that space has been allocated */ c->c_text_area = NULL; c->c_text_len = 0; } /* * At this point 'p' points to the name/value parameters. Need * to cycle through each pair. */ n = p; while (dlen > 0) { cur_pair = n; plen = strlen(n); if ((n = strchr(cur_pair, ISCSI_TEXT_SEPARATOR)) == NULL) { if (errcode != NULL) *errcode = (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | ISCSI_LOGIN_STATUS_INIT_ERR; rval = False; break; } else *n++ = '\0'; queue_prt(c->c_mgmtq, Q_CONN_LOGIN, "CON%x %-24s = %s\n", c->c_num, cur_pair, n); /* * At this point, 'cur_pair' points at the name and 'n' * points at the value. */ /* * []--------------------------------------------------[] * | The order of parameters processed matches the | * | the RFC in section 12. | * []--------------------------------------------------[] */ /* * 12.1 -- HeaderDigest * Negotiated */ if (strcmp("HeaderDigest", cur_pair) == 0) { rval = parse_digest_vals(&c->c_header_digest, cur_pair, n, text, text_length); /* * 12.1 -- DataDigest * Negotiated */ } else if (strcmp("DataDigest", cur_pair) == 0) { rval = parse_digest_vals(&c->c_data_digest, cur_pair, n, text, text_length); /* * 12.2 -- MaxConnections * Negotiated */ } else if (strcmp("MaxConnections", cur_pair) == 0) { /* ---- To be fixed ---- */ c->c_max_connections = 1; (void) snprintf(param_rsp, sizeof (param_rsp), "%d", c->c_max_connections); rval = add_text(text, text_length, cur_pair, param_rsp); /* * 12.3 -- SendTargets * Declarative */ } else if (strcmp("SendTargets", cur_pair) == 0) { if ((c->c_sess->s_type != SessionDiscovery) && (strcmp("All", n) == 0)) { rval = add_text(text, text_length, cur_pair, "Irrelevant"); } else { rval = add_targets(c, text, text_length); } /* * 12.4 -- TargetName * Declarative */ } else if (strcmp("TargetName", cur_pair) == 0) { send_named_msg(c, msg_target_name, n); target_name = n; /* * 12.5 -- IntiatorName * Declarative */ } else if (strcmp("InitiatorName", cur_pair) == 0) { send_named_msg(c, msg_initiator_name, n); initiator_name = n; /* ---- Section 12.6 is handled within TargetName ---- */ /* * 12.7 -- InitiatorAlias * Declarative */ } else if (strcmp("InitiatorAlias", cur_pair) == 0) { send_named_msg(c, msg_initiator_alias, n); /* * Sections 12.8 (TargetAddress) and 12.9 * (TargetPortalGroupTag) are handled during the SendTargets * processing. */ /* * 12.10 -- IntialR2T * Negotiated */ } else if (strcmp("InitialR2T", cur_pair) == 0) { c->c_initialR2T = True; rval = add_text(text, text_length, cur_pair, "Yes"); /* * 12.11 -- ImmediateData * Negotiated */ } else if (strcmp("ImmediateData", cur_pair) == 0) { /* * Since we can handle immediate data without * a problem just echo back what the initiator * sends. If the initiator decides to violate * the spec by sending immediate data even though * they've disabled it, it's their problem and * we'll deal with the data. */ c->c_immediate_data = strcmp(n, "No") ? True : False; rval = add_text(text, text_length, cur_pair, n); /* * 12.12 -- MaxRecvDataSegmentLength * Declarative */ } else if (strcmp("MaxRecvDataSegmentLength", cur_pair) == 0) { c->c_max_recv_data = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.13 -- MaxBurstLength * Negotiated */ } else if (strcmp("MaxBurstLength", cur_pair) == 0) { c->c_max_burst_len = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.14 -- FirstBurstLength * Negotiated */ } else if (strcmp("FirstBurstLength", cur_pair) == 0) { /* * We can handle anything the initiator wishes * to shove in our direction. So, store the value * in case we ever wish to validate input data, * but there's no real need to do so. */ c->c_first_burst_len = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.15 DefaultTime2Wait * Negotiated */ } else if (strcmp("DefaultTime2Wait", cur_pair) == 0) { c->c_default_time_2_wait = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.16 -- DefaultTime2Retain * Negotiated */ } else if (strcmp("DefaultTime2Retain", cur_pair) == 0) { c->c_default_time_2_retain = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.17 -- MaxOutstandingR2T * Negotiated */ } else if (strcmp("MaxOutstandingR2T", cur_pair) == 0) { /* * Save the value, but at most we'll toss out * one R2T packet. */ c->c_max_outstanding_r2t = strtol(n, NULL, 0); rval = add_text(text, text_length, cur_pair, n); /* * 12.18 -- DataPDUInOder * Negotiated */ } else if (strcmp("DataPDUInOrder", cur_pair) == 0) { /* * We can handle DataPDU's out of order and * currently we'll only send them in order. We're * to far removed from the hardware to see data * coming off of the platters out of order so * it's unlikely we'd ever implement this feature. * Store the parameter and echo back the initiators * request. */ c->c_data_pdu_in_order = strcmp(n, "Yes") == 0 ? True : False; rval = add_text(text, text_length, cur_pair, n); /* * 12.19 -- DataSequenceInOrder * Negotiated */ } else if (strcmp("DataSequenceInOrder", cur_pair) == 0) { /* * Currently we're set up to look at and require * PDU sequence numbers be in order. The check * now is only done as a prelude to supporting * MC/S and guaranteeing the order of incoming * packets on different connections. */ c->c_data_sequence_in_order = True; rval = add_text(text, text_length, cur_pair, "Yes"); /* * 12.20 -- ErrorRecoveryLevel * Negotiated */ } else if (strcmp("ErrorRecoveryLevel", cur_pair) == 0) { c->c_erl = 0; (void) snprintf(param_rsp, sizeof (param_rsp), "%d", c->c_erl); rval = add_text(text, text_length, cur_pair, param_rsp); /* * 12.21 -- SessionType * Declarative */ } else if (strcmp("SessionType", cur_pair) == 0) { c->c_sess->s_type = strcmp(n, "Discovery") == 0 ? SessionDiscovery : SessionNormal; /* * Appendix A 3.1 -- IFMarker * Negotiated */ } else if (strcmp("IFMarker", cur_pair) == 0) { c->c_ifmarker = False; rval = add_text(text, text_length, cur_pair, "No"); /* * Appendix A 3.1 -- OFMarker * Negotiated */ } else if (strcmp("OFMarker", cur_pair) == 0) { c->c_ofmarker = False; rval = add_text(text, text_length, cur_pair, "No"); } else if ((strcmp("AuthMethod", cur_pair) == 0) || (strcmp("CHAP_A", cur_pair) == 0) || (strcmp("CHAP_I", cur_pair) == 0) || (strcmp("CHAP_C", cur_pair) == 0) || (strcmp("CHAP_N", cur_pair) == 0) || (strcmp("CHAP_R", cur_pair) == 0)) { rval = add_text(&(c->auth_text), &c->auth_text_length, cur_pair, n); } else { /* * It's perfectly legitimate for an initiator to * send us a parameter we don't currently understand. * For example, an initiator that supports iSER will * send an RDMA options parameter. If we respond with * a valid return value it knows to switch to iSER * for future processing. */ rval = add_text(text, text_length, cur_pair, "NotUnderstood"); /* * Go ahead a log this information in case we see * something unexpected. */ queue_prt(c->c_mgmtq, Q_CONN_ERRS, "CON%x Unknown parameter %s=%s\n", c->c_num, cur_pair, n); } /* * If parsed both Initiator and Target names have been parsed, * then it is now time to load the connection parameters. * * This may fail because the target doesn't exist or the * initiator doesn't have permission to access this target. */ if ((target_name != NULL) && (initiator_name != NULL)) { if ((rval = connection_parameters_get(c, target_name)) == False) { if ((errcode != NULL) && (*errcode == 0)) *errcode = (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | ISCSI_LOGIN_STATUS_TGT_FORBIDDEN; } else if ((rval = add_text(text, text_length, "TargetAlias", c->c_targ_alias)) == True) { /* * Add TPGT now */ (void) snprintf(param_buf, sizeof (param_buf), "%d", c->c_tpgt); rval = add_text(text, text_length, "TargetPortalGroupTag", param_buf); target_name = initiator_name = NULL; } } if (rval == False) { /* * Make sure the caller wants error status and that it * hasn't already been set. */ if ((errcode != NULL) && (*errcode == 0)) *errcode = (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | ISCSI_LOGIN_STATUS_TARGET_ERROR; break; } /* * next pair of parameters. 1 is added to include the NULL * byte and the end of each string. */ n = cur_pair + plen + 1; dlen -= (plen + 1); } if (p != NULL) free(p); return (rval); }