• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * IPv6 static route table.
4  */
5 
6 /*
7  * Copyright (c) 2015 Nest Labs, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * Author: Pradip De <pradipd@google.com>
33  *
34  *
35  * Please coordinate changes and requests with Pradip De
36  * <pradipd@google.com>
37  */
38 
39 #include "lwip/opt.h"
40 
41 #if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
42 
43 #include "ip6_route_table.h"
44 #include "lwip/def.h"
45 #include "lwip/mem.h"
46 #include "lwip/netif.h"
47 #include "lwip/ip6.h"
48 #include "lwip/ip6_addr.h"
49 #include "lwip/nd6.h"
50 #include "lwip/debug.h"
51 #include "lwip/stats.h"
52 
53 #include "string.h"
54 
55 static struct ip6_route_entry static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES];
56 
57 /**
58  * Add the ip6 prefix route and target netif into the static route table while
59  * keeping all entries sorted in decreasing order of prefix length.
60  * 1. Search from the last entry up to find the correct slot to insert while
61  *    moving entries one position down to create room.
62  * 2. Insert into empty slot created.
63  *
64  * Subsequently, a linear search down the list can be performed to retrieve a
65  * matching route entry for a Longest Prefix Match.
66  *
67  * @param ip6_prefix the route prefix entry to add.
68  * @param netif pointer to target netif.
69  * @param gateway the gateway address to use to send through. Has to be link local.
70  * @param idx return value argument of index where route entry was added in table.
71  * @return ERR_OK  if addition was successful.
72  *         ERR_MEM if table is already full.
73  *         ERR_ARG if passed argument is bad or route already exists in table.
74  */
75 err_t
ip6_add_route_entry(const struct ip6_prefix * ip6_prefix,struct netif * netif,const ip6_addr_t * gateway,s8_t * idx)76 ip6_add_route_entry(const struct ip6_prefix *ip6_prefix, struct netif *netif, const ip6_addr_t *gateway, s8_t *idx)
77 {
78   s8_t i = -1;
79   err_t retval = ERR_OK;
80 
81   if (!ip6_prefix_valid(ip6_prefix->prefix_len) || (netif == NULL)) {
82     retval = ERR_ARG;
83     goto exit;
84   }
85 
86   /* Check if an entry already exists with matching prefix; If so, replace it. */
87   for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
88     if ((ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len) &&
89         memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr,
90                ip6_prefix->prefix_len / 8) == 0) {
91       /* Prefix matches; replace the netif with the one being added. */
92       goto insert;
93     }
94   }
95 
96   /* Check if the table is full */
97   if (static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES - 1].netif != NULL) {
98     retval = ERR_MEM;
99     goto exit;
100   }
101 
102   /* Shift all entries down the table until slot is found */
103   for (i = LWIP_IPV6_NUM_ROUTE_ENTRIES - 1;
104        i > 0 && (ip6_prefix->prefix_len > static_route_table[i - 1].prefix.prefix_len); i--) {
105     SMEMCPY(&static_route_table[i], &static_route_table[i - 1], sizeof(struct ip6_route_entry));
106   }
107 
108 insert:
109   /* Insert into the slot selected */
110   SMEMCPY(&static_route_table[i].prefix, ip6_prefix, sizeof(struct ip6_prefix));
111   static_route_table[i].netif = netif;
112 
113   /* Add gateway to route table */
114   static_route_table[i].gateway = gateway;
115 
116   if (idx != NULL) {
117     *idx = i;
118   }
119 
120 exit:
121   return retval;
122 }
123 
124 /**
125  * Removes the route entry from the static route table.
126  *
127  * @param ip6_prefix the route prefix entry to delete.
128  */
129 void
ip6_remove_route_entry(const struct ip6_prefix * ip6_prefix)130 ip6_remove_route_entry(const struct ip6_prefix *ip6_prefix)
131 {
132   int i, pos = -1;
133 
134   for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
135     /* compare prefix to find position to delete */
136     if (ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len &&
137         memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr,
138                ip6_prefix->prefix_len / 8) == 0) {
139       pos = i;
140       break;
141     }
142   }
143 
144   if (pos >= 0) {
145     /* Shift everything beyond pos one slot up */
146     for (i = pos; i < LWIP_IPV6_NUM_ROUTE_ENTRIES - 1; i++) {
147       SMEMCPY(&static_route_table[i], &static_route_table[i+1], sizeof(struct ip6_route_entry));
148       if (static_route_table[i].netif == NULL) {
149         break;
150       }
151     }
152     /* Zero the remaining entries */
153     for (; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
154       ip6_addr_set_zero((&static_route_table[i].prefix.addr));
155       static_route_table[i].netif = NULL;
156     }
157   }
158 }
159 
160 /**
161  * Finds the appropriate route entry in the static route table corresponding to the given
162  * destination IPv6 address. Since the entries in the route table are kept sorted in decreasing
163  * order of prefix length, a linear search down the list is performed to retrieve a matching
164  * index.
165  *
166  * @param ip6_dest_addr the destination address to match
167  * @return the idx of the found route entry; -1 if not found.
168  */
169 s8_t
ip6_find_route_entry(const ip6_addr_t * ip6_dest_addr)170 ip6_find_route_entry(const ip6_addr_t *ip6_dest_addr)
171 {
172   s8_t i, idx = -1;
173 
174   /* Search prefix in the sorted(decreasing order of prefix length) list */
175   for(i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
176     if (memcmp(ip6_dest_addr, &static_route_table[i].prefix.addr,
177         static_route_table[i].prefix.prefix_len / 8) == 0) {
178       idx = i;
179       break;
180     }
181   }
182 
183   return idx;
184 }
185 
186 /**
187  * Finds the appropriate network interface for a given IPv6 address from a routing table with
188  * static IPv6 routes.
189  *
190  * @param src the source IPv6 address, if known
191  * @param dest the destination IPv6 address for which to find the route
192  * @return the netif on which to send to reach dest
193  */
194 struct netif *
ip6_static_route(const ip6_addr_t * src,const ip6_addr_t * dest)195 ip6_static_route(const ip6_addr_t *src, const ip6_addr_t *dest)
196 {
197   int i;
198 
199   LWIP_UNUSED_ARG(src);
200 
201   /* Perform table lookup */
202   i = ip6_find_route_entry(dest);
203 
204   if (i >= 0) {
205     return static_route_table[i].netif;
206   } else {
207     return NULL;
208   }
209 }
210 
211 /**
212  * Finds the gateway IP6 address for a given destination IPv6 address and target netif
213  * from a routing table with static IPv6 routes.
214  *
215  * @param netif the netif used for sending
216  * @param dest the destination IPv6 address
217  * @return the ip6 address of the gateway to forward packet to
218  */
219 const ip6_addr_t *
ip6_get_gateway(struct netif * netif,const ip6_addr_t * dest)220 ip6_get_gateway(struct netif *netif, const ip6_addr_t *dest)
221 {
222   const ip6_addr_t *ret_gw = NULL;
223   const int i = ip6_find_route_entry(dest);
224 
225   LWIP_UNUSED_ARG(netif);
226 
227   if (i >= 0) {
228     if (static_route_table[i].gateway != NULL) {
229       ret_gw = static_route_table[i].gateway;
230     }
231   }
232 
233   return ret_gw;
234 }
235 
236 /**
237  * Returns the top of the route table.
238  * This should be used for debug printing only.
239  *
240  * @return the top of the route table.
241  */
242 const struct ip6_route_entry *
ip6_get_route_table(void)243 ip6_get_route_table(void)
244 {
245     return static_route_table;
246 }
247 
248 #endif /* LWIP_IPV6 */
249