1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 #define NX_SOURCE_CODE
12 
13 
14 /* Include necessary system files.  */
15 
16 #include "nx_api.h"
17 #include "nx_ipv6.h"
18 #include "nx_nd_cache.h"
19 
20 
21 
22 
23 #ifdef FEATURE_NX_IPV6
24 /**************************************************************************/
25 /**************************************************************************/
26 /**                                                                       */
27 /** NetX Component                                                        */
28 /**                                                                       */
29 /**   Internet Protocol version 6 Prefix Table (IPv6 prefix table)        */
30 /**                                                                       */
31 /**************************************************************************/
32 /**************************************************************************/
33 
34 
35 
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _nx_ipv6_prefix_list_add_entry                      PORTABLE C      */
42 /*                                                           6.1          */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Yuxin Zhou, Microsoft Corporation                                   */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This is an internal function.  It adds a prefix into the prefix     */
50 /*    table.                                                              */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    ip_ptr                                Pointer to IP control block   */
55 /*    prefix                                128-bit IPv6 prefix.          */
56 /*    prefix_length                         Length of the prefix.         */
57 /*    valid_lifetime                        Life time of this entry.      */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    Status                                NX_SUCCESS: The entry has been*/
62 /*                                             added to the prefix table. */
63 /*                                          NX_OVERFLOW: The prefix table */
64 /*                                             is full.                   */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    None                                                                */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    _nx_icmpv6_process_ra                 ICMPv6 Router Advertisement   */
73 /*                                          process routine.              */
74 /*                                                                        */
75 /*  NOTE                                                                  */
76 /*                                                                        */
77 /*    This function acquires the nx_ipv6_protection mutex.                */
78 /*    Make sure the mutex is not acquired before calling this function.   */
79 /*                                                                        */
80 /*    This function cannot be called from an ISR.                         */
81 /*                                                                        */
82 /*  RELEASE HISTORY                                                       */
83 /*                                                                        */
84 /*    DATE              NAME                      DESCRIPTION             */
85 /*                                                                        */
86 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
87 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
88 /*                                            resulting in version 6.1    */
89 /*                                                                        */
90 /**************************************************************************/
_nx_ipv6_prefix_list_add_entry(NX_IP * ip_ptr,ULONG * prefix,ULONG prefix_length,ULONG valid_lifetime)91 UINT  _nx_ipv6_prefix_list_add_entry(NX_IP *ip_ptr, ULONG *prefix,
92                                      ULONG prefix_length, ULONG valid_lifetime)
93 {
94 
95 INT                   invalid_bits;
96 INT                   i;
97 ULONG                 invalid_mask;
98 NX_IPV6_PREFIX_ENTRY *new_entry;      /* Pointer to the new entry. */
99 NX_IPV6_PREFIX_ENTRY *current;        /* Pointer to the location where the
100                                          new entry is gonig to be inserted before it. */
101 NX_IPV6_PREFIX_ENTRY *prev = NX_NULL; /* Pointer to the location where the
102                                          new entry is gonig to be inserted after it. */
103 
104 
105     /*
106        Insert the entry based on the prefix_length.
107        Maintain longest-match-first.
108      */
109 
110     /* Start with the head of the list. */
111     current = ip_ptr -> nx_ipv6_prefix_list_ptr;
112 
113     /* Find where we should insert the new element. */
114     while (current)
115     {
116 
117         /* Search for the right location based on longest-prefix-match. */
118         if (prefix_length > current -> nx_ipv6_prefix_entry_prefix_length)
119         {
120 
121             /* Find the right location. */
122             break;
123         }
124 
125         /* Check if the entry matches or not.  We start by checking the
126            length of the prefix.  This is a quick test. */
127         if (prefix_length == current -> nx_ipv6_prefix_entry_prefix_length)
128         {
129 
130             /* If the prefix_length is the same, check whether these
131                two prefixes are the same.  If they are the same, we
132                don't need to create a new entry. */
133             if (CHECK_IPV6_ADDRESSES_SAME(prefix, current -> nx_ipv6_prefix_entry_network_address))
134             {
135 
136                 /* We have the same entry.  Just update the
137                    valid_lifetime field, according to 5.5.3(e) in RFC 4862. */
138                 if ((valid_lifetime > 2 * 60 * 60) || /* if received lifetime is greater than 2 hours */
139                     (valid_lifetime > current -> nx_ipv6_prefix_entry_valid_lifetime))
140                 {
141 
142                     current -> nx_ipv6_prefix_entry_valid_lifetime = valid_lifetime;
143                 }
144                 else if (current -> nx_ipv6_prefix_entry_valid_lifetime <= 2 * 60 * 60)
145                 {
146 
147                     /* Do nothing. */
148                 }
149                 else
150                 {
151                     current -> nx_ipv6_prefix_entry_valid_lifetime = 2 * 60 * 60;
152                 }
153 
154                 /* The entry is already in the table and is still valid.
155                    No need to update.  Just return it.*/
156 
157                 return(NX_DUPLICATED_ENTRY);
158             }
159         }
160 
161         /* Move to next entry. */
162         prev = current;
163         current = current -> nx_ipv6_prefix_entry_next;
164     }
165 
166     /* We fall into this case if prefix length is greater than
167        the prefix length of the current entry.  So we
168        need to insert it in front of it. */
169 
170     /* Make sure the list is not full. */
171     if (ip_ptr -> nx_ipv6_prefix_entry_free_list == NX_NULL)
172     {
173         return(NX_OVERFLOW);
174     }
175 
176     /* Get a new entry from the free list. */
177     new_entry = ip_ptr -> nx_ipv6_prefix_entry_free_list;
178 
179     /* Move free list to the next element. */
180     ip_ptr -> nx_ipv6_prefix_entry_free_list = new_entry -> nx_ipv6_prefix_entry_next;
181 
182     if (ip_ptr -> nx_ipv6_prefix_entry_free_list)
183     {
184         ip_ptr -> nx_ipv6_prefix_entry_free_list -> nx_ipv6_prefix_entry_prev = NX_NULL;
185     }
186 
187     /* Fill information into the new entry */
188     COPY_IPV6_ADDRESS(prefix, new_entry -> nx_ipv6_prefix_entry_network_address);
189     new_entry -> nx_ipv6_prefix_entry_prefix_length = prefix_length;
190     new_entry -> nx_ipv6_prefix_entry_valid_lifetime = valid_lifetime;
191 
192     /* Zero out the bits in the prefix after the prefix length */
193     invalid_bits = (INT)(128 - prefix_length);
194     for (i = 3; i >= 0; i--)
195     {
196 
197         if (invalid_bits <= 0)
198         {
199             break;
200         }
201         if (invalid_bits < 32)
202         {
203             invalid_mask = (ULONG)(~(((ULONG)1 << invalid_bits) - 1));
204         }
205         else
206         {
207             invalid_mask = 0;
208         }
209 
210         new_entry -> nx_ipv6_prefix_entry_network_address[i] &= invalid_mask;
211 
212         invalid_bits -= 32;
213     }
214 
215     /* Insert the new entry between prev and current. */
216     new_entry -> nx_ipv6_prefix_entry_prev = prev;
217     new_entry -> nx_ipv6_prefix_entry_next = current;
218     if (current)
219     {
220         current -> nx_ipv6_prefix_entry_prev = new_entry;
221     }
222     if (prev)
223     {
224         prev -> nx_ipv6_prefix_entry_next = new_entry;
225     }
226     else
227     {
228         ip_ptr -> nx_ipv6_prefix_list_ptr = new_entry;
229     }
230 
231     /* All done. */
232     return(NX_SUCCESS);
233 }
234 
235 
236 #endif /* FEATURE_NX_IPV6 */
237 
238