Root/package/ead/src/libbridge_init.c

1/*
2 * Copyright (C) 2000 Lennert Buytenhek
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <errno.h>
23#include <string.h>
24#include <dirent.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27
28#include "libbridge.h"
29#include "libbridge_private.h"
30
31int br_socket_fd = -1;
32
33static int br_init(void)
34{
35    if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
36        return errno;
37    return 0;
38}
39
40static void br_shutdown(void)
41{
42    close(br_socket_fd);
43    br_socket_fd = -1;
44}
45
46/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
47static int isbridge(const struct dirent *entry)
48{
49    char path[SYSFS_PATH_MAX];
50    struct stat st;
51
52    snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", entry->d_name);
53    return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
54}
55
56/*
57 * New interface uses sysfs to find bridges
58 */
59static int new_foreach_bridge(int (*iterator)(const char *name, void *),
60                  void *arg)
61{
62    struct dirent **namelist;
63    int i, count = 0;
64
65    count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
66    if (count < 0)
67        return -1;
68
69    for (i = 0; i < count; i++) {
70        if (iterator(namelist[i]->d_name, arg))
71            break;
72    }
73
74    for (i = 0; i < count; i++)
75        free(namelist[i]);
76    free(namelist);
77
78    return count;
79}
80
81/*
82 * Old interface uses ioctl
83 */
84static int old_foreach_bridge(int (*iterator)(const char *, void *),
85                  void *iarg)
86{
87    int i, ret=0, num;
88    char ifname[IFNAMSIZ];
89    int ifindices[MAX_BRIDGES];
90    unsigned long args[3] = { BRCTL_GET_BRIDGES,
91                 (unsigned long)ifindices, MAX_BRIDGES };
92
93    num = ioctl(br_socket_fd, SIOCGIFBR, args);
94    if (num < 0) {
95        dprintf("Get bridge indices failed: %s\n",
96            strerror(errno));
97        return -errno;
98    }
99
100    for (i = 0; i < num; i++) {
101        if (!if_indextoname(ifindices[i], ifname)) {
102            dprintf("get find name for ifindex %d\n",
103                ifindices[i]);
104            return -errno;
105        }
106
107        ++ret;
108        if(iterator(ifname, iarg))
109            break;
110    }
111
112    return ret;
113
114}
115
116/*
117 * Go over all bridges and call iterator function.
118 * if iterator returns non-zero then stop.
119 */
120static int br_foreach_bridge(int (*iterator)(const char *, void *),
121             void *arg)
122{
123    int ret;
124
125    ret = new_foreach_bridge(iterator, arg);
126    if (ret <= 0)
127        ret = old_foreach_bridge(iterator, arg);
128
129    return ret;
130}
131
132/*
133 * Only used if sysfs is not available.
134 */
135static int old_foreach_port(const char *brname,
136                int (*iterator)(const char *br, const char *port,
137                        void *arg),
138                void *arg)
139{
140    int i, err, count;
141    struct ifreq ifr;
142    char ifname[IFNAMSIZ];
143    int ifindices[MAX_PORTS];
144    unsigned long args[4] = { BRCTL_GET_PORT_LIST,
145                  (unsigned long)ifindices, MAX_PORTS, 0 };
146
147    memset(ifindices, 0, sizeof(ifindices));
148    strncpy(ifr.ifr_name, brname, IFNAMSIZ);
149    ifr.ifr_data = (char *) &args;
150
151    err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
152    if (err < 0) {
153        dprintf("list ports for bridge:'%s' failed: %s\n",
154            brname, strerror(errno));
155        return -errno;
156    }
157
158    count = 0;
159    for (i = 0; i < MAX_PORTS; i++) {
160        if (!ifindices[i])
161            continue;
162
163        if (!if_indextoname(ifindices[i], ifname)) {
164            dprintf("can't find name for ifindex:%d\n",
165                ifindices[i]);
166            continue;
167        }
168
169        ++count;
170        if (iterator(brname, ifname, arg))
171            break;
172    }
173
174    return count;
175}
176
177/*
178 * Iterate over all ports in bridge (using sysfs).
179 */
180static int br_foreach_port(const char *brname,
181            int (*iterator)(const char *br, const char *port, void *arg),
182            void *arg)
183{
184    int i, count;
185    struct dirent **namelist;
186    char path[SYSFS_PATH_MAX];
187
188    snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
189    count = scandir(path, &namelist, 0, alphasort);
190    if (count < 0)
191        return old_foreach_port(brname, iterator, arg);
192
193    for (i = 0; i < count; i++) {
194        if (namelist[i]->d_name[0] == '.'
195            && (namelist[i]->d_name[1] == '\0'
196            || (namelist[i]->d_name[1] == '.'
197                && namelist[i]->d_name[2] == '\0')))
198            continue;
199
200        if (iterator(brname, namelist[i]->d_name, arg))
201            break;
202    }
203    for (i = 0; i < count; i++)
204        free(namelist[i]);
205    free(namelist);
206
207    return count;
208}
209

Archive Download this file



interactive