static int process_dreg_ack(struct vio_driver_state *vio, struct vio_dring_register *pkt) { struct vio_dring_state *dr; viodbg(HS, "GOT DRING_REG ACK ident[%llx] " "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n", (unsigned long long) pkt->dring_ident, pkt->num_descr, pkt->descr_size, pkt->options, pkt->num_cookies); dr = &vio->drings[VIO_DRIVER_TX_RING]; if (!(vio->dr_state & VIO_DR_STATE_TXREQ)) return handshake_failure(vio); dr->ident = pkt->dring_ident; vio->dr_state |= VIO_DR_STATE_TXREG; if (all_drings_registered(vio)) { if (send_rdx(vio) < 0) return handshake_failure(vio); vio->hs_state = VIO_HS_SENT_RDX; } return 0; }
static void handshake_cb(SoupSession *session, SoupMessage *message, void *user_data) { sr_session_t *s = user_data; struct sr_session_priv *priv = s->priv; const char *data, *end; if (!SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) { handshake_failure(s); return; } data = message->response_body->data; end = strchr(data, '\n'); if (!end) /* really bad */ return; if (strncmp(data, "OK", end - data) == 0) { priv->handshake_delay = 1; parse_handshake(s, data); sr_session_submit(s); } else if (strncmp(data, "BANNED", end - data) == 0) fatal_error(s, "Client is banned"); else if (strncmp(data, "BADAUTH", end - data) == 0) fatal_error(s, "Bad authorization"); else if (strncmp(data, "BADTIME", end - data) == 0) fatal_error(s, "Wrong system time"); else handshake_failure(s); }
static int process_attr(struct vio_driver_state *vio, void *pkt) { int err; if (!(vio->hs_state & VIO_HS_GOTVERS)) return handshake_failure(vio); if (!vio->ops) return 0; err = vio->ops->handle_attr(vio, pkt); if (err < 0) { return handshake_failure(vio); } else { vio->hs_state |= VIO_HS_GOT_ATTR; if ((vio->dr_state & VIO_DR_STATE_TXREQ) && !(vio->hs_state & VIO_HS_SENT_DREG)) { if (send_dreg(vio) < 0) return handshake_failure(vio); vio->hs_state |= VIO_HS_SENT_DREG; } } return 0; }
static int process_rdx(struct vio_driver_state *vio, struct vio_rdx *pkt) { if (!all_drings_registered(vio)) handshake_failure(vio); switch (pkt->tag.stype) { case VIO_SUBTYPE_INFO: return process_rdx_info(vio, pkt); case VIO_SUBTYPE_ACK: return process_rdx_ack(vio, pkt); case VIO_SUBTYPE_NACK: return process_rdx_nack(vio, pkt); default: return handshake_failure(vio); } }
static int process_rdx_ack(struct vio_driver_state *vio, struct vio_rdx *pkt) { viodbg(HS, "GOT RDX ACK\n"); if (!(vio->hs_state & VIO_HS_SENT_RDX)) return handshake_failure(vio); vio->hs_state |= VIO_HS_GOT_RDX_ACK; return 0; }
static int process_ver_nack(struct vio_driver_state *vio, struct vio_ver_info *pkt) { struct vio_version *nver; viodbg(HS, "GOT VERSION NACK maj[%u] min[%u] devclass[%u]\n", pkt->major, pkt->minor, pkt->dev_class); if (pkt->major == 0 && pkt->minor == 0) return handshake_failure(vio); nver = find_by_major(vio, pkt->major); if (!nver) return handshake_failure(vio); if (send_version(vio, nver->major, nver->minor) < 0) return handshake_failure(vio); return 0; }
static int process_dreg(struct vio_driver_state *vio, struct vio_dring_register *pkt) { if (!(vio->hs_state & VIO_HS_GOTVERS)) return handshake_failure(vio); switch (pkt->tag.stype) { case VIO_SUBTYPE_INFO: return process_dreg_info(vio, pkt); case VIO_SUBTYPE_ACK: return process_dreg_ack(vio, pkt); case VIO_SUBTYPE_NACK: return process_dreg_nack(vio, pkt); default: return handshake_failure(vio); } }
static int process_dreg_nack(struct vio_driver_state *vio, struct vio_dring_register *pkt) { viodbg(HS, "GOT DRING_REG NACK ident[%llx] " "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n", (unsigned long long) pkt->dring_ident, pkt->num_descr, pkt->descr_size, pkt->options, pkt->num_cookies); return handshake_failure(vio); }
static int process_rdx_info(struct vio_driver_state *vio, struct vio_rdx *pkt) { viodbg(HS, "GOT RDX INFO\n"); pkt->tag.stype = VIO_SUBTYPE_ACK; viodbg(HS, "SEND RDX ACK\n"); if (send_ctrl(vio, &pkt->tag, sizeof(*pkt)) < 0) return handshake_failure(vio); vio->hs_state |= VIO_HS_SENT_RDX_ACK; return 0; }
static int process_ver(struct vio_driver_state *vio, struct vio_ver_info *pkt) { switch (pkt->tag.stype) { case VIO_SUBTYPE_INFO: return process_ver_info(vio, pkt); case VIO_SUBTYPE_ACK: return process_ver_ack(vio, pkt); case VIO_SUBTYPE_NACK: return process_ver_nack(vio, pkt); default: return handshake_failure(vio); } }
static int process_rdx_nack(struct vio_driver_state *vio, struct vio_rdx *pkt) { viodbg(HS, "GOT RDX NACK\n"); return handshake_failure(vio); }
static int process_dreg_info(struct vio_driver_state *vio, struct vio_dring_register *pkt) { struct vio_dring_state *dr; int i, len; viodbg(HS, "GOT DRING_REG INFO ident[%llx] " "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n", (unsigned long long) pkt->dring_ident, pkt->num_descr, pkt->descr_size, pkt->options, pkt->num_cookies); if (!(vio->dr_state & VIO_DR_STATE_RXREQ)) goto send_nack; if (vio->dr_state & VIO_DR_STATE_RXREG) goto send_nack; BUG_ON(vio->desc_buf); vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC); if (!vio->desc_buf) goto send_nack; vio->desc_buf_len = pkt->descr_size; dr = &vio->drings[VIO_DRIVER_RX_RING]; dr->num_entries = pkt->num_descr; dr->entry_size = pkt->descr_size; dr->ncookies = pkt->num_cookies; for (i = 0; i < dr->ncookies; i++) { dr->cookies[i] = pkt->cookies[i]; viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n", i, (unsigned long long) pkt->cookies[i].cookie_addr, (unsigned long long) pkt->cookies[i].cookie_size); } pkt->tag.stype = VIO_SUBTYPE_ACK; pkt->dring_ident = ++dr->ident; viodbg(HS, "SEND DRING_REG ACK ident[%llx]\n", (unsigned long long) pkt->dring_ident); len = (sizeof(*pkt) + (dr->ncookies * sizeof(struct ldc_trans_cookie))); if (send_ctrl(vio, &pkt->tag, len) < 0) goto send_nack; vio->dr_state |= VIO_DR_STATE_RXREG; return 0; send_nack: pkt->tag.stype = VIO_SUBTYPE_NACK; viodbg(HS, "SEND DRING_REG NACK\n"); (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt)); return handshake_failure(vio); }
static int process_ver_info(struct vio_driver_state *vio, struct vio_ver_info *pkt) { struct vio_version *vap; int err; viodbg(HS, "GOT VERSION INFO maj[%u] min[%u] devclass[%u]\n", pkt->major, pkt->minor, pkt->dev_class); if (vio->hs_state != VIO_HS_INVALID) { /* XXX Perhaps invoke start_handshake? XXX */ memset(&vio->ver, 0, sizeof(vio->ver)); vio->hs_state = VIO_HS_INVALID; } vap = find_by_major(vio, pkt->major); vio->_peer_sid = pkt->tag.sid; if (!vap) { pkt->tag.stype = VIO_SUBTYPE_NACK; pkt->major = 0; pkt->minor = 0; viodbg(HS, "SEND VERSION NACK maj[0] min[0]\n"); err = send_ctrl(vio, &pkt->tag, sizeof(*pkt)); } else if (vap->major != pkt->major) { pkt->tag.stype = VIO_SUBTYPE_NACK; pkt->major = vap->major; pkt->minor = vap->minor; viodbg(HS, "SEND VERSION NACK maj[%u] min[%u]\n", pkt->major, pkt->minor); err = send_ctrl(vio, &pkt->tag, sizeof(*pkt)); } else { struct vio_version ver = { .major = pkt->major, .minor = pkt->minor, }; if (ver.minor > vap->minor) ver.minor = vap->minor; pkt->minor = ver.minor; pkt->tag.stype = VIO_SUBTYPE_ACK; viodbg(HS, "SEND VERSION ACK maj[%u] min[%u]\n", pkt->major, pkt->minor); err = send_ctrl(vio, &pkt->tag, sizeof(*pkt)); if (err > 0) { vio->ver = ver; vio->hs_state = VIO_HS_GOTVERS; } } if (err < 0) return handshake_failure(vio); return 0; } static int process_ver_ack(struct vio_driver_state *vio, struct vio_ver_info *pkt) { viodbg(HS, "GOT VERSION ACK maj[%u] min[%u] devclass[%u]\n", pkt->major, pkt->minor, pkt->dev_class); if (vio->hs_state & VIO_HS_GOTVERS) { if (vio->ver.major != pkt->major || vio->ver.minor != pkt->minor) { pkt->tag.stype = VIO_SUBTYPE_NACK; (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt)); return handshake_failure(vio); } } else { vio->ver.major = pkt->major; vio->ver.minor = pkt->minor; vio->hs_state = VIO_HS_GOTVERS; } switch (vio->dev_class) { case VDEV_NETWORK: case VDEV_DISK: if (send_attr(vio) < 0) return handshake_failure(vio); break; default: break; } return 0; }