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