- shrink a bit and implement time related fancy features. Improve help texts.
[platform/upstream/busybox.git] / networking / brctl.c
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  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9 /* This applet currently uses only the ioctl interface and no sysfs at all.
10  * At the time of this writing this was considered a feature.
11  */
12 #include "libbb.h"
13 #include <linux/sockios.h>
14 #include <net/if.h>
15
16 #ifdef ENABLE_FEATURE_BRCTL_SHOW
17 #error Remove these
18 #endif
19 #define ENABLE_FEATURE_BRCTL_SHOW 0
20 #define USE_FEATURE_BRCTL_SHOW(...)
21 #if 0
22 #define ENABLE_FEATURE_BRCTL_FANCY 0
23 #if ENABLE_FEATURE_BRCTL_FANCY
24 #define USE_FEATURE_BRCTL_FANCY(...) __VA_ARGS__
25 #else
26 #define USE_FEATURE_BRCTL_FANCY(...)
27 #endif
28 #endif
29 #if ENABLE_FEATURE_BRCTL_FANCY
30 #include <linux/if_bridge.h>
31 /* FIXME: These 4 funcs are not really clean and could be improved */
32 static inline ALWAYS_INLINE void strtotimeval(struct timeval *tv,
33                                                                                           const char *time_str)
34 {
35         double secs;
36         if (sscanf(time_str, "%lf", &secs) != 1)
37                 bb_error_msg_and_die (bb_msg_invalid_arg, time_str, "timespec");
38         tv->tv_sec = secs;
39         tv->tv_usec = 1000000 * (secs - tv->tv_sec);
40 }
41
42 static inline ALWAYS_INLINE unsigned long __tv_to_jiffies(const struct timeval *tv)
43 {
44         unsigned long long jif;
45
46         jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
47
48         return jif/10000;
49 }
50 # ifdef UNUSED && 00
51 static void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
52 {
53         unsigned long long tvusec;
54
55         tvusec = 10000ULL*jiffies;
56         tv->tv_sec = tvusec/1000000;
57         tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
58 }
59 # endif
60 static unsigned long str_to_jiffies(const char *time_str)
61 {
62         struct timeval tv;
63         strtotimeval(&tv, time_str);
64         return __tv_to_jiffies(&tv);
65 }
66 #endif
67
68
69 int brctl_main(int argc ATTRIBUTE_UNUSED, char **argv) MAIN_EXTERNALLY_VISIBLE;
70 int brctl_main(int argc ATTRIBUTE_UNUSED, char **argv)
71 {
72         int fd;
73         static const char keywords[] ALIGN1 =
74                 "addbr\0" "delbr\0" "addif\0" "delif\0"
75         USE_FEATURE_BRCTL_FANCY(
76                 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
77                 "setpathcost\0" "setportprio\0" "setbridgeprio\0"
78                 "stp\0"
79         )
80                 USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
81         enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
82                 USE_FEATURE_BRCTL_FANCY(,
83                    ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
84                    ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio,
85                    ARG_stp
86                 )
87                   USE_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show) };
88         smallint key;
89         struct ifreq ifr;
90         static char info[] = "bridge %s\0 iface %s";
91         char *br;
92
93         argv++;
94         while (*argv) {
95                 key = index_in_strings(keywords, *argv);
96                 if (key == -1) /* no match found in keywords array, bail out. */
97                         bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
98                 argv++;
99 #if ENABLE_FEATURE_BRCTL_SHOW
100                 if (key == ARG_show) { /* show */
101                         goto out; /* FIXME: implement me! :) */
102                 }
103 #endif
104                 fd = xsocket(AF_INET, SOCK_STREAM, 0);
105                 br = *(argv++);
106
107                 if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
108                         ioctl_or_perror_and_die(fd,
109                                                                 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
110                                                                 br, info, br);
111                         goto done;
112                 }
113                 if (!*argv) /* all but 'show' need at least one argument */
114                         bb_show_usage();
115                 safe_strncpy(ifr.ifr_name, br, IFNAMSIZ);
116                 if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
117                         char *brif;
118
119                         brif = *(argv++);
120                         if (!(ifr.ifr_ifindex = if_nametoindex(brif))) {
121                                 bb_perror_msg_and_die(info+11, brif);
122                         }
123                         ioctl_or_perror_and_die(fd,
124                                                                   key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
125                                                                   &ifr, info, br);
126                 }
127 #if ENABLE_FEATURE_BRCTL_FANCY
128                 if (key - ARG_delif < 5) { /* time related ops */
129                         unsigned long op = (key == ARG_setageing) ? BRCTL_SET_AGEING_TIME :
130                                                         (key == ARG_setfd) ? BRCTL_SET_BRIDGE_FORWARD_DELAY:
131                                                         (key == ARG_sethello) ? BRCTL_SET_BRIDGE_HELLO_TIME:
132                                                         (key == ARG_setmaxage) ? BRCTL_SET_BRIDGE_MAX_AGE :
133                                                         -1/*will never be used */;
134                         unsigned long jiff = str_to_jiffies (*(argv++));
135                         unsigned long args[4] = {op, jiff, 0, 0};
136                         ifr.ifr_data = (char *) &args;
137                         xioctl(fd, SIOCDEVPRIVATE, &ifr);
138                 }
139 #endif
140  done:
141                 if (ENABLE_FEATURE_CLEAN_UP)
142                         close(fd);
143         }
144  out:
145         return EXIT_SUCCESS;
146 }