blob: cc4ffd1cf03e4a5dfb77a002bf527f4a6ca461be [file] [log] [blame]
Austin Schuh41baf202022-01-01 14:33:40 -08001/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS)
30
31//--------------------------------------------------------------------+
32// INCLUDE
33//--------------------------------------------------------------------+
34#include "common/tusb_common.h"
35#include "cdc_host.h"
36#include "cdc_rndis_host.h"
37
38//--------------------------------------------------------------------+
39// MACRO CONSTANT TYPEDEF
40//--------------------------------------------------------------------+
41#define RNDIS_MSG_PAYLOAD_MAX (1024*4)
42
43CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8];
44CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX];
45
46static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX];
47
48// TODO Microsoft requires message length for any get command must be at least 4096 bytes
49
50//--------------------------------------------------------------------+
51// INTERNAL OBJECT & FUNCTION DECLARATION
52//--------------------------------------------------------------------+
53static tusb_error_t rndis_body_subtask(void);
54static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
55 uint8_t * p_mess, uint32_t mess_length,
56 uint8_t *p_response );
57
58//--------------------------------------------------------------------+
59// APPLICATION API
60//--------------------------------------------------------------------+
61tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6])
62{
63 TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
64 TU_VERIFY( mac_address, TUSB_ERROR_INVALID_PARA);
65
66 memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6);
67
68 return TUSB_ERROR_NONE;
69}
70
71//--------------------------------------------------------------------+
72// IMPLEMENTATION
73//--------------------------------------------------------------------+
74
75// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
76// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
77// forever loop cannot have any return at all.
78OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;)
79{
80 OSAL_TASK_BEGIN
81 rndis_body_subtask();
82 OSAL_TASK_END
83}
84
85static tusb_error_t rndis_body_subtask(void)
86{
87 static uint8_t relative_addr;
88
89 OSAL_SUBTASK_BEGIN
90
91 for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++)
92 {
93
94 }
95
96 osal_task_delay(100);
97
98 OSAL_SUBTASK_END
99}
100
101//--------------------------------------------------------------------+
102// RNDIS-CDC Driver API
103//--------------------------------------------------------------------+
104void rndish_init(void)
105{
106 tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX);
107
108 //------------- Task creation -------------//
109
110 //------------- semaphore creation for notificaiton pipe -------------//
111 for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
112 {
113 rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
114 }
115}
116
117void rndish_close(uint8_t dev_addr)
118{
119 osal_semaphore_reset( rndish_data[dev_addr-1].sem_notification_hdl );
120// tu_memclr(&rndish_data[dev_addr-1], sizeof(rndish_data_t)); TODO need to move semaphore & its handle out before memclr
121}
122
123
124static rndis_msg_initialize_t const msg_init =
125{
126 .type = RNDIS_MSG_INITIALIZE,
127 .length = sizeof(rndis_msg_initialize_t),
128 .request_id = 1, // TODO should use some magic number
129 .major_version = 1,
130 .minor_version = 0,
131 .max_xfer_size = 0x4000 // TODO mimic windows
132};
133
134static rndis_msg_query_t const msg_query_permanent_addr =
135{
136 .type = RNDIS_MSG_QUERY,
137 .length = sizeof(rndis_msg_query_t)+6,
138 .request_id = 1,
139 .oid = RNDIS_OID_802_3_PERMANENT_ADDRESS,
140 .buffer_length = 6,
141 .buffer_offset = 20,
142};
143
144static rndis_msg_set_t const msg_set_packet_filter =
145{
146 .type = RNDIS_MSG_SET,
147 .length = sizeof(rndis_msg_set_t)+4,
148 .request_id = 1,
149 .oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
150 .buffer_length = 4,
151 .buffer_offset = 20,
152};
153
154tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
155{
156 tusb_error_t error;
157
158 OSAL_SUBTASK_BEGIN
159
160 //------------- Message Initialize -------------//
161 memcpy(msg_payload, &msg_init, sizeof(rndis_msg_initialize_t));
162 STASK_INVOKE(
163 send_message_get_response_subtask( dev_addr, p_cdc,
164 msg_payload, sizeof(rndis_msg_initialize_t),
165 msg_payload),
166 error
167 );
168 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
169
170 // TODO currently not support multiple data packets per xfer
171 rndis_msg_initialize_cmplt_t * const p_init_cmpt = (rndis_msg_initialize_cmplt_t *) msg_payload;
172 STASK_ASSERT(p_init_cmpt->type == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS &&
173 p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX);
174 rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size;
175
176 //------------- Message Query 802.3 Permanent Address -------------//
177 memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t));
178 tu_memclr(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address
179
180 STASK_INVOKE(
181 send_message_get_response_subtask( dev_addr, p_cdc,
182 msg_payload, sizeof(rndis_msg_query_t) + 6,
183 msg_payload),
184 error
185 );
186 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
187
188 rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload;
189 STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS);
190 memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6);
191
192 //------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------//
193 memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t));
194 tu_memclr(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags
195 ((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST);
196
197 STASK_INVOKE(
198 send_message_get_response_subtask( dev_addr, p_cdc,
199 msg_payload, sizeof(rndis_msg_set_t) + 4,
200 msg_payload),
201 error
202 );
203 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
204
205 rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload;
206 STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS);
207
208 tusbh_cdc_rndis_mounted_cb(dev_addr);
209
210 OSAL_SUBTASK_END
211}
212
213void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes)
214{
215 if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) )
216 {
217 osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl );
218 }
219}
220
221//--------------------------------------------------------------------+
222// INTERNAL & HELPER
223//--------------------------------------------------------------------+
224static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
225 uint8_t * p_mess, uint32_t mess_length,
226 uint8_t *p_response)
227{
228 tusb_error_t error;
229
230 OSAL_SUBTASK_BEGIN
231
232 //------------- Send RNDIS Control Message -------------//
233 STASK_INVOKE(
234 usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
235 CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number,
236 mess_length, p_mess),
237 error
238 );
239 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
240
241 //------------- waiting for Response Available notification -------------//
242 (void) usbh_edpt_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8);
243 osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error);
244 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
245 STASK_ASSERT(msg_notification[dev_addr-1][0] == 1);
246
247 //------------- Get RNDIS Message Initialize Complete -------------//
248 STASK_INVOKE(
249 usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
250 CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number,
251 RNDIS_MSG_PAYLOAD_MAX, p_response),
252 error
253 );
254 if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
255
256 OSAL_SUBTASK_END
257}
258
259//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
260//{
261// tusb_error_t error;
262//
263// OSAL_SUBTASK_BEGIN
264//
265// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t)
266// {
267// .type = RNDIS_MSG_INITIALIZE,
268// .length = sizeof(rndis_msg_initialize_t),
269// .request_id = 1, // TODO should use some magic number
270// .major_version = 1,
271// .minor_version = 0,
272// .max_xfer_size = 0x4000 // TODO mimic windows
273// };
274//
275//
276//
277// OSAL_SUBTASK_END
278//}
279#endif