📄 initiator_rx.c
字号:
" 0x%02x, expected 0x%02x\n", nopout_cmd->opcode & ISCSI_OPCODE, ISCSI_INIT_NOP_OUT); } if (size != ntohl(nopout_cmd->length)) { TRACE_ERROR ("NopIn DSL is %u, expected %u\n", size, ntohl(nopout_cmd->length)); } else if (size > 0 && memcmp(*buffer, related_command->tx_iov[1]. iov_base, size) != 0) { TRACE_ERROR ("NopIn Data \"%s\", " "expected \"%s\"\n", *buffer, (char *) related_command-> tx_iov[1].iov_base); } else { TRACE(TRACE_ISCSI_FULL, "%u byte NopIn matches NopOut\n", size); } /* in any case, free up the related command */ related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, current_connection); } } } else { /* sent by target on its own to provoke a "ping" * response from us */ if (unlikely(local_itt != ALL_ONES)) { TRACE_ERROR("Invalid NopIn ITT %u when TTT is %u\n", local_itt, ntohl(header->target_xfer_tag)); } /* Draft 20, Section 10.19.3 Lun * "A LUN MUST be set to a correct value when the * Target Transfer Tag is valid (not the reserved * value 0xffffffff)." */ lun = unpack_lun((__u8 *) & header->lun); if (unlikely(!(related_session->lun_bits & (1 << lun)))) { TRACE(TRACE_ISCSI, "Invalid NopIn LUN %u\n", lun); } /* Now send a NopOut PDU in response to this NopIn */ if (unlikely(current_connection->connection_flags & SEND_NO_REPLY_TO_NOP_PING)) { TRACE(TRACE_ISCSI, "Not replying to NopIn ping from target\n"); } else { tx_nopout(current_connection, 0, header, buffer, size); } } TRACE(TRACE_ENTER_LEAVE, "Leave rx_nopin\n"); return 1; /* only success here */}/* * print out all keys sent by target in a text response * returns 1 on success, 0 on error (unterminated key) */static inttext_key_dump(char *buffer, __u32 size, char *message){ int retval = 1; char *ptr, *ptr2; if (likely(buffer != NULL && size > 0)) { /* print out the info sent by target */ for (ptr = buffer; size > 0; ptr = ptr2) { for (ptr2 = ptr; *ptr2 != '\0' && size > 0; ptr2++, size--) { /* skip over key itself */ } if (*ptr2 != '\0') { *ptr2 = '\0'; TRACE_ERROR("Unterminated key %s\n", ptr); retval = 0; } printk("%s %s %s\n", current->comm, message, ptr); for (; *ptr2 == '\0' && size > 0; ptr2++, size--) { /* skip over nulls between keys */ } } } else { TRACE(TRACE_ISCSI_FULL, "%s empty text response\n", current->comm); } return retval;}/* called only by rx_text_rsp() * Returns 1 if need reset due to error, 0 if all ok */static int __attribute__ ((no_instrument_function))accumulate_text(struct command *command, char *buffer, __u32 size){ int retval, total; if ((total = size) > 0) { /* buffer contains some data, must accumulate it */ if (command->buffer_to_free == NULL) { command->buffer_to_free = my_kmalloc(MAX_TEXT_LEN, "Text data"); if (command->buffer_to_free == NULL) { retval = 1; goto out; } } total += command->data_offset; if (total > MAX_TEXT_LEN) { TRACE_ERROR("%s too many total bytes %u in text data, " " max %u\n", current->comm, total, MAX_TEXT_LEN); retval = 1; goto out; } memcpy(command->buffer_to_free + command->data_offset, buffer, size); command->data_offset = total; } retval = 0;out: return retval;}/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the TextResponse header. * * Parameters: current_connection which is a ptr to the connection struct * where the TextResponse header was received. * Return Value: >0 success; ==0 on fatal error ***************************************************************************/static intrx_text_rsp(struct connection *current_connection, __u32 local_itt, struct command *related_command, __u32 size, char *buffer){ struct iscsi_targ_text_rsp *header; struct session *related_session; struct iscsi_init_text_cmnd *text_cmd; int retval = 1, need_reset = 0; TRACE(TRACE_ENTER_LEAVE, "Enter rx_text_rsp, current_connection %p\n", current_connection); header = (struct iscsi_targ_text_rsp *)current_connection->rx_buf; if (related_command == NULL) { TRACE_ERROR("%s ignoring Text Response that matches no " "command\n", current->comm); print_targ_text_rsp(header); goto out; } related_session = current_connection->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check if reserved fields are zero or not */ if (unlikely(!((header->flags & ~(F_BIT | C_BIT)) == 0 && header->rsvd2 == 0 && header->rsvd4 == 0 && header->rsvd5 == 0))) { reserved_not_0("Text Response"); }#endif if (unlikely(header->flags & C_BIT)) { /* C bit is set in Text Response * * RFC 3720 Section 10.11.2 C (Continue) Bit (in Text Response) * "A Text Response with the C bit set to 1 MUST have the * F bit set to 0." */ if (unlikely(header->flags & F_BIT)) { /* have C=1 and F=1 -- try to guess which is wrong */ if (header->target_xfer_tag == ALL_ONES) { /* this is ok when F=1, bad when C=1 */ TRACE_ERROR("Text Response with ITT %u has F=1 " "and C=1, expected C=0\n", local_itt); header->flags &= ~C_BIT; } else { TRACE_ERROR("Text Response with ITT %u has C=1 " "and F=1, expected F=0\n", local_itt); need_reset = 1; header->flags &= ~F_BIT; } } } if (!(header->flags & C_BIT)) { /* this pdu completes one full data payload */ if (related_command->data_offset) { /* previous response pdus were continued to this one. * append this new buffer, then dump the whole payload. */ need_reset = accumulate_text(related_command, buffer, size); buffer = related_command->buffer_to_free; size = related_command->data_offset; } if (!need_reset) { if (related_session->oper_param->SessionType) { text_key_dump(buffer, size, "discovery"); } else { text_key_dump(buffer, size, "text negotiation"); } } /* finished with any accumulated data payload */ related_command->data_offset = 0; } else { /* this pdu contains only part of the complete data payload */ if (related_command->data_offset == 0) { /* this is first continued pdu, free original request */ my_kfree((void **)&related_command->buffer_to_free, "Text data"); } need_reset = accumulate_text(related_command, buffer, size); } if (header->flags & F_BIT) { /* F Bit is 1, Target is finished sending everything */ if (unlikely(header->target_xfer_tag != ALL_ONES)) { /* RFC 3720 Section 10.11.1 F (Final) Bit in Text Resp * "A Text Response with the F bit set to 1 * MUST have a Target Transfer Tag field set to * the reserved value of 0xffffffff." */ TRACE_ERROR("Text Response with ITT %u has F=1 TTT=%u, " "expected 0xffffffff\n", local_itt, ntohl(header->target_xfer_tag)); /* ignore this since F=1 so we close it down anyway */ } /* in any case, free up the related command */ related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, current_connection); if (related_session->oper_param->SessionType) { /* in a discovery session, shut it down with a logout */ drive_logout(related_session, current_connection, LOGOUT_CLOSE_SESSION); } } else { /* F bit is 0, target has more to send after this * RFC 3720 Section 10.11.4 Target Transfer Tag * "When a target has more work to do (e.g., cannot transfer all * the remaining text data in a single Text Response or has to * continue the negotiation) and has enough resources to * proceed, it MUST set the Target Transfer Tag to a value other * than the reserved value of 0xffffffff. Otherwise, the Target * Transfer Tag MUST be set to 0xffffffff. * ... * The initiator MUST copy the Target Transfer Tag and LUN in * its next request to indicate that it wants the rest of the * data." */ if (unlikely(header->target_xfer_tag == ALL_ONES)) { /* RFC 3720 Section 10.11.1 F (Final) Bit in Text Resp * "A text response with the F bit set to 0 MUST * have a Target Transfer Tag field set to a value * other than the reserved 0xffffffff." */ TRACE_ERROR("Text Response with ITT %u F=0 has TTT=" "0x%8x, expected unreserved TTT\n", local_itt, ALL_ONES); need_reset = 1; } /* queue up an empty TextRequest to keep Target going */ text_cmd = (struct iscsi_init_text_cmnd *) &related_command->iscsi_cmd; if (need_reset) { text_cmd->target_xfer_tag = ALL_ONES; text_cmd->lun = 0; } else { text_cmd->target_xfer_tag = header->target_xfer_tag; text_cmd->lun = header->lun; } /* this follow-on TextRequest pdu has no data attached, * reset iov and msghdr so only header is sent */ text_cmd->length = 0; related_command->tx_iov->iov_len = related_command->tx_size = current_connection->basic_hdr_len; related_command->tx_iovlen = 1; /* reattach the existing Text Request command to end of * pending commands list. this also sets the CmdSN */ attach_pending_command(related_command, current_connection, 2); }out: TRACE(TRACE_ENTER_LEAVE, "Leave rx_text_rsp, retval %d\n", retval); return retval;}/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the LogoutResponse header. * * Parameters: current_connection which is a ptr to the connection struct * where the LogoutResponse header was received. * Return Value: =0 terminate connection on return, (session lock still locked) * <0 terminate connection on return, (session lock not locked) * >0 do not terminate connection (session lock still locked) ***************************************************************************/static intrx_logout_rsp(struct connection *conn, __u32 local_itt, struct command *related_command){ int reason, response = 1; struct iscsi_init_logout_cmnd *logout_cmd; struct iscsi_targ_logout_rsp *header; struct session *sess = NULL; struct semaphore rec_wait_sem; TRACE(TRACE_ENTER_LEAVE, "Enter rx_logout_rsp, current_connection %p\n", conn); header = (struct iscsi_targ_logout_rsp *)conn->rx_buf; /* store the session pointer - SAI */ sess = conn->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check if reserved fields are zero or not */ if (unlikely(!((header->flags & ~F_BIT) == 0 && header->rsvd1 == 0 && header->rsvd3 == 0 && header->rsvd4 == 0 && header->rsvd5 == 0))) { reserved_not_0("Logout Response"); }#endif /* this PDU should be a response to a LogoutRequest sent * earlier by us. */ if (likely(related_command != NULL)) { /* found the corresponding LogoutRequest command */ response = header->response; /* If connection recovery, start a Wait timer - SAI */ logout_cmd = (struct iscsi_init_logout_cmnd *) & (related_command->iscsi_cmd); reason = logout_cmd->flags & LOGOUT_REASON; related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, conn); switch (reason) { case LOGOUT_CLOSE_SESSION: if (response == 0) { sess->session_state = SESSION_LOGGED_OUT; } else { TRACE_ERROR("Logout to close session failed" ", response %u\n", response); } break; case LOGOUT_CLOSE_CONNECTION: if (response == 0) { /* stop using logged-out connection */ conn->connection_state = CONNECTION_LOGGED_OUT; } else { TRACE_ERROR("Logout to close connection failed" ", response %u\n", response); } break; case LOGOUT_REMOVE_CONN_FOR_RECOVERY: /* If the response is zero and ErrorRecoveryLevel > 1, * then wait until Time2Wait and then recover - SAI */ if (response == 0 && sess->oper_param->ErrorRecoveryLevel > 1) { UNH_UNLOCK(&sess->sess_lock, conn->rx_lock_flags); if (be16_to_cpu(header->time2wait) > 0) { init_MUTEX_LOCKED(&rec_wait_sem); start_connrec_timer(sess, &rec_wait_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -