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