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