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
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Component */
16 /** */
17 /** Internet Protocol (IP) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SOURCE_CODE
23
24 /* Include necessary system files. */
25
26 #include "nx_api.h"
27 #include "nx_tcp.h"
28 #include "nx_arp.h"
29 #include "nx_igmp.h"
30 #include "nx_ip.h"
31 #include "nx_packet.h"
32 #ifdef FEATURE_NX_IPV6
33 #include "nx_icmpv6.h"
34 #endif /* FEATURE_NX_IPV6 */
35
36 /**************************************************************************/
37 /* */
38 /* FUNCTION RELEASE */
39 /* */
40 /* _nx_ip_interface_detach PORTABLE C */
41 /* 6.1 */
42 /* AUTHOR */
43 /* */
44 /* Yuxin Zhou, Microsoft Corporation */
45 /* */
46 /* DESCRIPTION */
47 /* */
48 /* This function detaches a physical network interface from the IP */
49 /* instance. */
50 /* */
51 /* INPUT */
52 /* */
53 /* ip_ptr Pointer to IP control block */
54 /* index IP interface index */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* status Completion status */
59 /* */
60 /* CALLS */
61 /* */
62 /* tx_mutex_get Obtain protection mutex */
63 /* tx_mutex_put Release protection mutex */
64 /* _nx_tcp_socket_connection_reset Reset TCP connection */
65 /* _nx_arp_interface_entries_delete Remove specified ARP entries */
66 /* _nx_invalidate_destination_entry Invalidate the entry in the */
67 /* destination */
68 /* _nx_nd_cache_interface_entries_delete Delete ND cache entries */
69 /* associated with specific */
70 /* interface */
71 /* link_driver_entry Link driver */
72 /* memset Zero out the interface */
73 /* */
74 /* CALLED BY */
75 /* */
76 /* Application */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
83 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
84 /* resulting in version 6.1 */
85 /* */
86 /**************************************************************************/
_nx_ip_interface_detach(NX_IP * ip_ptr,UINT index)87 UINT _nx_ip_interface_detach(NX_IP *ip_ptr, UINT index)
88 {
89
90 NX_INTERFACE *interface_ptr;
91 NX_IP_DRIVER driver_request;
92 NX_TCP_SOCKET *socket_ptr;
93 NXD_IPV6_ADDRESS *next_ipv6_address;
94 NXD_IPV6_ADDRESS *ipv6_address;
95 UINT i;
96 #ifdef NX_ENABLE_IP_STATIC_ROUTING
97 UINT j;
98 #endif
99
100 #ifdef FEATURE_NX_IPV6
101 NX_IPV6_DEFAULT_ROUTER_ENTRY *rt_entry;
102 #endif
103
104
105 interface_ptr = &(ip_ptr -> nx_ip_interface[index]);
106
107 /* Check interface status. */
108 if (interface_ptr -> nx_interface_valid == NX_FALSE)
109 {
110
111 /* Invalid interface. */
112 return(NX_INVALID_INTERFACE);
113 }
114
115 /* Obtain the IP internal mutex before calling the driver. */
116 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
117
118 /* Loop through the list of created TCP sockets for this IP instance. */
119 socket_ptr = ip_ptr -> nx_ip_tcp_created_sockets_ptr;
120 if (socket_ptr != NX_NULL)
121 {
122 do
123 {
124 /* Reset TCP connection which is established or in progress on this interface. */
125 if (socket_ptr -> nx_tcp_socket_connect_interface == interface_ptr)
126 {
127 _nx_tcp_socket_connection_reset(socket_ptr);
128 }
129
130 /* Move to the next. */
131 socket_ptr = socket_ptr -> nx_tcp_socket_created_next;
132 } while (socket_ptr != ip_ptr -> nx_ip_tcp_created_sockets_ptr);
133 }
134
135 /* Release the IP internal mutex. */
136 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
137
138 #ifndef NX_DISABLE_IPV4
139 /* Remove ARP entries associated with this interface from ARP table. */
140 _nx_arp_interface_entries_delete(ip_ptr, index);
141 #endif /* !NX_DISABLE_IPV4 */
142
143 #ifdef FEATURE_NX_IPV6
144 /* Delete ND cache entries associated with this interface. */
145 _nx_nd_cache_interface_entries_delete(ip_ptr, index);
146 #endif /* FEATURE_NX_IPV6 */
147
148 /* Obtain the IP internal mutex before calling the driver. */
149 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
150
151 #ifndef NX_DISABLE_IPV4
152 #ifdef NX_ENABLE_IP_STATIC_ROUTING
153 /* Remove router iterms associated with the interface that will be detached from route table. */
154 for (i = 0; i < ip_ptr -> nx_ip_routing_table_entry_count; i++)
155 {
156
157 /* Is this router iterm related to the interface to be detached. */
158 if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface == interface_ptr)
159 {
160
161 /* Yes, we need to remove this iterm. */
162 /* If the entry is not the last one, we need to shift the table to fill the hole. */
163 for (j = i; j < ip_ptr -> nx_ip_routing_table_entry_count; j++)
164 {
165 ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_dest_ip =
166 ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_dest_ip;
167 ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_net_mask =
168 ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_net_mask;
169 ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_next_hop_address =
170 ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_next_hop_address;
171 ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_ip_interface =
172 ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_ip_interface;
173 }
174
175 ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_dest_ip = 0;
176 ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_net_mask = 0;
177 ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_next_hop_address = 0;
178 ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_entry_ip_interface = NX_NULL;
179
180 ip_ptr -> nx_ip_routing_table_entry_count--;
181 }
182 }
183 #endif /* NX_ENABLE_IP_STATIC_ROUTING */
184 #endif /* !NX_DISABLE_IPV4 */
185
186 #ifdef FEATURE_NX_IPV6
187 /* Remove IPv6 routers associated with this interface. */
188 for (i = 0; i < NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE; i++)
189 {
190 /* Set local pointer for convenience. */
191 rt_entry = &ip_ptr -> nx_ipv6_default_router_table[i];
192
193 /* Does this slot contain a router. */
194 if (rt_entry -> nx_ipv6_default_router_entry_flag & NX_IPV6_ROUTE_TYPE_VALID)
195 {
196 /* Is this router iterm related to the interface to be detached. */
197 if (rt_entry -> nx_ipv6_default_router_entry_interface_ptr == interface_ptr)
198 {
199
200 /* Yes, we need to remove this router iterm. */
201 /* Clean any entries in the destination table for this router. */
202 _nx_invalidate_destination_entry(ip_ptr, rt_entry -> nx_ipv6_default_router_entry_router_address);
203
204 /* Mark the entry as empty. */
205 rt_entry -> nx_ipv6_default_router_entry_flag = 0;
206
207 /* Clear the interface pointer .*/
208 rt_entry -> nx_ipv6_default_router_entry_interface_ptr = NX_NULL;
209
210 /* Decrease the count of available routers. */
211 ip_ptr -> nx_ipv6_default_router_table_size--;
212 }
213 }
214 }
215 #endif
216
217 #ifndef NX_DISABLE_IPV4
218 /* Clear gateway address related to the interface to be detached. */
219 if (ip_ptr -> nx_ip_gateway_interface == interface_ptr)
220 {
221 ip_ptr -> nx_ip_gateway_interface = NX_NULL;
222 ip_ptr -> nx_ip_gateway_address = 0;
223 }
224
225
226 /* Leave multicast groups related to the interface to be detached. */
227 for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
228 {
229
230 /* Skip entries not related to the interface. */
231 if (ip_ptr -> nx_ipv4_multicast_entry[i].nx_ipv4_multicast_join_interface_list != interface_ptr)
232 {
233 continue;
234 }
235
236 /* Set join count to 1 so force send multicast leave command. */
237 ip_ptr -> nx_ipv4_multicast_entry[i].nx_ipv4_multicast_join_count = 1;
238
239 /* Leave the multicast group. */
240 _nx_igmp_multicast_interface_leave_internal(ip_ptr,
241 ip_ptr -> nx_ipv4_multicast_entry[i].nx_ipv4_multicast_join_list,
242 index);
243 }
244 #endif /* !NX_DISABLE_IPV4 */
245
246 #ifdef NX_ENABLE_IPV6_MULTICAST
247 /* Leave IPv6 multicast groups related to the interface to be detached. */
248 for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
249 {
250 if (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list == interface_ptr)
251 {
252 ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_count = 0;
253
254 /* Clear the group join value. */
255 memset(ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list, 0, 4 * sizeof(ULONG));
256
257 /* Decrement the MLD groups joined count. */
258 ip_ptr -> nx_ipv6_multicast_groups_joined--;
259
260 /* Un-register the new multicast group with the underlying driver. */
261 driver_request.nx_ip_driver_ptr = ip_ptr;
262 driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_LEAVE;
263 driver_request.nx_ip_driver_physical_address_msw = 0x00003333;
264 driver_request.nx_ip_driver_physical_address_lsw =
265 ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list[3];
266 driver_request.nx_ip_driver_interface = interface_ptr;
267
268 (interface_ptr -> nx_interface_link_driver_entry)(&driver_request);
269
270 /* Now clear the interface entry. */
271 ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list = NX_NULL;
272 }
273 }
274 #endif
275
276 /* Detach the interface. */
277 /* First detach the interface from the device. */
278 driver_request.nx_ip_driver_ptr = ip_ptr;
279 driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_DETACH;
280 driver_request.nx_ip_driver_interface = interface_ptr;
281
282 (interface_ptr -> nx_interface_link_driver_entry)(&driver_request);
283
284 /* Release the IP internal mutex. */
285 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
286
287 /* Clear out IPv6 address. */
288 next_ipv6_address = interface_ptr -> nxd_interface_ipv6_address_list_head;
289
290 while (next_ipv6_address)
291 {
292 ipv6_address = next_ipv6_address;
293 next_ipv6_address = next_ipv6_address -> nxd_ipv6_address_next;
294 memset(ipv6_address, 0, sizeof(NXD_IPV6_ADDRESS));
295 }
296
297 /* Zero out the interface. */
298 memset(interface_ptr, 0, sizeof(NX_INTERFACE));
299
300 /* reserve the index. */
301 interface_ptr -> nx_interface_index = (UCHAR)index;
302
303 return(NX_SUCCESS);
304 }
305
306