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