// writes what has been buffered and clears memory void u2f_hid_flush() { if (_hid_offset) { usb_write(_hid_pkt, HID_PACKET_SIZE); } u2f_hid_reset_packet(); }
void u2f_hid_check_timeouts() { uint8_t i; for(i = 0; i < CID_MAX; i++) { if (CIDS[i].busy && ((get_ms() - CIDS[i].last_used) >= 750)) { u2f_printlx("timeout cid ",2,CIDS[i].cid,get_ms()); stamp_error(CIDS[i].cid, ERR_MSG_TIMEOUT); del_cid(CIDS[i].cid); u2f_hid_reset_packet(); } } }
void u2f_hid_request(struct u2f_hid_msg* req) { uint8_t* payload = req->pkt.init.payload; static int8_t last_seq = -1; struct CID* cid = get_cid(req->cid); if (cid != NULL) { refresh_cid(cid); } else if (req->cid == U2FHID_BROADCAST) { } else { // Ignore CID's we did not allocate. //u2f_printlx("ignoring pkt ",1,req->cid); return; } // ignore if we locked to a different cid if(hid_is_locked()) { if (!hid_is_lock_cid(cid)) { stamp_error(hid_layer.current_cid, ERR_CHANNEL_BUSY); return; } } hid_layer.state = (u2f_hid_busy()) ? HID_BUSY : HID_READY; switch(hid_layer.state) { case HID_READY: if (req->pkt.init.cmd & TYPE_INIT) { if (U2FHID_LEN(req) > U2FHID_MAX_PAYLOAD_SIZE) { //u2f_prints("length too big\r\n"); stamp_error(req->cid, ERR_INVALID_LEN); return; } u2f_hid_reset_packet(); hid_layer.current_cid = req->cid; hid_layer.current_cmd = req->pkt.init.cmd; hid_layer.last_buffered = get_ms(); last_seq = -1; } else { stamp_error(req->cid, ERR_INVALID_CMD); u2f_prints("ERR_INVALID_CMD\r\n"); return; } break; case HID_BUSY: // buffer long requests if (req->cid == hid_layer.current_cid) { if (req->pkt.init.cmd & TYPE_INIT) { u2f_hid_reset_packet(); u2f_hid_request(req); return; } hid_layer.last_buffered = get_ms(); // verify packets arrive in ascending order if (last_seq + 1 != req->pkt.cont.seq) { u2f_hid_reset_packet(); stamp_error(hid_layer.current_cid, ERR_INVALID_SEQ); return; } last_seq = req->pkt.cont.seq; } else if (U2FHID_TIMEOUT(&hid_layer)) { // return timeout error for old channel and run again for new channel //u2f_prints("timeout, switching\r\n"); hid_layer.state = HID_READY; u2f_hid_reset_packet(); stamp_error(hid_layer.current_cid, ERR_MSG_TIMEOUT); u2f_hid_request(req); return; } else { // Current application may not be interrupted stamp_error(req->cid, ERR_CHANNEL_BUSY); return; } break; } hid_u2f_parse(req); return; }
void u2f_hid_request(struct u2f_hid_msg* req) { static int8_t last_seq; struct CID* cid = NULL; cid = get_cid(req->cid); // Error checking if ((U2FHID_IS_INIT(req->pkt.init.cmd))) { if (U2FHID_LEN(req) > 7609) { stamp_error(req->cid, ERR_INVALID_LEN); return; } if (req->pkt.init.cmd != U2FHID_INIT && req->cid != hid_layer.current_cid && u2f_hid_busy()) { stamp_error(req->cid, ERR_CHANNEL_BUSY); return; } } else if (cid == NULL || !cid->busy) { // ignore random cont packets return; } if (!req->cid) { stamp_error(req->cid, ERR_SYNC_FAIL); return; } if (req->cid == U2FHID_BROADCAST) { if (!(req->pkt.init.cmd == U2FHID_INIT)) { stamp_error(req->cid, ERR_SYNC_FAIL); return; } cid = &BROADCAST_CID; BROADCAST_CID.cid = U2FHID_BROADCAST; } else if (U2FHID_IS_INIT(req->pkt.init.cmd) && cid == NULL) { add_new_cid(req->cid); cid = get_cid(req->cid); if (cid == NULL) { return; } cid->busy = 0; } // Reset init packets if (req->pkt.init.cmd == U2FHID_INIT) { cid->busy = 0; } hid_layer.current_cid = req->cid; hid_layer.last_buffered = get_ms(); cid->last_used = get_ms(); // ignore if we locked to a different cid #ifdef U2F_SUPPORT_HID_LOCK if(hid_is_locked() && req->pkt.init.cmd != U2FHID_INIT) { if (!hid_is_lock_cid(req->cid)) { stamp_error(req->cid, ERR_CHANNEL_BUSY); return; } } #endif if ((req->pkt.init.cmd & TYPE_INIT) && !cid->busy) { cid->last_cmd = req->pkt.init.cmd; hid_layer.current_cmd = req->pkt.init.cmd; last_seq = -1; } else { // verify packets arrive in ascending order hid_layer.last_buffered = get_ms(); if (last_seq + 1 != req->pkt.cont.seq) { stamp_error(hid_layer.current_cid, ERR_INVALID_SEQ); u2f_hid_reset_packet(); return; } last_seq = req->pkt.cont.seq; hid_layer.current_cmd = cid->last_cmd; } cid->busy = hid_u2f_parse(req); }