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