source: src/router/busybox/networking/libiproute/iplink.c @ 8864

Last change on this file since 8864 was 8864, checked in by BrainSlayer, 5 years ago

replace busybox with new version

File size: 6.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * iplink.c "ip link".
4 *
5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10//#include <sys/ioctl.h>
11//#include <sys/socket.h>
12#include <net/if.h>
13#include <net/if_packet.h>
14#include <netpacket/packet.h>
15#include <net/ethernet.h>
16
17#include "ip_common.h"  /* #include "libbb.h" is inside */
18#include "rt_names.h"
19#include "utils.h"
20
21/* taken from linux/sockios.h */
22#define SIOCSIFNAME     0x8923          /* set interface name */
23
24/* Exits on error */
25static int get_ctl_fd(void)
26{
27        int fd;
28
29        fd = socket(PF_INET, SOCK_DGRAM, 0);
30        if (fd >= 0)
31                return fd;
32        fd = socket(PF_PACKET, SOCK_DGRAM, 0);
33        if (fd >= 0)
34                return fd;
35        return xsocket(PF_INET6, SOCK_DGRAM, 0);
36}
37
38/* Exits on error */
39static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
40{
41        struct ifreq ifr;
42        int fd;
43
44        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
45        fd = get_ctl_fd();
46        xioctl(fd, SIOCGIFFLAGS, &ifr);
47        if ((ifr.ifr_flags ^ flags) & mask) {
48                ifr.ifr_flags &= ~mask;
49                ifr.ifr_flags |= mask & flags;
50                xioctl(fd, SIOCSIFFLAGS, &ifr);
51        }
52        close(fd);
53}
54
55/* Exits on error */
56static void do_changename(char *dev, char *newdev)
57{
58        struct ifreq ifr;
59        int fd;
60
61        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
62        strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
63        fd = get_ctl_fd();
64        xioctl(fd, SIOCSIFNAME, &ifr);
65        close(fd);
66}
67
68/* Exits on error */
69static void set_qlen(char *dev, int qlen)
70{
71        struct ifreq ifr;
72        int s;
73
74        s = get_ctl_fd();
75        memset(&ifr, 0, sizeof(ifr));
76        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
77        ifr.ifr_qlen = qlen;
78        xioctl(s, SIOCSIFTXQLEN, &ifr);
79        close(s);
80}
81
82/* Exits on error */
83static void set_mtu(char *dev, int mtu)
84{
85        struct ifreq ifr;
86        int s;
87
88        s = get_ctl_fd();
89        memset(&ifr, 0, sizeof(ifr));
90        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
91        ifr.ifr_mtu = mtu;
92        xioctl(s, SIOCSIFMTU, &ifr);
93        close(s);
94}
95
96/* Exits on error */
97static int get_address(char *dev, int *htype)
98{
99        struct ifreq ifr;
100        struct sockaddr_ll me;
101        socklen_t alen;
102        int s;
103
104        s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
105
106        memset(&ifr, 0, sizeof(ifr));
107        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
108        xioctl(s, SIOCGIFINDEX, &ifr);
109
110        memset(&me, 0, sizeof(me));
111        me.sll_family = AF_PACKET;
112        me.sll_ifindex = ifr.ifr_ifindex;
113        me.sll_protocol = htons(ETH_P_LOOP);
114        xbind(s, (struct sockaddr*)&me, sizeof(me));
115
116        alen = sizeof(me);
117        if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
118                bb_perror_msg_and_die("getsockname");
119        }
120        close(s);
121        *htype = me.sll_hatype;
122        return me.sll_halen;
123}
124
125/* Exits on error */
126static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
127{
128        int alen;
129
130        memset(ifr, 0, sizeof(*ifr));
131        strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));
132        ifr->ifr_hwaddr.sa_family = hatype;
133        alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);
134        if (alen < 0)
135                exit(1);
136        if (alen != halen) {
137                bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
138        }
139}
140
141/* Exits on error */
142static void set_address(struct ifreq *ifr, int brd)
143{
144        int s;
145
146        s = get_ctl_fd();
147        if (brd)
148                xioctl(s, SIOCSIFHWBROADCAST, ifr);
149        else
150                xioctl(s, SIOCSIFHWADDR, ifr);
151        close(s);
152}
153
154
155static void die_must_be_on_off(const char *msg) ATTRIBUTE_NORETURN;
156static void die_must_be_on_off(const char *msg)
157{
158        bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
159}
160
161/* Return value becomes exitcode. It's okay to not return at all */
162static int do_set(char **argv)
163{
164        char *dev = NULL;
165        uint32_t mask = 0;
166        uint32_t flags = 0;
167        int qlen = -1;
168        int mtu = -1;
169        char *newaddr = NULL;
170        char *newbrd = NULL;
171        struct ifreq ifr0, ifr1;
172        char *newname = NULL;
173        int htype, halen;
174        static const char keywords[] ALIGN1 =
175                "up\0""down\0""name\0""mtu\0""multicast\0""arp\0""addr\0""dev\0";
176        enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast, ARG_arp,
177                ARG_addr, ARG_dev };
178        static const char str_on_off[] ALIGN1 = "on\0""off\0";
179        enum { PARM_on = 0, PARM_off };
180        smalluint key;
181
182        while (*argv) {
183                key = index_in_strings(keywords, *argv);
184                if (key == ARG_up) {
185                        mask |= IFF_UP;
186                        flags |= IFF_UP;
187                }
188                if (key == ARG_down) {
189                        mask |= IFF_UP;
190                        flags &= ~IFF_UP;
191                }
192                if (key == ARG_name) {
193                        NEXT_ARG();
194                        newname = *argv;
195                }
196                if (key == ARG_mtu) {
197                        NEXT_ARG();
198                        if (mtu != -1)
199                                duparg("mtu", *argv);
200                        if (get_integer(&mtu, *argv, 0))
201                                invarg(*argv, "mtu");
202                }
203                if (key == ARG_multicast) {
204                        int param;
205                        NEXT_ARG();
206                        mask |= IFF_MULTICAST;
207                        param = index_in_strings(str_on_off, *argv);
208                        if (param < 0)
209                                die_must_be_on_off("multicast");
210                        if (param == PARM_on)
211                                flags |= IFF_MULTICAST;
212                        else
213                                flags &= ~IFF_MULTICAST;
214                }
215                if (key == ARG_arp) {
216                        int param;
217                        NEXT_ARG();
218                        mask |= IFF_NOARP;
219                        param = index_in_strings(str_on_off, *argv);
220                        if (param < 0)
221                                die_must_be_on_off("arp");
222                        if (param == PARM_on)
223                                flags &= ~IFF_NOARP;
224                        else
225                                flags |= IFF_NOARP;
226                }
227                if (key == ARG_addr) {
228                        NEXT_ARG();
229                        newaddr = *argv;
230                }
231                if (key >= ARG_dev) {
232                        if (key == ARG_dev) {
233                                NEXT_ARG();
234                        }
235                        if (dev)
236                                duparg2("dev", *argv);
237                        dev = *argv;
238                }
239                argv++;
240        }
241
242        if (!dev) {
243                bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
244        }
245
246        if (newaddr || newbrd) {
247                halen = get_address(dev, &htype);
248                if (newaddr) {
249                        parse_address(dev, htype, halen, newaddr, &ifr0);
250                }
251                if (newbrd) {
252                        parse_address(dev, htype, halen, newbrd, &ifr1);
253                }
254        }
255
256        if (newname && strcmp(dev, newname)) {
257                do_changename(dev, newname);
258                dev = newname;
259        }
260        if (qlen != -1) {
261                set_qlen(dev, qlen);
262        }
263        if (mtu != -1) {
264                set_mtu(dev, mtu);
265        }
266        if (newaddr || newbrd) {
267                if (newbrd) {
268                        set_address(&ifr1, 1);
269                }
270                if (newaddr) {
271                        set_address(&ifr0, 0);
272                }
273        }
274        if (mask)
275                do_chflags(dev, flags, mask);
276        return 0;
277}
278
279static int ipaddr_list_link(char **argv)
280{
281        preferred_family = AF_PACKET;
282        return ipaddr_list_or_flush(argv, 0);
283}
284
285/* Return value becomes exitcode. It's okay to not return at all */
286int do_iplink(char **argv)
287{
288        static const char keywords[] ALIGN1 =
289                "set\0""show\0""lst\0""list\0";
290        int key;
291        if (!*argv)
292                return ipaddr_list_link(argv);
293        key = index_in_substrings(keywords, *argv);
294        if (key < 0)
295                bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
296        argv++;
297        if (key == 0) /* set */
298                return do_set(argv);
299        /* show, lst, list */
300        return ipaddr_list_link(argv);
301}
Note: See TracBrowser for help on using the repository browser.