usbd_rndis.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /**
  2. * @file usbd_rndis.c
  3. * @brief
  4. *
  5. * Copyright (c) 2022 sakumisu
  6. *
  7. * Licensed to the Apache Software Foundation (ASF) under one or more
  8. * contributor license agreements. See the NOTICE file distributed with
  9. * this work for additional information regarding copyright ownership. The
  10. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  11. * "License"); you may not use this file except in compliance with the
  12. * License. You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  18. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  19. * License for the specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. */
  23. #include "usbd_core.h"
  24. #include "usbd_rndis.h"
  25. #include "rndis_protocol.h"
  26. #define RNDIS_INQUIRY_PUT(src, len) (memcpy(infomation_buffer, src, len))
  27. #define RNDIS_INQUIRY_PUT_LE32(value) (*(uint32_t *)infomation_buffer = (value))
  28. /* Device data structure */
  29. struct usbd_rndis_cfg_priv {
  30. uint32_t drv_version;
  31. uint32_t media_status;
  32. uint32_t speed;
  33. uint32_t mtu;
  34. uint32_t net_filter;
  35. usb_eth_stat_t eth_state;
  36. rndis_state_t init_state;
  37. uint8_t mac[6];
  38. uint32_t vendor_id;
  39. uint8_t *vendor_desc;
  40. } usbd_rndis_cfg = { .drv_version = 0x0001,
  41. .media_status = NDIS_MEDIA_STATE_DISCONNECTED,
  42. .mtu = RNDIS_MTU,
  43. .speed = 0,
  44. .init_state = rndis_uninitialized,
  45. .mac = { 0x00, 0x00, 0x5E, 0x00, 0x53, 0x01 },
  46. .vendor_id = 0xffffffff,
  47. .vendor_desc = "CherryUSB" };
  48. /* RNDIS options list */
  49. const uint32_t oid_supported_list[] = {
  50. OID_GEN_SUPPORTED_LIST,
  51. OID_GEN_HARDWARE_STATUS,
  52. OID_GEN_MEDIA_SUPPORTED,
  53. OID_GEN_MEDIA_IN_USE,
  54. OID_GEN_MAXIMUM_FRAME_SIZE,
  55. OID_GEN_LINK_SPEED,
  56. OID_GEN_TRANSMIT_BLOCK_SIZE,
  57. OID_GEN_RECEIVE_BLOCK_SIZE,
  58. OID_GEN_VENDOR_ID,
  59. OID_GEN_VENDOR_DESCRIPTION,
  60. OID_GEN_VENDOR_DRIVER_VERSION,
  61. OID_GEN_CURRENT_PACKET_FILTER,
  62. OID_GEN_MAXIMUM_TOTAL_SIZE,
  63. OID_GEN_PROTOCOL_OPTIONS,
  64. OID_GEN_MAC_OPTIONS,
  65. OID_GEN_MEDIA_CONNECT_STATUS,
  66. OID_GEN_MAXIMUM_SEND_PACKETS,
  67. OID_802_3_PERMANENT_ADDRESS,
  68. OID_802_3_CURRENT_ADDRESS,
  69. OID_802_3_MULTICAST_LIST,
  70. OID_802_3_MAXIMUM_LIST_SIZE,
  71. OID_802_3_MAC_OPTIONS
  72. };
  73. static uint8_t rndis_encapsulated_resp_buffer[CONFIG_RNDIS_RESP_BUFFER_SIZE];
  74. static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len);
  75. // static int rndis_encapsulated_resp_handler(uint8_t *data, uint32_t *len);
  76. static void rndis_notify_rsp(void);
  77. /**
  78. * @brief Handler called for Class requests not handled by the USB stack.
  79. *
  80. * @param setup Information about the request to execute.
  81. * @param len Size of the buffer.
  82. * @param data Buffer containing the request result.
  83. *
  84. * @return 0 on success, negative errno code on fail.
  85. */
  86. static int rndis_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
  87. {
  88. switch (setup->bRequest) {
  89. case CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
  90. rndis_encapsulated_cmd_handler(data, len);
  91. break;
  92. case CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
  93. *data = rndis_encapsulated_resp_buffer;
  94. *len = ((rndis_generic_msg_t *)rndis_encapsulated_resp_buffer)->MessageLength;
  95. break;
  96. default:
  97. return -1;
  98. }
  99. }
  100. static void rndis_notify_rsp(void)
  101. {
  102. uint8_t notify_buf[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  103. usbd_ep_write(0x81, notify_buf, 8, NULL);
  104. }
  105. static int rndis_init_cmd_handler(uint8_t *data, uint32_t len);
  106. static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len);
  107. static int rndis_query_cmd_handler(uint8_t *data, uint32_t len);
  108. static int rndis_set_cmd_handler(uint8_t *data, uint32_t len);
  109. static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len);
  110. static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len);
  111. static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len)
  112. {
  113. switch (((rndis_generic_msg_t *)data)->MessageType) {
  114. case REMOTE_NDIS_INITIALIZE_MSG:
  115. rndis_init_cmd_handler(data, len);
  116. break;
  117. case REMOTE_NDIS_HALT_MSG:
  118. rndis_halt_cmd_handler(data, len);
  119. break;
  120. case REMOTE_NDIS_QUERY_MSG:
  121. rndis_query_cmd_handler(data, len);
  122. break;
  123. case REMOTE_NDIS_SET_MSG:
  124. rndis_set_cmd_handler(data, len);
  125. break;
  126. case REMOTE_NDIS_RESET_MSG:
  127. rndis_reset_cmd_handler(data, len);
  128. break;
  129. case REMOTE_NDIS_KEEPALIVE_MSG:
  130. rndis_keepalive_cmd_handler(data, len);
  131. break;
  132. default:
  133. break;
  134. }
  135. }
  136. static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
  137. {
  138. rndis_initialize_msg_t *cmd = (rndis_initialize_msg_t *)data;
  139. rndis_initialize_cmplt_t *resp;
  140. resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
  141. resp->RequestId = cmd->RequestId;
  142. resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
  143. resp->MessageLength = sizeof(rndis_initialize_cmplt_t);
  144. resp->MajorVersion = RNDIS_MAJOR_VERSION;
  145. resp->MinorVersion = RNDIS_MINOR_VERSION;
  146. resp->Status = RNDIS_STATUS_SUCCESS;
  147. resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
  148. resp->Medium = RNDIS_MEDIUM_802_3;
  149. resp->MaxPacketsPerTransfer = 1;
  150. resp->MaxTransferSize = usbd_rndis_cfg.mtu + ETH_HEADER_SIZE + sizeof(rndis_data_packet_t);
  151. resp->PacketAlignmentFactor = 0;
  152. resp->AfListOffset = 0;
  153. resp->AfListSize = 0;
  154. usbd_rndis_cfg.init_state = rndis_initialized;
  155. rndis_notify_rsp();
  156. return 0;
  157. }
  158. static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len)
  159. {
  160. usbd_rndis_cfg.init_state = rndis_uninitialized;
  161. return 0;
  162. }
  163. static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
  164. {
  165. rndis_query_msg_t *cmd = (rndis_initialize_msg_t *)data;
  166. rndis_query_cmplt_t *resp;
  167. uint8_t *infomation_buffer;
  168. uint32_t infomation_len = 0;
  169. resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
  170. resp->Status = RNDIS_STATUS_SUCCESS;
  171. resp->RequestId = cmd->RequestId;
  172. resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
  173. resp->InformationBufferOffset = 16;
  174. infomation_buffer = (uint8_t *)resp + sizeof(rndis_initialize_cmplt_t);
  175. switch (cmd->Oid) {
  176. case OID_GEN_SUPPORTED_LIST:
  177. RNDIS_INQUIRY_PUT(oid_supported_list, sizeof(oid_supported_list));
  178. infomation_len = sizeof(oid_supported_list);
  179. break;
  180. case OID_GEN_VENDOR_DRIVER_VERSION:
  181. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.drv_version);
  182. infomation_len = 4;
  183. break;
  184. case OID_802_3_CURRENT_ADDRESS:
  185. RNDIS_INQUIRY_PUT(usbd_rndis_cfg.mac, 6);
  186. infomation_len = 6;
  187. break;
  188. case OID_802_3_PERMANENT_ADDRESS:
  189. RNDIS_INQUIRY_PUT(usbd_rndis_cfg.mac, 6);
  190. infomation_len = 6;
  191. break;
  192. case OID_GEN_MEDIA_SUPPORTED:
  193. RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
  194. infomation_len = 4;
  195. break;
  196. case OID_GEN_MEDIA_IN_USE:
  197. RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
  198. infomation_len = 4;
  199. break;
  200. case OID_GEN_PHYSICAL_MEDIUM:
  201. RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
  202. infomation_len = 4;
  203. break;
  204. case OID_GEN_HARDWARE_STATUS:
  205. RNDIS_INQUIRY_PUT_LE32(0);
  206. infomation_len = 4;
  207. break;
  208. case OID_GEN_LINK_SPEED:
  209. RNDIS_INQUIRY_PUT_LE32(RNDIS_LINK_SPEED / 100);
  210. infomation_len = 4;
  211. break;
  212. case OID_GEN_VENDOR_ID:
  213. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.vendor_id);
  214. infomation_len = 4;
  215. break;
  216. case OID_GEN_VENDOR_DESCRIPTION:
  217. RNDIS_INQUIRY_PUT(usbd_rndis_cfg.vendor_desc, strlen(usbd_rndis_cfg.vendor_desc) + 1);
  218. infomation_len = (strlen(usbd_rndis_cfg.vendor_desc) + 1);
  219. break;
  220. case OID_GEN_CURRENT_PACKET_FILTER:
  221. RNDIS_INQUIRY_PUT_LE32(0x00FFFFFF);
  222. infomation_len = 4;
  223. break;
  224. case OID_GEN_MAXIMUM_FRAME_SIZE:
  225. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.mtu);
  226. infomation_len = 4;
  227. break;
  228. case OID_GEN_MAXIMUM_TOTAL_SIZE:
  229. case OID_GEN_TRANSMIT_BLOCK_SIZE:
  230. case OID_GEN_RECEIVE_BLOCK_SIZE:
  231. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.mtu + ETH_HEADER_SIZE + sizeof(rndis_data_packet_t));
  232. infomation_len = 4;
  233. break;
  234. case OID_GEN_MEDIA_CONNECT_STATUS:
  235. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.media_status);
  236. infomation_len = 4;
  237. break;
  238. case OID_GEN_RNDIS_CONFIG_PARAMETER:
  239. RNDIS_INQUIRY_PUT_LE32(0);
  240. infomation_len = 4;
  241. break;
  242. case OID_802_3_MAXIMUM_LIST_SIZE:
  243. RNDIS_INQUIRY_PUT_LE32(1); /* one address */
  244. infomation_len = 4;
  245. break;
  246. case OID_802_3_MULTICAST_LIST:
  247. RNDIS_INQUIRY_PUT_LE32(0xE0000000); /* 224.0.0.0 */
  248. infomation_len = 4;
  249. break;
  250. case OID_802_3_MAC_OPTIONS:
  251. infomation_len = 0;
  252. break;
  253. case OID_GEN_MAC_OPTIONS:
  254. RNDIS_INQUIRY_PUT_LE32(0);
  255. infomation_len = 4;
  256. break;
  257. case OID_802_3_RCV_ERROR_ALIGNMENT:
  258. RNDIS_INQUIRY_PUT_LE32(0);
  259. infomation_len = 4;
  260. break;
  261. case OID_802_3_XMIT_ONE_COLLISION:
  262. RNDIS_INQUIRY_PUT_LE32(0);
  263. infomation_len = 4;
  264. break;
  265. case OID_802_3_XMIT_MORE_COLLISIONS:
  266. RNDIS_INQUIRY_PUT_LE32(0);
  267. infomation_len = 4;
  268. break;
  269. case OID_GEN_XMIT_OK:
  270. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.eth_state.txok);
  271. infomation_len = 4;
  272. break;
  273. case OID_GEN_RCV_OK:
  274. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.eth_state.rxok);
  275. infomation_len = 4;
  276. break;
  277. case OID_GEN_RCV_ERROR:
  278. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.eth_state.rxbad);
  279. infomation_len = 4;
  280. break;
  281. case OID_GEN_XMIT_ERROR:
  282. RNDIS_INQUIRY_PUT_LE32(usbd_rndis_cfg.eth_state.txbad);
  283. infomation_len = 4;
  284. break;
  285. case OID_GEN_RCV_NO_BUFFER:
  286. RNDIS_INQUIRY_PUT_LE32(0);
  287. infomation_len = 4;
  288. break;
  289. default:
  290. resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
  291. USB_LOG_WRN("Unhandled query for Object ID 0x%x\r\n", cmd->Oid);
  292. break;
  293. }
  294. resp->MessageLength = sizeof(rndis_query_cmplt_t) + infomation_len;
  295. resp->InformationBufferLength = infomation_len;
  296. rndis_notify_rsp();
  297. return 0;
  298. }
  299. static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
  300. {
  301. rndis_set_msg_t *cmd = (rndis_set_msg_t *)data;
  302. rndis_set_cmplt_t *resp;
  303. rndis_config_parameter_t *param;
  304. resp = ((rndis_set_cmplt_t *)rndis_encapsulated_resp_buffer);
  305. resp->RequestId = cmd->RequestId;
  306. resp->MessageType = REMOTE_NDIS_SET_CMPLT;
  307. resp->MessageLength = sizeof(rndis_set_cmplt_t);
  308. resp->Status = RNDIS_STATUS_SUCCESS;
  309. switch (cmd->Oid) {
  310. case OID_GEN_RNDIS_CONFIG_PARAMETER:
  311. break;
  312. case OID_GEN_CURRENT_PACKET_FILTER:
  313. if (cmd->InformationBufferLength < sizeof(usbd_rndis_cfg.net_filter)) {
  314. resp->Status = RNDIS_STATUS_INVALID_DATA;
  315. } else {
  316. /* Parameter starts at offset buf_offset of the req_id field */
  317. param = (rndis_config_parameter_t *)((uint8_t *)&cmd->RequestId + cmd->InformationBufferOffset);
  318. //usbd_rndis_cfg.net_filter = param->ParameterNameOffset;
  319. }
  320. break;
  321. case OID_GEN_CURRENT_LOOKAHEAD:
  322. break;
  323. case OID_GEN_PROTOCOL_OPTIONS:
  324. break;
  325. case OID_802_3_MULTICAST_LIST:
  326. break;
  327. case OID_PNP_ADD_WAKE_UP_PATTERN:
  328. case OID_PNP_REMOVE_WAKE_UP_PATTERN:
  329. case OID_PNP_ENABLE_WAKE_UP:
  330. default:
  331. resp->Status = RNDIS_STATUS_FAILURE;
  332. break;
  333. }
  334. rndis_notify_rsp();
  335. return 0;
  336. }
  337. static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
  338. {
  339. rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
  340. rndis_reset_cmplt_t *resp;
  341. resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
  342. resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
  343. resp->MessageLength = sizeof(rndis_reset_cmplt_t);
  344. resp->Status = RNDIS_STATUS_SUCCESS;
  345. resp->AddressingReset = 1;
  346. rndis_notify_rsp();
  347. return 0;
  348. }
  349. static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
  350. {
  351. rndis_keepalive_msg_t *cmd = (rndis_keepalive_msg_t *)data;
  352. rndis_keepalive_cmplt_t *resp;
  353. resp = ((rndis_keepalive_cmplt_t *)rndis_encapsulated_resp_buffer);
  354. resp->RequestId = cmd->RequestId;
  355. resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
  356. resp->MessageLength = sizeof(rndis_keepalive_cmplt_t);
  357. resp->Status = RNDIS_STATUS_SUCCESS;
  358. rndis_notify_rsp();
  359. return 0;
  360. }
  361. static void rndis_notify_handler(uint8_t event, void *arg)
  362. {
  363. switch (event) {
  364. case USBD_EVENT_RESET:
  365. break;
  366. default:
  367. break;
  368. }
  369. }
  370. void usbd_rndis_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
  371. {
  372. static usbd_class_t *last_class = NULL;
  373. if (last_class != devclass) {
  374. last_class = devclass;
  375. usbd_class_register(devclass);
  376. }
  377. intf->class_handler = rndis_class_request_handler;
  378. intf->custom_handler = NULL;
  379. intf->vendor_handler = NULL;
  380. intf->notify_handler = rndis_notify_handler;
  381. usbd_class_add_interface(devclass, intf);
  382. }