1 #include "tx_api.h"
2 #include "nx_api.h"
3 #include "netx_tahi.h"
4 #if defined(FEATURE_NX_IPV6) && defined(NX_TAHI_ENABLE)
5 #include "nx_udp.h"
6 #include "nx_ip.h"
7 #include "nx_ipv6.h"
8 #include "nxd_dhcpv6_client.h"
9 
10 
11 #define     DEMO_STACK_SIZE     2048
12 #define     TEST_INTERFACE      0
13 #define     DHCPV6_IANA_ID      0xC0DEDBAD
14 
15 static TX_THREAD                dhcpv6_client_thread;
16 static NX_PACKET_POOL           pool_0;
17 static NX_IP                    ip_0;
18 static NX_DHCPV6                dhcp_client;
19 
20 static ULONG                    error_counter;
21 
22 static void dhcpv6_client_thread_entry(ULONG thread_input);
23 extern void test_control_return(UINT status);
24 extern void _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req);
25 extern UINT (*advanced_packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
26 static UINT my_dhcpv6_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
27 static void my_dhcpv6_udp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
28 
29 static ULONG                    original_xid;
30 static UCHAR                    original_cid[18];
31 static UINT                     renew_count;
32 
33 extern TAHI_TEST_SEQ tahi_dhcpv6_01_068[];
34 extern int  tahi_dhcpv6_01_068_size;
35 
36 #ifdef CTEST
test_application_define(void * first_unused_memory)37 VOID test_application_define(void *first_unused_memory)
38 #else
39 void netx_tahi_dhcpv6_test_01_068_define(void * first_unused_memory)
40 #endif
41 {
42 CHAR    *pointer;
43 UINT    status;
44 
45     /* Setup the working pointer.  */
46     pointer = (CHAR *) first_unused_memory;
47 
48     error_counter = 0;
49     renew_count = 0;
50 
51     /* Initialize the NetX system.  */
52     nx_system_initialize();
53 
54     /* Create a packet pool.  */
55     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1536, pointer, 1536*16);
56     pointer = pointer + 1536*16;
57     if(status)
58         error_counter++;
59 
60     /* Create an IP instance.  */
61     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1,2,3,4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_1500,
62                           pointer, 2048, 1);
63     pointer = pointer + 2048;
64 
65     /* Enable IPv6 */
66     status = nxd_ipv6_enable(&ip_0);
67     if(status)
68         error_counter++;
69 
70     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
71     status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
72     pointer = pointer + 1024;
73     if(status)
74         error_counter++;
75 
76     /* Enable ICMP for IP Instance 0 and 1.  */
77     status = nxd_icmp_enable(&ip_0);
78     if(status)
79         error_counter++;
80 
81     status = nx_udp_enable(&ip_0);
82     if(status)
83         error_counter++;
84 
85     /* Enable fragment processing for IP Instance 0.  */
86     status = nx_ip_fragment_enable(&ip_0);
87     if(status)
88         error_counter++;
89 
90     /* Create a DHCPv6 Client. */
91     status = nx_dhcpv6_client_create(&dhcp_client, &ip_0, "DHCPv6 Client", &pool_0, pointer, 2048, NX_NULL, NX_NULL);
92     pointer += 2048;
93     if(status)
94         error_counter++;
95 
96     /* Create the main thread.  */
97     tx_thread_create(&dhcpv6_client_thread, "dhcpv6 client thread", dhcpv6_client_thread_entry, 0,
98                      pointer, DEMO_STACK_SIZE,
99                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
100 
101     pointer = pointer + DEMO_STACK_SIZE;
102 
103 }
104 
dhcpv6_client_thread_entry(ULONG thread_input)105 void dhcpv6_client_thread_entry(ULONG thread_input)
106 {
107 NXD_ADDRESS ipv6_address;
108 UINT        status;
109 
110     status = nxd_ipv6_address_set(&ip_0, 0, NX_NULL, 10, NX_NULL);
111     if(status)
112         error_counter++;
113 
114     /* Create a Link Layer Plus Time DUID for the DHCPv6 Client. Set time ID field
115        to NULL; the DHCPv6 Client API will supply one. */
116     status = nx_dhcpv6_create_client_duid(&dhcp_client, NX_DHCPV6_DUID_TYPE_LINK_TIME,
117             NX_DHCPV6_HW_TYPE_IEEE_802, 0);
118     if(status)
119         error_counter++;
120 
121     /* Create the DHCPv6 client's Identity Association (IA-NA) now. */
122     status = nx_dhcpv6_create_client_iana(&dhcp_client, DHCPV6_IANA_ID, 0xFFFFFFFF,  0xFFFFFFFF);
123     if(status)
124         error_counter++;
125 
126     memset(&ipv6_address,0x0, sizeof(NXD_ADDRESS));
127     ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
128 
129     /* Create an IA address option. */
130     if((ipv6_address.nxd_ip_address.v6[0] != 0) ||
131        (ipv6_address.nxd_ip_address.v6[1] != 0) ||
132        (ipv6_address.nxd_ip_address.v6[2] != 0) ||
133        (ipv6_address.nxd_ip_address.v6[3] != 0))
134     {
135 
136         status = nx_dhcpv6_create_client_ia(&dhcp_client, &ipv6_address, 0xFFFFFFFF,
137                 0xFFFFFFFF);
138 
139         if (status != NX_SUCCESS)
140         {
141             return;
142         }
143     }
144 
145     /* Set the list of desired options to enabled. */
146     nx_dhcpv6_request_option_timezone(&dhcp_client, NX_TRUE);
147     nx_dhcpv6_request_option_DNS_server(&dhcp_client, NX_TRUE);
148     nx_dhcpv6_request_option_time_server(&dhcp_client, NX_TRUE);
149     nx_dhcpv6_request_option_domain_name(&dhcp_client, NX_TRUE);
150 
151     /* Wait to finish the DAD. */
152     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
153 
154     /* Start the NetX DHCPv6 Client.  */
155     status =  nx_dhcpv6_start(&dhcp_client);
156 
157     advanced_packet_process_callback = my_dhcpv6_packet_process;
158     ip_0.nx_ip_udp_packet_receive = my_dhcpv6_udp_packet_receive;
159 
160     status = nx_dhcpv6_request_solicit(&dhcp_client);
161 
162     netx_tahi_run_test_case(&ip_0, &tahi_dhcpv6_01_068[0], tahi_dhcpv6_01_068_size);
163 
164     nx_dhcpv6_client_delete(&dhcp_client);
165 
166     test_control_return(0xdeadbeef);
167 }
168 
169 
my_dhcpv6_packet_process(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT * operation_ptr,UINT * delay_ptr)170 UINT my_dhcpv6_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr)
171 {
172 NX_UDP_HEADER   *udp_header_ptr;
173 ULONG           src_dst_port;
174 ULONG           message_type;
175 NX_IPV6_HEADER  *ip_header;
176 ULONG           checksum;
177 ULONG           *ip_src_addr, *ip_dest_addr;
178 UCHAR           cid[18] = {0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01,
179                            0xac, 0x7d, 0x87, 0x3a, 0x00, 0x11, 0x22, 0x33,
180                            0x44, 0x56};
181 
182 
183     udp_header_ptr = (NX_UDP_HEADER*)(packet_ptr -> nx_packet_prepend_ptr + 40);
184     src_dst_port = udp_header_ptr -> nx_udp_header_word_0;
185     NX_CHANGE_ULONG_ENDIAN(src_dst_port);
186 
187 
188     /* From port 546(client) to 547(server). Check if this is a DHCPv6 packet sent from client to server*/
189     if(src_dst_port == 0x02220223)
190     {
191         packet_ptr -> nx_packet_prepend_ptr += 40;
192         packet_ptr -> nx_packet_length -= 40;
193 
194         /* Get IP address for checksum computing. */
195         ip_header = (NX_IPV6_HEADER *)(packet_ptr -> nx_packet_ip_header);
196         NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header -> nx_ip_header_source_ip);
197         NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header -> nx_ip_header_destination_ip);
198         ip_src_addr  = &(ip_header -> nx_ip_header_source_ip[0]);
199         ip_dest_addr = &(ip_header -> nx_ip_header_destination_ip[0]);
200 
201         /* Get message type. */
202         _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 8, 1, &message_type);
203 
204         if(message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
205         {
206             /* Record original xid, modify the xid to be the same with Tahi test packet. */
207             _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 9, 3, &original_xid);
208             *(ULONG *)(packet_ptr -> nx_packet_prepend_ptr + 8) = 0x12f03e01;
209         }
210         else if(message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST)
211         {
212             /* Record original xid, modify the xid to be the same with Tahi test packet. */
213             _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 9, 3, &original_xid);
214             *(ULONG *)(packet_ptr -> nx_packet_prepend_ptr + 8) = 0x900e0803;
215         }
216         else if((message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) && (renew_count == 0))
217         {
218             /* Record original xid, modify the xid to be the same with Tahi test packet. */
219             _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 9, 3, &original_xid);
220             *(ULONG *)(packet_ptr -> nx_packet_prepend_ptr + 8) = 0x66915200 + message_type;
221             renew_count++;
222         }
223         else if((message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
224                 (message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
225         {
226 
227             /* Record original xid, modify the xid to be the same with Tahi test packet. */
228             _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 9, 3, &original_xid);
229             *(ULONG *)(packet_ptr -> nx_packet_prepend_ptr + 8) = 0xa4e49600 + message_type;
230         }
231 
232         /* Record original cid, modify the cid to be the same with Tahi test packet. */
233         memcpy(original_cid, (packet_ptr -> nx_packet_prepend_ptr + 12), 18);
234         memcpy(packet_ptr -> nx_packet_prepend_ptr + 12, cid, 18);
235 
236 
237         /* Compute the checksum. */
238         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
239 
240         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & 0xFFFF0000;
241 
242         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
243 
244         /* Yes, we need to compute the UDP checksum.  */
245         checksum = _nx_ip_checksum_compute(packet_ptr,
246                 NX_PROTOCOL_UDP,
247                 packet_ptr -> nx_packet_length,
248                 ip_src_addr,
249                 ip_dest_addr);
250         checksum = ~checksum & NX_LOWER_16_MASK;
251 
252         /* If the computed checksum is zero, it is transmitted as all ones. */
253         /* RFC 768, page 2. */
254         if(checksum == 0)
255             checksum = 0xFFFF;
256 
257         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
258 
259         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & 0xFFFF0000;
260 
261         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
262 
263         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
264 
265         packet_ptr -> nx_packet_prepend_ptr -= 40;
266         packet_ptr -> nx_packet_length += 40;
267 
268         NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header -> nx_ip_header_source_ip);
269         NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header -> nx_ip_header_destination_ip);
270     }
271 
272     return NX_TRUE;
273 
274 }
275 
my_dhcpv6_udp_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)276 void    my_dhcpv6_udp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
277 {
278 
279 ULONG                   *ip_src_addr, *ip_dest_addr;
280 ULONG                   dst_port;
281 NX_UDP_HEADER           *udp_header_ptr;
282 ULONG                   checksum;
283 NX_IPV6_HEADER          *ip_header;
284 ULONG                   message_type;
285 
286     udp_header_ptr = (NX_UDP_HEADER*)(packet_ptr -> nx_packet_prepend_ptr);
287     dst_port = udp_header_ptr -> nx_udp_header_word_0;
288     NX_CHANGE_ULONG_ENDIAN(dst_port);
289 
290     /* Check if this is a DHCPv6 packet sent to client. */
291     if((dst_port & 0x0000FFFF) == 0x00000222)
292     {
293 
294         /* Get IP address for checksum computing. */
295         ip_header = (NX_IPV6_HEADER *)(packet_ptr -> nx_packet_ip_header);
296         ip_src_addr  = &(ip_header -> nx_ip_header_source_ip[0]);
297         ip_dest_addr= &(ip_header -> nx_ip_header_destination_ip[0]);
298 
299 
300         /* Modify the xid and cid. */
301         _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr + 8, 1, &message_type);
302         NX_CHANGE_ULONG_ENDIAN(original_xid);
303         *(ULONG *)(packet_ptr -> nx_packet_prepend_ptr + 8) = original_xid + message_type;
304         memcpy(packet_ptr -> nx_packet_prepend_ptr + 12, original_cid, 18);
305 
306 
307         /* Compute the checksum. */
308         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
309 
310         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & 0xFFFF0000;
311 
312         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
313 
314         /* Yes, we need to compute the UDP checksum.  */
315         checksum = _nx_ip_checksum_compute(packet_ptr,
316                 NX_PROTOCOL_UDP,
317                 packet_ptr -> nx_packet_length,
318                 ip_src_addr,
319                 ip_dest_addr);
320         checksum = ~checksum & NX_LOWER_16_MASK;
321 
322         /* If the computed checksum is zero, it is transmitted as all ones. */
323         /* RFC 768, page 2. */
324         if(checksum == 0)
325             checksum = 0xFFFF;
326 
327         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
328 
329         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & 0xFFFF0000;
330 
331         udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
332 
333         NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
334     }
335 
336     _nx_udp_packet_receive(ip_ptr, packet_ptr);
337 
338 }
339 #endif
340