xref: /haiku/src/kits/network/libnetapi/NetworkInterface.cpp (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
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 
18 static int
family_from_interface_address(const BNetworkInterfaceAddress & address)19 family_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 
32 static status_t
do_ifaliasreq(const char * name,int32 option,BNetworkInterfaceAddress & address,bool readBack=false)33 do_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 
70 static status_t
do_ifaliasreq(const char * name,int32 option,const BNetworkInterfaceAddress & address)71 do_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 
79 template<typename T> status_t
do_request(int family,T & request,const char * name,int option)80 do_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 
BNetworkInterfaceAddress()98 BNetworkInterfaceAddress::BNetworkInterfaceAddress()
99 	:
100 	fIndex(-1),
101 	fFlags(0)
102 {
103 }
104 
105 
~BNetworkInterfaceAddress()106 BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
107 {
108 }
109 
110 
111 status_t
SetTo(const BNetworkInterface & interface,int32 index)112 BNetworkInterfaceAddress::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 
119 void
SetAddress(const BNetworkAddress & address)120 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address)
121 {
122 	fAddress = address;
123 }
124 
125 
126 void
SetMask(const BNetworkAddress & mask)127 BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask)
128 {
129 	fMask = mask;
130 }
131 
132 
133 void
SetBroadcast(const BNetworkAddress & broadcast)134 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast)
135 {
136 	fBroadcast = broadcast;
137 }
138 
139 
140 void
SetDestination(const BNetworkAddress & destination)141 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination)
142 {
143 	fBroadcast = destination;
144 }
145 
146 
147 void
SetFlags(uint32 flags)148 BNetworkInterfaceAddress::SetFlags(uint32 flags)
149 {
150 	fFlags = flags;
151 }
152 
153 
154 // #pragma mark -
155 
156 
BNetworkInterface()157 BNetworkInterface::BNetworkInterface()
158 {
159 	Unset();
160 }
161 
162 
BNetworkInterface(const char * name)163 BNetworkInterface::BNetworkInterface(const char* name)
164 {
165 	SetTo(name);
166 }
167 
168 
BNetworkInterface(uint32 index)169 BNetworkInterface::BNetworkInterface(uint32 index)
170 {
171 	SetTo(index);
172 }
173 
174 
~BNetworkInterface()175 BNetworkInterface::~BNetworkInterface()
176 {
177 }
178 
179 
180 void
Unset()181 BNetworkInterface::Unset()
182 {
183 	fName[0] = '\0';
184 }
185 
186 
187 void
SetTo(const char * name)188 BNetworkInterface::SetTo(const char* name)
189 {
190 	strlcpy(fName, name, IF_NAMESIZE);
191 }
192 
193 
194 status_t
SetTo(uint32 index)195 BNetworkInterface::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 
209 bool
Exists() const210 BNetworkInterface::Exists() const
211 {
212 	ifreq request;
213 	return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK;
214 }
215 
216 
217 const char*
Name() const218 BNetworkInterface::Name() const
219 {
220 	return fName;
221 }
222 
223 
224 uint32
Index() const225 BNetworkInterface::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 
235 uint32
Flags() const236 BNetworkInterface::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 
246 uint32
MTU() const247 BNetworkInterface::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 
257 int32
Media() const258 BNetworkInterface::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 
268 uint32
Metric() const269 BNetworkInterface::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 
279 uint32
Type() const280 BNetworkInterface::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 
290 status_t
GetStats(ifreq_stats & stats)291 BNetworkInterface::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 
303 bool
HasLink() const304 BNetworkInterface::HasLink() const
305 {
306 	return (Flags() & IFF_LINK) != 0;
307 }
308 
309 
310 status_t
SetFlags(uint32 flags)311 BNetworkInterface::SetFlags(uint32 flags)
312 {
313 	ifreq request;
314 	request.ifr_flags = flags;
315 	return do_request(AF_INET, request, Name(), SIOCSIFFLAGS);
316 }
317 
318 
319 status_t
SetMTU(uint32 mtu)320 BNetworkInterface::SetMTU(uint32 mtu)
321 {
322 	ifreq request;
323 	request.ifr_mtu = mtu;
324 	return do_request(AF_INET, request, Name(), SIOCSIFMTU);
325 }
326 
327 
328 status_t
SetMedia(int32 media)329 BNetworkInterface::SetMedia(int32 media)
330 {
331 	ifreq request;
332 	request.ifr_media = media;
333 	return do_request(AF_INET, request, Name(), SIOCSIFMEDIA);
334 }
335 
336 
337 status_t
SetMetric(uint32 metric)338 BNetworkInterface::SetMetric(uint32 metric)
339 {
340 	ifreq request;
341 	request.ifr_metric = metric;
342 	return do_request(AF_INET, request, Name(), SIOCSIFMETRIC);
343 }
344 
345 
346 int32
CountAddresses() const347 BNetworkInterface::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 
357 status_t
GetAddressAt(int32 index,BNetworkInterfaceAddress & address)358 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
359 {
360 	return address.SetTo(*this, index);
361 }
362 
363 
364 int32
FindAddress(const BNetworkAddress & address)365 BNetworkInterface::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 
387 int32
FindFirstAddress(int family)388 BNetworkInterface::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 
410 status_t
AddAddress(const BNetworkInterfaceAddress & address)411 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
412 {
413 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
414 }
415 
416 
417 status_t
AddAddress(const BNetworkAddress & local)418 BNetworkInterface::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 
427 status_t
SetAddress(const BNetworkInterfaceAddress & address)428 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
429 {
430 	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
431 }
432 
433 
434 status_t
RemoveAddress(const BNetworkInterfaceAddress & address)435 BNetworkInterface::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 
446 status_t
RemoveAddress(const BNetworkAddress & address)447 BNetworkInterface::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 
456 status_t
RemoveAddressAt(int32 index)457 BNetworkInterface::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 
468 status_t
GetHardwareAddress(BNetworkAddress & address)469 BNetworkInterface::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 
486 status_t
AddRoute(const BNetworkRoute & route)487 BNetworkInterface::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 
499 status_t
AddDefaultRoute(const BNetworkAddress & gateway)500 BNetworkInterface::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 
512 status_t
RemoveRoute(const BNetworkRoute & route)513 BNetworkInterface::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 
523 status_t
RemoveRoute(int family,const BNetworkRoute & route)524 BNetworkInterface::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 
532 status_t
RemoveDefaultRoute(int family)533 BNetworkInterface::RemoveDefaultRoute(int family)
534 {
535 	BNetworkRoute route;
536 	route.SetFlags(RTF_STATIC | RTF_DEFAULT);
537 	return RemoveRoute(family, route);
538 }
539 
540 
541 status_t
GetRoutes(int family,BObjectList<BNetworkRoute> & routes) const542 BNetworkInterface::GetRoutes(int family,
543 	BObjectList<BNetworkRoute>& routes) const
544 {
545 	return BNetworkRoute::GetRoutes(family, Name(), routes);
546 }
547 
548 
549 status_t
GetDefaultRoute(int family,BNetworkRoute & route) const550 BNetworkInterface::GetDefaultRoute(int family, BNetworkRoute& route) const
551 {
552 	return BNetworkRoute::GetDefaultRoute(family, Name(), route);
553 }
554 
555 
556 status_t
GetDefaultGateway(int family,BNetworkAddress & gateway) const557 BNetworkInterface::GetDefaultGateway(int family, BNetworkAddress& gateway) const
558 {
559 	return BNetworkRoute::GetDefaultGateway(family, Name(), gateway);
560 }
561 
562 
563 status_t
AutoConfigure(int family)564 BNetworkInterface::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