bgpd: tighten bounds checking in RR ORF msg reader
[jleu-quagga.git] / zebra / connected.c
blob95399fa16ebf8968136c9622464be6536a051221
1 /*
2 * Address linked list routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
23 #include <zebra.h>
25 #include "prefix.h"
26 #include "linklist.h"
27 #include "if.h"
28 #include "table.h"
29 #include "rib.h"
30 #include "table.h"
31 #include "log.h"
32 #include "memory.h"
34 #include "zebra/zserv.h"
35 #include "zebra/redistribute.h"
36 #include "zebra/interface.h"
37 #include "zebra/connected.h"
38 extern struct zebra_t zebrad;
40 /* withdraw a connected address */
41 static void
42 connected_withdraw (struct connected *ifc)
44 if (! ifc)
45 return;
47 /* Update interface address information to protocol daemon. */
48 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
50 zebra_interface_address_delete_update (ifc->ifp, ifc);
52 if_subnet_delete (ifc->ifp, ifc);
54 if (ifc->address->family == AF_INET)
55 connected_down_ipv4 (ifc->ifp, ifc);
56 #ifdef HAVE_IPV6
57 else
58 connected_down_ipv6 (ifc->ifp, ifc);
59 #endif
61 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
64 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
66 listnode_delete (ifc->ifp->connected, ifc);
67 connected_free (ifc);
71 static void
72 connected_announce (struct interface *ifp, struct connected *ifc)
74 if (!ifc)
75 return;
77 listnode_add (ifp->connected, ifc);
79 /* Update interface address information to protocol daemon. */
80 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
82 if (ifc->address->family == AF_INET)
83 if_subnet_add (ifp, ifc);
85 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
87 zebra_interface_address_add_update (ifp, ifc);
89 if (if_is_operative(ifp))
91 if (ifc->address->family == AF_INET)
92 connected_up_ipv4 (ifp, ifc);
93 #ifdef HAVE_IPV6
94 else
95 connected_up_ipv6 (ifp, ifc);
96 #endif
101 /* If same interface address is already exist... */
102 struct connected *
103 connected_check (struct interface *ifp, struct prefix *p)
105 struct connected *ifc;
106 struct listnode *node;
108 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
109 if (prefix_same (ifc->address, p))
110 return ifc;
112 return NULL;
115 /* Check if two ifc's describe the same address */
116 static int
117 connected_same (struct connected *ifc1, struct connected *ifc2)
119 if (ifc1->ifp != ifc2->ifp)
120 return 0;
122 if (ifc1->destination)
123 if (!ifc2->destination)
124 return 0;
125 if (ifc2->destination)
126 if (!ifc1->destination)
127 return 0;
129 if (ifc1->destination && ifc2->destination)
130 if (!prefix_same (ifc1->destination, ifc2->destination))
131 return 0;
133 if (ifc1->flags != ifc2->flags)
134 return 0;
136 return 1;
139 /* Handle implicit withdrawals of addresses, where a system ADDs an address
140 * to an interface which already has the same address configured.
142 * Returns the struct connected which must be announced to clients,
143 * or NULL if nothing to do.
145 static struct connected *
146 connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
148 struct connected *current;
150 /* Check same connected route. */
151 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
153 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
154 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
156 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
157 * back an address we have already added.
159 if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
161 /* nothing to do */
162 connected_free (ifc);
163 return NULL;
166 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
167 connected_withdraw (current); /* implicit withdraw - freebsd does this */
169 return ifc;
172 /* Called from if_up(). */
173 void
174 connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
176 struct prefix_ipv4 p;
178 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
179 return;
181 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
183 /* Apply mask to the network. */
184 apply_mask_ipv4 (&p);
186 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
187 address. */
188 if (prefix_ipv4_any (&p))
189 return;
191 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
192 RT_TABLE_MAIN, ifp->metric, 0);
194 rib_update ();
197 /* Add connected IPv4 route to the interface. */
198 void
199 connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
200 u_char prefixlen, struct in_addr *broad,
201 const char *label)
203 struct prefix_ipv4 *p;
204 struct connected *ifc;
206 /* Make connected structure. */
207 ifc = connected_new ();
208 ifc->ifp = ifp;
209 ifc->flags = flags;
211 /* Allocate new connected address. */
212 p = prefix_ipv4_new ();
213 p->family = AF_INET;
214 p->prefix = *addr;
215 p->prefixlen = prefixlen;
216 ifc->address = (struct prefix *) p;
218 /* If there is broadcast or peer address. */
219 if (broad)
221 p = prefix_ipv4_new ();
222 p->family = AF_INET;
223 p->prefix = *broad;
224 p->prefixlen = prefixlen;
225 ifc->destination = (struct prefix *) p;
227 /* validate the destination address */
228 if (CONNECTED_PEER(ifc))
230 if (IPV4_ADDR_SAME(addr,broad))
231 zlog_warn("warning: interface %s has same local and peer "
232 "address %s, routing protocols may malfunction",
233 ifp->name,inet_ntoa(*addr));
235 else
237 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
239 char buf[2][INET_ADDRSTRLEN];
240 struct in_addr bcalc;
241 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
242 zlog_warn("warning: interface %s broadcast addr %s/%d != "
243 "calculated %s, routing protocols may malfunction",
244 ifp->name,
245 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
246 prefixlen,
247 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
252 else
254 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
256 zlog_warn("warning: %s called for interface %s "
257 "with peer flag set, but no peer address supplied",
258 __func__, ifp->name);
259 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
262 /* no broadcast or destination address was supplied */
263 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
264 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
265 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
268 /* Label of this address. */
269 if (label)
270 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
272 /* nothing to do? */
273 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
274 return;
276 connected_announce (ifp, ifc);
279 void
280 connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
282 struct prefix_ipv4 p;
284 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
285 return;
287 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
289 /* Apply mask to the network. */
290 apply_mask_ipv4 (&p);
292 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
293 address. */
294 if (prefix_ipv4_any (&p))
295 return;
297 /* Same logic as for connected_up_ipv4(): push the changes into the head. */
298 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
300 rib_update ();
303 /* Delete connected IPv4 route to the interface. */
304 void
305 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
306 u_char prefixlen, struct in_addr *broad)
308 struct prefix_ipv4 p;
309 struct connected *ifc;
311 memset (&p, 0, sizeof (struct prefix_ipv4));
312 p.family = AF_INET;
313 p.prefix = *addr;
314 p.prefixlen = prefixlen;
316 ifc = connected_check (ifp, (struct prefix *) &p);
317 if (! ifc)
318 return;
320 connected_withdraw (ifc);
322 rib_update();
325 #ifdef HAVE_IPV6
326 void
327 connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
329 struct prefix_ipv6 p;
331 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
332 return;
334 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
336 /* Apply mask to the network. */
337 apply_mask_ipv6 (&p);
339 #if ! defined (MUSICA) && ! defined (LINUX)
340 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
341 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
342 return;
343 #endif
345 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
346 ifp->metric, 0);
348 rib_update ();
351 /* Add connected IPv6 route to the interface. */
352 void
353 connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
354 u_char prefixlen, struct in6_addr *broad,
355 const char *label)
357 struct prefix_ipv6 *p;
358 struct connected *ifc;
360 /* Make connected structure. */
361 ifc = connected_new ();
362 ifc->ifp = ifp;
363 ifc->flags = flags;
365 /* Allocate new connected address. */
366 p = prefix_ipv6_new ();
367 p->family = AF_INET6;
368 IPV6_ADDR_COPY (&p->prefix, addr);
369 p->prefixlen = prefixlen;
370 ifc->address = (struct prefix *) p;
372 /* If there is broadcast or peer address. */
373 if (broad)
375 if (IN6_IS_ADDR_UNSPECIFIED(broad))
376 zlog_warn("warning: %s called for interface %s with unspecified "
377 "destination address; ignoring!", __func__, ifp->name);
378 else
380 p = prefix_ipv6_new ();
381 p->family = AF_INET6;
382 IPV6_ADDR_COPY (&p->prefix, broad);
383 p->prefixlen = prefixlen;
384 ifc->destination = (struct prefix *) p;
387 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
389 zlog_warn("warning: %s called for interface %s "
390 "with peer flag set, but no peer address supplied",
391 __func__, ifp->name);
392 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
395 /* Label of this address. */
396 if (label)
397 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
399 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
400 return;
402 connected_announce (ifp, ifc);
405 void
406 connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
408 struct prefix_ipv6 p;
410 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
411 return;
413 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
415 apply_mask_ipv6 (&p);
417 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
418 return;
420 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
422 rib_update ();
425 void
426 connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
427 u_char prefixlen, struct in6_addr *broad)
429 struct prefix_ipv6 p;
430 struct connected *ifc;
432 memset (&p, 0, sizeof (struct prefix_ipv6));
433 p.family = AF_INET6;
434 memcpy (&p.prefix, address, sizeof (struct in6_addr));
435 p.prefixlen = prefixlen;
437 ifc = connected_check (ifp, (struct prefix *) &p);
438 if (! ifc)
439 return;
441 connected_withdraw (ifc);
443 rib_update();
445 #endif /* HAVE_IPV6 */