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