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 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _nx_ip_static_route_add                             PORTABLE C      */
36 /*                                                           6.1          */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Yuxin Zhou, Microsoft Corporation                                   */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function adds a static routing entry to the routing table.     */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    ip_ptr                                Pointer to IP instance        */
48 /*    network_address                       Network address, in host byte */
49 /*                                            order.                      */
50 /*    net_mask                              Network Mask, in host byte    */
51 /*                                            order.                      */
52 /*    next_hop                              Next Hop address, in host     */
53 /*                                            byte order.                 */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    tx_mutex_get                          Obtain a protection mutex     */
62 /*    tx_mutex_put                          Release protection mutex      */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application                                                         */
67 /*                                                                        */
68 /*  NOTE:                                                                 */
69 /*                                                                        */
70 /*    next hop address must be on the local network.                      */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
77 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
78 /*                                            resulting in version 6.1    */
79 /*                                                                        */
80 /**************************************************************************/
_nx_ip_static_route_add(NX_IP * ip_ptr,ULONG network_address,ULONG net_mask,ULONG next_hop)81 UINT  _nx_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address,
82                               ULONG net_mask, ULONG next_hop)
83 {
84 #if !defined(NX_DISABLE_IPV4) && defined(NX_ENABLE_IP_STATIC_ROUTING)
85 INT           i;
86 NX_INTERFACE *nx_ip_interface = NX_NULL;
87 
88     /* If trace is enabled, insert this event into the trace buffer.  */
89     NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_STATIC_ROUTE_ADD, ip_ptr, network_address, net_mask, next_hop, NX_TRACE_IP_EVENTS, 0, 0);
90 
91     /* Obtain the IP mutex so we can manipulate the internal routing table. */
92     /* This routine does not need to be protected by mask off interrupt
93        because it cannot be invoked from ISR. */
94     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
95 
96     /* Make sure next hop is on one of the interfaces. */
97     for (i = 0; i < NX_MAX_IP_INTERFACES; i++)
98     {
99 
100         if (ip_ptr -> nx_ip_interface[i].nx_interface_valid &&
101             ((next_hop & (ip_ptr -> nx_ip_interface[i].nx_interface_ip_network_mask)) == ip_ptr -> nx_ip_interface[i].nx_interface_ip_network))
102         {
103 
104             nx_ip_interface = &(ip_ptr -> nx_ip_interface[i]);
105 
106             /* Break out of the for loop */
107             break;
108         }
109     }
110 
111     /* If no matching interface, return the error status. */
112     if (nx_ip_interface == NX_NULL)
113     {
114 
115         /* Unlock the mutex, and return the error status. */
116         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
117 
118         return(NX_IP_ADDRESS_ERROR);
119     }
120 
121     /* Obtain the network address, based on net_mask passed in. */
122     network_address = network_address & net_mask;
123 
124     /* Search through the routing table, check whether the same entry exists. */
125     for (i = 0; i < (INT)ip_ptr -> nx_ip_routing_table_entry_count; i++)
126     {
127 
128         if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_dest_ip == network_address &&
129             ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_net_mask == net_mask)
130         {
131 
132             /* Found the same entry: only need to update the next hop field */
133             ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_next_hop_address = next_hop;
134 
135             /* All done.  Unlock the mutex, and return */
136             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
137             return(NX_SUCCESS);
138         }
139 
140         /* The net mask that has more top bits set has a greater numerical value than the
141            one with less top bits set.  During a search we want to match smaller nets
142            (more top bits set, or larger numerical value) before matching larger nets. */
143         if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_net_mask <= net_mask)
144         {
145 
146         INT j;
147 
148             /* Check whether the table is full. */
149             if (ip_ptr -> nx_ip_routing_table_entry_count == NX_IP_ROUTING_TABLE_SIZE)
150             {
151 
152                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
153                 return(NX_OVERFLOW);
154             }
155 
156             /* The entry pointed to by "i" is a larger network (thus smaller net mask
157                value.  The new entry needs to be inserted before "i".
158 
159                To do so, we need to make room for the new entry, by shifting entries i and
160                after one slot. */
161             for (j = (INT)ip_ptr -> nx_ip_routing_table_entry_count - 1; j >= i; j--)
162             {
163 
164                 ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_dest_ip =
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_net_mask =
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_next_hop_address =
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_entry_ip_interface =
171                     ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_ip_interface;
172             }
173 
174             break;
175         }
176     }
177 
178     /* Check whether the table is full. */
179     if (i == NX_IP_ROUTING_TABLE_SIZE)
180     {
181         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
182         return(NX_OVERFLOW);
183     }
184 
185     ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_dest_ip = network_address;
186     ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_net_mask = net_mask;
187     ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_next_hop_address = next_hop;
188     ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface = nx_ip_interface;
189 
190     ip_ptr -> nx_ip_routing_table_entry_count++;
191 
192     /* Unlock the mutex. */
193     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
194 
195     /* Return success to the caller.  */
196     return(NX_SUCCESS);
197 
198 #else /* !NX_DISABLE_IPV4 && NX_ENABLE_IP_STATIC_ROUTING  */
199     NX_PARAMETER_NOT_USED(ip_ptr);
200     NX_PARAMETER_NOT_USED(network_address);
201     NX_PARAMETER_NOT_USED(net_mask);
202     NX_PARAMETER_NOT_USED(next_hop);
203 
204     return(NX_NOT_SUPPORTED);
205 
206 #endif /* !NX_DISABLE_IPV4 && NX_ENABLE_IP_STATIC_ROUTING  */
207 }
208 
209