2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
6 #include <NetworkInterface.h>
10 #include <sys/sockio.h>
12 #include <AutoDeleter.h>
13 #include <Messenger.h>
14 #include <NetServer.h>
15 #include <NetworkRoute.h>
19 family_from_interface_address(const BNetworkInterfaceAddress
& address
)
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();
33 do_ifaliasreq(const char* name
, int32 option
, BNetworkInterfaceAddress
& address
,
34 bool readBack
= false)
38 family
= family_from_interface_address(address
);
40 int socket
= ::socket(family
, SOCK_DGRAM
, 0);
44 FileDescriptorCloser
closer(socket
);
47 strlcpy(request
.ifra_name
, name
, IF_NAMESIZE
);
48 request
.ifra_index
= address
.Index();
49 request
.ifra_flags
= address
.Flags();
51 memcpy(&request
.ifra_addr
, &address
.Address().SockAddr(),
52 address
.Address().Length());
53 memcpy(&request
.ifra_mask
, &address
.Mask().SockAddr(),
54 address
.Mask().Length());
55 memcpy(&request
.ifra_broadaddr
, &address
.Broadcast().SockAddr(),
56 address
.Broadcast().Length());
58 if (ioctl(socket
, option
, &request
, sizeof(struct ifaliasreq
)) < 0)
62 address
.SetFlags(request
.ifra_flags
);
63 address
.Address().SetTo(request
.ifra_addr
);
64 address
.Mask().SetTo(request
.ifra_mask
);
65 address
.Broadcast().SetTo(request
.ifra_broadaddr
);
73 do_ifaliasreq(const char* name
, int32 option
,
74 const BNetworkInterfaceAddress
& address
)
76 return do_ifaliasreq(name
, option
,
77 const_cast<BNetworkInterfaceAddress
&>(address
));
81 template<typename T
> status_t
82 do_request(int family
, T
& request
, const char* name
, int option
)
84 int socket
= ::socket(family
, SOCK_DGRAM
, 0);
88 FileDescriptorCloser
closer(socket
);
90 strlcpy(((struct ifreq
&)request
).ifr_name
, name
, IF_NAMESIZE
);
92 if (ioctl(socket
, option
, &request
, sizeof(T
)) < 0)
102 BNetworkInterfaceAddress::BNetworkInterfaceAddress()
110 BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
116 BNetworkInterfaceAddress::SetTo(const BNetworkInterface
& interface
, int32 index
)
119 return do_ifaliasreq(interface
.Name(), B_SOCKET_GET_ALIAS
, *this, true);
124 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress
& address
)
131 BNetworkInterfaceAddress::SetMask(const BNetworkAddress
& mask
)
138 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress
& broadcast
)
140 fBroadcast
= broadcast
;
145 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress
& destination
)
147 fBroadcast
= destination
;
152 BNetworkInterfaceAddress::SetFlags(uint32 flags
)
161 BNetworkInterface::BNetworkInterface()
167 BNetworkInterface::BNetworkInterface(const char* name
)
173 BNetworkInterface::BNetworkInterface(uint32 index
)
179 BNetworkInterface::~BNetworkInterface()
185 BNetworkInterface::Unset()
192 BNetworkInterface::SetTo(const char* name
)
194 strlcpy(fName
, name
, IF_NAMESIZE
);
199 BNetworkInterface::SetTo(uint32 index
)
202 request
.ifr_index
= index
;
204 status_t status
= do_request(AF_INET
, request
, "", SIOCGIFNAME
);
208 strlcpy(fName
, request
.ifr_name
, IF_NAMESIZE
);
214 BNetworkInterface::Exists() const
217 return do_request(AF_INET
, request
, Name(), SIOCGIFINDEX
) == B_OK
;
222 BNetworkInterface::Name() const
229 BNetworkInterface::Index() const
232 if (do_request(AF_INET
, request
, Name(), SIOCGIFINDEX
) != B_OK
)
235 return request
.ifr_index
;
240 BNetworkInterface::Flags() const
243 if (do_request(AF_INET
, request
, Name(), SIOCGIFFLAGS
) != B_OK
)
246 return request
.ifr_flags
;
251 BNetworkInterface::MTU() const
254 if (do_request(AF_INET
, request
, Name(), SIOCGIFMTU
) != B_OK
)
257 return request
.ifr_mtu
;
262 BNetworkInterface::Media() const
265 request
.ifm_count
= 0;
266 request
.ifm_ulist
= NULL
;
268 if (do_request(AF_INET
, request
, Name(), SIOCGIFMEDIA
) != B_OK
)
271 return request
.ifm_current
;
276 BNetworkInterface::Metric() const
279 if (do_request(AF_INET
, request
, Name(), SIOCGIFMETRIC
) != B_OK
)
282 return request
.ifr_metric
;
287 BNetworkInterface::Type() const
290 if (do_request(AF_INET
, request
, Name(), SIOCGIFTYPE
) != B_OK
)
293 return request
.ifr_type
;
298 BNetworkInterface::GetStats(ifreq_stats
& stats
)
301 status_t status
= do_request(AF_INET
, request
, Name(), SIOCGIFSTATS
);
305 memcpy(&stats
, &request
.ifr_stats
, sizeof(ifreq_stats
));
311 BNetworkInterface::HasLink() const
313 return (Flags() & IFF_LINK
) != 0;
318 BNetworkInterface::SetFlags(uint32 flags
)
321 request
.ifr_flags
= flags
;
322 return do_request(AF_INET
, request
, Name(), SIOCSIFFLAGS
);
327 BNetworkInterface::SetMTU(uint32 mtu
)
330 request
.ifr_mtu
= mtu
;
331 return do_request(AF_INET
, request
, Name(), SIOCSIFMTU
);
336 BNetworkInterface::SetMedia(int32 media
)
339 request
.ifr_media
= media
;
340 return do_request(AF_INET
, request
, Name(), SIOCSIFMEDIA
);
345 BNetworkInterface::SetMetric(uint32 metric
)
348 request
.ifr_metric
= metric
;
349 return do_request(AF_INET
, request
, Name(), SIOCSIFMETRIC
);
354 BNetworkInterface::CountAddresses() const
357 if (do_request(AF_INET
, request
, Name(), B_SOCKET_COUNT_ALIASES
) != B_OK
)
360 return request
.ifr_count
;
365 BNetworkInterface::GetAddressAt(int32 index
, BNetworkInterfaceAddress
& address
)
367 return address
.SetTo(*this, index
);
372 BNetworkInterface::FindAddress(const BNetworkAddress
& address
)
374 int socket
= ::socket(address
.Family(), SOCK_DGRAM
, 0);
378 FileDescriptorCloser
closer(socket
);
381 memset(&request
, 0, sizeof(ifaliasreq
));
383 strlcpy(request
.ifra_name
, Name(), IF_NAMESIZE
);
384 request
.ifra_index
= -1;
385 memcpy(&request
.ifra_addr
, &address
.SockAddr(), address
.Length());
387 if (ioctl(socket
, B_SOCKET_GET_ALIAS
, &request
, sizeof(struct ifaliasreq
))
392 return request
.ifra_index
;
397 BNetworkInterface::FindFirstAddress(int family
)
399 int socket
= ::socket(family
, SOCK_DGRAM
, 0);
403 FileDescriptorCloser
closer(socket
);
406 memset(&request
, 0, sizeof(ifaliasreq
));
408 strlcpy(request
.ifra_name
, Name(), IF_NAMESIZE
);
409 request
.ifra_index
= -1;
410 request
.ifra_addr
.ss_family
= AF_UNSPEC
;
412 if (ioctl(socket
, B_SOCKET_GET_ALIAS
, &request
, sizeof(struct ifaliasreq
))
417 return request
.ifra_index
;
422 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress
& address
)
424 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS
, address
);
429 BNetworkInterface::AddAddress(const BNetworkAddress
& local
)
431 BNetworkInterfaceAddress address
;
432 address
.SetAddress(local
);
434 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS
, address
);
439 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress
& address
)
441 return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS
, address
);
446 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress
& address
)
449 memcpy(&request
.ifr_addr
, &address
.Address().SockAddr(),
450 address
.Address().Length());
452 return do_request(family_from_interface_address(address
), request
, Name(),
453 B_SOCKET_REMOVE_ALIAS
);
458 BNetworkInterface::RemoveAddress(const BNetworkAddress
& address
)
461 memcpy(&request
.ifr_addr
, &address
.SockAddr(), address
.Length());
463 return do_request(address
.Family(), request
, Name(), B_SOCKET_REMOVE_ALIAS
);
468 BNetworkInterface::RemoveAddressAt(int32 index
)
470 BNetworkInterfaceAddress address
;
471 status_t status
= GetAddressAt(index
, address
);
475 return RemoveAddress(address
);
480 BNetworkInterface::GetHardwareAddress(BNetworkAddress
& address
)
482 int socket
= ::socket(AF_LINK
, SOCK_DGRAM
, 0);
486 FileDescriptorCloser
closer(socket
);
489 strlcpy(request
.ifr_name
, Name(), IF_NAMESIZE
);
491 if (ioctl(socket
, SIOCGIFADDR
, &request
, sizeof(struct ifreq
)) < 0)
494 address
.SetTo(request
.ifr_addr
);
500 BNetworkInterface::AddRoute(const BNetworkRoute
& route
)
502 int family
= route
.AddressFamily();
503 if (family
== AF_UNSPEC
)
507 request
.ifr_route
= route
.RouteEntry();
508 return do_request(family
, request
, Name(), SIOCADDRT
);
513 BNetworkInterface::AddDefaultRoute(const BNetworkAddress
& gateway
)
516 status_t result
= route
.SetGateway(gateway
);
520 route
.SetFlags(RTF_STATIC
| RTF_DEFAULT
| RTF_GATEWAY
);
521 return AddRoute(route
);
526 BNetworkInterface::RemoveRoute(const BNetworkRoute
& route
)
528 int family
= route
.AddressFamily();
529 if (family
== AF_UNSPEC
)
532 return RemoveRoute(family
, route
);
537 BNetworkInterface::RemoveRoute(int family
, const BNetworkRoute
& route
)
540 request
.ifr_route
= route
.RouteEntry();
541 return do_request(family
, request
, Name(), SIOCDELRT
);
546 BNetworkInterface::RemoveDefaultRoute(int family
)
549 route
.SetFlags(RTF_STATIC
| RTF_DEFAULT
);
550 return RemoveRoute(family
, route
);
555 BNetworkInterface::GetRoutes(int family
,
556 BObjectList
<BNetworkRoute
>& routes
) const
558 return BNetworkRoute::GetRoutes(family
, Name(), routes
);
563 BNetworkInterface::GetDefaultRoute(int family
, BNetworkRoute
& route
) const
565 return BNetworkRoute::GetDefaultRoute(family
, Name(), route
);
570 BNetworkInterface::GetDefaultGateway(int family
, BNetworkAddress
& gateway
) const
572 return BNetworkRoute::GetDefaultGateway(family
, Name(), gateway
);
577 BNetworkInterface::AutoConfigure(int family
)
579 BMessage
message(kMsgConfigureInterface
);
580 message
.AddString("device", Name());
583 address
.AddInt32("family", family
);
584 address
.AddBool("auto_config", true);
585 message
.AddMessage("address", &address
);
587 BMessenger
networkServer(kNetServerSignature
);
589 status_t status
= networkServer
.SendMessage(&message
, &reply
);
591 reply
.FindInt32("status", &status
);