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 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Component                                                        */
17 /**                                                                       */
18 /**   Internet Protocol (IP)                                              */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "nx_ipv6.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nxd_ipv6_address_set                               PORTABLE C      */
37 /*                                                           6.1.11       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function sets the IP address and the prefix length for the     */
45 /*    supplied IP instance.                                               */
46 /*                                                                        */
47 /*    For the IPv6 address, an application is only allowed to change the  */
48 /*    global IP address.  The link local address is generated through the */
49 /*    underlying interface address, therefore cannot be reconfigured by   */
50 /*    user level applications.                                            */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    ip_ptr                                IP control block pointer      */
55 /*    interface_index                       The index to the physical     */
56 /*                                            interface this address      */
57 /*                                            belongs to                  */
58 /*    ip_address                            Pointer to IP address         */
59 /*                                            structure                   */
60 /*    prefix_length                         Prefix length                 */
61 /*    address_index                         Index to the IPv6 address     */
62 /*                                            table                       */
63 /*                                                                        */
64 /*  OUTPUT                                                                */
65 /*                                                                        */
66 /*    NX_SUCCESS                            Completion status             */
67 /*                                                                        */
68 /*  CALLS                                                                 */
69 /*                                                                        */
70 /*    _nx_ipv6_multicast_join               Multicast group join service  */
71 /*    [ipv6_address_change_notify]          User callback function        */
72 /*    tx_mutex_get                          Get protection mutex          */
73 /*    tx_mutex_put                          Put protection mutex          */
74 /*                                                                        */
75 /*  CALLED BY                                                             */
76 /*                                                                        */
77 /*    Application Code                                                    */
78 /*                                                                        */
79 /*  RELEASE HISTORY                                                       */
80 /*                                                                        */
81 /*    DATE              NAME                      DESCRIPTION             */
82 /*                                                                        */
83 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
84 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
85 /*                                            resulting in version 6.1    */
86 /*  04-25-2022     Yuxin Zhou               Modified comment(s), and      */
87 /*                                            added internal ip address   */
88 /*                                            change notification,        */
89 /*                                            resulting in version 6.1.11 */
90 /*                                                                        */
91 /**************************************************************************/
_nxd_ipv6_address_set(NX_IP * ip_ptr,UINT interface_index,NXD_ADDRESS * ip_address,ULONG prefix_length,UINT * address_index)92 UINT  _nxd_ipv6_address_set(NX_IP *ip_ptr, UINT interface_index, NXD_ADDRESS *ip_address, ULONG prefix_length, UINT *address_index)
93 {
94 #ifdef FEATURE_NX_IPV6
95 
96 TX_INTERRUPT_SAVE_AREA
97 #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
98 VOID                (*address_change_notify)(NX_IP *, UINT, UINT, UINT, ULONG *);
99 VOID                (*address_change_notify_internal)(NX_IP *, UINT, UINT, UINT, ULONG *);
100 #endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
101 NXD_IPV6_ADDRESS *ipv6_addr;
102 NXD_IPV6_ADDRESS *interface_ipv6_address;
103 UINT              index = (UINT)0xFFFFFFFF;
104 UINT              i;
105 ULONG             multicast_address[4];
106 
107     /* Place protection while the IPv6 address is modified. */
108     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
109 
110     if (ip_address)
111     {
112 
113         /* Perform duplicate address detection.  */
114         for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
115         {
116             if ((ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid) &&
117                 (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[0] == ip_address -> nxd_ip_address.v6[0]) &&
118                 (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[1] == ip_address -> nxd_ip_address.v6[1]) &&
119                 (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[2] == ip_address -> nxd_ip_address.v6[2]) &&
120                 (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[3] == ip_address -> nxd_ip_address.v6[3]))
121             {
122 
123                 /* The IPv6 address already exists.  */
124                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
125                 return(NX_DUPLICATED_ENTRY);
126             }
127         }
128     }
129 
130     /* Find an avaiable IPv6 address structure. */
131     for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
132     {
133         /* Look for invalid entries. */
134         if (!ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid)
135         {
136 
137             /* An available entry is found. */
138             index = i;
139             break;
140         }
141     }
142 
143     if (index == (UINT)0xFFFFFFFF)
144     {
145         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
146         return(NX_NO_MORE_ENTRIES);
147     }
148 
149     if (address_index)
150     {
151         *address_index = index;
152     }
153 
154     /* Pointer to the IPv6 address that needs to be modified. */
155     ipv6_addr = &(ip_ptr -> nx_ipv6_address[index]);
156 
157     /* The address is null.  */
158     if ((!ip_address) && (prefix_length == 10))
159     {
160 
161     /* No address supplied. Assume it is link local address, constructed from the physical interface. */
162     ULONG word2, word3;
163 
164         /* Construct Interface Identifier, following RFC2464, page 3 */
165         /* Assign link local address.
166            LL address is constructed by:
167            0xFE80::{64 bit interface ID}.  See RFC 4291 */
168 
169         word2 = ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_msw << 16 |
170             ((ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0xFF000000) >> 16) | 0xFF;
171 
172         /* Fix the 2nd lower-order bit of the 1st byte, RFC2464, page 3 */
173         word2 = (word2 & 0xFDFFFFFF) | (~(word2 | 0xFDFFFFFF));
174         word3 = (ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0x00FFFFFF) | 0xFE000000;
175 
176         /* Point to interface link list head  */
177         interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;
178 
179         /* Perform link local duplicate address detection.  */
180         while (interface_ipv6_address)
181         {
182             if ((interface_ipv6_address -> nxd_ipv6_address[0] == 0xFE800000) &&
183                 (interface_ipv6_address -> nxd_ipv6_address[1] == 0x00000000) &&
184                 (interface_ipv6_address -> nxd_ipv6_address[2] == word2) &&
185                 (interface_ipv6_address -> nxd_ipv6_address[3] == word3))
186             {
187 
188                 /* The IPv6 address already exists.  */
189                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
190                 return(NX_DUPLICATED_ENTRY);
191             }
192 
193             /* Walk down the list.  */
194             interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
195         }
196 
197         /* Set up the link local address. */
198         ipv6_addr -> nxd_ipv6_address[0] = 0xFE800000;
199         ipv6_addr -> nxd_ipv6_address[1] = 0x00000000;
200         ipv6_addr -> nxd_ipv6_address[2] = word2;
201         ipv6_addr -> nxd_ipv6_address[3] = word3;
202     }
203     else if (ip_address != NX_NULL)
204     {
205         ipv6_addr -> nxd_ipv6_address[0] = ip_address -> nxd_ip_address.v6[0];
206         ipv6_addr -> nxd_ipv6_address[1] = ip_address -> nxd_ip_address.v6[1];
207         ipv6_addr -> nxd_ipv6_address[2] = ip_address -> nxd_ip_address.v6[2];
208         ipv6_addr -> nxd_ipv6_address[3] = ip_address -> nxd_ip_address.v6[3];
209     }
210     else
211     {
212         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
213         return(NX_IP_ADDRESS_ERROR);
214     }
215 
216     ipv6_addr -> nxd_ipv6_address_valid = NX_TRUE;
217     ipv6_addr -> nxd_ipv6_address_type = NX_IP_VERSION_V6;
218     ipv6_addr -> nxd_ipv6_address_prefix_length = (UCHAR)(prefix_length & 0xFF);
219     ipv6_addr -> nxd_ipv6_address_next = NX_NULL;
220 
221     /* Attach to the interface.  */
222     ipv6_addr -> nxd_ipv6_address_attached = &ip_ptr -> nx_ip_interface[interface_index];
223 
224     /* Point to interface link list head  */
225     interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;
226 
227     /* Walk to the end of the list.  */
228     while (interface_ipv6_address)
229     {
230 
231         /* If the next entry does not exist, we already reach the end of the list.
232             Add the IPv6 address towards the end. */
233         if (interface_ipv6_address -> nxd_ipv6_address_next)
234         {
235             interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
236         }
237         else
238         {
239             interface_ipv6_address -> nxd_ipv6_address_next = ipv6_addr;
240             break;
241         }
242     }
243 
244     /* Check whether the head is NULL  */
245     if (interface_ipv6_address == NX_NULL)
246     {
247         /* This interface does not have IPv6 addresses yet.  */
248         ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head = ipv6_addr;
249     }
250 
251     /* If trace is enabled, insert this event into the trace buffer.  */
252     NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INTERFACE_ADDRESS_SET, ip_ptr, ipv6_addr -> nxd_ipv6_address[3], prefix_length, index, NX_TRACE_IP_EVENTS, 0, 0);
253 
254     /* Set the configuration type to manual. */
255     ipv6_addr -> nxd_ipv6_address_ConfigurationMethod = NX_IPV6_ADDRESS_MANUAL_CONFIG;
256 
257     /* Release the IP protection.  nx_ipv6_multicast_join would need to obtain the mutex. */
258     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
259     /* Join the solicited-node multicast group */
260     /* FF02::1:FFXX:XXXX */
261     SET_SOLICITED_NODE_MULTICAST_ADDRESS(multicast_address, ipv6_addr -> nxd_ipv6_address);
262     _nx_ipv6_multicast_join(ip_ptr, &multicast_address[0], ipv6_addr -> nxd_ipv6_address_attached);
263 
264     /* Obtain the IP protection again. */
265     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
266 
267     TX_DISABLE
268 #ifndef NX_DISABLE_IPV6_DAD
269 
270     /* If ICMPv6 is enabled, mark the address as tentative, per RFC2462.
271        If DAD is not enabled, start the address in VALID state. */
272     if (ip_ptr -> nx_ip_icmpv6_packet_process)
273     {
274 
275         /* Start DAD */
276         ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_TENTATIVE;
277         ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = NX_IPV6_DAD_TRANSMITS;
278 
279         /* If trace is enabled, log the start of DAD process. */
280         NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INITIATE_DAD_PROCESS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
281     }
282     else
283     {
284 
285         /* If ICMPv6 is not enabled on this interface, the DAD process is eliminated,
286            so mark the input IP address directly as valid. */
287         ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_VALID;
288         ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = 0;
289     }
290 #else
291     /* Set the input address as valid. */
292     ipv6_addr -> nxd_ipv6_address_state                     = NX_IPV6_ADDR_STATE_VALID;
293 #endif
294 
295     /* Restore interrupts.  */
296     TX_RESTORE
297 #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
298     /* Pickup the current notification callback and additional information pointers.  */
299     address_change_notify =  ip_ptr -> nx_ipv6_address_change_notify;
300     address_change_notify_internal =  ip_ptr -> nx_ipv6_address_change_notify_internal;
301 #endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
302     /* Release the protection while the IPv6 address is modified. */
303     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
304 
305 #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
306     /* Is the application configured for notification of address changes and/or
307        prefix_length change?  */
308     if (address_change_notify)
309     {
310 
311         /* Yes, call the application's address change notify function.  */
312         (address_change_notify)(ip_ptr, NX_IPV6_ADDRESS_MANUAL_CONFIG, interface_index, index, &ipv6_addr -> nxd_ipv6_address[0]);
313     }
314 
315     /* Is the internal application configured for notification of address changes and/or
316        prefix_length change?  */
317     if ((address_change_notify_internal) && (ipv6_addr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID))
318     {
319 
320         /* Yes, call the internal application's address change notify function.  */
321         (address_change_notify_internal)(ip_ptr, NX_IPV6_ADDRESS_MANUAL_CONFIG, interface_index, index, &ipv6_addr -> nxd_ipv6_address[0]);
322     }
323 #endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
324 
325     /* Return completion status.  */
326     return(NX_SUCCESS);
327 
328 #else /* !FEATURE_NX_IPV6 */
329     NX_PARAMETER_NOT_USED(ip_ptr);
330     NX_PARAMETER_NOT_USED(interface_index);
331     NX_PARAMETER_NOT_USED(ip_address);
332     NX_PARAMETER_NOT_USED(prefix_length);
333     NX_PARAMETER_NOT_USED(address_index);
334 
335     return(NX_NOT_SUPPORTED);
336 
337 #endif /* FEATURE_NX_IPV6 */
338 }
339 
340