#include #include #include #include #include "hook/iobuf.h" #include "iccard/felica.h" #include "util/dprintf.h" #include "util/dump.h" static HRESULT felica_cmd_poll( struct felica *f, struct const_iobuf *req, struct iobuf *res); static HRESULT felica_cmd_get_system_code( struct felica *f, struct const_iobuf *req, struct iobuf *res); static HRESULT felica_cmd_nda_a4( struct felica *f, struct const_iobuf *req, struct iobuf *res); uint64_t felica_get_generic_PMm(void) { /* A FeliCa PMm contains low-level protocol timing information for communicating with a particular IC card. The exact values are not particularly important for our purposes, so we'll just return a hard- coded PMm. This was taken from a SuiCa train pass I bought in Japan. */ return 0x053143454682B7FFULL; } HRESULT felica_transact( struct felica *f, struct const_iobuf *req, struct iobuf *res) { uint64_t IDm; uint8_t code; HRESULT hr; assert(f != NULL); assert(req != NULL); assert(res != NULL); hr = iobuf_read_8(req, &code); if (FAILED(hr)) { return hr; } hr = iobuf_write_8(res, code + 1); if (FAILED(hr)) { return hr; } if (code != FELICA_CMD_POLL) { hr = iobuf_read_be64(req, &IDm); if (FAILED(hr)) { return hr; } if (IDm != f->IDm) { return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } hr = iobuf_write_be64(res, IDm); if (FAILED(hr)) { return hr; } } switch (code) { case FELICA_CMD_POLL: return felica_cmd_poll(f, req, res); case FELICA_CMD_GET_SYSTEM_CODE: return felica_cmd_get_system_code(f, req, res); case FELICA_CMD_NDA_A4: return felica_cmd_nda_a4(f, req, res); default: dprintf("FeliCa: Unimplemented command %02x, payload:\n", code); dump_const_iobuf(req); return E_NOTIMPL; } } static HRESULT felica_cmd_poll( struct felica *f, struct const_iobuf *req, struct iobuf *res) { uint16_t system_code; uint8_t request_code; uint8_t time_slot; HRESULT hr; /* Request: */ hr = iobuf_read_be16(req, &system_code); if (FAILED(hr)) { return hr; } hr = iobuf_read_8(req, &request_code); if (FAILED(hr)) { return hr; } hr = iobuf_read_8(req, &time_slot); if (FAILED(hr)) { return hr; } if (system_code != 0xFFFF && system_code != f->system_code) { return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } // TODO handle other params correctly... /* Response: */ hr = iobuf_write_be64(res, f->IDm); if (FAILED(hr)) { return hr; } hr = iobuf_write_be64(res, f->PMm); if (FAILED(hr)) { return hr; } if (request_code == 0x01) { hr = iobuf_write_be16(res, f->system_code); if (FAILED(hr)) { return hr; } } return S_OK; } static HRESULT felica_cmd_get_system_code( struct felica *f, struct const_iobuf *req, struct iobuf *res) { HRESULT hr; hr = iobuf_write_8(res, 1); /* Number of system codes */ if (FAILED(hr)) { return hr; } hr = iobuf_write_be16(res, f->system_code); if (FAILED(hr)) { return hr; } return S_OK; } static HRESULT felica_cmd_nda_a4( struct felica *f, struct const_iobuf *req, struct iobuf *res) { /* The specification for this command is probably only available under NDA. Returning what the driver seems to want. */ return iobuf_write_8(res, 0); }