static size_t idle_process_cmd(const union hci_packet* cmd, struct nfc_device* nfc, union hci_answer* rsp) { size_t len = 0; assert(cmd); if (cmd->control.service == HCI_SERVICE_BCM2079x) { switch (cmd->control.cmd) { case HCI_MESSAGE_RFU|HCI_BCM2079x_CMD_WRITE_SLEEP_MODE: len = idle_process_bcm2079x_write_sleep_mode_cmd(cmd, nfc, rsp); break; default: NFC_D("unknown command"); return 0; } } NFC_D("result length=%ld", (long)len); return len; }
static size_t process_ptype_rnr(struct nfc_re* re, const struct llcp_pdu* llcp, size_t len, uint8_t* consumed, struct llcp_pdu* rsp) { struct llcp_data_link* dl; unsigned int nr; nr = llcp->info[0] & 0xf; NFC_D("LLCP RNR N(R)=%d", nr); dl = re->llcp_dl[llcp->ssap] + llcp->dsap; dl->v_sa = nr; update_last_saps(re, llcp->ssap, llcp->dsap); *consumed = sizeof(*llcp) + 1; return 0; }
static size_t process_ptype_dm(struct nfc_re* re, const struct llcp_pdu* llcp, size_t len, uint8_t* consumed, struct llcp_pdu* rsp) { struct llcp_data_link* dl; NFC_D("LLCP DM, reason=%d\n", llcp->info[0]); dl = re->llcp_dl[llcp->ssap] + llcp->dsap; dl->status = LLCP_DATA_LINK_DISCONNECTED; update_last_saps(re, llcp->ssap, llcp->dsap); /* consume 1 extra byte for 'reason' field */ *consumed = sizeof(*llcp) + 1; return 0; }
static size_t process_ptype_frmr(struct nfc_re* re, const struct llcp_pdu* llcp, size_t len, uint8_t* consumed, struct llcp_pdu* rsp) { unsigned int flags = (llcp->info[0] >> 4) & 0xf; unsigned int ptype = llcp->info[0] & 0xf; unsigned int v_s = (llcp->info[2] >> 4) & 0xf; unsigned int v_r = llcp->info[2] & 0xf; unsigned int v_sa = (llcp->info[3] >> 4) & 0xf; unsigned int v_ra = llcp->info[3] & 0xf; NFC_D("LLCP FRMR flags=%x ptype=%u sequence=%u v_s=%u v_r=%u v_sa=%u " "v_sr=%u\n", flags, ptype, llcp->info[1], v_s, v_r, v_sa, v_ra); update_last_saps(re, llcp->ssap, llcp->dsap); *consumed = sizeof(*llcp) + 4; return 0; }
static size_t process_ptype_connect(struct nfc_re* re, const struct llcp_pdu* llcp, size_t len, uint8_t* consumed, struct llcp_pdu* rsp) { struct llcp_data_link* dl; const uint8_t* opt; assert(re); assert(llcp); assert(consumed); assert(rsp); dl = llcp_init_data_link(re->llcp_dl[llcp->ssap] + llcp->dsap); dl->status = LLCP_DATA_LINK_CONNECTED; *consumed = sizeof(*llcp); len -= *consumed; opt = ((const uint8_t*)llcp) + *consumed; while (len >= 2) { len -= 2; switch (opt[0]) { case LLCP_PARAM_MIUX: if ((opt[1] != 2) || (len < opt[1])) { continue; } { const struct llcp_param_miux* param = (const struct llcp_param_miux*)(opt + 2); dl->miu = param->miux - 128; } NFC_D("LLCP MIU size=%d", dl->miu); break; case LLCP_PARAM_RW: if ((opt[1] != 1) || (len < opt[1])) { continue; } { const struct llcp_param_rw* param = (const struct llcp_param_rw*)(opt + 2); dl->rw_r = param->rw; } NFC_D("LLCP remote RW size %d", dl->rw_r); break; case LLCP_PARAM_SN: if (len < opt[1]) { continue; } NFC_D("requesting LLCP service %.*s\n", opt[1], (const char*)opt+2); break; default: NFC_D("Ignoring unknown LLCP parameter %d\n", opt[0]); break; } } update_last_saps(re, llcp->ssap, llcp->dsap); /* switch DSAP and SSAP in outgoing PDU */ return llcp_create_pdu(rsp, llcp->ssap, LLCP_PTYPE_CC, llcp->dsap); }