void conn_dispatch(int fd, short event, void *arg) { struct connection *c = arg; ssize_t n; if (!(event & EV_READ)) { log_debug("spurious read call"); return; } if ((n = pdu_read(c)) == -1) { if (errno == EAGAIN || errno == ENOBUFS || errno == EINTR) /* try later */ return; log_warn("pdu_read"); conn_fsm(c, CONN_EV_FAIL); return; } if (n == 0) { /* connection closed */ conn_fsm(c, CONN_EV_CLOSED); return; } pdu_parse(c); }
void pdu_receive(struct pdu *pdu) { size_t len, padding; char dummy[4]; #ifdef ICL_KERNEL_PROXY if (pdu->pdu_connection->conn_conf.isc_iser != 0) return (pdu_receive_proxy(pdu)); #endif assert(pdu->pdu_connection->conn_conf.isc_iser == 0); pdu_read(pdu->pdu_connection->conn_socket, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs)); len = pdu_ahs_length(pdu); if (len > 0) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); if (len > 0) { if (len > ISCSI_MAX_DATA_SEGMENT_LENGTH) { log_errx(1, "protocol error: received PDU " "with DataSegmentLength exceeding %d", ISCSI_MAX_DATA_SEGMENT_LENGTH); } pdu->pdu_data_len = len; pdu->pdu_data = malloc(len); if (pdu->pdu_data == NULL) log_err(1, "malloc"); pdu_read(pdu->pdu_connection->conn_socket, (char *)pdu->pdu_data, pdu->pdu_data_len); padding = pdu_padding(pdu); if (padding != 0) { assert(padding < sizeof(dummy)); pdu_read(pdu->pdu_connection->conn_socket, (char *)dummy, padding); } } }
static int p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, va_list ap) { const char *ptr; int errcode = 0; for (ptr = fmt; *ptr; ptr++) { switch (*ptr) { case 'b': { int8_t *val = va_arg(ap, int8_t *); if (pdu_read(pdu, val, sizeof(*val))) { errcode = -EFAULT; break; } } break; case 'w': { int16_t *val = va_arg(ap, int16_t *); __le16 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le16_to_cpu(le_val); } break; case 'd': { int32_t *val = va_arg(ap, int32_t *); __le32 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le32_to_cpu(le_val); } break; case 'q': { int64_t *val = va_arg(ap, int64_t *); __le64 le_val; if (pdu_read(pdu, &le_val, sizeof(le_val))) { errcode = -EFAULT; break; } *val = le64_to_cpu(le_val); } break; case 's': { char **sptr = va_arg(ap, char **); int16_t len; int size; errcode = p9pdu_readf(pdu, proto_version, "w", &len); if (errcode) break; size = MAX(len, 0); *sptr = kmalloc(size + 1, GFP_KERNEL); if (*sptr == NULL) { errcode = -EFAULT; break; } if (pdu_read(pdu, *sptr, size)) { errcode = -EFAULT; kfree(*sptr); *sptr = NULL; } else (*sptr)[size] = 0; } break; case 'Q': { struct p9_qid *qid = va_arg(ap, struct p9_qid *); errcode = p9pdu_readf(pdu, proto_version, "bdq", &qid->type, &qid->version, &qid->path); } break; case 'S': { struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); memset(stbuf, 0, sizeof(struct p9_wstat)); stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; errcode = p9pdu_readf(pdu, proto_version, "wwdQdddqssss?sddd", &stbuf->size, &stbuf->type, &stbuf->dev, &stbuf->qid, &stbuf->mode, &stbuf->atime, &stbuf->mtime, &stbuf->length, &stbuf->name, &stbuf->uid, &stbuf->gid, &stbuf->muid, &stbuf->extension, &stbuf->n_uid, &stbuf->n_gid, &stbuf->n_muid); if (errcode) p9stat_free(stbuf); } break; case 'D': { int32_t *count = va_arg(ap, int32_t *); void **data = va_arg(ap, void **); errcode = p9pdu_readf(pdu, proto_version, "d", count); if (!errcode) { *count = MIN(*count, pdu->size - pdu->offset); *data = &pdu->sdata[pdu->offset]; } } break; case 'T': { int16_t *nwname = va_arg(ap, int16_t *); char ***wnames = va_arg(ap, char ***); errcode = p9pdu_readf(pdu, proto_version, "w", nwname); if (!errcode) { *wnames = kmalloc(sizeof(char *) * *nwname, GFP_KERNEL); if (!*wnames) errcode = -ENOMEM; } if (!errcode) { int i; for (i = 0; i < *nwname; i++) { errcode = p9pdu_readf(pdu, proto_version, "s", &(*wnames)[i]); if (errcode) break; } } if (errcode) { if (*wnames) { int i; for (i = 0; i < *nwname; i++) kfree((*wnames)[i]); } kfree(*wnames); *wnames = NULL; } } break; case 'R': { int16_t *nwqid = va_arg(ap, int16_t *); struct p9_qid **wqids = va_arg(ap, struct p9_qid **); *wqids = NULL; errcode = p9pdu_readf(pdu, proto_version, "w", nwqid); if (!errcode) { *wqids = kmalloc(*nwqid * sizeof(struct p9_qid), GFP_KERNEL); if (*wqids == NULL) errcode = -ENOMEM; } if (!errcode) { int i; for (i = 0; i < *nwqid; i++) { errcode = p9pdu_readf(pdu, proto_version, "Q", &(*wqids)[i]); if (errcode) break; } } if (errcode) { kfree(*wqids); *wqids = NULL; } } break; case '?': if ((proto_version != p9_proto_2000u) && (proto_version != p9_proto_2000L)) return 0; break; default: BUG(); break; } if (errcode) break; } return errcode; }