add chaos_calmer branch
[15.05/openwrt.git] / package / network / services / 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 #ifdef linux
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <dirent.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/socket.h>
30 #include <linux/if.h>
31 #include <linux/in6.h>
32 #include <linux/if_bridge.h>
33
34 #include "libbridge.h"
35 #include "libbridge_private.h"
36
37 static int br_socket_fd = -1;
38
39 int br_init(void)
40 {
41         if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
42                 return errno;
43         return 0;
44 }
45
46 void br_shutdown(void)
47 {
48         close(br_socket_fd);
49         br_socket_fd = -1;
50 }
51
52 /* If /sys/class/net/XXX/bridge exists then it must be a bridge */
53 static int isbridge(const struct dirent *entry)
54 {
55         char path[SYSFS_PATH_MAX];
56         struct stat st;
57
58         snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", entry->d_name);
59         return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
60 }
61
62 /*
63  * New interface uses sysfs to find bridges
64  */
65 static int new_foreach_bridge(int (*iterator)(const char *name, void *),
66                               void *arg)
67 {
68         struct dirent **namelist;
69         int i, count = 0;
70
71         count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
72         if (count < 0)
73                 return -1;
74
75         for (i = 0; i < count; i++) {
76                 if (iterator(namelist[i]->d_name, arg))
77                         break;
78         }
79
80         for (i = 0; i < count; i++)
81                 free(namelist[i]);
82         free(namelist);
83
84         return count;
85 }
86
87 /*
88  * Go over all bridges and call iterator function.
89  * if iterator returns non-zero then stop.
90  */
91 int br_foreach_bridge(int (*iterator)(const char *, void *), void *arg)
92 {
93         return new_foreach_bridge(iterator, arg);
94 }
95
96 /*
97  * Iterate over all ports in bridge (using sysfs).
98  */
99 int br_foreach_port(const char *brname,
100                     int (*iterator)(const char *br, const char *port, void *arg),
101                     void *arg)
102 {
103         int i, count;
104         struct dirent **namelist;
105         char path[SYSFS_PATH_MAX];
106
107         snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
108         count = scandir(path, &namelist, 0, alphasort);
109
110         for (i = 0; i < count; i++) {
111                 if (namelist[i]->d_name[0] == '.'
112                     && (namelist[i]->d_name[1] == '\0'
113                         || (namelist[i]->d_name[1] == '.'
114                             && namelist[i]->d_name[2] == '\0')))
115                         continue;
116
117                 if (iterator(brname, namelist[i]->d_name, arg))
118                         break;
119         }
120         for (i = 0; i < count; i++)
121                 free(namelist[i]);
122         free(namelist);
123
124         return count;
125 }
126
127 #endif