1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /** */
13 /** USBX Component */
14 /** */
15 /** Device RNDIS Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_rndis.h"
27 #include "ux_device_stack.h"
28
29 UX_DEVICE_CLASS_RNDIS_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT
30
31 /* Define list of supported OIDs (ends with zero-terminator) */
32 ULONG ux_device_class_rndis_oid_supported_list[UX_DEVICE_CLASS_RNDIS_OID_SUPPORTED_LIST_LENGTH + 1] =
33 {
34 /* Mandatory general OIDs. */
35 UX_DEVICE_CLASS_RNDIS_OID_GEN_SUPPORTED_LIST,
36 UX_DEVICE_CLASS_RNDIS_OID_GEN_HARDWARE_STATUS,
37 UX_DEVICE_CLASS_RNDIS_OID_GEN_MEDIA_SUPPORTED,
38 UX_DEVICE_CLASS_RNDIS_OID_GEN_MEDIA_IN_USE,
39 UX_DEVICE_CLASS_RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
40 UX_DEVICE_CLASS_RNDIS_OID_GEN_LINK_SPEED,
41 UX_DEVICE_CLASS_RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
42 UX_DEVICE_CLASS_RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
43 UX_DEVICE_CLASS_RNDIS_OID_GEN_VENDOR_ID,
44 UX_DEVICE_CLASS_RNDIS_OID_GEN_VENDOR_DESCRIPTION,
45 UX_DEVICE_CLASS_RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
46 UX_DEVICE_CLASS_RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
47 UX_DEVICE_CLASS_RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
48 UX_DEVICE_CLASS_RNDIS_OID_GEN_MAC_OPTIONS,
49 UX_DEVICE_CLASS_RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
50 UX_DEVICE_CLASS_RNDIS_OID_GEN_PHYSICAL_MEDIUM,
51 UX_DEVICE_CLASS_RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER,
52
53 /* Mandatory statistical OIDs. */
54 UX_DEVICE_CLASS_RNDIS_OID_GEN_XMIT_OK,
55 UX_DEVICE_CLASS_RNDIS_OID_GEN_RCV_OK,
56 UX_DEVICE_CLASS_RNDIS_OID_GEN_XMIT_ERROR,
57 UX_DEVICE_CLASS_RNDIS_OID_GEN_RCV_ERROR,
58 UX_DEVICE_CLASS_RNDIS_OID_GEN_RCV_NO_BUFFER,
59
60 /* Mandatory 802.3 OIDs. */
61 UX_DEVICE_CLASS_RNDIS_OID_802_3_PERMANENT_ADDRESS,
62 UX_DEVICE_CLASS_RNDIS_OID_802_3_CURRENT_ADDRESS,
63 UX_DEVICE_CLASS_RNDIS_OID_802_3_MULTICAST_LIST,
64 UX_DEVICE_CLASS_RNDIS_OID_802_3_MAC_OPTIONS,
65 UX_DEVICE_CLASS_RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
66
67 /* Mandatory 802.3 statistical OIDs. */
68 UX_DEVICE_CLASS_RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
69 UX_DEVICE_CLASS_RNDIS_OID_802_3_XMIT_ONE_COLLISION,
70 UX_DEVICE_CLASS_RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
71
72 0,
73 };
74
75 /**************************************************************************/
76 /* */
77 /* FUNCTION RELEASE */
78 /* */
79 /* _ux_device_class_rndis_initialize PORTABLE C */
80 /* 6.3.0 */
81 /* AUTHOR */
82 /* */
83 /* Chaoqiong Xiao, Microsoft Corporation */
84 /* */
85 /* DESCRIPTION */
86 /* */
87 /* This function initializes the USB RNDIS device. */
88 /* */
89 /* INPUT */
90 /* */
91 /* command Pointer to rndis command */
92 /* */
93 /* OUTPUT */
94 /* */
95 /* Completion Status */
96 /* */
97 /* CALLS */
98 /* */
99 /* _ux_utility_memory_allocate Allocate memory */
100 /* _ux_utility_memory_copy Copy memory */
101 /* _ux_utility_memory_free Free memory */
102 /* _ux_utility_event_flags_create Create Flag group */
103 /* _ux_utility_event_flags_delete Delete Flag group */
104 /* _ux_utility_mutex_create Create mutex */
105 /* _ux_device_mutex_delete Delete mutex */
106 /* _ux_device_semaphore_create Create semaphore */
107 /* _ux_device_semaphore_delete Delete semaphore */
108 /* _ux_device_thread_create Create thread */
109 /* _ux_device_thread_delete Delete thread */
110 /* nx_packet_pool_create Create NetX packet pool */
111 /* nx_packet_pool_delete Delete NetX packet pool */
112 /* */
113 /* CALLED BY */
114 /* */
115 /* USBX Source Code */
116 /* */
117 /* RELEASE HISTORY */
118 /* */
119 /* DATE NAME DESCRIPTION */
120 /* */
121 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
122 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
123 /* verified memset and memcpy */
124 /* cases, used UX prefix to */
125 /* refer to TX symbols instead */
126 /* of using them directly, */
127 /* resulting in version 6.1 */
128 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
129 /* refined macros names, */
130 /* resulting in version 6.1.10 */
131 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
132 /* fixed standalone compile, */
133 /* resulting in version 6.1.11 */
134 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
135 /* fixed parameter/variable */
136 /* names conflict C++ keyword, */
137 /* resulting in version 6.1.12 */
138 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
139 /* removed internal NX pool, */
140 /* resulting in version 6.2.0 */
141 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
142 /* added a new mode to manage */
143 /* endpoint buffer in classes, */
144 /* checked compile options, */
145 /* resulting in version 6.3.0 */
146 /* */
147 /**************************************************************************/
_ux_device_class_rndis_initialize(UX_SLAVE_CLASS_COMMAND * command)148 UINT _ux_device_class_rndis_initialize(UX_SLAVE_CLASS_COMMAND *command)
149 {
150 #if defined(UX_DEVICE_STANDALONE)
151 UX_PARAMETER_NOT_USED(command);
152 return(UX_FUNCTION_NOT_SUPPORTED);
153 #else
154
155 UX_SLAVE_CLASS_RNDIS *rndis;
156 UX_SLAVE_CLASS_RNDIS_PARAMETER *rndis_parameter;
157 UX_SLAVE_CLASS *class_ptr;
158 UINT status = UX_SUCCESS;
159
160
161 /* Compile option checks. */
162 UX_ASSERT(UX_DEVICE_CLASS_RNDIS_MAX_CONTROL_RESPONSE_LENGTH <= UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
163 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
164 UX_ASSERT(UX_DEVICE_CLASS_RNDIS_BULKOUT_BUFFER_SIZE <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
165 UX_ASSERT(UX_DEVICE_CLASS_RNDIS_BULKIN_BUFFER_SIZE <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
166 UX_ASSERT(UX_DEVICE_CLASS_RNDIS_INTERRUPTIN_BUFFER_SIZE <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
167 #endif
168
169 /* Get the class container. */
170 class_ptr = command -> ux_slave_class_command_class_ptr;
171
172 /* Create an instance of the device rndis class. */
173 rndis = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_RNDIS));
174
175 /* Check for successful allocation. */
176 if (rndis == UX_NULL)
177 return(UX_MEMORY_INSUFFICIENT);
178
179 /* Save the address of the RNDIS instance inside the RNDIS container. */
180 class_ptr -> ux_slave_class_instance = (VOID *) rndis;
181
182 /* Get the pointer to the application parameters for the rndis class. */
183 rndis_parameter = command -> ux_slave_class_command_parameter;
184
185 /* Store the start and stop signals if needed by the application. */
186 rndis -> ux_slave_class_rndis_parameter.ux_slave_class_rndis_instance_activate = rndis_parameter -> ux_slave_class_rndis_instance_activate;
187 rndis -> ux_slave_class_rndis_parameter.ux_slave_class_rndis_instance_deactivate = rndis_parameter -> ux_slave_class_rndis_instance_deactivate;
188
189 /* Save the Netx IP passed by the application. */
190 rndis -> ux_slave_class_rndis_nx_ip = rndis_parameter -> ux_slave_class_rndis_parameter_nx_ip;
191
192 /* Save the Netx IP address passed by the application. */
193 rndis -> ux_slave_class_rndis_nx_ip_address = rndis_parameter -> ux_slave_class_rndis_parameter_nx_ip_address;
194
195 /* Save the Netx IP address network mask passed by the application. */
196 rndis -> ux_slave_class_rndis_nx_ip_network_mask = rndis_parameter -> ux_slave_class_rndis_parameter_nx_ip_network_mask;
197
198 /* Copy the local node ID. */
199 _ux_utility_memory_copy(rndis -> ux_slave_class_rndis_local_node_id, rndis_parameter -> ux_slave_class_rndis_parameter_local_node_id,
200 UX_DEVICE_CLASS_RNDIS_NODE_ID_LENGTH); /* Use case of memcpy is verified. */
201
202 /* Copy the remote node ID. */
203 _ux_utility_memory_copy(rndis -> ux_slave_class_rndis_remote_node_id, rndis_parameter -> ux_slave_class_rndis_parameter_remote_node_id,
204 UX_DEVICE_CLASS_RNDIS_NODE_ID_LENGTH); /* Use case of memcpy is verified. */
205
206 /* Store the rest of the parameters as they are in the local instance. */
207 _ux_utility_memory_copy(&rndis -> ux_slave_class_rndis_parameter, rndis_parameter, sizeof (UX_SLAVE_CLASS_RNDIS_PARAMETER)); /* Use case of memcpy is verified. */
208
209 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
210
211 /* Allocate memory for endpoints. */
212 UX_ASSERT(!UX_DEVICE_CLASS_RNDIS_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
213 rndis -> ux_device_class_rndis_endpoint_buffer = _ux_utility_memory_allocate(
214 UX_NO_ALIGN,UX_CACHE_SAFE_MEMORY,
215 UX_DEVICE_CLASS_RNDIS_ENDPOINT_BUFFER_SIZE);
216 if (rndis -> ux_device_class_rndis_endpoint_buffer == UX_NULL)
217 status = UX_MEMORY_INSUFFICIENT;
218 #else
219 status = UX_SUCCESS;
220 #endif
221
222 /* Create a mutex to protect the RNDIS thread and the application messing up the transmit queue. */
223 if (status == UX_SUCCESS)
224 {
225 status = _ux_utility_mutex_create(&rndis -> ux_slave_class_rndis_mutex, "ux_slave_class_rndis_mutex");
226 if (status != UX_SUCCESS)
227 status = UX_MUTEX_ERROR;
228 }
229
230 /* Allocate some memory for the interrupt thread stack. */
231 if (status == UX_SUCCESS)
232 {
233 rndis -> ux_slave_class_rndis_interrupt_thread_stack =
234 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
235
236 /* Check for successful allocation. */
237 if (rndis -> ux_slave_class_rndis_interrupt_thread_stack == UX_NULL)
238
239 /* Set status to memory insufficient. */
240 status = UX_MEMORY_INSUFFICIENT;
241 }
242
243 /* Interrupt endpoint treatment needs to be running in a different thread. So start
244 a new thread. We pass a pointer to the rndis instance to the new thread. This thread
245 does not start until we have a instance of the class. */
246 if (status == UX_SUCCESS)
247 {
248 status = _ux_device_thread_create(&rndis -> ux_slave_class_rndis_interrupt_thread , "ux_slave_class_rndis_interrupt_thread",
249 _ux_device_class_rndis_interrupt_thread,
250 (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) rndis -> ux_slave_class_rndis_interrupt_thread_stack ,
251 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
252 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
253
254 /* Check the creation of this thread. */
255 if (status != UX_SUCCESS)
256 status = UX_THREAD_ERROR;
257 }
258
259 UX_THREAD_EXTENSION_PTR_SET(&(rndis -> ux_slave_class_rndis_interrupt_thread), class_ptr)
260
261 /* Allocate some memory for the bulk out thread stack. */
262 if (status == UX_SUCCESS)
263 {
264 rndis -> ux_slave_class_rndis_bulkout_thread_stack =
265 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
266
267 /* Check for successful allocation. */
268 if (rndis -> ux_slave_class_rndis_bulkout_thread_stack == UX_NULL)
269 status = UX_MEMORY_INSUFFICIENT;
270 }
271
272 /* Bulk endpoint treatment needs to be running in a different thread. So start
273 a new thread. We pass a pointer to the rndis instance to the new thread. This thread
274 does not start until we have a instance of the class. */
275 if (status == UX_SUCCESS)
276 {
277 status = _ux_device_thread_create(&rndis -> ux_slave_class_rndis_bulkout_thread , "ux_slave_class_rndis_bulkout_thread",
278 _ux_device_class_rndis_bulkout_thread,
279 (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) rndis -> ux_slave_class_rndis_bulkout_thread_stack ,
280 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
281 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
282
283 /* Check the creation of this thread. */
284 if (status != UX_SUCCESS)
285 status = UX_THREAD_ERROR;
286 }
287
288 UX_THREAD_EXTENSION_PTR_SET(&(rndis -> ux_slave_class_rndis_bulkout_thread), class_ptr)
289
290 /* Allocate some memory for the bulk in thread stack. */
291 if (status == UX_SUCCESS)
292 {
293 rndis -> ux_slave_class_rndis_bulkin_thread_stack =
294 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
295
296 /* Check for successful allocation. */
297 if (rndis -> ux_slave_class_rndis_bulkin_thread_stack == UX_NULL)
298 status = UX_MEMORY_INSUFFICIENT;
299 }
300
301 /* Bulk endpoint treatment needs to be running in a different thread. So start
302 a new thread. We pass a pointer to the rndis instance to the new thread. This thread
303 does not start until we have a instance of the class. */
304 if (status == UX_SUCCESS)
305 {
306 status = _ux_device_thread_create(&rndis -> ux_slave_class_rndis_bulkin_thread , "ux_slave_class_rndis_bulkin_thread",
307 _ux_device_class_rndis_bulkin_thread,
308 (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) rndis -> ux_slave_class_rndis_bulkin_thread_stack ,
309 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
310 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
311
312 /* Check the creation of this thread. */
313 if (status != UX_SUCCESS)
314 status = UX_THREAD_ERROR;
315 }
316
317 UX_THREAD_EXTENSION_PTR_SET(&(rndis -> ux_slave_class_rndis_bulkin_thread), class_ptr)
318
319 /* Create a event flag group for the rndis class to synchronize with the event interrupt thread. */
320 if (status == UX_SUCCESS)
321 {
322 status = _ux_utility_event_flags_create(&rndis -> ux_slave_class_rndis_event_flags_group, "ux_device_class_rndis_event_flag");
323
324 /* Check status. */
325 if (status != UX_SUCCESS)
326 status = UX_EVENT_ERROR;
327 }
328
329 /* Create a semaphore for protecting the driver entry. */
330 if (status == UX_SUCCESS)
331 {
332 status = _ux_device_semaphore_create(&rndis -> ux_slave_class_rndis_semaphore, "ux_device_class_rndis_semaphore", 1);
333 if (status == UX_SUCCESS)
334
335 /* Return success. */
336 return(UX_SUCCESS);
337
338 /* Semaphore creation error. */
339 status = UX_SEMAPHORE_ERROR;
340 }
341
342 /* Failed! Free up resources. */
343
344 /* Delete semaphore for protecting the driver entry. */
345 if (rndis -> ux_slave_class_rndis_semaphore.tx_semaphore_id != 0)
346 _ux_device_semaphore_delete(&rndis -> ux_slave_class_rndis_semaphore);
347
348 /* Delete rndis -> ux_slave_class_rndis_event_flags_group. */
349 if (rndis -> ux_slave_class_rndis_event_flags_group.tx_event_flags_group_id != 0)
350 _ux_utility_event_flags_delete(&rndis -> ux_slave_class_rndis_event_flags_group);
351
352 /* Delete rndis -> ux_slave_class_rndis_bulkin_thread. */
353 if (rndis -> ux_slave_class_rndis_bulkin_thread.tx_thread_id != 0)
354 _ux_device_thread_delete(&rndis -> ux_slave_class_rndis_bulkin_thread);
355
356 /* Free rndis -> ux_slave_class_rndis_bulkin_thread_stack. */
357 if (rndis -> ux_slave_class_rndis_bulkin_thread_stack)
358 _ux_utility_memory_free(rndis -> ux_slave_class_rndis_bulkin_thread_stack);
359
360 /* Delete rndis -> ux_slave_class_rndis_bulkout_thread. */
361 if (rndis -> ux_slave_class_rndis_bulkout_thread.tx_thread_id != 0)
362 _ux_device_thread_delete(&rndis -> ux_slave_class_rndis_bulkout_thread);
363
364 /* Free rndis -> ux_slave_class_rndis_bulkout_thread_stack. */
365 if (rndis -> ux_slave_class_rndis_bulkout_thread_stack)
366 _ux_utility_memory_free(rndis -> ux_slave_class_rndis_bulkout_thread_stack);
367
368 /* Delete rndis -> ux_slave_class_rndis_interrupt_thread. */
369 if (rndis -> ux_slave_class_rndis_interrupt_thread.tx_thread_id != 0)
370 _ux_device_thread_delete(&rndis -> ux_slave_class_rndis_interrupt_thread);
371
372 /* Free rndis -> ux_slave_class_rndis_interrupt_thread_stack. */
373 if (rndis -> ux_slave_class_rndis_interrupt_thread_stack)
374 _ux_utility_memory_free(rndis -> ux_slave_class_rndis_interrupt_thread_stack);
375
376 /* Delete rndis -> ux_slave_class_rndis_mutex. */
377 if (rndis -> ux_slave_class_rndis_mutex.tx_mutex_id != 0)
378 _ux_device_mutex_delete(&rndis -> ux_slave_class_rndis_mutex);
379
380 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
381 if (rndis -> ux_device_class_rndis_endpoint_buffer != UX_NULL)
382 _ux_utility_memory_free(rndis -> ux_device_class_rndis_endpoint_buffer);
383 #endif
384
385 /* Free memory for rndis instance. */
386 _ux_utility_memory_free(rndis);
387
388 /* Return completion status. */
389 return(status);
390 #endif
391 }
392