1/*
2 * Copyright 2010, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <NetworkRoster.h>
8
9#include <errno.h>
10#include <sys/sockio.h>
11
12#include <NetworkDevice.h>
13#include <NetworkInterface.h>
14
15#include <net_notifications.h>
16#include <AutoDeleter.h>
17#include <NetServer.h>
18
19
20// TODO: using AF_INET for the socket isn't really a smart idea, as one
21// could completely remove IPv4 support from the stack easily.
22// Since in the stack, device_interfaces are pretty much interfaces now, we
23// could get rid of them more or less, and make AF_LINK provide the same
24// information as AF_INET for the interface functions mostly.
25
26
27BNetworkRoster BNetworkRoster::sDefault;
28
29
30/*static*/ BNetworkRoster&
31BNetworkRoster::Default()
32{
33	return sDefault;
34}
35
36
37size_t
38BNetworkRoster::CountInterfaces() const
39{
40	FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
41	if (!socket.IsSet())
42		return 0;
43
44	ifconf config;
45	config.ifc_len = sizeof(config.ifc_value);
46	if (ioctl(socket.Get(), SIOCGIFCOUNT, &config, sizeof(struct ifconf)) != 0)
47		return 0;
48
49	return (size_t)config.ifc_value;
50}
51
52
53status_t
54BNetworkRoster::GetNextInterface(uint32* cookie,
55	BNetworkInterface& interface) const
56{
57	// TODO: think about caching the interfaces!
58
59	if (cookie == NULL)
60		return B_BAD_VALUE;
61
62	// get a list of all interfaces
63
64	FileDescriptorCloser socket (::socket(AF_INET, SOCK_DGRAM, 0));
65	if (!socket.IsSet())
66		return errno;
67
68	ifconf config;
69	config.ifc_len = sizeof(config.ifc_value);
70	if (ioctl(socket.Get(), SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
71		return errno;
72
73	size_t count = (size_t)config.ifc_value;
74	if (count == 0)
75		return B_BAD_VALUE;
76
77	char* buffer = (char*)malloc(count * sizeof(struct ifreq));
78	if (buffer == NULL)
79		return B_NO_MEMORY;
80
81	MemoryDeleter deleter(buffer);
82
83	config.ifc_len = count * sizeof(struct ifreq);
84	config.ifc_buf = buffer;
85	if (ioctl(socket.Get(), SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
86		return errno;
87
88	ifreq* interfaces = (ifreq*)buffer;
89	ifreq* end = (ifreq*)(buffer + config.ifc_len);
90
91	for (uint32 i = 0; interfaces < end; i++) {
92		interface.SetTo(interfaces[0].ifr_name);
93		if (i == *cookie) {
94			(*cookie)++;
95			return B_OK;
96		}
97
98		interfaces = (ifreq*)((uint8*)interfaces
99			+ _SIZEOF_ADDR_IFREQ(interfaces[0]));
100	}
101
102	return B_BAD_VALUE;
103}
104
105
106status_t
107BNetworkRoster::AddInterface(const char* name)
108{
109	FileDescriptorCloser socket (::socket(AF_INET, SOCK_DGRAM, 0));
110	if (!socket.IsSet())
111		return errno;
112
113	ifaliasreq request;
114	memset(&request, 0, sizeof(ifaliasreq));
115	strlcpy(request.ifra_name, name, IF_NAMESIZE);
116
117	if (ioctl(socket.Get(), SIOCAIFADDR, &request, sizeof(request)) != 0)
118		return errno;
119
120	return B_OK;
121}
122
123
124status_t
125BNetworkRoster::AddInterface(const BNetworkInterface& interface)
126{
127	return AddInterface(interface.Name());
128}
129
130
131status_t
132BNetworkRoster::RemoveInterface(const char* name)
133{
134	FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
135	if (!socket.IsSet())
136		return errno;
137
138	ifreq request;
139	strlcpy(request.ifr_name, name, IF_NAMESIZE);
140
141	request.ifr_addr.sa_family = AF_UNSPEC;
142
143	if (ioctl(socket.Get(), SIOCDIFADDR, &request, sizeof(request)) != 0)
144		return errno;
145
146	return B_OK;
147}
148
149
150status_t
151BNetworkRoster::RemoveInterface(const BNetworkInterface& interface)
152{
153	return RemoveInterface(interface.Name());
154}
155
156
157int32
158BNetworkRoster::CountPersistentNetworks() const
159{
160	BMessenger networkServer(kNetServerSignature);
161	BMessage message(kMsgCountPersistentNetworks);
162	BMessage reply;
163	if (networkServer.SendMessage(&message, &reply) != B_OK)
164		return 0;
165
166	int32 count = 0;
167	if (reply.FindInt32("count", &count) != B_OK)
168		return 0;
169
170	return count;
171}
172
173
174status_t
175BNetworkRoster::GetNextPersistentNetwork(uint32* cookie,
176	wireless_network& network) const
177{
178	BMessenger networkServer(kNetServerSignature);
179	BMessage message(kMsgGetPersistentNetwork);
180	message.AddInt32("index", (int32)*cookie);
181
182	BMessage reply;
183	status_t result = networkServer.SendMessage(&message, &reply);
184	if (result != B_OK)
185		return result;
186
187	status_t status;
188	if (reply.FindInt32("status", &status) != B_OK)
189		return B_ERROR;
190	if (status != B_OK)
191		return status;
192
193	BMessage networkMessage;
194	if (reply.FindMessage("network", &networkMessage) != B_OK)
195		return B_ERROR;
196
197	BString networkName;
198	if (networkMessage.FindString("name", &networkName) != B_OK)
199		return B_ERROR;
200
201	memset(network.name, 0, sizeof(network.name));
202	strlcpy(network.name, networkName.String(), sizeof(network.name));
203
204	BNetworkAddress address;
205	if (networkMessage.FindFlat("address", &network.address) != B_OK)
206		network.address.Unset();
207
208	if (networkMessage.FindUInt32("flags", &network.flags) != B_OK)
209		network.flags = 0;
210
211	if (networkMessage.FindUInt32("authentication_mode",
212			&network.authentication_mode) != B_OK) {
213		network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
214	}
215
216	if (networkMessage.FindUInt32("cipher", &network.cipher) != B_OK)
217		network.cipher = B_NETWORK_CIPHER_NONE;
218
219	if (networkMessage.FindUInt32("group_cipher", &network.group_cipher)
220			!= B_OK) {
221		network.group_cipher = B_NETWORK_CIPHER_NONE;
222	}
223
224	if (networkMessage.FindUInt32("key_mode", &network.key_mode) != B_OK)
225		network.key_mode = B_KEY_MODE_NONE;
226
227	return B_OK;
228}
229
230
231status_t
232BNetworkRoster::AddPersistentNetwork(const wireless_network& network)
233{
234	BMessage message(kMsgAddPersistentNetwork);
235	BString networkName;
236	networkName.SetTo(network.name, sizeof(network.name));
237	status_t status = message.AddString("name", networkName);
238	if (status == B_OK) {
239		BNetworkAddress address = network.address;
240		status = message.AddFlat("address", &address);
241	}
242
243	if (status == B_OK)
244		status = message.AddUInt32("flags", network.flags);
245	if (status == B_OK) {
246		status = message.AddUInt32("authentication_mode",
247			network.authentication_mode);
248	}
249	if (status == B_OK)
250		status = message.AddUInt32("cipher", network.cipher);
251	if (status == B_OK)
252		status = message.AddUInt32("group_cipher", network.group_cipher);
253	if (status == B_OK)
254		status = message.AddUInt32("key_mode", network.key_mode);
255
256	if (status != B_OK)
257		return status;
258
259	BMessenger networkServer(kNetServerSignature);
260	BMessage reply;
261	status = networkServer.SendMessage(&message, &reply);
262	if (status == B_OK)
263		reply.FindInt32("status", &status);
264
265	return status;
266}
267
268
269status_t
270BNetworkRoster::RemovePersistentNetwork(const char* name)
271{
272	BMessage message(kMsgRemovePersistentNetwork);
273	status_t status = message.AddString("name", name);
274	if (status != B_OK)
275		return status;
276
277	BMessenger networkServer(kNetServerSignature);
278	BMessage reply;
279	status = networkServer.SendMessage(&message, &reply);
280	if (status == B_OK)
281		reply.FindInt32("status", &status);
282
283	return status;
284}
285
286
287status_t
288BNetworkRoster::StartWatching(const BMessenger& target, uint32 eventMask)
289{
290	return start_watching_network(eventMask, target);
291}
292
293
294void
295BNetworkRoster::StopWatching(const BMessenger& target)
296{
297	stop_watching_network(target);
298}
299
300
301// #pragma mark - private
302
303
304BNetworkRoster::BNetworkRoster()
305{
306}
307
308
309BNetworkRoster::~BNetworkRoster()
310{
311}
312