1/*
2 * Interface functions.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your
10 * option) any later version.
11 *
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.
16 *
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
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
26#include "vector.h"
27#include "vty.h"
28#include "command.h"
29#include "if.h"
30#include "sockunion.h"
31#include "prefix.h"
32#include "zebra/connected.h"
33#include "memory.h"
34#include "table.h"
35#include "buffer.h"
36#include "str.h"
37#include "log.h"
38
39/* Master list of interfaces. */
40struct list *iflist;
41
42/* One for each program.  This structure is needed to store hooks. */
43struct if_master
44{
45  int (*if_new_hook) (struct interface *);
46  int (*if_delete_hook) (struct interface *);
47} if_master;
48
49/* Create new interface structure. */
50struct interface *
51if_new ()
52{
53  struct interface *ifp;
54
55  ifp = XMALLOC (MTYPE_IF, sizeof (struct interface));
56  memset (ifp, 0, sizeof (struct interface));
57  return ifp;
58}
59
60struct interface *
61if_create ()
62{
63  struct interface *ifp;
64
65  ifp = if_new ();
66
67  listnode_add (iflist, ifp);
68  ifp->connected = list_new ();
69  ifp->connected->del = (void (*) (void *)) connected_free;
70
71  if (if_master.if_new_hook)
72    (*if_master.if_new_hook) (ifp);
73
74  return ifp;
75}
76
77/* Delete and free interface structure. */
78void
79if_delete (struct interface *ifp)
80{
81  listnode_delete (iflist, ifp);
82
83  if (if_master.if_delete_hook)
84    (*if_master.if_delete_hook) (ifp);
85
86  /* Free connected address list */
87  list_delete (ifp->connected);
88
89  XFREE (MTYPE_IF, ifp);
90}
91
92/* Add hook to interface master. */
93void
94if_add_hook (int type, int (*func)(struct interface *ifp))
95{
96  switch (type) {
97  case IF_NEW_HOOK:
98    if_master.if_new_hook = func;
99    break;
100  case IF_DELETE_HOOK:
101    if_master.if_delete_hook = func;
102    break;
103  default:
104    break;
105  }
106}
107
108/* Interface existance check by index. */
109struct interface *
110if_lookup_by_index (unsigned int index)
111{
112  listnode node;
113  struct interface *ifp;
114
115  for (node = listhead (iflist); node; nextnode (node))
116    {
117      ifp = getdata (node);
118      if (ifp->ifindex == index)
119	return ifp;
120    }
121  return NULL;
122}
123
124char *
125ifindex2ifname (unsigned int index)
126{
127  listnode node;
128  struct interface *ifp;
129
130  for (node = listhead (iflist); node; nextnode (node))
131    {
132      ifp = getdata (node);
133      if (ifp->ifindex == index)
134	return ifp->name;
135    }
136  return "unknown";
137}
138
139/* Interface existance check by interface name. */
140struct interface *
141if_lookup_by_name (char *name)
142{
143  listnode node;
144  struct interface *ifp;
145
146  for (node = listhead (iflist); node; nextnode (node))
147    {
148      ifp = getdata (node);
149      if (strncmp (name, ifp->name, sizeof ifp->name) == 0)
150	return ifp;
151    }
152  return NULL;
153}
154
155/* Lookup interface by IPv4 address. */
156struct interface *
157if_lookup_exact_address (struct in_addr src)
158{
159  listnode node;
160  listnode cnode;
161  struct interface *ifp;
162  struct prefix *p;
163  struct connected *c;
164
165  for (node = listhead (iflist); node; nextnode (node))
166    {
167      ifp = getdata (node);
168
169      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
170	{
171	  c = getdata (cnode);
172
173	  p = c->address;
174
175	  if (p && p->family == AF_INET)
176	    {
177	      if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
178		return ifp;
179	    }
180	}
181    }
182  return NULL;
183}
184
185/* Lookup interface by IPv4 address. */
186struct interface *
187if_lookup_address (struct in_addr src)
188{
189  listnode node;
190  struct prefix addr;
191  struct prefix best;
192  listnode cnode;
193  struct interface *ifp;
194  struct prefix *p;
195  struct connected *c;
196  struct interface *match;
197
198  /* Zero structures - get rid of rubbish from stack */
199  memset(&addr, 0, sizeof(addr));
200  memset(&best, 0, sizeof(best));
201
202  addr.family = AF_INET;
203  addr.u.prefix4 = src;
204  addr.prefixlen = IPV4_MAX_BITLEN;
205
206  match = NULL;
207
208  for (node = listhead (iflist); node; nextnode (node))
209    {
210      ifp = getdata (node);
211
212      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
213	{
214	  c = getdata (cnode);
215
216	  if (if_is_pointopoint (ifp))
217	    {
218	      p = c->address;
219
220	      if (p && p->family == AF_INET)
221		{
222#ifdef OLD_RIB	 /* PTP  links are conventionally identified
223		     by the address of the far end - MAG */
224		  if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
225		    return ifp;
226#endif
227		  p = c->destination;
228		  if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src))
229		    return ifp;
230		}
231	    }
232	  else
233	    {
234	      p = c->address;
235
236	      if (p->family == AF_INET)
237		{
238		  if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
239		    {
240		      best = *p;
241		      match = ifp;
242		    }
243		}
244	    }
245	}
246    }
247  return match;
248}
249
250/* Get interface by name if given name interface doesn't exist create
251   one. */
252struct interface *
253if_get_by_name (char *name)
254{
255  struct interface *ifp;
256
257  ifp = if_lookup_by_name (name);
258  if (ifp == NULL)
259    {
260      ifp = if_create ();
261      strncpy (ifp->name, name, IFNAMSIZ);
262    }
263  return ifp;
264}
265
266/* Does interface up ? */
267int
268if_is_up (struct interface *ifp)
269{
270  return ifp->flags & IFF_UP;
271}
272
273/* Is this loopback interface ? */
274int
275if_is_loopback (struct interface *ifp)
276{
277  return ifp->flags & IFF_LOOPBACK;
278}
279
280/* Does this interface support broadcast ? */
281int
282if_is_broadcast (struct interface *ifp)
283{
284  return ifp->flags & IFF_BROADCAST;
285}
286
287/* Does this interface support broadcast ? */
288int
289if_is_pointopoint (struct interface *ifp)
290{
291  return ifp->flags & IFF_POINTOPOINT;
292}
293
294/* Does this interface support multicast ? */
295int
296if_is_multicast (struct interface *ifp)
297{
298/* Foxconn add by fred 20060221 */
299// Use M.conf file instead of multicast flag //
300// M.conf create from rc/service.c //
301  FILE *fp;
302  if(!(fp=fopen("/tmp/M.conf","r")))
303	return 0;
304  else
305  	fclose(fp);
306/* Foxconn end */
307  return ifp->flags & IFF_MULTICAST;
308}
309
310#ifdef FOX_RIP_DEBUG
311/* Printout flag information into log */
312const char *
313if_flag_dump (unsigned long flag)
314{
315  int separator = 0;
316  static char logbuf[BUFSIZ];
317
318#define IFF_OUT_LOG(X,STR) \
319  if ((X) && (flag & (X))) \
320    { \
321      if (separator) \
322	strlcat (logbuf, ",", BUFSIZ); \
323      else \
324	separator = 1; \
325      strlcat (logbuf, STR, BUFSIZ); \
326    }
327
328  strlcpy (logbuf, "  <", BUFSIZ);
329  IFF_OUT_LOG (IFF_UP, "UP");
330  IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST");
331  IFF_OUT_LOG (IFF_DEBUG, "DEBUG");
332  IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK");
333  IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT");
334  IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS");
335  IFF_OUT_LOG (IFF_RUNNING, "RUNNING");
336  IFF_OUT_LOG (IFF_NOARP, "NOARP");
337  IFF_OUT_LOG (IFF_PROMISC, "PROMISC");
338  IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI");
339  IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE");
340  IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX");
341  IFF_OUT_LOG (IFF_LINK0, "LINK0");
342  IFF_OUT_LOG (IFF_LINK1, "LINK1");
343  IFF_OUT_LOG (IFF_LINK2, "LINK2");
344  IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST");
345
346  strlcat (logbuf, ">", BUFSIZ);
347
348  return logbuf;
349}
350#endif /* FOX_RIP_DEBUG */
351
352#ifdef FOX_CMD_SUPPORT
353/* For debugging */
354void
355if_dump (struct interface *ifp)
356{
357  listnode node;
358#ifdef FOX_RIP_DEBUG
359  zlog_info ("Interface %s index %d metric %d mtu %d %s",
360	     ifp->name, ifp->ifindex, ifp->metric, ifp->mtu,
361	     if_flag_dump (ifp->flags));
362#endif /* FOX_RIP_DEBUG */
363  for (node = listhead (ifp->connected); node; nextnode (node))
364    ;
365}
366
367/* Interface printing for all interface. */
368void
369if_dump_all ()
370{
371  listnode node;
372
373  for (node = listhead (iflist); node; nextnode (node))
374    if_dump (getdata (node));
375}
376
377DEFUN (interface_desc,
378       interface_desc_cmd,
379       "description .LINE",
380       "Interface specific description\n"
381       "Characters describing this interface\n")
382{
383  int i;
384  struct interface *ifp;
385  struct buffer *b;
386
387  if (argc == 0)
388    return CMD_SUCCESS;
389
390  ifp = vty->index;
391  if (ifp->desc)
392    XFREE (0, ifp->desc);
393
394  b = buffer_new (1024);
395  for (i = 0; i < argc; i++)
396    {
397      buffer_putstr (b, (u_char *)argv[i]);
398      buffer_putc (b, ' ');
399    }
400  buffer_putc (b, '\0');
401
402  ifp->desc = buffer_getstr (b);
403  buffer_free (b);
404
405  return CMD_SUCCESS;
406}
407
408DEFUN (no_interface_desc,
409       no_interface_desc_cmd,
410       "no description",
411       NO_STR
412       "Interface specific description\n")
413{
414  struct interface *ifp;
415
416  ifp = vty->index;
417  if (ifp->desc)
418    XFREE (0, ifp->desc);
419  ifp->desc = NULL;
420
421  return CMD_SUCCESS;
422}
423#endif /* FOX_CMD_SUPPORT */
424
425/* See also wrapper function zebra_interface() in zebra/interface.c */
426DEFUN (interface,
427       interface_cmd,
428       "interface IFNAME",
429       "Select an interface to configure\n"
430       "Interface's name\n")
431{
432  struct interface *ifp;
433
434  ifp = if_lookup_by_name (argv[0]);
435
436  if (ifp == NULL)
437    {
438      ifp = if_create ();
439      strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ);
440    }
441  vty->index = ifp;
442  vty->node = INTERFACE_NODE;
443
444  return CMD_SUCCESS;
445}
446
447#ifdef FOX_CMD_SUPPORT
448/* For debug purpose. */
449DEFUN (show_address,
450       show_address_cmd,
451       "show address",
452       SHOW_STR
453       "address\n")
454{
455  listnode node;
456  listnode node2;
457  struct interface *ifp;
458  struct connected *ifc;
459  struct prefix *p;
460
461  for (node = listhead (iflist); node; nextnode (node))
462    {
463      ifp = getdata (node);
464
465      for (node2 = listhead (ifp->connected); node2; nextnode (node2))
466	{
467	  ifc = getdata (node2);
468	  p = ifc->address;
469
470	  if (p->family == AF_INET)
471	    vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
472		     VTY_NEWLINE);
473	}
474    }
475  return CMD_SUCCESS;
476}
477#endif /* FOX_CMD_SUPPORT */
478
479/* Allocate connected structure. */
480struct connected *
481connected_new ()
482{
483  struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected));
484  memset (new, 0, sizeof (struct connected));
485  return new;
486}
487
488/* Free connected structure. */
489void
490connected_free (struct connected *connected)
491{
492  if (connected->address)
493    prefix_free (connected->address);
494
495  if (connected->destination)
496    prefix_free (connected->destination);
497
498  if (connected->label)
499    free (connected->label);
500
501  XFREE (MTYPE_CONNECTED, connected);
502}
503
504#ifdef FOX_RIP_DEBUG
505/* Print if_addr structure. */
506void
507connected_log (struct connected *connected, char *str)
508{
509  struct prefix *p;
510  struct interface *ifp;
511  char logbuf[BUFSIZ];
512  char buf[BUFSIZ];
513
514  ifp = connected->ifp;
515  p = connected->address;
516
517  snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ",
518	    str, ifp->name, prefix_family_str (p),
519	    inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
520	    p->prefixlen);
521
522  p = connected->destination;
523  if (p)
524    {
525      strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
526	       BUFSIZ - strlen(logbuf));
527    }
528  zlog (NULL, LOG_INFO, logbuf);
529}
530#endif /* FOX_RIP_DEBUG */
531
532/* If two connected address has same prefix return 1. */
533int
534connected_same_prefix (struct prefix *p1, struct prefix *p2)
535{
536  if (p1->family == p2->family)
537    {
538      if (p1->family == AF_INET &&
539	  IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4))
540	return 1;
541#ifdef HAVE_IPV6
542      if (p1->family == AF_INET6 &&
543	  IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6))
544	return 1;
545#endif /* HAVE_IPV6 */
546    }
547  return 0;
548}
549
550struct connected *
551connected_delete_by_prefix (struct interface *ifp, struct prefix *p)
552{
553  struct listnode *node;
554  struct listnode *next;
555  struct connected *ifc;
556
557  /* In case of same prefix come, replace it with new one. */
558  for (node = listhead (ifp->connected); node; node = next)
559    {
560      ifc = getdata (node);
561      next = node->next;
562
563      if (connected_same_prefix (ifc->address, p))
564	{
565	  listnode_delete (ifp->connected, ifc);
566	  return ifc;
567	}
568    }
569  return NULL;
570}
571
572/* Check the connected information is PtP style or not.  */
573int
574ifc_pointopoint (struct connected *ifc)
575{
576  struct prefix *p;
577  int ptp = 0;
578
579  /* When interface has PtP flag.  */
580  if (if_is_pointopoint (ifc->ifp))
581    return 1;
582
583  /* RFC3021 PtP check.  */
584  p = ifc->address;
585
586  if (p->family == AF_INET)
587    ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1);
588#ifdef HAVE_IPV6
589  if (p->family == AF_INET6)
590    ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1);
591#endif /* HAVE_IPV6 */
592
593  return ptp;
594}
595
596#ifndef HAVE_IF_NAMETOINDEX
597unsigned int
598if_nametoindex (const char *name)
599{
600  listnode node;
601  struct interface *ifp;
602
603  for (node = listhead (iflist); node; nextnode (node))
604    {
605      ifp = getdata (node);
606      if (strcmp (ifp->name, name) == 0)
607	return ifp->ifindex;
608    }
609  return 0;
610}
611#endif
612
613#ifndef HAVE_IF_INDEXTONAME
614char *
615if_indextoname (unsigned int ifindex, char *name)
616{
617  listnode node;
618  struct interface *ifp;
619
620  for (node = listhead (iflist); node; nextnode (node))
621    {
622      ifp = getdata (node);
623      if (ifp->ifindex == ifindex)
624	{
625	  memcpy (name, ifp->name, IFNAMSIZ);
626	  return ifp->name;
627	}
628    }
629  return NULL;
630}
631#endif
632
633/* Interface looking up by interface's address. */
634
635/* Interface's IPv4 address reverse lookup table. */
636struct route_table *ifaddr_ipv4_table;
637/* struct route_table *ifaddr_ipv6_table; */
638
639void
640ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp)
641{
642  struct route_node *rn;
643  struct prefix_ipv4 p;
644
645  p.family = AF_INET;
646  p.prefixlen = IPV4_MAX_PREFIXLEN;
647  p.prefix = *ifaddr;
648
649  rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p);
650  if (rn)
651    {
652      route_unlock_node (rn);
653#ifdef FOX_RIP_DEBUG
654      zlog_info ("ifaddr_ipv4_add(): address %s is already added",
655		 inet_ntoa (*ifaddr));
656#endif /* FOX_RIP_DEBUG */
657      return;
658    }
659  rn->info = ifp;
660}
661
662void
663ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp)
664{
665  struct route_node *rn;
666  struct prefix_ipv4 p;
667
668  p.family = AF_INET;
669  p.prefixlen = IPV4_MAX_PREFIXLEN;
670  p.prefix = *ifaddr;
671
672  rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
673  if (! rn)
674    {
675#ifdef FOX_RIP_DEBUG
676      zlog_info ("ifaddr_ipv4_delete(): can't find address %s",
677		 inet_ntoa (*ifaddr));
678#endif /* FOX_RIP_DEBUG */
679      return;
680    }
681  rn->info = NULL;
682  route_unlock_node (rn);
683  route_unlock_node (rn);
684}
685
686/* Lookup interface by interface's IP address or interface index. */
687struct interface *
688ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
689{
690  struct prefix_ipv4 p;
691  struct route_node *rn;
692  struct interface *ifp;
693  listnode node;
694
695  if (addr)
696    {
697      p.family = AF_INET;
698      p.prefixlen = IPV4_MAX_PREFIXLEN;
699      p.prefix = *addr;
700
701      rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
702      if (! rn)
703	return NULL;
704
705      ifp = rn->info;
706      route_unlock_node (rn);
707      return ifp;
708    }
709  else
710    {
711      for (node = listhead (iflist); node; nextnode (node))
712	{
713	  ifp = getdata (node);
714
715	  if (ifp->ifindex == ifindex)
716	    return ifp;
717	}
718    }
719  return NULL;
720}
721
722/* Initialize interface list. */
723void
724if_init (int mcast_fox_onoff)
725{
726  iflist = list_new ();
727  ifaddr_ipv4_table = route_table_init ();
728
729  if (iflist)
730    return;
731
732  memset (&if_master, 0, sizeof if_master);
733}
734