1 #include "ux_api.h"
2 #include "ux_system.h"
3 #include "ux_utility.h"
4 #include "ux_network_driver.h"
5 #include "ux_host_class_cdc_ecm.h"
6 #include "ux_device_class_rndis.h"
7 #include "ux_device_class_cdc_ecm.h"
8 #include "ux_test_dcd_sim_slave.h"
9 #include "ux_test_hcd_sim_host.h"
10 #include "ux_test_utility_sim.h"
11 #include "ux_test.h"
12 #include "ux_hcd_sim_host.h"
13 #include "ux_dcd_sim_slave.h"
14 
15 #define DEMO_IP_THREAD_STACK_SIZE           (8*1024)
16 #define HOST_IP_ADDRESS                     IP_ADDRESS(192,168,1,176)
17 #define HOST_SOCKET_PORT_UDP                    45054
18 #define DEVICE_IP_ADDRESS                   IP_ADDRESS(192,168,1,175)
19 #define DEVICE_SOCKET_PORT_UDP                  45055
20 
21 #define PACKET_PAYLOAD                      1400
22 #define PACKET_POOL_SIZE                    (PACKET_PAYLOAD*10000)
23 #define ARP_MEMORY_SIZE                     1024
24 
25 /* Define local constants.  */
26 
27 #define UX_DEMO_STACK_SIZE                  (4*1024)
28 #define UX_USBX_MEMORY_SIZE                 (128*1024)
29 
30 /* Host */
31 
32 static UX_HOST_CLASS                        *class_driver_host;
33 static UX_HOST_CLASS_CDC_ECM                *cdc_ecm_host;
34 static UX_HOST_CLASS_CDC_ECM                **cdc_ecm_host_ptr;
35 static TX_THREAD                            thread_host;
36 static UCHAR                                thread_stack_host[UX_DEMO_STACK_SIZE];
37 static NX_IP                                nx_ip_host;
38 static NX_PACKET_POOL                       packet_pool_host;
39 static NX_UDP_SOCKET                        udp_socket_host;
40 static CHAR                                 *packet_pool_memory_host;
41 static CHAR                                 ip_thread_stack_host[DEMO_IP_THREAD_STACK_SIZE];
42 static CHAR                                 arp_memory_host[ARP_MEMORY_SIZE];
43 
44 /* Device */
45 
46 static TX_THREAD                            thread_device;
47 static UX_HOST_CLASS                        *class_driver_device;
48 static UX_SLAVE_CLASS_RNDIS                 *rndis_device;
49 static UX_SLAVE_CLASS_RNDIS_PARAMETER       rndis_parameter;
50 static UCHAR                                thread_stack_device[UX_DEMO_STACK_SIZE];
51 static NX_IP                                nx_ip_device;
52 static NX_PACKET_POOL                       packet_pool_device;
53 static NX_UDP_SOCKET                        udp_socket_device;
54 static CHAR                                 *packet_pool_memory_device;
55 static CHAR                                 ip_thread_stack_device[DEMO_IP_THREAD_STACK_SIZE];
56 static CHAR                                 arp_memory_device[ARP_MEMORY_SIZE];
57 
58 static UCHAR                                global_is_device_initialized;
59 
60 static ULONG global_basic_test_num_writes_host;
61 static ULONG global_basic_test_num_reads_host;
62 
63 static ULONG global_basic_test_num_writes_device;
64 static ULONG global_basic_test_num_reads_device;
65 
66 /* Define local prototypes and definitions.  */
67 static void thread_entry_host(ULONG arg);
68 static void thread_entry_device(ULONG arg);
69 
70 //#define USE_ZERO_ENDPOINT_SETTING
71 
72 static unsigned char device_framework_high_speed[] = {
73 
74     /* Device Descriptor */
75     0x12, /* bLength */
76     0x01, /* bDescriptorType */
77     0x10, 0x01, /* bcdUSB */
78     0xef, /* bDeviceClass - Depends on bDeviceSubClass */
79     0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */
80     0x01, /* bDeviceProtocol - There's an IAD */
81     0x40, /* bMaxPacketSize0 */
82     0x70, 0x07, /* idVendor */
83     0x42, 0x10, /* idProduct */
84     0x00, 0x01, /* bcdDevice */
85     0x01, /* iManufacturer */
86     0x02, /* iProduct */
87     0x03, /* iSerialNumber */
88     0x01, /* bNumConfigurations */
89 
90     /* Configuration Descriptor */
91     0x09, /* bLength */
92     0x02, /* bDescriptorType */
93 
94 #ifdef USE_ZERO_ENDPOINT_SETTING
95     0x58, 0x00, /* wTotalLength */
96 #else
97     0x4f, 0x00, /* wTotalLength */
98 #endif
99     0x02, /* bNumInterfaces */
100     0x01, /* bConfigurationValue */
101     0x00, /* iConfiguration */
102     0xc0, /* bmAttributes - Self-powered */
103     0x00, /* bMaxPower */
104 
105     /* Interface Association Descriptor */
106     0x08, /* bLength */
107     0x0b, /* bDescriptorType */
108     0x00, /* bFirstInterface */
109     0x02, /* bInterfaceCount */
110     0x02, /* bFunctionClass - CDC - Communication */
111     0x06, /* bFunctionSubClass - ECM */
112     0x00, /* bFunctionProtocol - No class specific protocol required */
113     0x00, /* iFunction */
114 
115     /* Interface Descriptor */
116     0x09, /* bLength */
117     0x04, /* bDescriptorType */
118     0x00, /* bInterfaceNumber */
119     0x00, /* bAlternateSetting */
120     0x01, /* bNumEndpoints */
121     0x02, /* bInterfaceClass - CDC - Communication */
122     0x06, /* bInterfaceSubClass - ECM */
123     0x00, /* bInterfaceProtocol - No class specific protocol required */
124     0x00, /* iInterface */
125 
126     /* CDC Header Functional Descriptor */
127     0x05, /* bLength */
128     0x24, /* bDescriptorType */
129     0x00, /* bDescriptorSubType */
130     0x10, 0x01, /* bcdCDC */
131 
132     /* CDC ECM Functional Descriptor */
133     0x0d, /* bLength */
134     0x24, /* bDescriptorType */
135     0x0f, /* bDescriptorSubType */
136     0x04, /* iMACAddress */
137     0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */
138     0xea, 0x05, /* wMaxSegmentSize */
139     0x00, 0x00, /* wNumberMCFilters */
140     0x00, /* bNumberPowerFilters */
141 
142     /* CDC Union Functional Descriptor */
143     0x05, /* bLength */
144     0x24, /* bDescriptorType */
145     0x06, /* bDescriptorSubType */
146     0x00, /* bmMasterInterface */
147     0x01, /* bmSlaveInterface0 */
148 
149     /* Endpoint Descriptor */
150     0x07, /* bLength */
151     0x05, /* bDescriptorType */
152     0x83, /* bEndpointAddress */
153     0x03, /* bmAttributes - Interrupt */
154     0x08, 0x00, /* wMaxPacketSize */
155     0x08, /* bInterval */
156 
157 #ifdef USE_ZERO_ENDPOINT_SETTING
158     /* Interface Descriptor */
159     0x09, /* bLength */
160     0x04, /* bDescriptorType */
161     0x01, /* bInterfaceNumber */
162     0x00, /* bAlternateSetting */
163     0x00, /* bNumEndpoints */
164     0x0a, /* bInterfaceClass - CDC - Data */
165     0x00, /* bInterfaceSubClass - Should be 0x00 */
166     0x00, /* bInterfaceProtocol - No class specific protocol required */
167     0x00, /* iInterface */
168 
169     /* Interface Descriptor */
170     0x09, /* bLength */
171     0x04, /* bDescriptorType */
172     0x01, /* bInterfaceNumber */
173     0x01, /* bAlternateSetting */
174     0x02, /* bNumEndpoints */
175     0x0a, /* bInterfaceClass - CDC - Data */
176     0x00, /* bInterfaceSubClass - Should be 0x00 */
177     0x00, /* bInterfaceProtocol - No class specific protocol required */
178     0x00, /* iInterface */
179 #else
180     /* Interface Descriptor */
181     0x09, /* bLength */
182     0x04, /* bDescriptorType */
183     0x01, /* bInterfaceNumber */
184     0x00, /* bAlternateSetting */
185     0x02, /* bNumEndpoints */
186     0x0a, /* bInterfaceClass - CDC - Data */
187     0x00, /* bInterfaceSubClass - Should be 0x00 */
188     0x00, /* bInterfaceProtocol - No class specific protocol required */
189     0x00, /* iInterface */
190 #endif
191 
192     /* Endpoint Descriptor */
193     0x07, /* bLength */
194     0x05, /* bDescriptorType */
195     0x02, /* bEndpointAddress */
196     0x02, /* bmAttributes - Bulk */
197     0x40, 0x00, /* wMaxPacketSize */
198     0x00, /* bInterval */
199 
200     /* Endpoint Descriptor */
201     0x07, /* bLength */
202     0x05, /* bDescriptorType */
203     0x81, /* bEndpointAddress */
204     0x02, /* bmAttributes - Bulk */
205     0x40, 0x00, /* wMaxPacketSize */
206     0x00, /* bInterval */
207 
208 };
209 
210 static unsigned char string_framework[] = {
211 
212     /* Manufacturer string descriptor : Index 1 - "Express Logic" */
213         0x09, 0x04, 0x01, 0x0c,
214         0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c,
215         0x6f, 0x67, 0x69, 0x63,
216 
217     /* Product string descriptor : Index 2 - "EL CDCECM Device" */
218         0x09, 0x04, 0x02, 0x10,
219         0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43,
220         0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
221 
222     /* Serial Number string descriptor : Index 3 - "0001" */
223         0x09, 0x04, 0x03, 0x04,
224         0x30, 0x30, 0x30, 0x31,
225 
226     /* MAC Address string descriptor : Index 4 - "001E5841B879" */
227         0x09, 0x04, 0x04, 0x0C,
228         0x30, 0x30, 0x31, 0x45, 0x35, 0x38,
229         0x34, 0x31, 0x42, 0x38, 0x37, 0x39,
230 
231 };
232 
233 static unsigned char *device_framework_full_speed = device_framework_high_speed;
234 #define FRAMEWORK_LENGTH sizeof(device_framework_high_speed)
235 
236     /* Multiple languages are supported on the device, to add
237        a language besides english, the unicode language code must
238        be appended to the language_id_framework array and the length
239        adjusted accordingly. */
240 static unsigned char language_id_framework[] = {
241 
242     /* English. */
243         0x09, 0x04
244     };
245 
246 /* Define local variables.  */
247 
class_cdc_ecm_get_host(void)248 static UINT class_cdc_ecm_get_host(void)
249 {
250 
251 UX_HOST_CLASS   *class;
252 UINT            status;
253 
254     /* Find the main storage container */
255     status =  ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class);
256     if (status != UX_SUCCESS)
257         test_control_return(0);
258 
259     /* We get the first instance of the storage device */
260     do
261     {
262         status =  ux_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host);
263         tx_thread_sleep(10);
264     } while (status != UX_SUCCESS);
265 
266     /* We still need to wait for the cdc-ecm status to be live */
267     while (cdc_ecm_host -> ux_host_class_cdc_ecm_state != UX_HOST_CLASS_INSTANCE_LIVE)
268         tx_thread_sleep(10);
269 
270     return(UX_SUCCESS);
271 }
272 
demo_rndis_instance_activate(VOID * rndis_instance)273 static VOID demo_rndis_instance_activate(VOID *rndis_instance)
274 {
275 
276     /* Save the CDC instance.  */
277     rndis_device = (UX_SLAVE_CLASS_RNDIS *) rndis_instance;
278 }
279 
demo_rndis_instance_deactivate(VOID * rndis_instance)280 static VOID demo_rndis_instance_deactivate(VOID *rndis_instance)
281 {
282 
283     /* Reset the CDC instance.  */
284     rndis_device = UX_NULL;
285 }
286 
read_packet_udp(NX_UDP_SOCKET * udp_socket,ULONG num_reads,CHAR * name)287 static void read_packet_udp(NX_UDP_SOCKET *udp_socket, ULONG num_reads, CHAR *name)
288 {
289 
290 NX_PACKET 	*rcv_packet;
291 ULONG       num_writes_from_peer;
292 
293 #ifndef LOCAL_MACHINE
294     if (num_reads % 100 == 0)
295 #endif
296         stepinfo("%s reading packet# %lu\n", name, num_reads);
297 
298     UX_TEST_CHECK_SUCCESS(nx_udp_socket_receive(udp_socket, &rcv_packet, NX_WAIT_FOREVER));
299 
300     num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr;
301     if (num_writes_from_peer != num_reads)
302         test_control_return(0);
303 
304     UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet));
305 }
306 
write_packet_udp(NX_UDP_SOCKET * udp_socket,NX_PACKET_POOL * packet_pool,ULONG ip_address,ULONG port,ULONG num_writes,CHAR * name)307 static void write_packet_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name)
308 {
309 
310 NX_PACKET 	*out_packet;
311 
312     UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_UDP_PACKET, MS_TO_TICK(1000)));
313 
314     *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes;
315     out_packet->nx_packet_length = sizeof(ULONG);
316     out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length;
317 
318 #ifndef LOCAL_MACHINE
319     if (num_writes % 100 == 0)
320 #endif
321         stepinfo("%s writing packet# %lu\n", name, num_writes);
322 
323     UX_TEST_CHECK_SUCCESS(nx_udp_socket_send(udp_socket, out_packet, ip_address, port));
324 }
325 
326 /* Define what the initial system looks like.  */
327 #ifdef CTEST
test_application_define(void * first_unused_memory)328 void test_application_define(void *first_unused_memory)
329 #else
330 void usbx_rndis_basic_test_application_define(void *first_unused_memory)
331 #endif
332 {
333 
334 CHAR *memory_pointer = first_unused_memory;
335 
336     /* Inform user.  */
337     printf("Running RNDIS Basic Functionality Test.............................. ");
338 
339     stepinfo("\n");
340 
341     /* Initialize USBX Memory. */
342     UX_TEST_CHECK_SUCCESS(ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0));
343     memory_pointer += UX_USBX_MEMORY_SIZE;
344 
345     /* It looks weird if this doesn't have a comment! */
346     ux_utility_error_callback_register(ux_test_error_callback);
347 
348     /* Perform the initialization of the network driver. */
349     UX_TEST_CHECK_SUCCESS(ux_network_driver_init());
350 
351     /* Initialize the NetX system. */
352     nx_system_initialize();
353 
354     /* Now allocate memory for the packet pools. Note that using the memory passed
355        to us by ThreadX is mucho bettero than putting it in global memory because
356        we can reuse the memory for each test. So no more having to worry about
357        running out of memory! */
358     packet_pool_memory_host = memory_pointer;
359     memory_pointer += PACKET_POOL_SIZE;
360     packet_pool_memory_device = memory_pointer;
361     memory_pointer += PACKET_POOL_SIZE;
362 
363     /* Create the host thread. */
364     UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_host, "host thread", thread_entry_host, 0,
365                                            thread_stack_host, UX_DEMO_STACK_SIZE,
366                                            30, 30, 1, TX_AUTO_START));
367 
368     /* Create the slave thread. */
369     UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, 0,
370                                            thread_stack_device, UX_DEMO_STACK_SIZE,
371                                            30, 30, 1, TX_AUTO_START));
372 }
373 
374 /* Needs to be large enough to hold NetX packet data and RNDIS header. */
375 static UCHAR host_bulk_endpoint_transfer_data[16*1024];
376 
my_ux_hcd_sim_host_entry(UX_HCD * hcd,UINT function,VOID * parameter)377 static UINT  my_ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter)
378 {
379 
380 UX_TRANSFER *transfer_request;
381 UX_ENDPOINT *endpoint;
382 
383 
384     if (function == UX_HCD_TRANSFER_REQUEST)
385     {
386 
387         transfer_request = parameter;
388         endpoint = transfer_request->ux_transfer_request_endpoint;
389 
390         /* Bulk out? */
391         if ((endpoint->ux_endpoint_descriptor.bmAttributes == 0x02) &&
392             (endpoint->ux_endpoint_descriptor.bEndpointAddress & 0x80) == 0)
393         {
394 
395             UX_TEST_ASSERT(transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH <= sizeof(host_bulk_endpoint_transfer_data));
396 
397             /* Fix it, now! - we need to add the RNDIS header. */
398 
399             /* Copy that packet payload. */
400             memcpy(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH,
401                    transfer_request->ux_transfer_request_data_pointer,
402                    transfer_request->ux_transfer_request_requested_length);
403 
404             /* Add the RNDIS header to this packet.  */
405 
406             _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE, UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG);
407 
408             _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_LENGTH,
409                                  transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH);
410 
411             _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET,
412                                  UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH - UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET);
413 
414             _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH,
415                                  transfer_request->ux_transfer_request_requested_length);
416 
417             /* The original data pointer points to the packet, so no leak. We also
418                only allow one transfer at a time, so no worries with overriding data. */
419             transfer_request->ux_transfer_request_data_pointer = host_bulk_endpoint_transfer_data;
420             transfer_request->ux_transfer_request_requested_length += UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH;
421         }
422     }
423 
424     return _ux_hcd_sim_host_entry(hcd, function, parameter);
425 }
426 
my_ux_dcd_sim_slave_function(UX_SLAVE_DCD * dcd,UINT function,VOID * parameter)427 static UINT  my_ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter)
428 {
429 
430 UX_SLAVE_TRANSFER   *transfer_request;
431 UX_SLAVE_ENDPOINT   *endpoint;
432 UINT                netx_packet_length;
433 UINT                i;
434 
435 
436     if (function == UX_HCD_TRANSFER_REQUEST)
437     {
438 
439         transfer_request = parameter;
440         endpoint = transfer_request->ux_slave_transfer_request_endpoint;
441 
442         /* Bulk in? */
443         if ((endpoint->ux_slave_endpoint_descriptor.bmAttributes == 0x02) &&
444             (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) != 0)
445         {
446 
447             /* Fix it, now! - we need to remove the RNDIS header. */
448 
449             netx_packet_length = transfer_request->ux_slave_transfer_request_requested_length - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH;
450 
451             /* Just shift the packet over the RNDIS header. */
452             for (i = 0; i < netx_packet_length; i++)
453             {
454 
455                 transfer_request->ux_slave_transfer_request_data_pointer[i] = transfer_request->ux_slave_transfer_request_data_pointer[i + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH];
456             }
457 
458             transfer_request->ux_slave_transfer_request_requested_length = netx_packet_length;
459         }
460     }
461 
462     return _ux_dcd_sim_slave_function(dcd, function, parameter);
463 }
464 
thread_entry_host(ULONG input)465 static void thread_entry_host(ULONG input)
466 {
467 
468 UINT 		    i;
469 UINT 		    num_iters;
470 
471     /* Wait for device to initialize before starting the HCD thread; also, there
472        seems to be some race condition with simultaneous NetX initialization:
473        somehow, device was calling the host CDC-ECM write. */
474     while (!global_is_device_initialized)
475         tx_thread_sleep(10);
476 
477     /* Wait for device to initialize. */
478     while (!global_is_device_initialized)
479         tx_thread_sleep(10);
480 
481     /* Create the IP instance. */
482 
483     UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_host, "NetX Host Packet Pool", PACKET_PAYLOAD, packet_pool_memory_host, PACKET_POOL_SIZE));
484     UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_host, "NetX Host Thread", HOST_IP_ADDRESS, 0xFF000000UL,
485                           &packet_pool_host, _ux_network_driver_entry, ip_thread_stack_host, DEMO_IP_THREAD_STACK_SIZE, 1));
486 
487     /* Setup ARP. */
488 
489     UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_host, (void *)arp_memory_host, ARP_MEMORY_SIZE));
490     UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_host, DEVICE_IP_ADDRESS, 0x0000001E, 0x80032CD8));
491 
492     /* Setup UDP. */
493 
494     UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_host));
495     UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_host, &udp_socket_host, "USB HOST UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20));
496     UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_host, HOST_SOCKET_PORT_UDP, NX_NO_WAIT));
497 
498     /* The code below is required for installing the host portion of USBX. */
499     UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(UX_NULL));
500 
501     /* Register cdc_ecm class.  */
502     UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry));
503 
504     ux_test_ignore_all_errors();
505 
506     /* Register all the USB host controllers available in this system. */
507     UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0));
508 
509     /* Change entry function.  */
510     _ux_system_host->ux_system_host_hcd_array[0].ux_hcd_entry_function = my_ux_hcd_sim_host_entry;
511 
512     /* Find the storage class. */
513     class_cdc_ecm_get_host();
514 
515 	/* Now wait for the link to be up.  */
516     while (cdc_ecm_host -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)
517         tx_thread_sleep(10);
518 
519     for (num_iters = 0; num_iters < 100; num_iters++)
520     {
521 
522         for (i = 0; i < 10; i++)
523             write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host");
524 
525         for (i = 0; i < 10; i++)
526             read_packet_udp(&udp_socket_host, global_basic_test_num_reads_host++, "host");
527     }
528 
529     /* Wait for all transfers to complete. */
530     while (global_basic_test_num_reads_host != 1000 || global_basic_test_num_reads_device != 1000)
531         tx_thread_sleep(10);
532 
533     /* And finally the usbx system resources.  */
534     _ux_system_uninitialize();
535 
536     /* Successful test.  */
537     printf("SUCCESS!\n");
538     test_control_return(0);
539 }
540 
thread_entry_device(ULONG input)541 static void thread_entry_device(ULONG input)
542 {
543 
544 UINT                i;
545 UINT 		        status;
546 UINT                num_iters;
547 UCHAR               *notification_buffer;
548 UX_SLAVE_TRANSFER   *interrupt_transfer;
549 
550     /* Create the IP instance.  */
551 
552     UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_device, "NetX Device Packet Pool", PACKET_PAYLOAD, packet_pool_memory_device, PACKET_POOL_SIZE));
553 
554     UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_device, "NetX Device Thread", DEVICE_IP_ADDRESS, 0xFF000000L, &packet_pool_device,
555                                        _ux_network_driver_entry, ip_thread_stack_device, DEMO_IP_THREAD_STACK_SIZE, 1));
556 
557     /* Setup ARP.  */
558 
559     UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_device, (void *)arp_memory_device, ARP_MEMORY_SIZE));
560     UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_device, HOST_IP_ADDRESS, 0x0000001E, 0x5841B878));
561 
562     /* Setup UDP.  */
563 
564     UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_device));
565     UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_device, &udp_socket_device, "USB DEVICE UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20));
566     UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_device, DEVICE_SOCKET_PORT_UDP, NX_NO_WAIT));
567 
568     /* The code below is required for installing the device portion of USBX. */
569     status = ux_device_stack_initialize(device_framework_high_speed, FRAMEWORK_LENGTH,
570                                         device_framework_full_speed, FRAMEWORK_LENGTH,
571                                         string_framework, sizeof(string_framework),
572                                         language_id_framework, sizeof(language_id_framework),
573                                         UX_NULL);
574     if (status)
575         test_control_return(0);
576 
577     /* Set the parameters for callback when insertion/extraction of a CDC device. */
578     rndis_parameter.ux_slave_class_rndis_instance_activate   =  demo_rndis_instance_activate;
579     rndis_parameter.ux_slave_class_rndis_instance_deactivate =  demo_rndis_instance_deactivate;
580 
581     /* Define a local NODE ID.  */
582     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[0] = 0x00;
583     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[1] = 0x1e;
584     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[2] = 0x58;
585     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[3] = 0x41;
586     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[4] = 0xb8;
587     rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[5] = 0x78;
588 
589     /* Define a remote NODE ID.  */
590     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[0] = 0x00;
591     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[1] = 0x1e;
592     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[2] = 0x58;
593     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[3] = 0x41;
594     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[4] = 0xb8;
595     rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[5] = 0x79;
596 
597     /* Set extra parameters used by the RNDIS query command with certain OIDs.  */
598     rndis_parameter.ux_slave_class_rndis_parameter_vendor_id          =  0x04b4 ;
599     rndis_parameter.ux_slave_class_rndis_parameter_driver_version     =  0x1127;
600     ux_utility_memory_copy(rndis_parameter.ux_slave_class_rndis_parameter_vendor_description, "ELOGIC RNDIS", 12);
601 
602     /* Initialize the device rndis class. This class owns both interfaces. */
603     status =  ux_device_stack_class_register(_ux_system_slave_class_rndis_name, ux_device_class_rndis_entry, 1, 0, &rndis_parameter);
604     if (status)
605         test_control_return(0);
606 
607     /* Initialize the simulated device controller.  */
608     status =  _ux_dcd_sim_slave_initialize();
609     if (status)
610         test_control_return(0);
611 
612     _ux_system_slave->ux_system_slave_dcd.ux_slave_dcd_function = my_ux_dcd_sim_slave_function;
613 
614     global_is_device_initialized = UX_TRUE;
615 
616     while (!rndis_device)
617         tx_thread_sleep(10);
618 
619     while (rndis_device -> ux_slave_class_rndis_link_state != UX_DEVICE_CLASS_RNDIS_LINK_STATE_UP)
620         tx_thread_sleep(10);
621 
622     /* Since host is CDC-ECM, it's waiting for the LINK_UP notification from the
623        interrupt endpoint. RNDIS does not send this, so we have to do it manually. */
624     {
625         interrupt_transfer = &rndis_device->ux_slave_class_rndis_interrupt_endpoint->ux_slave_endpoint_transfer_request;
626 
627         /* Build the Network Notification response.  */
628         notification_buffer = interrupt_transfer->ux_slave_transfer_request_data_pointer;
629 
630         /* Set the request type.  */
631         *(notification_buffer + UX_SETUP_REQUEST_TYPE) = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
632 
633         /* Set the request itself.  */
634         *(notification_buffer + UX_SETUP_REQUEST) = 0;
635 
636         /* Set the value. It is the network link.  */
637         _ux_utility_short_put(notification_buffer + UX_SETUP_VALUE, (USHORT)(rndis_device->ux_slave_class_rndis_link_state));
638 
639         /* Set the Index. It is interface.  The interface used is the DATA interface. Here we simply take the interface number of the CONTROL and add 1 to it
640            as it is assumed the classes are contiguous in number. */
641         _ux_utility_short_put(notification_buffer + UX_SETUP_INDEX, (USHORT)(rndis_device->ux_slave_class_rndis_interface->ux_slave_interface_descriptor.bInterfaceNumber + 1));
642 
643         /* And the length is zero.  */
644         *(notification_buffer + UX_SETUP_LENGTH) = 0;
645 
646         /* Send the request to the device controller.  */
647         status =  _ux_device_stack_transfer_request(interrupt_transfer, UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH,
648                                                             UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH);
649         /* Check error code. */
650         if (status != UX_SUCCESS)
651             test_control_return(0);
652     }
653 
654     for (num_iters = 0; num_iters < 100; num_iters++)
655     {
656 
657         for (i = 0; i < 10; i++)
658             write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, global_basic_test_num_writes_device++, "device");
659 
660         for (i = 0; i < 10; i++)
661             read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device");
662     }
663 }