1/*
2 * Copyright 2010, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <NetworkInterface.h>
7
8#include <errno.h>
9#include <net/if.h>
10#include <sys/sockio.h>
11
12#include <AutoDeleter.h>
13#include <Messenger.h>
14#include <NetServer.h>
15#include <NetworkRoute.h>
16
17
18static int
19family_from_interface_address(const BNetworkInterfaceAddress& address)
20{
21	if (address.Address().Family() != AF_UNSPEC)
22		return address.Address().Family();
23	if (address.Mask().Family() != AF_UNSPEC)
24		return address.Mask().Family();
25	if (address.Destination().Family() != AF_UNSPEC)
26		return address.Destination().Family();
27
28	return AF_INET;
29}
30
31
32static status_t
33do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
34	bool readBack = false)
35{
36	int family = AF_INET;
37	if (!readBack)
38		family = family_from_interface_address(address);
39
40	FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0));
41	if (!socket.IsSet())
42		return errno;
43
44	ifaliasreq request;
45	strlcpy(request.ifra_name, name, IF_NAMESIZE);
46	request.ifra_index = address.Index();
47	request.ifra_flags = address.Flags();
48
49	memcpy(&request.ifra_addr, &address.Address().SockAddr(),
50		address.Address().Length());
51	memcpy(&request.ifra_mask, &address.Mask().SockAddr(),
52		address.Mask().Length());
53	memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(),
54		address.Broadcast().Length());
55
56	if (ioctl(socket.Get(), option, &request, sizeof(struct ifaliasreq)) < 0)
57		return errno;
58
59	if (readBack) {
60		address.SetFlags(request.ifra_flags);
61		address.Address().SetTo(request.ifra_addr);
62		address.Mask().SetTo(request.ifra_mask);
63		address.Broadcast().SetTo(request.ifra_broadaddr);
64	}
65
66	return B_OK;
67}
68
69
70static status_t
71do_ifaliasreq(const char* name, int32 option,
72	const BNetworkInterfaceAddress& address)
73{
74	return do_ifaliasreq(name, option,
75		const_cast<BNetworkInterfaceAddress&>(address));
76}
77
78
79template<typename T> status_t
80do_request(int family, T& request, const char* name, int option)
81{
82	FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0));
83	if (!socket.IsSet())
84		return errno;
85
86	strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE);
87
88	if (ioctl(socket.Get(), option, &request, sizeof(T)) < 0)
89		return errno;
90
91	return B_OK;
92}
93
94
95// #pragma mark -
96
97
98BNetworkInterfaceAddress::BNetworkInterfaceAddress()
99	:
100	fIndex(-1),
101	fFlags(0)
102{
103}
104
105
106BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
107{
108}
109
110
111status_t
112BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index)
113{
114	fIndex = index;
115	return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true);
116}
117
118
119void
120BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address)
121{
122	fAddress = address;
123}
124
125
126void
127BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask)
128{
129	fMask = mask;
130}
131
132
133void
134BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast)
135{
136	fBroadcast = broadcast;
137}
138
139
140void
141BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination)
142{
143	fBroadcast = destination;
144}
145
146
147void
148BNetworkInterfaceAddress::SetFlags(uint32 flags)
149{
150	fFlags = flags;
151}
152
153
154// #pragma mark -
155
156
157BNetworkInterface::BNetworkInterface()
158{
159	Unset();
160}
161
162
163BNetworkInterface::BNetworkInterface(const char* name)
164{
165	SetTo(name);
166}
167
168
169BNetworkInterface::BNetworkInterface(uint32 index)
170{
171	SetTo(index);
172}
173
174
175BNetworkInterface::~BNetworkInterface()
176{
177}
178
179
180void
181BNetworkInterface::Unset()
182{
183	fName[0] = '\0';
184}
185
186
187void
188BNetworkInterface::SetTo(const char* name)
189{
190	strlcpy(fName, name, IF_NAMESIZE);
191}
192
193
194status_t
195BNetworkInterface::SetTo(uint32 index)
196{
197	ifreq request;
198	request.ifr_index = index;
199
200	status_t status = do_request(AF_INET, request, "", SIOCGIFNAME);
201	if (status != B_OK)
202		return status;
203
204	strlcpy(fName, request.ifr_name, IF_NAMESIZE);
205	return B_OK;
206}
207
208
209bool
210BNetworkInterface::Exists() const
211{
212	ifreq request;
213	return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK;
214}
215
216
217const char*
218BNetworkInterface::Name() const
219{
220	return fName;
221}
222
223
224uint32
225BNetworkInterface::Index() const
226{
227	ifreq request;
228	if (do_request(AF_INET, request, Name(), SIOCGIFINDEX) != B_OK)
229		return 0;
230
231	return request.ifr_index;
232}
233
234
235uint32
236BNetworkInterface::Flags() const
237{
238	ifreq request;
239	if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK)
240		return 0;
241
242	return request.ifr_flags;
243}
244
245
246uint32
247BNetworkInterface::MTU() const
248{
249	ifreq request;
250	if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK)
251		return 0;
252
253	return request.ifr_mtu;
254}
255
256
257int32
258BNetworkInterface::Media() const
259{
260	ifreq request;
261	if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK)
262		return -1;
263
264	return request.ifr_media;
265}
266
267
268uint32
269BNetworkInterface::Metric() const
270{
271	ifreq request;
272	if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK)
273		return 0;
274
275	return request.ifr_metric;
276}
277
278
279uint32
280BNetworkInterface::Type() const
281{
282	ifreq request;
283	if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK)
284		return 0;
285
286	return request.ifr_type;
287}
288
289
290status_t
291BNetworkInterface::GetStats(ifreq_stats& stats)
292{
293	ifreq request;
294	status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS);
295	if (status != B_OK)
296		return status;
297
298	memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats));
299	return B_OK;
300}
301
302
303bool
304BNetworkInterface::HasLink() const
305{
306	return (Flags() & IFF_LINK) != 0;
307}
308
309
310status_t
311BNetworkInterface::SetFlags(uint32 flags)
312{
313	ifreq request;
314	request.ifr_flags = flags;
315	return do_request(AF_INET, request, Name(), SIOCSIFFLAGS);
316}
317
318
319status_t
320BNetworkInterface::SetMTU(uint32 mtu)
321{
322	ifreq request;
323	request.ifr_mtu = mtu;
324	return do_request(AF_INET, request, Name(), SIOCSIFMTU);
325}
326
327
328status_t
329BNetworkInterface::SetMedia(int32 media)
330{
331	ifreq request;
332	request.ifr_media = media;
333	return do_request(AF_INET, request, Name(), SIOCSIFMEDIA);
334}
335
336
337status_t
338BNetworkInterface::SetMetric(uint32 metric)
339{
340	ifreq request;
341	request.ifr_metric = metric;
342	return do_request(AF_INET, request, Name(), SIOCSIFMETRIC);
343}
344
345
346int32
347BNetworkInterface::CountAddresses() const
348{
349	ifreq request;
350	if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK)
351		return 0;
352
353	return request.ifr_count;
354}
355
356
357status_t
358BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
359{
360	return address.SetTo(*this, index);
361}
362
363
364int32
365BNetworkInterface::FindAddress(const BNetworkAddress& address)
366{
367	FileDescriptorCloser socket(::socket(address.Family(), SOCK_DGRAM, 0));
368	if (!socket.IsSet())
369		return -1;
370
371	ifaliasreq request;
372	memset(&request, 0, sizeof(ifaliasreq));
373
374	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
375	request.ifra_index = -1;
376	memcpy(&request.ifra_addr, &address.SockAddr(), address.Length());
377
378	if (ioctl(socket.Get(), B_SOCKET_GET_ALIAS, &request,
379		sizeof(struct ifaliasreq)) < 0) {
380		return -1;
381	}
382
383	return request.ifra_index;
384}
385
386
387int32
388BNetworkInterface::FindFirstAddress(int family)
389{
390	FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0));
391	if (!socket.IsSet())
392		return -1;
393
394	ifaliasreq request;
395	memset(&request, 0, sizeof(ifaliasreq));
396
397	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
398	request.ifra_index = -1;
399	request.ifra_addr.ss_family = AF_UNSPEC;
400
401	if (ioctl(socket.Get(), B_SOCKET_GET_ALIAS, &request,
402		sizeof(struct ifaliasreq)) < 0) {
403		return -1;
404	}
405
406	return request.ifra_index;
407}
408
409
410status_t
411BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
412{
413	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
414}
415
416
417status_t
418BNetworkInterface::AddAddress(const BNetworkAddress& local)
419{
420	BNetworkInterfaceAddress address;
421	address.SetAddress(local);
422
423	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
424}
425
426
427status_t
428BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
429{
430	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
431}
432
433
434status_t
435BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
436{
437	ifreq request;
438	memcpy(&request.ifr_addr, &address.Address().SockAddr(),
439		address.Address().Length());
440
441	return do_request(family_from_interface_address(address), request, Name(),
442		B_SOCKET_REMOVE_ALIAS);
443}
444
445
446status_t
447BNetworkInterface::RemoveAddress(const BNetworkAddress& address)
448{
449	ifreq request;
450	memcpy(&request.ifr_addr, &address.SockAddr(), address.Length());
451
452	return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS);
453}
454
455
456status_t
457BNetworkInterface::RemoveAddressAt(int32 index)
458{
459	BNetworkInterfaceAddress address;
460	status_t status = GetAddressAt(index, address);
461	if (status != B_OK)
462		return status;
463
464	return RemoveAddress(address);
465}
466
467
468status_t
469BNetworkInterface::GetHardwareAddress(BNetworkAddress& address)
470{
471	FileDescriptorCloser socket(::socket(AF_LINK, SOCK_DGRAM, 0));
472	if (!socket.IsSet())
473		return errno;
474
475	ifreq request;
476	strlcpy(request.ifr_name, Name(), IF_NAMESIZE);
477
478	if (ioctl(socket.Get(), SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0)
479		return errno;
480
481	address.SetTo(request.ifr_addr);
482	return B_OK;
483}
484
485
486status_t
487BNetworkInterface::AddRoute(const BNetworkRoute& route)
488{
489	int family = route.AddressFamily();
490	if (family == AF_UNSPEC)
491		return B_BAD_VALUE;
492
493	ifreq request;
494	request.ifr_route = route.RouteEntry();
495	return do_request(family, request, Name(), SIOCADDRT);
496}
497
498
499status_t
500BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway)
501{
502	BNetworkRoute route;
503	status_t result = route.SetGateway(gateway);
504	if (result != B_OK)
505		return result;
506
507	route.SetFlags(RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY);
508	return AddRoute(route);
509}
510
511
512status_t
513BNetworkInterface::RemoveRoute(const BNetworkRoute& route)
514{
515	int family = route.AddressFamily();
516	if (family == AF_UNSPEC)
517		return B_BAD_VALUE;
518
519	return RemoveRoute(family, route);
520}
521
522
523status_t
524BNetworkInterface::RemoveRoute(int family, const BNetworkRoute& route)
525{
526	ifreq request;
527	request.ifr_route = route.RouteEntry();
528	return do_request(family, request, Name(), SIOCDELRT);
529}
530
531
532status_t
533BNetworkInterface::RemoveDefaultRoute(int family)
534{
535	BNetworkRoute route;
536	route.SetFlags(RTF_STATIC | RTF_DEFAULT);
537	return RemoveRoute(family, route);
538}
539
540
541status_t
542BNetworkInterface::GetRoutes(int family,
543	BObjectList<BNetworkRoute>& routes) const
544{
545	return BNetworkRoute::GetRoutes(family, Name(), routes);
546}
547
548
549status_t
550BNetworkInterface::GetDefaultRoute(int family, BNetworkRoute& route) const
551{
552	return BNetworkRoute::GetDefaultRoute(family, Name(), route);
553}
554
555
556status_t
557BNetworkInterface::GetDefaultGateway(int family, BNetworkAddress& gateway) const
558{
559	return BNetworkRoute::GetDefaultGateway(family, Name(), gateway);
560}
561
562
563status_t
564BNetworkInterface::AutoConfigure(int family)
565{
566	BMessage message(kMsgConfigureInterface);
567	message.AddString("device", Name());
568
569	BMessage address;
570	address.AddInt32("family", family);
571	address.AddBool("auto_config", true);
572	message.AddMessage("address", &address);
573
574	BMessenger networkServer(kNetServerSignature);
575	BMessage reply;
576	status_t status = networkServer.SendMessage(&message, &reply);
577	if (status == B_OK)
578		reply.FindInt32("status", &status);
579
580	return status;
581}
582