1/*
2 * $Id: libbridge_init.c,v 1.1.1.1 2008/10/15 03:28:31 james26_jang Exp $
3 *
4 * Copyright (C) 2000 Lennert Buytenhek
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <errno.h>
24#include <sys/fcntl.h>
25#include <sys/ioctl.h>
26#include <sys/time.h>
27#include "libbridge.h"
28#include "libbridge_private.h"
29
30int br_socket_fd;
31struct bridge *bridge_list;
32
33static void __bridge_info_copy(struct bridge_info *info, struct __bridge_info *i)
34{
35	memcpy(&info->designated_root, &i->designated_root, 8);
36	memcpy(&info->bridge_id, &i->bridge_id, 8);
37	info->root_path_cost = i->root_path_cost;
38	info->topology_change = i->topology_change;
39	info->topology_change_detected = i->topology_change_detected;
40	info->root_port = i->root_port;
41	info->stp_enabled = i->stp_enabled;
42	__jiffies_to_tv(&info->max_age, i->max_age);
43	__jiffies_to_tv(&info->hello_time, i->hello_time);
44	__jiffies_to_tv(&info->forward_delay, i->forward_delay);
45	__jiffies_to_tv(&info->bridge_max_age, i->bridge_max_age);
46	__jiffies_to_tv(&info->bridge_hello_time, i->bridge_hello_time);
47	__jiffies_to_tv(&info->bridge_forward_delay, i->bridge_forward_delay);
48	__jiffies_to_tv(&info->ageing_time, i->ageing_time);
49	__jiffies_to_tv(&info->gc_interval, i->gc_interval);
50	__jiffies_to_tv(&info->hello_timer_value, i->hello_timer_value);
51	__jiffies_to_tv(&info->tcn_timer_value, i->tcn_timer_value);
52	__jiffies_to_tv(&info->topology_change_timer_value,
53			i->topology_change_timer_value);
54	__jiffies_to_tv(&info->gc_timer_value, i->gc_timer_value);
55}
56
57static void __port_info_copy(struct port_info *info, struct __port_info *i)
58{
59	memcpy(&info->designated_root, &i->designated_root, 8);
60	memcpy(&info->designated_bridge, &i->designated_bridge, 8);
61	info->port_id = i->port_id;
62	info->designated_port = i->designated_port;
63	info->path_cost = i->path_cost;
64	info->designated_cost = i->designated_cost;
65	info->state = i->state;
66	info->top_change_ack = i->top_change_ack;
67	info->config_pending = i->config_pending;
68	__jiffies_to_tv(&info->message_age_timer_value,
69			i->message_age_timer_value);
70	__jiffies_to_tv(&info->forward_delay_timer_value,
71			i->forward_delay_timer_value);
72	__jiffies_to_tv(&info->hold_timer_value,
73			i->hold_timer_value);
74}
75
76int br_read_info(struct bridge *br)
77{
78	struct __bridge_info i;
79
80	if (if_indextoname(br->ifindex, br->ifname) == NULL)
81		return 1;
82
83	if (br_device_ioctl(br, BRCTL_GET_BRIDGE_INFO,
84			    (unsigned long)&i, 0, 0) < 0)
85		return 1;
86
87	__bridge_info_copy(&br->info, &i);
88	return 0;
89}
90
91int br_read_port_info(struct port *p)
92{
93	struct __port_info i;
94
95	if (br_device_ioctl(p->parent, BRCTL_GET_PORT_INFO,
96			    (unsigned long)&i, p->index, 0) < 0)
97		return errno;
98
99	__port_info_copy(&p->info, &i);
100	return 0;
101}
102
103void br_nuke_bridge(struct bridge *b)
104{
105	struct port *p;
106
107	p = b->firstport;
108	while (p != NULL) {
109		struct port *pnext;
110
111		pnext = p->next;
112		free(p);
113		p = pnext;
114	}
115
116	free(b);
117}
118
119int br_make_port_list(struct bridge *br)
120{
121	int err;
122	int i;
123	int ifindices[256];
124
125	if (br_device_ioctl(br, BRCTL_GET_PORT_LIST, (unsigned long)ifindices,
126			    0, 0) < 0)
127		return errno;
128
129	for (i=255;i>=0;i--) {
130		struct port *p;
131
132		if (!ifindices[i])
133			continue;
134
135		p = malloc(sizeof(struct port));
136		p->index = i;
137		p->ifindex = ifindices[i];
138		p->parent = br;
139		br->ports[i] = p;
140		p->next = br->firstport;
141		br->firstport = p;
142		if ((err = br_read_port_info(p)) != 0)
143			goto error_out;
144	}
145
146	return 0;
147
148 error_out:
149	while (++i < 256)
150		free(br->ports[i]);
151
152	return err;
153}
154
155int br_make_bridge_list()
156{
157	int err;
158	int i;
159	int ifindices[32];
160	int num;
161
162	num = br_ioctl(BRCTL_GET_BRIDGES, (unsigned long)ifindices, 32);
163	if (num < 0)
164		return errno;
165
166	bridge_list = NULL;
167	for (i=0;i<num;i++) {
168		struct bridge *br;
169
170		br = malloc(sizeof(struct bridge));
171		memset(br, 0, sizeof(struct bridge));
172		br->ifindex = ifindices[i];
173		br->firstport = NULL;
174		br->next = bridge_list;
175		bridge_list = br;
176		if ((err = br_read_info(br)) != 0)
177			goto error_out;
178		if ((err = br_make_port_list(br)) != 0)
179			goto error_out;
180	}
181
182	return 0;
183
184 error_out:
185	while (bridge_list != NULL) {
186		struct bridge *nxt;
187
188		nxt = bridge_list->next;
189		br_nuke_bridge(bridge_list);
190		bridge_list = nxt;
191	}
192
193	return err;
194}
195
196int br_init()
197{
198	int err;
199
200	if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
201		return errno;
202
203	if (br_get_version() != BRCTL_VERSION)
204		return 12345;
205
206	if ((err = br_make_bridge_list()) != 0)
207		return err;
208
209	return 0;
210}
211
212int br_refresh()
213{
214	struct bridge *b;
215
216	b = bridge_list;
217	while (b != NULL) {
218		struct bridge *bnext;
219
220		bnext = b->next;
221		br_nuke_bridge(b);
222		b = bnext;
223	}
224
225	return br_make_bridge_list();
226}
227