10f66f451Sopenharmony_ci/* brctl.c - ethernet bridge control
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * No Standard
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig BRCTL
110f66f451Sopenharmony_ci  bool "brctl"
120f66f451Sopenharmony_ci  default n
130f66f451Sopenharmony_ci  help
140f66f451Sopenharmony_ci    usage: brctl COMMAND [BRIDGE [INTERFACE]]
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    Manage ethernet bridges
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ci    Commands:
190f66f451Sopenharmony_ci    show                  Show a list of bridges
200f66f451Sopenharmony_ci    addbr BRIDGE          Create BRIDGE
210f66f451Sopenharmony_ci    delbr BRIDGE          Delete BRIDGE
220f66f451Sopenharmony_ci    addif BRIDGE IFACE    Add IFACE to BRIDGE
230f66f451Sopenharmony_ci    delif BRIDGE IFACE    Delete IFACE from BRIDGE
240f66f451Sopenharmony_ci    setageing BRIDGE TIME Set ageing time
250f66f451Sopenharmony_ci    setfd BRIDGE TIME     Set bridge forward delay
260f66f451Sopenharmony_ci    sethello BRIDGE TIME  Set hello time
270f66f451Sopenharmony_ci    setmaxage BRIDGE TIME Set max message age
280f66f451Sopenharmony_ci    setpathcost BRIDGE PORT COST   Set path cost
290f66f451Sopenharmony_ci    setportprio BRIDGE PORT PRIO   Set port priority
300f66f451Sopenharmony_ci    setbridgeprio BRIDGE PRIO      Set bridge priority
310f66f451Sopenharmony_ci    stp BRIDGE [1/yes/on|0/no/off] STP on/off
320f66f451Sopenharmony_ci*/
330f66f451Sopenharmony_ci
340f66f451Sopenharmony_ci#define FOR_brctl
350f66f451Sopenharmony_ci#include "toys.h"
360f66f451Sopenharmony_ci#include <linux/if_bridge.h>
370f66f451Sopenharmony_ci
380f66f451Sopenharmony_ciGLOBALS(
390f66f451Sopenharmony_ci    int sockfd;
400f66f451Sopenharmony_ci)
410f66f451Sopenharmony_ci#define MAX_BRIDGES 1024 //same is no of ports supported
420f66f451Sopenharmony_ci
430f66f451Sopenharmony_cistatic void get_ports(char *bridge, int *indices)
440f66f451Sopenharmony_ci{
450f66f451Sopenharmony_ci  struct ifreq ifr;
460f66f451Sopenharmony_ci  int ifindices[MAX_BRIDGES];
470f66f451Sopenharmony_ci  unsigned long args[4] = { BRCTL_GET_PORT_LIST,
480f66f451Sopenharmony_ci    (unsigned long) ifindices, MAX_BRIDGES, 0 };
490f66f451Sopenharmony_ci
500f66f451Sopenharmony_ci  memset(ifindices, 0, MAX_BRIDGES);
510f66f451Sopenharmony_ci  args[1] = (unsigned long)ifindices;
520f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ);
530f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
540f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
550f66f451Sopenharmony_ci  if (indices) memcpy(indices, ifindices, sizeof(ifindices));
560f66f451Sopenharmony_ci}
570f66f451Sopenharmony_ci
580f66f451Sopenharmony_civoid get_br_info(char *bridge, struct __bridge_info *info)
590f66f451Sopenharmony_ci{
600f66f451Sopenharmony_ci  struct ifreq ifr;
610f66f451Sopenharmony_ci  unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
620f66f451Sopenharmony_ci    (unsigned long) info, 0, 0 };
630f66f451Sopenharmony_ci
640f66f451Sopenharmony_ci  memset(info, 0, sizeof(*info));
650f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ);
660f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
670f66f451Sopenharmony_ci
680f66f451Sopenharmony_ci  if (ioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr) < 0) {
690f66f451Sopenharmony_ci    perror_msg("%s: can't get info %s\n", bridge, strerror(errno));
700f66f451Sopenharmony_ci    return;
710f66f451Sopenharmony_ci  }
720f66f451Sopenharmony_ci}
730f66f451Sopenharmony_ci
740f66f451Sopenharmony_civoid br_show(char **argv)
750f66f451Sopenharmony_ci{
760f66f451Sopenharmony_ci  struct __bridge_info info;
770f66f451Sopenharmony_ci  int num, cnt, i, j, ifindices[MAX_BRIDGES], pindices[MAX_BRIDGES];
780f66f451Sopenharmony_ci  unsigned long args[4] = { BRCTL_GET_BRIDGES,
790f66f451Sopenharmony_ci    (unsigned long)ifindices, MAX_BRIDGES,0 };
800f66f451Sopenharmony_ci  char br[IF_NAMESIZE], ifn[IF_NAMESIZE];
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci  num = ioctl(TT.sockfd, SIOCGIFBR, args); //ret is num of bridges found
830f66f451Sopenharmony_ci  if (num < 0) error_exit("get bridges fail");
840f66f451Sopenharmony_ci  printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
850f66f451Sopenharmony_ci
860f66f451Sopenharmony_ci  for (i = 0; i < num; i++) {
870f66f451Sopenharmony_ci    unsigned char *id;
880f66f451Sopenharmony_ci
890f66f451Sopenharmony_ci    if (!if_indextoname(ifindices[i], br)) perror_exit("interface not found");
900f66f451Sopenharmony_ci    get_br_info(br, &info);
910f66f451Sopenharmony_ci    id = (unsigned char*)&(info.bridge_id);
920f66f451Sopenharmony_ci    printf("%s\t\t",br);
930f66f451Sopenharmony_ci    printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", id[0], id[1],
940f66f451Sopenharmony_ci        id[2], id[3], id[4], id[5], id[6], id[7]);
950f66f451Sopenharmony_ci    printf("\t%s\t\t",(info.stp_enabled)?"yes" : "no");
960f66f451Sopenharmony_ci
970f66f451Sopenharmony_ci    memset(pindices, 0, sizeof(pindices));
980f66f451Sopenharmony_ci    get_ports(br, pindices);
990f66f451Sopenharmony_ci    for (j = 0, cnt = 0; j < MAX_BRIDGES; j++) {
1000f66f451Sopenharmony_ci      if (!pindices[j]) continue;
1010f66f451Sopenharmony_ci      if (!if_indextoname(pindices[j], ifn)) {
1020f66f451Sopenharmony_ci        error_msg("no name for index :%d", pindices[j]);
1030f66f451Sopenharmony_ci        continue;
1040f66f451Sopenharmony_ci      }
1050f66f451Sopenharmony_ci      if (cnt) printf("\n\t\t\t\t\t\t\t");
1060f66f451Sopenharmony_ci      printf("%s", ifn);
1070f66f451Sopenharmony_ci      cnt++;
1080f66f451Sopenharmony_ci    }
1090f66f451Sopenharmony_ci    xputc('\n');
1100f66f451Sopenharmony_ci  }
1110f66f451Sopenharmony_ci}
1120f66f451Sopenharmony_ci
1130f66f451Sopenharmony_civoid br_addbr(char **argv)
1140f66f451Sopenharmony_ci{
1150f66f451Sopenharmony_ci  char br[IFNAMSIZ];
1160f66f451Sopenharmony_ci  unsigned long args[4] = {BRCTL_ADD_BRIDGE, (unsigned long) br, 0, 0};
1170f66f451Sopenharmony_ci
1180f66f451Sopenharmony_ci#ifdef SIOCBRADDBR
1190f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCBRADDBR, argv[0]);
1200f66f451Sopenharmony_ci#else
1210f66f451Sopenharmony_ci  xstrncpy(br, argv[0], IFNAMSIZ);
1220f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCSIFBR, args);
1230f66f451Sopenharmony_ci#endif
1240f66f451Sopenharmony_ci}
1250f66f451Sopenharmony_ci
1260f66f451Sopenharmony_civoid br_delbr(char **argv)
1270f66f451Sopenharmony_ci{
1280f66f451Sopenharmony_ci  char br[IFNAMSIZ];
1290f66f451Sopenharmony_ci  unsigned long args[4] = {BRCTL_DEL_BRIDGE, (unsigned long) br, 0, 0};
1300f66f451Sopenharmony_ci
1310f66f451Sopenharmony_ci#ifdef SIOCBRDELBR
1320f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCBRDELBR, argv[0]);
1330f66f451Sopenharmony_ci#else
1340f66f451Sopenharmony_ci  xstrncpy(br, argv[0], IFNAMSIZ);
1350f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCSIFBR, args);
1360f66f451Sopenharmony_ci#endif
1370f66f451Sopenharmony_ci}
1380f66f451Sopenharmony_ci
1390f66f451Sopenharmony_civoid br_addif(char **argv)
1400f66f451Sopenharmony_ci{
1410f66f451Sopenharmony_ci  int index;
1420f66f451Sopenharmony_ci  struct ifreq ifr;
1430f66f451Sopenharmony_ci  unsigned long args[4] = {BRCTL_ADD_IF, 0, 0, 0};
1440f66f451Sopenharmony_ci
1450f66f451Sopenharmony_ci  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s", argv[1]);
1460f66f451Sopenharmony_ci#ifdef SIOCBRADDIF
1470f66f451Sopenharmony_ci  ifr.ifr_ifindex = index;
1480f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCBRADDIF, &ifr);
1490f66f451Sopenharmony_ci#else
1500f66f451Sopenharmony_ci  args[1] = index;
1510f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
1520f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
1530f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
1540f66f451Sopenharmony_ci#endif
1550f66f451Sopenharmony_ci}
1560f66f451Sopenharmony_ci
1570f66f451Sopenharmony_civoid br_delif(char **argv)
1580f66f451Sopenharmony_ci{
1590f66f451Sopenharmony_ci  int index;
1600f66f451Sopenharmony_ci  struct ifreq ifr;
1610f66f451Sopenharmony_ci  unsigned long args[4] = {BRCTL_DEL_IF, 0, 0, 0};
1620f66f451Sopenharmony_ci
1630f66f451Sopenharmony_ci  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s",argv[1]);
1640f66f451Sopenharmony_ci#ifdef SIOCBRDELIF
1650f66f451Sopenharmony_ci  ifr.ifr_ifindex = ifindex;
1660f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCBRDELIF, &ifr);
1670f66f451Sopenharmony_ci#else
1680f66f451Sopenharmony_ci  args[1] = index;
1690f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
1700f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
1710f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
1720f66f451Sopenharmony_ci#endif
1730f66f451Sopenharmony_ci}
1740f66f451Sopenharmony_ci
1750f66f451Sopenharmony_cistatic void strtotimeval(struct timeval *tv, char *time)
1760f66f451Sopenharmony_ci{
1770f66f451Sopenharmony_ci  double secs;
1780f66f451Sopenharmony_ci
1790f66f451Sopenharmony_ci  if (sscanf(time, "%lf", &secs) != 1) error_exit("time format not proper");
1800f66f451Sopenharmony_ci  tv->tv_sec = secs;
1810f66f451Sopenharmony_ci  tv->tv_usec = 1000000 * (secs - tv->tv_sec);
1820f66f451Sopenharmony_ci}
1830f66f451Sopenharmony_ci
1840f66f451Sopenharmony_cistatic unsigned long tv_to_jify(struct timeval *tv)
1850f66f451Sopenharmony_ci{
1860f66f451Sopenharmony_ci  unsigned long long jify;
1870f66f451Sopenharmony_ci
1880f66f451Sopenharmony_ci  jify = 1000000ULL * tv->tv_sec + tv->tv_usec;
1890f66f451Sopenharmony_ci  return (jify/10000);
1900f66f451Sopenharmony_ci}
1910f66f451Sopenharmony_ci
1920f66f451Sopenharmony_civoid set_time(char *br, unsigned long cmd, unsigned long val)
1930f66f451Sopenharmony_ci{
1940f66f451Sopenharmony_ci  struct ifreq ifr;
1950f66f451Sopenharmony_ci  unsigned long args[4] = {cmd, val, 0, 0};
1960f66f451Sopenharmony_ci
1970f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
1980f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
1990f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
2000f66f451Sopenharmony_ci}
2010f66f451Sopenharmony_ci
2020f66f451Sopenharmony_civoid br_set_ageing_time(char **argv)
2030f66f451Sopenharmony_ci{
2040f66f451Sopenharmony_ci  struct timeval tv;
2050f66f451Sopenharmony_ci
2060f66f451Sopenharmony_ci  strtotimeval(&tv, argv[1]);
2070f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_AGEING_TIME, tv_to_jify(&tv));
2080f66f451Sopenharmony_ci}
2090f66f451Sopenharmony_ci
2100f66f451Sopenharmony_civoid br_set_fwd_delay(char **argv)
2110f66f451Sopenharmony_ci{
2120f66f451Sopenharmony_ci  struct timeval tv;
2130f66f451Sopenharmony_ci
2140f66f451Sopenharmony_ci  strtotimeval(&tv, argv[1]);
2150f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_BRIDGE_FORWARD_DELAY, tv_to_jify(&tv));
2160f66f451Sopenharmony_ci}
2170f66f451Sopenharmony_ci
2180f66f451Sopenharmony_civoid br_set_hello_time(char **argv)
2190f66f451Sopenharmony_ci{
2200f66f451Sopenharmony_ci  struct timeval tv;
2210f66f451Sopenharmony_ci
2220f66f451Sopenharmony_ci  strtotimeval(&tv, argv[1]);
2230f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_BRIDGE_HELLO_TIME, tv_to_jify(&tv));
2240f66f451Sopenharmony_ci}
2250f66f451Sopenharmony_ci
2260f66f451Sopenharmony_civoid br_set_max_age(char **argv)
2270f66f451Sopenharmony_ci{
2280f66f451Sopenharmony_ci  struct timeval tv;
2290f66f451Sopenharmony_ci
2300f66f451Sopenharmony_ci  strtotimeval(&tv, argv[1]);
2310f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_BRIDGE_MAX_AGE, tv_to_jify(&tv));
2320f66f451Sopenharmony_ci}
2330f66f451Sopenharmony_ci
2340f66f451Sopenharmony_civoid br_set_bridge_prio(char **argv)
2350f66f451Sopenharmony_ci{
2360f66f451Sopenharmony_ci  int prio;
2370f66f451Sopenharmony_ci
2380f66f451Sopenharmony_ci  if (sscanf(argv[1], "%i", &prio) != 1) error_exit("prio not proper");
2390f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_BRIDGE_PRIORITY, prio);
2400f66f451Sopenharmony_ci}
2410f66f451Sopenharmony_ci
2420f66f451Sopenharmony_civoid br_set_stp(char **argv)
2430f66f451Sopenharmony_ci{
2440f66f451Sopenharmony_ci  int i;
2450f66f451Sopenharmony_ci  struct stp {
2460f66f451Sopenharmony_ci    char *n;
2470f66f451Sopenharmony_ci    int set;
2480f66f451Sopenharmony_ci  } ss[] = {{"1", 1}, {"yes", 1},{"on", 1},
2490f66f451Sopenharmony_ci    {"0", 0}, {"no", 0},{"off", 0}};
2500f66f451Sopenharmony_ci
2510f66f451Sopenharmony_ci  for (i = 0; i < ARRAY_LEN(ss); i++) {
2520f66f451Sopenharmony_ci    if (!strcmp(ss[i].n, argv[1])) break;
2530f66f451Sopenharmony_ci  }
2540f66f451Sopenharmony_ci  if (i >= ARRAY_LEN(ss)) error_exit("invalid stp state");
2550f66f451Sopenharmony_ci  set_time(argv[0], BRCTL_SET_BRIDGE_STP_STATE, ss[i].set);
2560f66f451Sopenharmony_ci}
2570f66f451Sopenharmony_ci
2580f66f451Sopenharmony_civoid set_cost_prio(char *br, char *port, unsigned long cmd, unsigned long val)
2590f66f451Sopenharmony_ci{
2600f66f451Sopenharmony_ci  struct ifreq ifr;
2610f66f451Sopenharmony_ci  int i, index, pindices[MAX_BRIDGES];
2620f66f451Sopenharmony_ci  unsigned long args[4] = {cmd, 0, val, 0};
2630f66f451Sopenharmony_ci
2640f66f451Sopenharmony_ci  if (!(index = if_nametoindex(port))) error_exit("invalid port");
2650f66f451Sopenharmony_ci
2660f66f451Sopenharmony_ci  memset(pindices, 0, sizeof(pindices));
2670f66f451Sopenharmony_ci  get_ports(br, pindices);
2680f66f451Sopenharmony_ci  for (i = 0; i < MAX_BRIDGES; i++) {
2690f66f451Sopenharmony_ci    if (index == pindices[i]) break;
2700f66f451Sopenharmony_ci  }
2710f66f451Sopenharmony_ci  if (i >= MAX_BRIDGES) error_exit("%s not in bridge", port);
2720f66f451Sopenharmony_ci  args[1] = i;
2730f66f451Sopenharmony_ci  xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
2740f66f451Sopenharmony_ci  ifr.ifr_data = (char *)args;
2750f66f451Sopenharmony_ci  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
2760f66f451Sopenharmony_ci}
2770f66f451Sopenharmony_ci
2780f66f451Sopenharmony_civoid br_set_path_cost(char **argv)
2790f66f451Sopenharmony_ci{
2800f66f451Sopenharmony_ci  int cost;
2810f66f451Sopenharmony_ci
2820f66f451Sopenharmony_ci  cost = atolx_range(argv[2], 0, INT_MAX);
2830f66f451Sopenharmony_ci  set_cost_prio(argv[0], argv[1], BRCTL_SET_PATH_COST, cost);
2840f66f451Sopenharmony_ci}
2850f66f451Sopenharmony_ci
2860f66f451Sopenharmony_civoid br_set_port_prio(char **argv)
2870f66f451Sopenharmony_ci{
2880f66f451Sopenharmony_ci  int prio;
2890f66f451Sopenharmony_ci
2900f66f451Sopenharmony_ci  prio = atolx_range(argv[2], 0, INT_MAX);
2910f66f451Sopenharmony_ci  set_cost_prio(argv[0], argv[1], BRCTL_SET_PORT_PRIORITY, prio);
2920f66f451Sopenharmony_ci
2930f66f451Sopenharmony_ci}
2940f66f451Sopenharmony_ci
2950f66f451Sopenharmony_civoid brctl_main(void)
2960f66f451Sopenharmony_ci{
2970f66f451Sopenharmony_ci  int i;
2980f66f451Sopenharmony_ci  struct cmds {
2990f66f451Sopenharmony_ci    char *cmd;
3000f66f451Sopenharmony_ci    int nargs;
3010f66f451Sopenharmony_ci    void (*f)(char **argv);
3020f66f451Sopenharmony_ci  } cc[] = {{"show", 0, br_show},
3030f66f451Sopenharmony_ci    {"addbr", 1, br_addbr}, {"delbr", 1, br_delbr},
3040f66f451Sopenharmony_ci    {"addif", 2, br_addif}, {"delif", 2, br_delif},
3050f66f451Sopenharmony_ci    {"setageing", 2, br_set_ageing_time},
3060f66f451Sopenharmony_ci    {"setfd", 2, br_set_fwd_delay},
3070f66f451Sopenharmony_ci    {"sethello", 2, br_set_hello_time},
3080f66f451Sopenharmony_ci    {"setmaxage", 2, br_set_max_age},
3090f66f451Sopenharmony_ci    {"setpathcost", 3, br_set_path_cost},
3100f66f451Sopenharmony_ci    {"setportprio", 3, br_set_port_prio},
3110f66f451Sopenharmony_ci    {"setbridgeprio", 2, br_set_bridge_prio},
3120f66f451Sopenharmony_ci    {"stp", 2, br_set_stp},
3130f66f451Sopenharmony_ci  };
3140f66f451Sopenharmony_ci
3150f66f451Sopenharmony_ci  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
3160f66f451Sopenharmony_ci  while (*toys.optargs) {
3170f66f451Sopenharmony_ci    for (i = 0; i < ARRAY_LEN(cc); i++) {
3180f66f451Sopenharmony_ci      struct cmds *t = cc + i;
3190f66f451Sopenharmony_ci
3200f66f451Sopenharmony_ci      if (strcmp(t->cmd, *toys.optargs)) continue;
3210f66f451Sopenharmony_ci
3220f66f451Sopenharmony_ci      toys.optargs++, toys.optc--;
3230f66f451Sopenharmony_ci      if (toys.optc < t->nargs) help_exit("check args");
3240f66f451Sopenharmony_ci      t->f(toys.optargs);
3250f66f451Sopenharmony_ci      toys.optargs += t->nargs;
3260f66f451Sopenharmony_ci      toys.optc -= t->nargs;
3270f66f451Sopenharmony_ci      break;
3280f66f451Sopenharmony_ci    }
3290f66f451Sopenharmony_ci
3300f66f451Sopenharmony_ci    if (i == ARRAY_LEN(cc)) help_exit("invalid option '%s'", *toys.optargs);
3310f66f451Sopenharmony_ci  }
3320f66f451Sopenharmony_ci  xclose(TT.sockfd);
3330f66f451Sopenharmony_ci}
334