3
0

brctl.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Small implementation of brctl for busybox.
  4. *
  5. * Copyright (C) 2008 by Bernhard Fischer
  6. *
  7. * Some helper functions from bridge-utils are
  8. * Copyright (C) 2000 Lennert Buytenhek
  9. *
  10. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  11. */
  12. /* This applet currently uses only the ioctl interface and no sysfs at all.
  13. * At the time of this writing this was considered a feature.
  14. */
  15. #include "libbb.h"
  16. #include <linux/sockios.h>
  17. #include <net/if.h>
  18. /* Maximum number of ports supported per bridge interface. */
  19. #ifndef MAX_PORTS
  20. #define MAX_PORTS 32
  21. #endif
  22. /* Use internal number parsing and not the "exact" conversion. */
  23. /* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
  24. #define BRCTL_USE_INTERNAL 1
  25. #ifdef ENABLE_FEATURE_BRCTL_SHOW
  26. #error Remove these
  27. #endif
  28. #define ENABLE_FEATURE_BRCTL_SHOW 0
  29. #define USE_FEATURE_BRCTL_SHOW(...)
  30. #if ENABLE_FEATURE_BRCTL_FANCY
  31. #include <linux/if_bridge.h>
  32. /* FIXME: These 4 funcs are not really clean and could be improved */
  33. static ALWAYS_INLINE void strtotimeval(struct timeval *tv,
  34. const char *time_str)
  35. {
  36. double secs;
  37. #if BRCTL_USE_INTERNAL
  38. secs = /*bb_*/strtod(time_str, NULL);
  39. if (!secs)
  40. #else
  41. if (sscanf(time_str, "%lf", &secs) != 1)
  42. #endif
  43. bb_error_msg_and_die (bb_msg_invalid_arg, time_str, "timespec");
  44. tv->tv_sec = secs;
  45. tv->tv_usec = 1000000 * (secs - tv->tv_sec);
  46. }
  47. static ALWAYS_INLINE unsigned long __tv_to_jiffies(const struct timeval *tv)
  48. {
  49. unsigned long long jif;
  50. jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
  51. return jif/10000;
  52. }
  53. # if 0
  54. static void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
  55. {
  56. unsigned long long tvusec;
  57. tvusec = 10000ULL*jiffies;
  58. tv->tv_sec = tvusec/1000000;
  59. tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
  60. }
  61. # endif
  62. static unsigned long str_to_jiffies(const char *time_str)
  63. {
  64. struct timeval tv;
  65. strtotimeval(&tv, time_str);
  66. return __tv_to_jiffies(&tv);
  67. }
  68. static void arm_ioctl(unsigned long *args,
  69. unsigned long arg0, unsigned long arg1, unsigned long arg2)
  70. {
  71. args[0] = arg0;
  72. args[1] = arg1;
  73. args[2] = arg2;
  74. args[3] = 0;
  75. }
  76. #endif
  77. int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  78. int brctl_main(int argc ATTRIBUTE_UNUSED, char **argv)
  79. {
  80. static const char keywords[] ALIGN1 =
  81. "addbr\0" "delbr\0" "addif\0" "delif\0"
  82. USE_FEATURE_BRCTL_FANCY(
  83. "stp\0"
  84. "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
  85. "setpathcost\0" "setportprio\0" "setbridgeprio\0"
  86. )
  87. USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
  88. enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
  89. USE_FEATURE_BRCTL_FANCY(,
  90. ARG_stp,
  91. ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
  92. ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
  93. )
  94. USE_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show)
  95. };
  96. int fd;
  97. smallint key;
  98. struct ifreq ifr;
  99. char *br, *brif;
  100. #if ENABLE_FEATURE_BRCTL_FANCY
  101. unsigned long args[4] = {0, 0, 0, 0};
  102. int port;
  103. int tmp;
  104. #endif
  105. argv++;
  106. while (*argv) {
  107. key = index_in_strings(keywords, *argv);
  108. if (key == -1) /* no match found in keywords array, bail out. */
  109. bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
  110. argv++;
  111. #if ENABLE_FEATURE_BRCTL_SHOW
  112. if (key == ARG_show) { /* show */
  113. goto out; /* FIXME: implement me! :) */
  114. }
  115. #endif
  116. fd = xsocket(AF_INET, SOCK_STREAM, 0);
  117. br = *argv++;
  118. if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
  119. ioctl_or_perror_and_die(fd,
  120. key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
  121. br, "bridge %s", br);
  122. goto done;
  123. }
  124. if (!*argv) /* all but 'show' need at least one argument */
  125. bb_show_usage();
  126. safe_strncpy(ifr.ifr_name, br, IFNAMSIZ);
  127. if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
  128. brif = *argv++;
  129. ifr.ifr_ifindex = if_nametoindex(brif);
  130. if (!ifr.ifr_ifindex) {
  131. bb_perror_msg_and_die("iface %s", brif);
  132. }
  133. ioctl_or_perror_and_die(fd,
  134. key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
  135. &ifr, "bridge %s", br);
  136. goto done;
  137. }
  138. #if ENABLE_FEATURE_BRCTL_FANCY
  139. ifr.ifr_data = (char *) &args;
  140. if (key == ARG_stp) { /* stp */
  141. /* FIXME: parsing yes/y/on/1 versus no/n/off/0 is too involved */
  142. arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE,
  143. (unsigned)(**argv - '0'), 0);
  144. goto fire;
  145. }
  146. if ((unsigned)(key - ARG_stp) < 5) { /* time related ops */
  147. unsigned long op = (key == ARG_setageing) ? BRCTL_SET_AGEING_TIME :
  148. (key == ARG_setfd) ? BRCTL_SET_BRIDGE_FORWARD_DELAY :
  149. (key == ARG_sethello) ? BRCTL_SET_BRIDGE_HELLO_TIME :
  150. /*key == ARG_setmaxage*/ BRCTL_SET_BRIDGE_MAX_AGE;
  151. arm_ioctl(args, op, str_to_jiffies(*argv), 0);
  152. goto fire;
  153. }
  154. port = -1;
  155. if (key == ARG_setpathcost || key == ARG_setportprio) {/* get portnum */
  156. int ifidx[MAX_PORTS];
  157. unsigned i;
  158. port = if_nametoindex(*argv);
  159. if (!port)
  160. bb_error_msg_and_die(bb_msg_invalid_arg, *argv, "port");
  161. argv++;
  162. memset(ifidx, 0, sizeof ifidx);
  163. arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx,
  164. MAX_PORTS);
  165. xioctl(fd, SIOCDEVPRIVATE, &ifr);
  166. for (i = 0; i < MAX_PORTS; i++) {
  167. if (ifidx[i] == port) {
  168. port = i;
  169. break;
  170. }
  171. }
  172. }
  173. if (key == ARG_setpathcost
  174. || key == ARG_setportprio
  175. || key == ARG_setbridgeprio
  176. ) {
  177. unsigned long op = (key == ARG_setpathcost) ? BRCTL_SET_PATH_COST :
  178. (key == ARG_setportprio) ? BRCTL_SET_PORT_PRIORITY :
  179. /*key == ARG_setbridgeprio*/ BRCTL_SET_BRIDGE_PRIORITY;
  180. unsigned long arg1 = port;
  181. unsigned long arg2;
  182. # if BRCTL_USE_INTERNAL
  183. tmp = xatoi(*argv);
  184. # else
  185. if (sscanf(*argv, "%i", &tmp) != 1)
  186. bb_error_msg_and_die(bb_msg_invalid_arg, *argv,
  187. key == ARG_setpathcost ? "cost" : "prio");
  188. # endif
  189. if (key == ARG_setbridgeprio) {
  190. arg1 = tmp;
  191. arg2 = 0;
  192. } else
  193. arg2 = tmp;
  194. arm_ioctl(args, op, arg1, arg2);
  195. }
  196. fire:
  197. /* Execute the previously set command. */
  198. xioctl(fd, SIOCDEVPRIVATE, &ifr);
  199. argv++;
  200. #endif
  201. done:
  202. if (ENABLE_FEATURE_CLEAN_UP)
  203. close(fd);
  204. }
  205. USE_FEATURE_BRCTL_SHOW(out:)
  206. return EXIT_SUCCESS;
  207. }