int control_compose(void *ch, u_int16_t type, void *buf, size_t len) { struct pdu *pdu; struct ctrlmsghdr *cmh; void *ptr; if (PDU_LEN(len) > CONTROL_READ_SIZE - PDU_LEN(sizeof(*cmh))) return -1; if ((pdu = pdu_new()) == NULL) return -1; if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL) goto fail; bzero(cmh, sizeof(*cmh)); cmh->type = type; cmh->len[0] = len; pdu_addbuf(pdu, cmh, sizeof(*cmh), 0); if (len > 0) { if ((ptr = pdu_alloc(len)) == NULL) goto fail; bcopy(buf, ptr, len); pdu_addbuf(pdu, ptr, len, 1); } return control_queue(ch, pdu); fail: pdu_free(pdu); return -1; }
static struct pdu * text_receive(struct connection *conn) { struct pdu *response; struct iscsi_bhs_text_response *bhstr; response = pdu_new(conn); pdu_receive(response); if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_TEXT_RESPONSE) log_errx(1, "protocol error: received invalid opcode 0x%x", response->pdu_bhs->bhs_opcode); bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs; #if 0 if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) == 0) log_errx(1, "received Text PDU without the \"F\" flag"); #endif /* * XXX: Implement the C flag some day. */ if ((bhstr->bhstr_flags & BHSTR_FLAGS_CONTINUE) != 0) log_errx(1, "received Text PDU with unsupported \"C\" flag"); if (ntohl(bhstr->bhstr_statsn) != conn->conn_statsn + 1) { log_errx(1, "received Text PDU with wrong StatSN: " "is %u, should be %u", ntohl(bhstr->bhstr_statsn), conn->conn_statsn + 1); } conn->conn_statsn = ntohl(bhstr->bhstr_statsn); return (response); }
int llc_connection_connect (struct llc_connection *connection) { assert (connection); assert (connection->link); uint8_t buffer[BUFSIZ]; size_t len = 0; if (connection->remote_uri) { int r = parameter_encode_sn (buffer, sizeof (buffer) - len, connection->remote_uri); if (r >= 0) len += r; } struct pdu *pdu = pdu_new (connection->remote_sap, PDU_CONNECT, connection->local_sap, 0, 0, buffer, len); int res = llc_link_send_pdu (connection->link, pdu); pdu_free (pdu); if (res >= 0) { connection->link->transmission_handlers[connection->local_sap] = connection; connection->status = DLC_NEW; res = llc_connection_start (connection); } return res; }
static struct pdu * login_receive(struct connection *conn, bool initial) { struct pdu *request; struct iscsi_bhs_login_request *bhslr; request = pdu_new(conn); pdu_receive(request); if ((request->pdu_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) != ISCSI_BHS_OPCODE_LOGIN_REQUEST) { /* * The first PDU in session is special - if we receive any PDU * different than login request, we have to drop the connection * without sending response ("A target receiving any PDU * except a Login request before the Login Phase is started MUST * immediately terminate the connection on which the PDU * was received.") */ if (initial == false) login_send_error(request, 0x02, 0x0b); log_errx(1, "protocol error: received invalid opcode 0x%x", request->pdu_bhs->bhs_opcode); } bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; /* * XXX: Implement the C flag some day. */ if ((bhslr->bhslr_flags & BHSLR_FLAGS_CONTINUE) != 0) { login_send_error(request, 0x03, 0x00); log_errx(1, "received Login PDU with unsupported \"C\" flag"); } if (bhslr->bhslr_version_max != 0x00) { login_send_error(request, 0x02, 0x05); log_errx(1, "received Login PDU with unsupported " "Version-max 0x%x", bhslr->bhslr_version_max); } if (bhslr->bhslr_version_min != 0x00) { login_send_error(request, 0x02, 0x05); log_errx(1, "received Login PDU with unsupported " "Version-min 0x%x", bhslr->bhslr_version_min); } if (initial == false && ISCSI_SNLT(ntohl(bhslr->bhslr_cmdsn), conn->conn_cmdsn)) { login_send_error(request, 0x02, 0x00); log_errx(1, "received Login PDU with decreasing CmdSN: " "was %u, is %u", conn->conn_cmdsn, ntohl(bhslr->bhslr_cmdsn)); } if (initial == false && ntohl(bhslr->bhslr_expstatsn) != conn->conn_statsn) { login_send_error(request, 0x02, 0x00); log_errx(1, "received Login PDU with wrong ExpStatSN: " "is %u, should be %u", ntohl(bhslr->bhslr_expstatsn), conn->conn_statsn); } conn->conn_cmdsn = ntohl(bhslr->bhslr_cmdsn); return (request); }
struct pdu * control_getpdu(char *buf, size_t len) { struct pdu *p; struct ctrlmsghdr *cmh; void *data; size_t n; int i; if (len < sizeof(*cmh)) return NULL; if (!(p = pdu_new())) return NULL; n = sizeof(*cmh); cmh = pdu_alloc(n); bcopy(buf, cmh, n); buf += n; len -= n; if (pdu_addbuf(p, cmh, n, 0)) { free(cmh); fail: pdu_free(p); return NULL; } for (i = 0; i < 3; i++) { n = cmh->len[i]; if (n == 0) continue; if (PDU_LEN(n) > len) goto fail; if (!(data = pdu_alloc(n))) goto fail; bcopy(buf, data, n); if (pdu_addbuf(p, data, n, i + 1)) { free(data); goto fail; } buf += PDU_LEN(n); len -= PDU_LEN(n); } return p; }
static struct pdu * logout_new_request(struct connection *conn) { struct pdu *request; struct iscsi_bhs_logout_request *bhslr; request = pdu_new(conn); bhslr = (struct iscsi_bhs_logout_request *)request->pdu_bhs; bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST | ISCSI_BHS_OPCODE_IMMEDIATE; bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION; bhslr->bhslr_reason |= 0x80; bhslr->bhslr_initiator_task_tag = 0; /* XXX */ bhslr->bhslr_cmdsn = 0; /* XXX */ bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1); return (request); }
static struct pdu * text_new_request(struct connection *conn) { struct pdu *request; struct iscsi_bhs_text_request *bhstr; request = pdu_new(conn); bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs; bhstr->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_REQUEST | ISCSI_BHS_OPCODE_IMMEDIATE; bhstr->bhstr_flags = BHSTR_FLAGS_FINAL; bhstr->bhstr_initiator_task_tag = 0; bhstr->bhstr_target_transfer_tag = 0xffffffff; bhstr->bhstr_initiator_task_tag = 0; /* XXX */ bhstr->bhstr_cmdsn = 0; /* XXX */ bhstr->bhstr_expstatsn = htonl(conn->conn_statsn + 1); return (request); }
int control_build(void *ch, u_int16_t type, int argc, struct ctrldata *argv) { struct pdu *pdu; struct ctrlmsghdr *cmh; size_t size = 0; int i; if (argc > (int)nitems(cmh->len)) return -1; for (i = 0; i < argc; i++) size += argv[i].len; if (PDU_LEN(size) > CONTROL_READ_SIZE - PDU_LEN(sizeof(*cmh))) return -1; if ((pdu = pdu_new()) == NULL) return -1; if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL) goto fail; bzero(cmh, sizeof(*cmh)); cmh->type = type; pdu_addbuf(pdu, cmh, sizeof(*cmh), 0); for (i = 0; i < argc; i++) if (argv[i].len > 0) { void *ptr; cmh->len[i] = argv[i].len; if ((ptr = pdu_alloc(argv[i].len)) == NULL) goto fail; memcpy(ptr, argv[i].buf, argv[i].len); pdu_addbuf(pdu, ptr, argv[i].len, i + 1); } control_queue(ch, pdu); return 0; fail: pdu_free(pdu); return -1; }
static struct pdu * logout_receive(struct connection *conn) { struct pdu *response; struct iscsi_bhs_logout_response *bhslr; response = pdu_new(conn); pdu_receive(response); if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGOUT_RESPONSE) log_errx(1, "protocol error: received invalid opcode 0x%x", response->pdu_bhs->bhs_opcode); bhslr = (struct iscsi_bhs_logout_response *)response->pdu_bhs; if (ntohs(bhslr->bhslr_response) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY) log_warnx("received Logout Response with reason %d", ntohs(bhslr->bhslr_response)); if (ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) { log_errx(1, "received Logout PDU with wrong StatSN: " "is %u, should be %u", ntohl(bhslr->bhslr_statsn), conn->conn_statsn + 1); } conn->conn_statsn = ntohl(bhslr->bhslr_statsn); return (response); }
struct pdu * pdu_new_response(struct pdu *request) { return (pdu_new(request->pdu_connection)); }